Как стать автором
Обновить

Комментарии 76

По сути ссылками на исходники ты анонсировал утилиту, которую не хочешь пока анонсировать?=)
dklab_realsync?
Она описывалась автором на Хабре: habrahabr.ru/post/139348/
☃­
Я ею пользовался с тех самых пор около полугода, пока она вдруг не перестала работать через rsync по неясным мне причинам — запускалась где-то раза с пятого. Пришлось даже осилить Perl, чтобы заменить rsync на robocopy — настолько я привык к автоматической синхронизации изменений :) А затем я вдруг узнал, что моя IDE умеет делать такое «искаропки» :)
Вы все-все ссылки на исходники открывали? =) realsync-ом и я пользуюсь уже давно.
как тяжела участь Dropbox и подобных программ, которым требуется со всем этим уживаться
В питоне же вроде был платформонезависимый интерфейс для слежения за файлами?

И да: почему пример для Windows — на C++, а для остальных ОС — на C? И что вы имеете в виду под «простейшей реализацией», что должны уметь? В той же версии для MacOs я не увидел никаких проверок на ошибки инициализации, коих полно в linux-версии. И гугл находит более простые версии для работы с inotify
В питоне же вроде был платформонезависимый интерфейс для слежения за файлами?

Честно скажу — я не пользовался этим API. В любом случае, любые платформонезависимые интерфейсы будут всё равно пользоваться описанными мной API с соответствующими недостатками.
И да: почему пример для Windows — на C++, а для остальных ОС — на C?

Несмотря на расширение cpp, для windows код тоже на чистом Си.
И что вы имеете в виду под «простейшей реализацией», что должны уметь?

Непрерывно уведомлять обо всех изменениях содержимого файлов в отслеживаемой директории, с изменениями во всех вложенных директориях.
В той же версии для MacOs я не увидел никаких проверок на ошибки инициализации

Согласен, но это добавит ещё строк 10 к реализации. Остальное необходимо для реализации рекурсивного отслеживания за директорией.

И гугл находит более простые версии для работы с inotify

Вы уверены, что они позволяют рекурсивно отслеживать изменения в директории, не пропуская при этом события?
Вы уверены, что они позволяют рекурсивно отслеживать изменения в директории, не пропуская при этом события?

Самому стало интересно, сейчас более подробно посмотрю и отпишусь :)
Цитата из мана ( linux.die.net/man/1/inotifywatch ):

Bugs

There are race conditions in the recursive directory watching code which can cause events to be missed if they occur in a directory immediately after that directory is created. This is probably not fixable.
It is assumed the inotify event queue will never overflow.


Такая реализация вообще никуда не годится, уж извините.
This is probably not fixable.

Те есть просканировать директорию после начала слежения разработчики догадываются не могут…
Вообще они странные ребята, если честно… Почему они ничего не делают в случае переполнения очереди тоже не очень понятно. Ну и строки в исходниках немного странноватые:
fprintf(stderr, "Inotify reported end-of-file.  Possibly too many "
		                "events occurred at once.\n"); // что значит "possibly"..? что мешало заглянуть в документацию?
...
niceassert( first_byte <= bytes, "ridiculously long filename, things will "
	                                 "almost certainly screw up." );
...
niceassert( (long)((char *)&event[0] +
			            sizeof(struct inotify_event) +
			            event[0].len) <= (long)ret,
			            "extremely unlucky user, death imminent" );


