переписать существующий файл так, чтобы он был заменен новой версией атомарно, только после полной записи


18

Я смутно припоминаю, что где-то читал, что в некоторых Unix-системах был способ открыть существующий файл для записи с флагом, который запрашивал у ядра использовать старую версию (для других процессов, обращающихся к ней для чтения), до тех пор, пока «новый msgstr "версия была полностью написана (закрыта), с этого момента файл появился как новая версия.

Другими словами, другие процессы либо видели старую версию, либо новую, а не полностью написанную.

Может ли кто-нибудь знающий указать мне ссылку?


Похоже, что может сделать Plan 9 , но нет.
Жиль "ТАК - перестань быть злым"

2
Похоже на Files-11 в OpenVMS: «Каждый раз, когда файл сохраняется, вместо перезаписи существующей версии, создается новый файл с тем же именем, но с увеличенным номером версии».
Мат

Почему ты спросил? Вам нужна эта функциональность, или это было просто любопытство?
Нильс

1
Я был бы счастлив иметь такую ​​функциональность, и я вспомнил, что где-то читал, что она существует. Итак, смесь как потребности, так и любопытства.
eudoxos

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

Ответы:


14

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

Когда вы переименовываете / перемещаете один файл поверх другого, старый файл не связывается. Это означает, что файл все еще существует, но его больше нет в дереве файловой системы. Таким образом, старые приложения будут по-прежнему иметь возможность доступа к файлу, пока они остаются открытыми. После того, как все приложения закрыли старый файл, он фактически не распределяется на диске.

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


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

1
@eudoxos ваш комментарий не имеет смысла. Вы говорите, что программы должны быть написаны специально для того, чтобы делать renameсвоп. Даже если бы существовала такая «ОС-функция», о которой вы говорите, программу все равно нужно было бы написать, чтобы воспользоваться этой возможностью. Какая разница?
Патрик

Существует разница, если вы передаете (возможно, неподдерживаемый) флаг openсистемному вызову или если вам нужно делать то, что вы описываете вручную.
Евдоксос

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

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

6

Как пишет Патрик , обычный способ сделать это - записать новую версию в отдельный файл, а по окончании переименовать новую версию в старое имя файла, перезаписав ее атомарно. Эта вторая операция называется перезапись-переименованием .

Теперь несколько ссылок:


man 3p renameговорит мне, что renameэто действительно атомарно, и я думаю, это предназначено для всех файловых систем Linux. И когда я читаю первую статью, которую вы связали, я все еще думаю, что операции переименования Btrfs являются атомарными.
Гагелло

1

Это напоминает мне о Allocate On Flush . Когда файловая система использует эту функцию, вместо записи данных непосредственно на диск, она вычитает размер данных, которые должны быть записаны, из счетчика свободного пространства на диске и хранит данные в памяти, пока не будет выполнен системный вызов синхронизации или пока ядро ​​не решит очистить грязные буферы.

В этом случае, если файл изменяется одним процессом и открывается другим процессом, последний «увидит» неизмененную ( или «старую», если хотите ) версию файла.

Конечно, вышесказанное является теоретическим и зависит от различных факторов, и я бы сказал, что это немного непредсказуемо, поскольку вы точно не знаете, когда ядро ​​очистит грязные страницы. Например, в Linux ( как вы также можете прочитать в разделе 15.3 «Понимание ядра Linux» ), грязные страницы записываются на диск при следующих условиях:

  • Кэш страниц переполняется и требуется больше страниц, или количество грязных страниц становится слишком большим.

  • Слишком много времени прошло с тех пор, как страница осталась грязной.

  • Процесс запрашивает все ожидающие изменения блочного устройства или определенного файла для сброса; это делается путем вызова системных вызовов sync (), fsync () или fdatasync ().

Известно, что эта функция реализована в файловых системах HFS +, XFS, Reiser4, ZFS, Btrfs и ext4.


2
То, что вы описываете, - это метод файловой системы, который должен быть невидим для пользовательского пространства (и, следовательно, не делать то, что вы указываете) в POSIX (файловых) системах (см. Запись : «Если чтение () файловых данных может быть доказано (любым способом) чтобы происходить после записи () данных, он должен отражать эту запись (), даже если вызовы выполняются различными процессами . ") Другие процессы не увидят старые данные (в POSIX).
Мат

Спасибо за исправление. Я думаю, что мое понимание этой техники файловой системы было неверным.
dkaragasidis

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