Представьте себе два процесса, читатель и писатель, взаимодействующие через обычный файл на файловой системе ext3. Читатель IN_MODIFY
следит за файлом inotify. Писатель записывает 1000 байт в файл за один write()
вызов. Читатель получает событие inotify и вызывает fstat
файл. Что видит Читатель?
Есть ли гарантия, что Reader получит обратно хотя бы 1000 за
st_size
файл? Из моих экспериментов, похоже, нет.Есть ли гарантия, что Reader действительно сможет прочитать
read()
1000 байт?
Это происходит на блоке с серьезными ограничениями ввода-вывода. Например, sar
показывает время ожидания около 1 секунды. В моем случае Reader на самом деле ждет 10 секунд ПОСЛЕ получения события inotify перед вызовом stat
и получает слишком маленькие результаты.
Я надеялся, что событие inotify не будет доставлено, пока файл не будет готов. Я подозреваю, что на самом деле происходит то, что событие inotify срабатывает ВО ВРЕМЯ вызова write()
в Writer, и данные фактически доступны другим процессам в системе, когда они будут готовы. В этом случае 10 секунд недостаточно.
Думаю, я просто ищу подтверждение того, что ядро действительно реализует inotify так, как я предполагаю. Также, если есть какие-то варианты, возможно, изменить это поведение?
Наконец, в чем смысл inotify, учитывая такое поведение? Вам в любом случае придется опрашивать файл/каталог после получения события, пока данные не станут доступны. Можно было бы делать это все время и забыть об inotify.
***РЕДАКТИРОВАТЬ**** Хорошо, как это часто бывает, поведение, которое я наблюдаю, на самом деле имеет смысл, теперь, когда я понимаю, что я на самом деле делаю. ^_^
На самом деле я реагирую на событие IN_CREATE в каталоге, в котором находится файл. Таким образом, я фактически запускаю stat() для файла в ответ на создание файла, а не обязательно на событие IN_MODIFY, которое может появиться позже.
Я собираюсь изменить свой код так, чтобы, как только я получу событие IN_CREATE, я подписался на IN_MODIFY в самом файле, и я не буду фактически пытаться прочитать файл, пока не получу событие IN_MODIFY. Я понимаю, что есть небольшое окно, в котором я могу пропустить запись в файл, но это приемлемо для моего приложения, потому что в худшем случае файл будет закрыт через максимальное количество секунд.
решение1
Из того, что я вижу висходный код ядра, inotify запускается только после завершения записи (т. е. ваша догадка неверна). После срабатывания уведомления в , sys_write
функции, реализующей write
системный вызов, происходят еще две вещи: установка некоторых параметров планировщика и обновление позиции в дескрипторе файла. Этот код был похож еще в2.6.14К моменту срабатывания уведомления файл уже имеет новый размер.
Проверьте, что может пойти не так:
- Возможно, читатель получает старые уведомления от предыдущей записи.
- Если читатель вызывает
stat
, а затем вызываетread
или наоборот, что-то может произойти между ними. Если вы продолжаете добавлять данные в файл, вызовstat
first гарантирует, что вы сможете прочитать это расстояние, но возможно, что к моменту вызова читателя будет записано больше данныхread
, даже если он еще не получил уведомление inotify. - Просто потому, что вызывается writer,
write
это не означает, что ядро запишет требуемое количество символов. Существует очень мало обстоятельств, когда атомарная запись гарантирована до любого размера.write
Однако каждый вызов гарантированно атомарен: в какой-то момент данные еще не записаны, а затем внезапнонбайты были записаны, гденэто возвращаемое значение вызоваwrite
. Если вы наблюдаете частично записанный файл, это означает, что онwrite
вернул меньше своего аргумента размера.
Полезные инструменты для расследования происходящего включают в себя:
strace -tt
- подсистема аудита