Поэтому я решил написать свою версию, которая не будет иметь зависимостей и будет работать адекватно в случае проблем :).
Dropbox на Linux использует inotify. Вот, например.
НЛО прилетело и опубликовало эту надпись здесь
Ну и ссылку на сам класс приложу: QFileSystemWatcher.
Увы, но QFileSystemWatcher только сообщает о факте изменения файла/директории, а вот уточнять не хочет. Если нужно получать имена создаваемых файлов, стандартные средства Qt не работают :(
FSEvents предоствляет изменения по файлам начиная с OSX 10.7.
Спасибо, не знал, что в Lion уже появился соответствующий API. Сейчас обновлю статью.
НЛО прилетело и опубликовало эту надпись здесь
Я имел в виду API, а не возможности системы.
Пользоваться интерфейсом правильно в 100% случаев, поскольку даже минорные обновления операционной системы могут поломать ваше приложение.
НЛО прилетело и опубликовало эту надпись здесь
FSEvents оказались довольно неудачными.
Во-первых, при старте слежения «начиная с сейчас», может прислать события из прошлого.
Во-вторых, очень неудачно объединяет события. Часто из маски невозможно выяснить, в каком порядке произошли события. Например, файл был создан, а потом удалён, или наоборот.
И, наконец, до сих пор по этим «новым» флагам, добавленным в 10.7, нет никакой внятной документации, кроме простого перечня флагов.
Поэтому надо всё определять самим :)
Я в django проектах недавно начал пользоваться функционалом uwsgi еще и для слежения за изменениями в папке.
Может кому-то пригодится если проект деплоится через uwsgi тут документация.
Обрабатывает ли dklab_realsync случаи когда у одна файловая система case-preserving, case-insensitive а другая case-sensitive? Как на счёт Unicode normalization (NFC, NFD, Mac-NFD) у имён файлов? Как на счёт случая когда на одной машине одна файловая система case-sensitive, а в её сабдиректорию примонтирована case-insensitive.
Как на счёт точек в конце имени файла, или прочих символов — www.dropbox.com/help/145/en?
dklab_realsync не является конкурентом dropbox, потому что dklab_realsync осуществляет одностороннюю синхронизацию. Насколько я знаю, ответ на все ваши вопросы — нет, ничего из этого не учитывается. Это не должно представлять большой проблемы при целевом её использовании — синхронизации файлов в веб-проекте с локального компьютера на *nix-сервер.
Ну ок, а то я думал если поддерживает, то обменяться опытом, у меня тоже проект есть где важны имена файлов, думаю как это всё реализовать…
Вообще, только то что типичный случай здесь — веб разработка, оправдывает игнорировыние проблемы :)
То что синхронизация в одно сторону, и целевой сервер — *nix особо ничего не меняет.

Например если у нас есть директория public/München, в которой 1000 файлов,
он отправлена в git на линуксе, затем получена в git на MacOSX, затем с обоих машин происходит
синхронизация на веб сервер, то во первый Linux будет создавать директорию со строкой «M\x{fc}nchen», macosx будет создавать «Mu\x{308}nchen» (выглядит на экране часто как «Munchen»). При этом они это будут делать по-очереди, в результате будет DDoS.
Так же если сервер под Linux, он не найдёт «M\x{fc}nchen»

Кстати мой проект тоже на perl, опубликован здесь habrahabr.ru/post/150324/ но с именами файлов по большей части ничего почти не реализовано, пока.
DDoS не будет, потому что синхронизация тригается после локальных изменений, т.е. пройдёт две синхронизации — с OS X и Linux, и победит тот, кто был последним, или же у вас на сервере окажутся две директории — «M\x{fc}nchen» и «Mu\x{308}nchen».
В Windows на NTFS и ReFS ещё можно просматривать журнал USN, а там есть все последние операции с файлами.
Честно говоря, я не знаю, насколько realtime будут такие события, поэтому не стал об этом ничего писать. Но, возможно, этот API тоже может решить проблему потери событий.
Просмотр всего журнала довольно быстрая операция, по идее. Вот здесь с помощью USN-журнала реализовали мгновенный поиск файлов в Windows (на самом деле мгновенный поиск по части файлов). Все последние операции с файлами там конечно сразу появляются, но вот если операций очень много, журнал может и переполниться. Я своей программой NTFS Stream Explorer полазил по системе, и очень часто встречается ситуация, что USN-идентификатор файла указывает на запись в журнале, которая относится к совсем другому файлу. То есть с тех пор как был изменён старый файл, журнал уже переполнялся и записи были перезаписаны.
OSX-овые FSEvents — это как раз аналог виндового USN Journals, а не ReadDirectoryChanges.
Писал кроссплатформенную следилку за изменениями директорий когда работал в freebrie.net/ (a-la p2p дропбокс)
Делалось на Python на базе Twisted. Ну и было важное ограничение — нужно чтобы следилка работала в неблокирующем режиме.

В Windows всё просто было — ReadDirectoryChangesW + WaitForMultipleObjects (??). Из плюсов — автоматически обрабатывает переименования; поддерживает рекурсивное отслеживание (это очень сильно всё упрощает). Минусов что-то даже не припомню.
В Linux — inotify. Из плюсов — довольно удобное API, много опций, практически неограниченное кол-во одновременно отслеживаемых директорий (~60000). Переименовывание отслеживается полуавтоматически (через cookie). Из минусов — нет поддержки рекурсии (как описано в статье). Навешиваешь следилку на дерикторию и оно сообщает если что-то изменилось непосредственно в этой директории, но не во вложенных. В целом жить можно =)

