Чи додається файл атомним в UNIX?


106

Загалом, що ми можемо сприймати як належне, коли ми додаємо файл у UNIX з декількох процесів? Чи можливо втратити дані (один процес замінює зміни іншого)? Чи можливо, щоб дані були забруднені? (Наприклад, кожен процес додає по одному рядку в додаток до файлу журналу, чи можливо, що два рядки переплуталися?) Якщо додаток не є атомарним у наведеному вище значенні, то який найкращий спосіб забезпечити взаємне виключення?

Відповіді:


65

Запис, який має розмір "PIPE_BUF", повинен бути атомним. Це має бути принаймні 512 байт, хоча він може бути легко більшим (начебто, у Linux це встановлено 4096).

Це передбачає, що ви говорите про всі повністю сумісні з POSIX компоненти. Наприклад, це не вірно в NFS.

Але якщо ви запишете у файл журналу, який ви відкрили в режимі "O_APPEND", і тримати рядки (включаючи новий рядок) в байтах "PIPE_BUF", ви повинні мати можливість декількох авторів у файл журналу без жодних проблем з корупцією. Будь-які переривання надійдуть до або після написання, а не посередині. Якщо ви хочете, щоб цілісність файлів пережила перезавантаження, вам також потрібно буде дзвонити fsync(2)після кожного запису, але це страшно для продуктивності.

Уточнення : прочитайте коментарі та відповідь Оз Соломона . Я не впевнений, що O_APPENDмає бути PIPE_BUFатомність цього розміру. Цілком можливо, що саме так реалізовано Linux write(), або це може бути пов'язано з розмірами блоків, що лежать в основі файлової системи.


11
У здорових файлових системах fsync(2)дається стільки ж гарантії, скільки є sync(2), і не має настільки ж великого впливу на продуктивність.
ефемія

4
Ви впевнені в цьому? Не могли б ви надати посилання про таку поведінку? Я знайшов це підтвердженим, якщо дескриптор - це труба, але я не зміг знайти докази того, що він працює для будь-якого файлу. включаючи звичайні об'єкти файлів, що не належать до NFS.
Алан Францоні

6
Де саме в ... / write.html? Для O_APPEND я не бачу жодної згадки про PIPE_BUF, і я бачу обіцянку, що " між зміною зсуву файлу та операцією запису не відбудеться жодна операція по зміні файлів , але я не впевнений, чи означає це, що сама операція запису є безперебійно ...
akavel

6
Як вказується ця відповідь , заява про PIPE_BUFцю сторінку стосується лише труб та FIFO, а не звичайних файлів.
Грег Іноземцев

3
З надходженням сигналів це може стати ще гіршим: bugzilla.kernel.org/show_bug.cgi?id=55651 . Чому це навіть позначено як відповідь? PIPE_BUF не має нічого спільного з файлами.
розріджений

35

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

Я збираюся дати вам відповідь із посиланнями на тестовий код та результати, як автор запропонованого Boost.AFIO, який реалізує асинхронну файлову систему та файли i / o 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: оновлення atomicity = 1 байт до включення 10.0.10240, з 10.0.14393 принаймні 1 Мбіт, ймовірно, нескінченно (*).

Linux 4.2.6 з ext4: оновлення atomicity = 1 байт

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

O_DIRECT / FILE_FLAG_NO_BUFFERING:

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

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

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


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

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


(*) "Мабуть нескінченна" випливає з цих пунктів у специфікації POSIX:

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

і

Записи можуть бути серіалізовані стосовно інших читань і записів. Якщо читання () даних файлів може бути доведено (будь-якими способами) після запису () даних, воно повинно відображати це записування (), навіть якщо виклики здійснюються різними процесами. [Джерело]

але навпаки:

Цей том POSIX.1-2008 не визначає поведінку одночасного запису у файл із декількох процесів. Програми повинні використовувати певну форму контролю за одночасністю. [Джерело]

Детальніше про значення цих питань ви можете прочитати у цій відповіді


29

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

Дійсний максимальний розмір атомного додатка змінюється не тільки в ОС, але і у файловій системі.

Для Linux + ext3 розмір - 4096, а в Windows + NTFS - 1024. Для отримання додаткових розмірів див. Коментарі нижче.


З якою файловою системою ви протестували в Linux? Мені цікаво, чи може це базуватися на розмірах блоку файлової системи.
freiheit

@freiheit Я вірю, що я тестував його на ext3. Якщо ви запускаєте його на іншому FS і отримуєте інший результат, будь ласка, опублікуйте коментар.
Оз Соломон

3
@OzSolomon, я використовував ваш сценарій на Debian 7.8, і мені вдалося отримати атомні записи до 1008 байт (включаючи 1024-16 байтів накладних витрат?) На моєму розділі ext4 і на монтажі tmpfs. Все, що перевищує це, щоразу призводило до корупції.
Ерік Прутт

6
Схоже, ваш тест припускає, що echo $line >> $OUTPUT_FILEодин раз дзвонить writeнезалежно від розміру $line.
Томаш

16

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

Якщо встановлено O_APPENDпрапор прапорців статусу файлу, зміщення файлу встановлюється в кінці файлу перед кожним записом і між зміною зсуву файлу та операцією запису не повинно відбуватися жодної операції по зміні файлу.


20
"між" - але як щодо втручань під час запису, які, на моє розуміння, трапляються після "між"? (Тобто: <change_offset washing> ... "the_between_period" ... <write washing>) - чи можу я зрозуміти, що немає гарантій щодо цього?
akavel

@akavel погодився; немає гарантії, що сама запис є атомною. Але я плутаюся: виходячи з гарантії, наданої у вашій цитаті, здається, ми можемо зробити висновок, що багатопотокова програма, що додає один і той же файл, не змішає частини різних письмових записів. Однак з експериментів, про які повідомляв ОзСоломон, ми бачимо, що навіть це припущення порушено. Чому?
макс

@Max вибачте, я боюся , що я не розумію ваше запитання: у - перших, експеримент OzSolomon є мульти- процес , а НЕ мульти- різьбова (один процес) додаток; по-друге, я не розумію, як ви робите висновок про те, що "багатопотокове додаток [...] не буде змішуватися" - саме це я не вважаю гарантованим цитатою Бастієна, як я згадую у своєму коментарі. Чи можете ви уточнити своє запитання?
akavel

2
Хм, я не можу реконструювати власну логіку під час написання цього коментаря ... Так, якщо ваше тлумачення правильне, то, звичайно, різні записи можуть бути змішані. Але тепер, коли я перечитую цитату Бастієна, я думаю, це повинно означати, що ніхто не може перебивати "під час запису" - інакше весь параграф у стандарті був би марним, не даючи буквально ніяких гарантій (навіть не те, що запис відбудеться врешті-решт, оскільки хтось інший може змістити зсув, коли крок "запису" буде виконаний.
макс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.