Как долго переименовать файл в POSIX?

Каков правильный способ долговременного переименования файла в файловой системе POSIX? В частности, интересно узнать о fsyncs в каталогах. (Если это зависит от ОС /FS, я спрашиваю о Linux и ext3/ext4).

Примечание. В StackOverflow есть другие вопросы о прочных переименованиях, но AFAICT они не адресуют fsync-ing каталогов (что для меня важно - я даже не модифицирую данные файла).

В настоящее время у меня (на Python):

dstdirfd = open(dstdirpath, O_DIRECTORY|O_RDONLY)
rename(srcdirpath + '/' + filename, dstdirpath + '/' + filename)
fsync(dstdirfd)

Конкретные вопросы:

  • Это также неявно fsync исходный каталог? Или я могу закончить с файлом, появляющимся в обоих каталогах после силового цикла (что означает, что мне нужно будет проверить количество жестких ссылок и выполнить ручное восстановление), т.е. Невозможно гарантировать долговременную работу атомарного перемещения?
  • Если я fsync исходный каталог вместо целевого каталога, это также неявно fsync каталог назначения?
  • Есть ли какие-либо полезные инструменты для тестирования/отладки/обучения (инжекторы ошибок, инструменты самоанализа, ложные файловые системы и т.д.)?

Спасибо заранее.

Ответы

Ответ 1

POSIX определяет, что функция переименования должна быть атомарной:

http://pubs.opengroup.org/onlinepubs/009695399/functions/rename.html

Итак, если вы переименовываете (A, B), ни при каких обстоятельствах не должны видеть состояние с файлом в обоих каталогах или ни в одной из каталогов. Всегда будет точно один, независимо от того, что вы делаете с fsync() или сбой системы.

Но это не решает проблему обеспечения надежности операции rename(). POSIX отвечает на этот вопрос:

Если определена _POSIX_SYNCHRONIZED_IO, функция fsync() должна принудительно выполнить все текущие операции ввода-вывода в очереди, связанные с файлом, указанным файловыми файловыми файлами, в состояние завершения синхронизированного ввода-вывода. Все операции ввода-вывода должны быть завершены, как определено для завершения целостности файла с синхронизированным вводом-выводом.

(из http://pubs.opengroup.org/onlinepubs/009695399/functions/fsync.html)

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

Наконец, в отличие от претензии в блоге, упомянутой в другом ответе, обоснование для этого объясняет следующее:

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

Система, которая утверждала, что она совместима с POSIX, и считала ее правильным поведением (то есть не ошибкой или аппаратным сбоем) для завершения fsync() и не сохраняла эти изменения во время сбоя системы, должна была бы сознательно искажать себя с уважением к спецификации.

(обновлено с дополнительной информацией: Linux-специфическое и портативное поведение)

Ответ 2

К сожалению, ответ Daves неверен.

Не все системы POSIX могут даже иметь надежное хранилище. И если они это сделают, все равно "разрешено" закрываться после сбоя системы. Для этих систем имеет смысл no-op fsync(), и такой fsync() явно разрешен в POSIX. Также законно восстанавливать файл в старом каталоге, в новом каталоге, как в другом, так и в любом другом месте. POSIX не дает никаких гарантий для сбоев системы или восстановления файловой системы.

Реальный вопрос:

Как сделать прочное переименование систем, которые поддерживают это через POSIX API?

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

Является ли fsync (destdirfd) также неявным fsync исходным каталогом?

  • POSIX вообще: нет, ничего не подразумевает, что
  • ext3/4: Я не уверен, что оба изменения источника и конечного каталога заканчиваются одной и той же транзакцией в журнале. Если они это сделают, они оба совершают вместе.

Или я могу закончить с файлом, отображающимся в обоих каталогах после силового цикла ( "сбой" ), т.е. невозможно гарантировать долговременную работу атомарного перемещения?

  • POSIX вообще: никаких гарантий, но вы должны использовать fsync() обе каталоги, которые могут быть не атомно-прочными
  • ext3/4: сколько минимальной потребности fsync() зависит от параметров монтирования. Например. если он установлен с "dirsync", вам не нужен ни один из этих двух fsync() s. В лучшем случае вам нужны как fsync() s, но Im почти уверен, что одного достаточно (атомно-долговечный).

Если fsync исходный каталог вместо целевого каталога, это также неявно fsync в каталоге назначения?

  • POSIX: no
  • ext3/4: Я действительно верю, что оба заканчиваются в одной транзакции, поэтому не имеет значения, какой из них вы fsync()
  • старшие ядра ext3: (если они не совпадают с одной транзакцией), некоторая не очень оптимальная реализация сделала слишком много синхронизации на fsync(), я уверен, что она совершила каждую транзакцию, которая была раньше. И да, нормальная реализация сначала привяжет его к месту назначения, а затем удалит его из источника. Таким образом, fsync (srcdirfd) также инициирует fsync() адресата.
  • ext4/last ext3: если они не совпадают с одной транзакцией, вы можете полностью синхронизировать их самостоятельно (так же, как и они)

Есть ли какие-либо полезные связанные инструменты тестирования/отладки/обучения (инжекторы ошибок, инструменты самоанализа, ложные файловые системы и т.д.)?

Для реальной аварии нет. Кстати, настоящий крах выходит за рамки ядра. Аппаратное обеспечение может изменять порядок записи (и не записывать все), повреждая файловую систему. Ext4 лучше подготовлен к этому, потому что он позволяет по умолчанию писать строки (параметры монтирования) (ext3 не делает) и может обнаруживать повреждение с контрольными суммами журнала (также опция mount).

И для изучения: узнайте, как оба изменения каким-то образом связаны в журнале!:-P

Ответ 3

Ответ на ваш вопрос будет сильно зависеть от конкретной используемой ОС, типа используемой файловой системы и того, находятся ли источник и dest на одном устройстве или нет.

Я бы начал с чтения справочной страницы переименования (2) на используемой вами платформе.

Ответ 4

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

В любом случае, эта статья, похоже, касается ваших вопросов относительно fsync: http://blogs.gnome.org/alexl/2009/03/16/ext4-vs-fsync-my-take/