Самый геморрой был с MacOS. Для fsnotify не удалось найти неблокирующего API (для python по крайней мере), так что решили взять kqueue. Прикол в том, что в kqueue нельзя навесить следилку только на директорию. Нужно навешивать её НА КАЖДЫЙ ФАЙЛ. Если навесить на директорию, то будут видны только изменения, при которых что-то вносится в «файл директории» (удаление/добавление файла). А лимит на количество открытых файлов обычно выставлен в 1024 файла.

Ну и во всех случаях желательно иметь полный снимок структуры отслеживаемого дерева файлов и фоллбек в виде периодического полного сканирования структуры ФС.
Кому интересно — можете посмотреть как в UbuntuOne реализовано слежение под Linux Windows и Mac

НЛО прилетело и опубликовало эту надпись здесь
В случае kqueue не просто видны удаления и добавления файлов, а видны факты таких событий. Просто так получить имена этих файлов не получится :(
При навешивании на fd директории? Да, нужно делать дифф содержимого директории до и после события, т.е. хранить всегда где-то список содержимого.
Я, может, не в тему, но — по поводу кода реализации на Windows — если уж ручками SubSystem
#pragma comment(linker, "/SUBSYSTEM:console")
указан, так и Character Set — скажите, что не Unicode :)
#undef UNICODE
#undef _UNICODE
Конкретно для Windows реализацию писал не я, а Дмитрий Котеров (DmitryKoterov), поэтому ничего ответить про особенности реализации не могу.
А вы не думали использовать готовые кросс-платформенные решения? Например, libuv
Думал. Есть API для слежения за директориями в Glib, wxWidgets и т.д., но я не хочу для утилиты синхронизации файлов тащить библиотеки в много мегабайт. Поэтому, например, для linux мне в итоге пришлось написать свою реализацию с нуля, с корректной обработкой всех ошибок.
Интересно, хоть и на ruby, спасибо.
Какая разница на чём?
Остальная часть моей утилиты на PHP. Демон уведомлений о файловой системе на Ruby и демон синхронизации файлов на PHP выглядит немного странно :).
Я понимаю зачем вам вообще демон. Тем более на PHP. Просто заливать рсинком те файлы что изменились да и все.

Для гарда есть вагон плагинов на все случаи жизни.
Rsync через ssh может давать весьма ощутимую задержку в несколько секунд при соединении с сервером, если сервер находится довольно далеко. Написание простенького демона, который может один раз установить соединение и в дальнейшем слушать события ФС и заливать файлы (как это делает realsync) дает намного лучшую latency. Это уже обсуждалось в статье на хабре про dklab_realsync ( habrahabr.ru/post/139348/ ), хотя Дима Котеров приводит другую причину — это медленная работа rsync под windows.
Rsync через ssh может давать весьма ощутимую задержку в несколько секунд при соединении с сервером, если сервер находится довольно далеко.
Учите матчасть. В ssh есть вещь называемая ControlMaster, которая как раз и позволят устанавливать одно соединение и реиспользовать его.

Про медленный рсинк не верю. Где цифры?
Видимо, Вы упустили, что речь идет о rsync через ssh. Попробуйте сравнить копирование одного (большого) файла при помощи scp и, скажем, того же «голого» rsync'а. И ControlMaster тут совсем не причем. Шифрование прогоняет данные через CPU — вот и вся причина, тогда как простая отправка данных с HDD в сеть может происходить вообще без его участия, что гораздо быстрее. Более того, в рамках ssh скорость сильно зависит от используемого блокшифратора, arcfour самый быстрый.
Ой, да ладно вам. Вот отличная тема для новой статьи: что быстрее самопальный велик или rsync over ssh?
Про велик ничего сказать не могу, но rsync+ssh будет работать медленней, чем просто rsync. Я только об этом.
Ну при передаче по сети всё равно должен быть какой-то медиум. В случае, если вы инициируете подключение это чаще всего ssh. Надо будет попрыгать с бубном на досуге и подобрать самый быстрый протокол.
finger же.
Что_угодно over ssh будет работать медленнее, чем просто что_угодно. Это, очевидно, связано с тем, что каждый пакет оборачивается на источнике и разворачивается на приемнике. Еще что_угодно over ssh будет на маленьких пакетах жрать в разы больше траффика.
Только при чем тут это?
Абсолютно не при чем см. ПС :)
Ладно. Последняя попытка убедить вас в том, что эта вещь не делается с помощью rsync.
Какую вы предлагаете использовать реализацию для того, чтобы обеспечивать (пускай одностороннюю, хотя я хочу двухсторонюю, что более-менее реализуется с помощью unison)?
Я полагаю, раз вы рассуждаете о ненужности событий ФС, вы предлагаете использовать что-то вроде
while true; do rsync $dir $host:$dir; done


