Вопрос по atomic, posix, atomicity, unix, file-io – Является ли файл append атомарным в UNIX?

92

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

Ваш Ответ

4   ответа
30

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

Я собираюсь дать вам ответ со ссылками на тестовый код и результаты, предложенные автором.Boost.AFIO который реализует асинхронную файловую систему и библиотеку файлового ввода / вывода C ++.

Во-первых, O_APPEND или эквивалентный FILE_APPEND_DATA в Windows означает, что приращения максимального экстента файла (file & quot; length & quot;)atomic при одновременной работе авторов. Это гарантируется POSIX, и Linux, FreeBSD, OS X и Windows все реализуют это правильно. Samba также реализует это правильно, NFS до v5 нет, так как ему не хватает возможности форматирования проводов для атомарного добавления. Так что если вы откроете свой файл только для добавления,concurrent writes will not tear with respect to one another on any major OS если NFS не участвует.

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

No O_DIRECT/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: атомарность обновления = не менее 1 МБ, возможно, бесконечна (*)

O_DIRECT/FILE_FLAG_NO_BUFFERING:

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

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

FreeBSD 10.2 с ZFS: атомарность обновления = не менее 1 МБ, возможно, бесконечна (*)

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

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

(*) "Возможно, бесконечен" вытекает из этих пунктов в спецификации POSIX:

All of the following functions shall be atomic with respect to each other in the effects specified in POSIX.1-2008 when they operate on regular files or symbolic links ... [many functions] ... read() ... write() ... If two threads each call one of these functions, each call shall either see all of the specified effects of the other call, or none of them. [Source]

а также

Writes can be serialized with respect to other reads and writes. If a read() of file data can be proven (by any means) to occur after a write() of the data, it must reflect that write(), even if the calls are made by different processes. [Source]

но наоборот:

This volume of POSIX.1-2008 does not specify behavior of concurrent writes to a file from multiple processes. Applications should use some form of concurrency control. [Source]

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

54

должен быть атомным. Это должно быть не менее 512 байт, хотя оно может быть и больше (похоже, для linux установлено значение 4096).

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

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

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

Вы уверены, что? Не могли бы вы дать ссылку на это поведение? Я нашел подтвержденным, если дескриптор является каналом, но я не смог найти доказательств того, что он работает дляany файл . включая обычные, не NFS файловые объекты.
На вменяемых файловых системах,fsync(2) дает столько же гарантии, сколькоsync(2) делает, и не так сильно влияет на производительность.
Какthis answer указывает на утверждение оPIPE_BUF на этой странице применяется только к каналам и FIFO, а не к обычным файлам.
С приходом сигналов это может стать еще хуже:bugzilla.kernel.org/show_bug.cgi?id=55651, Почему это даже помечено как ответ? PIPE_BUF не имеет ничего общего с файлами.
Где именно в ... / write.html? Что касается O_APPEND, я не вижу упоминания о PIPE_BUF и вижу обещание, что"no intervening file modification operation shall occur between changing the file offset and the write operation", но я не уверен, что это означает, что сама операция записи не прерывается ...
20

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

The actual maximum atomic append size varies not only by OS, but by filesystem.

В Linux + ext3 размер составляет 4096, а в Windows + NTFS - 1024. Дополнительные комментарии см. В комментариях ниже.

Ваш тест предполагает, чтоecho $line >> $OUTPUT_FILE приведет к одному звонкуwrite независимо от размера$line.
@freiheit Я считаю, что в то время я тестировал его на ext3. Если вы запускаете его на другой FS и получаете другой результат, пожалуйста, оставьте комментарий.
С какой файловой системой вы тестировали Linux? Мне интересно, может быть, оно основано на размерах блоков файловой системы.
@OzSolomon, я использовал ваш скрипт на Debian 7.8, и мне удалось получить только атомарные записи до 1008 байтов включительно (1024-16 байтов служебных данных?) Как на моем разделе ext4, так и на монтировании tmpfs. Все, что кроме этого, каждый раз приводило к коррупции.
14

http://www.opengroup.org/onlinepubs/009695399/functions/pwrite.html.

If the O_APPEND flag of the file status flags is set, the file offset shall be set to the end of the file prior to each write and no intervening file modification operation shall occur between changing the file offset and the write operation.

& Quot; между & Quot; - но как насчет вмешательствduring запись, которая, по моему пониманию, происходит после "между"? (Т.е.: & lt; change_offset_action & gt; ... "the_between_period & quot; ... & lt; write_action & gt;) - я понимаю, что нет никаких гарантий по этому поводу?
Хм, я не могу восстановить свою собственную логику во время написания этого комментария ... Да, если ваша интерпретация верна, то, конечно, разные записи могут быть смешаны. Но теперь, когда я перечитываю цитату Бастиена, я думаю, это должно означать, что никто не может прервать "во время записи". - в противном случае весь абзац в стандарте был бы бесполезен, что вообще не давало бы никаких гарантий (даже в том случае, если запись произойдет в конце, поскольку кто-то еще может сдвинуть смещение при выполнении шага «запись»).
@ max Извините, я боюсь, что я не понимаю ваш вопрос: во-первых, эксперимент Оззоломона являетсяprocessне мультиthreaded приложение (один процесс); во-вторых, я не понимаю, как вы делаете вывод, что"a multithreaded app [...] will not mix" & # X2014; это именно то, что я не вижу гарантированной цитатой из Бастьена, как я упоминаю в своем комментарии. Вы можете уточнить свой вопрос?
@akavel согласился; нет никакой гарантии, что сама запись является атомарной. Но я в замешательстве: исходя из гарантии, предоставленной в вашей цитате, кажется, что мы можем сделать вывод, что многопоточное приложение, добавляющее один и тот же файл, не будет смешивать части разных письменных записей. Однако из экспериментов, о которых сообщил ОзСоломон, мы видим, что даже это предположение нарушается. Зачем?

Похожие вопросы