Является ли файл append atomic в UNIX?


В общем, что мы можем считать само собой разумеющимся, когда мы добавляем к файлу в UNIX из нескольких процессов? Можно ли потерять данные (один процесс перезаписывает изменения другого)? Возможно ли, чтобы данные были искажены? (Например, каждый процесс добавляет одну строку на добавление в файл журнала, возможно ли, что две строки будут искажены?) Если приложение не является атомарным в вышеуказанном смысле, то каков наилучший способ обеспечения взаимного исключения?

4 87

4 ответа:

запись, которая находится под размером 'PIPE_BUF', должна быть атомарной. Это должно быть не менее 512 байт, хотя это может быть легко больше (linux, кажется, имеет значение 4096).

это предполагает, что вы говорите все полностью POSIX-совместимые компоненты. Например, это не верно для NFS.

но предполагая, что вы пишете в файл журнала, который вы открыли в режиме "O_APPEND", и сохраняете свои строки (включая новую строку) под байтами "PIPE_BUF", вы должны иметь несколько записей в файл журнала без каких-либо проблем с коррупцией. Любые прерывания будут поступать до или после записи, а не в середине. Если вы хотите, чтобы целостность файла пережила перезагрузку, вам также нужно позвонить fsync(2) после каждой записи, но это ужасно для производительности.

уточнение: читаю комментарии и ответ Оза Соломона. Я не уверен, что O_APPEND предполагается, что PIPE_BUF размер атомарность. Вполне возможно, что это просто как Linux реализован write(), или это может быть связано с размерами блоков базовой файловой системы.

Edit: Обновлено в августе 2017 года с последними результатами Windows.

Я дам вам ответ со ссылками на тестовый код и результаты как автор предложил!--5-->импульс.АФИО который реализует асинхронную файловую систему и библиотеку файлового ввода-вывода c++.

во-первых, O_APPEND или эквивалентный FILE_APPEND_DATA в Windows означает, что приращения максимального экстента файла (файл "длина") являются atomic при одновременных писателей. Это гарантируется POSIX, а также Linux, FreeBSD, OS X и Windows все реализуют его правильно. Samba также реализует его правильно, NFS до v5 не делает, поскольку ему не хватает возможности формата провода для атомарного добавления. Поэтому, если вы откроете свой файл с помощью append-only,параллельные записи не будут рваться по отношению друг к другу на любой крупной ОС если NFS не участвует.

одновременно читает к атомарному добавляется мая см порванные записи в зависимости от ОС, файловая система и какие флаги вы открыли файл - приращение максимального экстента файла является атомарным, но видимость записи по отношению к чтению может быть или не быть атомарной. Вот краткое резюме по флагам, ОС и файловой системы:

нет под д ержка/file_flag_no_buffering без кэширования:

Microsoft Windows 10 с NTFS: обновление атомарности = 1 байт до и включая 10.0.10240, от 10.0.14393 по крайней мере 1 Мб, вероятно, бесконечный (*).

Linux 4.2.6 с ext4: обновить атомарность = 1 байт

FreeBSD 10.2 с ZFS: update atomicity = по крайней мере 1Mb, вероятно, бесконечный (*)

ПОД Д ЕРЖКА/FILE_FLAG_NO_BUFFERING БЕЗ КЭШИРОВАНИЯ:

Microsoft Windows 10 с NTFS: update atomicity = до и включая 10.0.10240 до 4096 байт только если выровнена страница, в противном случае 512 байт, если FILE_FLAG_WRITE_THROUGH выключен, иначе 64 байта. Обратите внимание, что эта атомарность, вероятно, является особенностью PCIe DMA, а не предназначена. С 10.0.14393, по крайней мере, 1 Мб, вероятно, бесконечный (*).

Linux 4.2.6 с ext4: обновить атомарность = по крайней мере 1 Мб, вероятно, бесконечный (*). Обратите внимание, что более ранние линуксы с ext4 определенно не превышали 4096 байт, XFS, безусловно, использовал пользовательскую блокировку, но похоже, что недавний Linux наконец исправил это.

FreeBSD 10.2 с ZFS: update atomicity = по крайней мере 1Mb, вероятно, бесконечный (*)


вы можете увидеть необработанные результаты эмпирического теста на https://github.com/ned14/afio/tree/master/programs/fs-probe. Примечание мы тестируем разрывные смещения только на 512 байтовых кратных, поэтому я не могу сказать, будет ли частичное обновление 512-байтового сектора разрываться во время цикла чтения-изменения-записи.

Итак, чтобы ответить на вопрос OP, записи O_APPEND не будут мешать друг другу, но чтение одновременно с записью O_APPEND, вероятно, увидит, что torn пишет на Linux с ext4, если O_DIRECT не включен, после чего ваши записи O_APPEND понадобятся чтобы быть кратным размеру сектора.


(*) "вероятно, бесконечный" проистекает из этих предложений в спецификации POSIX:

все следующие функции должны быть атомарными по отношению друг к другу других последствий, указанных в POSIX.1-2008, когда они работают на обычные файлы или символические ссылки ... [многие функции. ].. читать. )(.. писать. )(.. Если два потока каждый вызов одной из этих функций, каждый вызов либо увидеть все указанные эффекты другого звонок или ни один из них. [источник]

и

записи могут быть сериализованы относительно других операций чтения и записи. Если чтение() данных файла может быть доказано (любыми средствами), чтобы произойти после write() данных, он должен отражать, что write (), даже если вызовы производятся разными процессами. [источник]

но и наоборот:

этот объем POSIX.1-2008 не указан поведение параллельных запись в файл из нескольких процессов. Приложения должны использовать некоторые форма управления параллелизмом. [источник]

вы можете прочитать больше о значении этих в этом ответе

Я написал сценарий, чтобы эмпирически проверить максимальный атомарный размер добавления. Сценарий, написанный в bash, порождает несколько рабочих процессов, которые все записывают рабочие подписи в один и тот же файл. Затем он читает файл, ища перекрывающиеся или поврежденные подписи. Вы можете увидеть источник для скрипта на этом блоге.

фактический максимальный размер атомарного приложения зависит не только от ОС, но и от файловой системы.

на Linux + ext3 размер 4096, а на Windows+NTFS размер 1024. См. комментарии ниже для получения дополнительных размеров.

вот что говорит Стандарт:http://www.opengroup.org/onlinepubs/009695399/functions/pwrite.html.

Если O_APPEND флаг флагов состояния файла установлен, смещение файла должно быть установлено в конец файла перед каждой записью, и никакая промежуточная операция изменения файла не должна происходить между изменением смещения файла и операцией записи.