Таким образом, мы получим 100% утилизацию одного ядра в системе. Например, в моем компьютере их всего 2… Помимо этого, возможно вы слышали про такую вещь, как ноутбуки. И они начинают греться и шуметь вентиляторами, как правило, даже при загрузке одного ядра на 100%.

И тут почему-то решение с событиями ФС уже не такое глупое и ненужное, неправда ли?
К сожалению я имею ввиду не циклический рсинк, а запуск рсинка по событию в фс, что обеспечивает гард и его плагин guard-process в частности.
В таком случае есть и другие готовые решения, например lsyncd. Но вот только они все обеспечивают более-менее реалтаймовую синхронизацию в одном направлении. Я же хочу иметь двухсторонюю синхронизацию, причём сразу на много серверов. Поэтому хоть и это и велосипед, но всё остальное работает не лучше.
Я постараюсь сделать замеры и привести вам аргументы в пользу того, что в случае изменения одного файла послать один пакет быстрее, чем послать и принять stat от всех файлов :), если это для вас ещё не очевидно.
Мля, а rsync'y низя передать список изменённых файлов? :)
Вы меня не слышите (и не слушаете). Повторю ещё раз:

1. Если бы я делал исключительно однонаправленную синхронизацию, я согласен, можно было бы поспорить по поводу того, что rsync здесь плохо подходит (на самом деле он очень хорош при отсутствии обратной связи с сервера)
2. Мне нужна двунаправленная (!) синхронизация на много серверов одновременно, значит вместо rsync нужно уже использовать unison
3. Чтобы unison мог коннектиться «обратно» к моей машине, нужно создавать обратные тоннели или создавать другие костыли. К тому же, под windows пришлось бы вообще заставлять пользователя поднимать ssh-сервер, что мне кажется весьма неправильным.
4. Просто с помощью rsync я не могу контролировать, что именно отсылается на другую сторону, поскольку rsync не печатает stat() от посланных файлов. Мне же важно, что именно было отправлено, поскольку мне нужно как-то контролировать то, что я не вызываю rsync/unison и тд в цикле, т.к. синхронизация изменений с локальной машины вызовет цепочку событий на удаленной машине, которые в свою очередь… ну вы поняли.
Я уже понял, что все велосипеды оправдываются двунаправленной синхронизацией. Удачи вам.
Спасибо
События это ок. Отдельный велосипед нет.
На любом линуксе при установке пакета dropbox четко видно, что он тянет за собой rsync. Наверняка в дропбоксе сидят глупые ребята, они не умеют писать собственные велосипеды.

;-)
Вы уверены? Судя по ману и отзывам в сети, это поможет если делается несколько одновременных соединений. А тут обсуждается случай, когда идут последовательные соединения.
Безусловно, ControlMaster помогает ускорить трансфер при нескольких одновременных соединениях. Я написал лишь, что ssh в принципе медленнее, чем «голый» TCP.

ПС. Перечитал всю ветку, и понял, что все, включая меня, дискутируют о разных проблемах. Каждый о своем… )
Ага :)
Я правильно понимаю, что на inotify на каждый следимый файл открывает по десктриптору? Или только на директорию? Если на каждый файл, то 65k это как-то мало очень.
Для слежения с помощью inotify достаточно открывать только директории, причём он не требуется делать open(), декскрипторы получаются с помощью inotify_add_watch. Вот только откуда вы взяли 65k, по умолчанию max_user_watches составляет всего 8192 (директории).
$ cat /proc/sys/fs/inotify/max_user_watches
65536

opensuse 12.2, свежеустановленная, ничего не трогал. Ядро 3.4.11

На ядрах linux, начиная с 3.6.26 есть fanotify, который должен будет заменить inotify. Этот механизм пока еще плохо документирован ( www.spinics.net/lists/linux-man/msg02302.html, lwn.net/Articles/360955/). Пишут, что также можно блокировать вызов open() и в user space давать разрешение на открытие файла.
Насколько я смог понять из скудной информации в интернете насчёт fanotify, он именно из-за его постоянных обращений в userspace является, прямо скажем, неоптимальным, поэтому на него забили и больше не развивают :). А жаль, выглядит интересно.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории