- PVSM.RU - https://www.pvsm.ru -
Я бы хотел посвятить статью обзору API, предоставляемых разными ОС для слежения за изменениями в директории. Статья появилась как результат моей работы над демонами слежения за изменениями для утилиты dklab_realsync (статья на хабре [1], github репозиторий [2]) и своей собственной, которую я пока что не хочу анонсировать.
Для операционной системы Windows есть замечательная функция ReadDirectoryChangesW [3], которая возвращает набор изменений для директории, в том числе содержит флаг для работы рекурсивно (bWatchSubtree). Таким образом, реализация слежения за изменениями в директории не представляет особого труда и в том же dklab_realsync реализация [4] занимает 80 строк кода или 3.5 Кб. Интересно, что в Windows эти события поддерживаются даже через SMB!
Тем не менее, существуют определенные подводные камни:
Вывод: Функция ReadDirectoryChangesW позволяет легко узнавать обо всех событиях в файлах, но, очередь событий может переполниться и тогда нужно будет выполнять полное сканирование ФС. Также, возможна доставка событий до того, как они станут актуальны.
В Mac OS X также есть удобный и простой API для слежения за изменениями в файловой системе под названием FSEvents [6]. С использованием этого API простейшая реализация демона [7] составляет 50 строк кода или 1.8 кб. Очередь не может переполниться (!), но полное сканирование все же может потребоваться, если демон fseventsd «упадет». Стоит отметить, что этот API не предоставляет изменения по файлам, он сообщает только директории, в которых что-то изменилось. Поскольку события никуда не деваются и пишутся в лог (FSEvents service stores events in a persistent, per-volume database [8]), детализация с точностью для директории позволяет сэкономить место на диске.
Вывод: FSEvents API для Mac OS X является самым необычным из всех подобных API. Очередь не переполняется и даже имеется возможность получить события из прошлого. Тем не менее, детализация событий дается с точностью до директории, что означает меньшую эффективность демона для синхронизации файлов.
В linux vanilla kernel существует один способ слежения за изменениями в директории — это inotify [9]. Для этого API существует хорошая и подробная документация, но нет поддержки рекурсивного слежения за изменениями! Также, у inotify есть ограничение на максимальное количество объектов, за которыми можно следить. Простейшая реализация [10] демона занимает уже 250 строк кода или 8 кб. Статическая сборка с использованием dietlibc [11] занимает примерно 14 кб. Другим неприятным моментом является то, что приложение должно само поддерживать соответствия между watch descriptor (в нашем случае это всегда директория) и именем. Есть функция inotify_add_watch [12], которой передается путь до отслеживаемой директории, но нет обратной — inotify_get_path, которая бы возвращала этот самый путь по переданному дескриптору. События же содержат только watch descriptor и относительный путь до изменившегося файла внутри директории.
Подводные камни рекурсивного слежения за директорией через inotify:
FreeBSD и Mac OS X позволяют отслеживать за изменениями с помощью kqueue, который аналогичен inotify по своим характеристикам и также не имеет возможности рекурсивного слежения за директориями. Также, kqueue принимает в качестве аргументов дескрипторы открытых файлов (директорий), поэтому при использовании этого API ограничения на количество отслеживаемых директорий ещё более строгие.
Механизм | Переполнение очереди | Рекурсивный? | Макс. объектов | Детализация |
---|---|---|---|---|
ReadDirectoryChangesW | Да | Да | — | файл |
FSEvents | Нет | Да | — | директория |
inotify | Да | Нет | 8192 | файл |
kqueue | Да | Нет | 1024 | файл |
Как можно видеть, у всех API существуют свои достоинства и недостатки. Наименее удобными являются механизмы kqueue и inotify, но они же являются самыми эффективными и надежными. Коммерческие ОС предоставляют более удобные механизмы слежения за изменениями, но у них тоже есть свои особенности. Надеюсь, теперь вы имеете больше представления о том, как тяжела участь Dropbox и подобных программ, которым требуется со всем этим уживаться и осуществлять надежную и эффективную синхронизацию данных :).
* Картинка взята с www.alexblogger.com/2008_01_01_archive.html [13]
Автор: youROCK
Источник [14]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/linux/24094
Ссылки в тексте:
[1] статья на хабре: http://habrahabr.ru/post/139348/
[2] github репозиторий: https://github.com/DmitryKoterov/dklab_realsync
[3] ReadDirectoryChangesW: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx
[4] реализация: https://github.com/DmitryKoterov/dklab_realsync/blob/master/src/win32/main.cpp
[5] watchdog package: http://packages.python.org/watchdog/installation.html
[6] FSEvents: https://developer.apple.com/library/mac/#documentation/Darwin/Conceptual/FSEvents_ProgGuide/UsingtheFSEventsFramework/UsingtheFSEventsFramework.html
[7] простейшая реализация демона: https://github.com/DmitryKoterov/dklab_realsync/blob/master/src/darwin/notify.c
[8] FSEvents service stores events in a persistent, per-volume database: https://developer.apple.com/library/mac/#documentation/Darwin/Reference/FSEvents_Ref/Reference/reference.html
[9] inotify: http://linux.die.net/man/7/inotify
[10] Простейшая реализация: https://github.com/YuriyNasretdinov/unrealsync/blob/master/src/linux/notify.c
[11] dietlibc: http://www.fefe.de/dietlibc/
[12] inotify_add_watch: http://linux.die.net/man/2/inotify_add_watch
[13] www.alexblogger.com/2008_01_01_archive.html: http://www.alexblogger.com/2008_01_01_archive.html
[14] Источник: http://habrahabr.ru/post/164775/
Нажмите здесь для печати.