Является ли файл append атомарным в UNIX? - PullRequest
94 голосов
/ 20 июля 2009

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

Ответы [ 4 ]

56 голосов
/ 20 июля 2009

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

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

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

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

30 голосов
/ 07 февраля 2016

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

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

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

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


Нет 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: * +1030 * 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: Все следующие функции должны быть атомарными по отношению к каждой другие в эффектах, указанных в POSIX.1-2008, когда они действуют на обычные файлы или символические ссылки ... [много функций] ... читать () ... write () ... Если два потока каждый вызывают одну из этих функций, каждый вызов либо увидит все указанные эффекты другого вызова, либо никто из них. [Источник] и Записи могут быть сериализованы относительно других операций чтения и записи. Если Доказано, что read () данных файла (любым способом) происходит после write () данных, он должен отражать эту write (), даже если вызовы сделаны разными процессами. [Источник] но наоборот: Этот том POSIX.1-2008 не определяет поведение одновременных пишет в файл из нескольких процессов. Приложения должны использовать некоторые форма параллельного контроля. [Источник] Подробнее о значении этого вопроса вы можете прочитать в этом ответе

21 голосов
/ 17 июня 2014

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

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

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

15 голосов
/ 20 июля 2009

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

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

...