перезапишіть існуючий файл, щоб він був замінений новою версією атомно, лише один раз повністю написаний


18

Я смутно пригадую, що десь читав, що в деяких Unices був спосіб відкрити існуючий файл для запису, з прапором, який попросив ядро ​​використовувати стару версію (для інших процесів, що отримують доступ до нього для читання), до "нового "версія була повністю написана (fd закрита), з цього моменту файл з'явився як нова версія.

Іншими словами, інші процеси або бачили стару версію, або нову, ніколи не повністю написану.

Чи може хтось знаючий вказати мені на довідку?


Схоже, що може зробити План 9 , але ні.
Жил 'ТАК - перестань бути злим'

2
На OpenVMS звучить як Файли-11 : "Кожен раз, коли файл зберігається, а не перезаписується існуюча версія, створюється новий файл з тим самим іменем, але збільшений номер версії."
Мат

Чому ти запитав? Вам потрібна ця функціональність, чи це була просто цікавість?
Нілс

1
Я був би радий, що це функціонування, і я згадав десь читати, що він існує. Тож суміш як потреби, так і цікавості.
eudoxos

Усі системи Unix дозволяють зробити це іншим способом - створюйте новий файл у тій самій каталозі, наповнюйте зміненим вмістом і виконайте перейменування атомів. Це набагато дорожче для невеликих змін, але працює.
Netch

Відповіді:


14

Те, що ви описуєте, звучить точно як базове перейменування, щоб перезаписати файл.

Коли ви перейменовуєте / переміщуєте один файл поверх іншого, старий файл від’єднується. Значення файлу все ще існує, але його вже немає в дереві файлових систем. Таким чином, старі програми надалі матимуть доступ до файлу до тих пір, поки вони не відкриватимуть його. Коли всі програми закрили старий файл, то він фактично не розміщений на диску.

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


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

1
@eudoxos ваш коментар не має сенсу. Ви говорите, що програми повинні бути написані спеціально, щоб зробити renameзаміну. Навіть якщо така функція ОС, про яку ви говорили, існувала, програму все одно доведеться писати, щоб також скористатися цим. Яка різниця?
Патрік

Існує різниця, якщо ви передасте прапор (можливо, не підтримується) на openсистемний виклик або якщо вам потрібно робити те, що ви описуєте вручну.
eudoxos

Майте на увазі, що для збереження старої або повністю написаної нової версії у випадку аварії вам потрібно додатково синхронізувати новий файл на диску з fsync або подібним
texthell

@textshell без синхронізації ви все одно отримаєте атомність, хоча .... просто не довговічність ... правильно? Я не розумію аргументу на goo.gl/qfQQfy в цьому випадку. У моєму випадку у мене система перебуває під надзвичайним навантаженням, і я хочу уникнути помилок файлової системи, і мені все одно, чи не витримає файл збій.
wcochran

6

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

Тепер кілька посилань:


man 3p renameговорить мені, що renameце справді атомно, і я думаю, що це призначено для всіх файлових систем Linux. І коли я прочитав першу статтю, яку ви пов’язали, я все ще думаю, що операції з перейменуванням Btrfs є атомними.
hagello

1

Це нагадує мені Allocate On Flush . Коли файлова система використовує цю функцію, замість того, щоб записувати дані безпосередньо на диск, вона віднімає розмір даних, що підлягають запису з лічильника вільного простору на диску, і зберігає дані в пам'яті, поки не буде виконано системний виклик синхронізації або вирішення ядра для промивання брудних буферів.

У цьому випадку, якщо файл модифікується одним процесом і відкривається іншим процесом, останній процес "побачить" немодифіковану ( або "стару", якщо ви бажаєте ) версію файлу.

Звичайно, вищезазначене є теоретичним і залежить від різних факторів, і я б сказав трохи непередбачувано - оскільки ви точно не знаєте, коли ядро ​​збирає брудні сторінки. Наприклад, у Linux ( як ви також можете прочитати у розділі 15.3 Розуміння ядра Linux ), брудні сторінки записуються на диск за таких умов:

  • Кеш сторінок стає занадто повним, і потрібно більше сторінок, або кількість брудних сторінок стає занадто великою.

  • Забагато часу минуло, оскільки сторінка залишилася брудною.

  • Процес вимагає очистити всі очікувані зміни блокового пристрою або певного файлу; це робиться шляхом виклику системного виклику sync (), fsync () або fdatasync ().

Ця функція, як відомо, реалізується в файлових системах HFS +, XFS, Reiser4, ZFS, Btrfs та ext4.


2
Те, що ви описуєте, це техніка файлової системи, яка повинна бути невидимою з простору користувачів (і, отже, не виконує те, що ви вказуєте) в POSIX (файлових) системах (див. Запис : "Якщо зчитування () даних файлів може бути доведено (будь-якими способами) відбуватись після запису () даних, він повинен відображати це записування (), навіть якщо виклики здійснюються різними процесами . "). Інші процеси не бачать старих даних (на POSIX).
Мат

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

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