POSIX でファイルの名前を永続的に変更するにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/3764822

質問

POSIX ファイル システムでファイルの名前を永続的に変更する正しい方法は何ですか?特に fsync について疑問に思っているのは、 ディレクトリ. 。(これが OS/FS に依存する場合は、Linux と ext3/ext4 について質問しています)。

注記:StackOverflow には永続的な名前変更に関する他の質問もありますが、私の知る限りでは、ディレクトリの fsync については触れられていません (これが私にとって重要です。ファイル データは変更していません)。

私は現在(Pythonで)次のものを持っています:

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

具体的な質問:

  • これはソースディレクトリも暗黙的に fsync しますか?あるいは、電源を入れ直しても両方のディレクトリにファイルが表示されることになる可能性があります (つまり、ハード リンク数を確認し、手動でリカバリを実行する必要があります)。永続的なアトミックな移動操作を保証することは不可能ですか?
  • ソースディレクトリを fsync すると の代わりに 宛先ディレクトリを指定すると、暗黙的に宛先ディレクトリも fsync されますか?
  • 関連する便利なテスト/デバッグ/学習ツール (フォールト インジェクター、イントロスペクション ツール、モック ファイルシステムなど) はありますか?

前もって感謝します。

役に立ちましたか?

解決

Posixはそれを定義します 改名関数はアトミックでなければなりません.

したがって、(a、b)の名前を変更した場合、いかなる状況でも、ディレクトリまたはどちらのディレクトリの両方にファイルがある状態が表示されてはなりません。 FSYNC()で何をしても、システムがクラッシュするかどうかに関係なく、常に正確に1つあります。

しかし、それは、rename()操作が耐久性があることを確認するという問題を解決しません。 Posixはこの質問に答えます:

_posix_synchronized_ioが定義されている場合、fsync()関数は、ファイル記述子フィルデによって示されているファイルに関連付けられているすべての現在キューに入れられたすべてのI/O操作を同期I/O完了状態に強制するものとします。すべてのI/O操作は、同期されたI/Oファイルの整合性完了のために定義されているように完了するものとします。

したがって、ディレクトリをfsync()の場合、保留中の名前変更操作は、これが戻るまでにディスクに転送する必要があります。 rename()操作の原子性は、両方のディレクトリの変更を原子的に同期する必要があるため、いずれかのディレクトリのfsync()で十分である必要があります。

最後に、別の回答に記載されているブログ投稿の主張とは対照的に、これの理論的根拠は以下を説明しています。

fsync()関数は、バッファキャッシュからデータの物理的な書き込みを強制し、システムがクラッシュまたはその他の障害後にすべてのデータがFSYNC()の時間までのすべてのデータがディスクに記録されることを保証することを目的としています。 「バッファーキャッシュ」、「システムクラッシュ」、「物理書き込み」、および「不揮発性ストレージ」の概念はここでは定義されていないため、文言はより抽象的でなければなりません。

POSIXに準拠していると主張し、FSYNC()を完成させるための正しい動作(つまり、バグやハードウェアの障害ではない)と見なしたシステムは、システムクラッシュ全体でそれらの変更を維持しないことは、仕様に関して意図的に誤って伝えられる必要があります。

(追加情報で更新されたRe:Linux固有とポータブル動作)

他のヒント

残念ながら、デイブの答えは間違っています。

すべてのPOSIXシステムには、耐久性のあるストレージさえあるわけではありません。そして、もしそうなら、システムがクラッシュした後、まだ「許可」されます。これらのシステムでは、no-op fsync()が理にかなっており、そのようなfsync()はPOSIXで明示的に許可されています。また、ファイルが古いディレクトリ、新しいディレクトリ、両方、またはその他の場所で回復可能であることも合法です。 POSIXは、システムのクラッシュまたはファイルシステムの回復を保証しません。

本当の質問は次のとおりです。

POSIX APIを介してそれをサポートするシステムで耐久性のある名前を変更するにはどうすればよいですか?

両方のソースでfsync()を行う必要があります 宛先ディレクトリは、これらのfsync()が行うべき最小値は、ソースまたは宛先ディレクトリがどのように見えるかを永続化することです。

FSYNC(DestDirfd)は、Sourceディレクトリを暗黙的にfsyncしますか?

  • 一般的なPosix:いいえ、それを意味するものはありません
  • Ext3/4:ソースと宛先DIRの両方がジャーナルで同じトランザクションに変更されるかどうかはわかりません。もしそうなら、彼らは両方を一緒にコミットします。

または、パワーサイクル(「クラッシュ」)の後、両方のディレクトリにファイルが表示されることになってしまう可能性があります。つまり、耐久性のある原子移動操作を保証することは不可能です。

  • 一般的なPosix:保証はありませんが、あなたは両方のディレクトリをfsync()することになっています。
  • ext3/4:最小限の必要なfsync()の量は、マウントオプションによって異なります。たとえば、「dirsync」で取り付けられている場合、これらの2つのfsync()のいずれも必要ありません。せいぜいfsync()sの両方が必要ですが、私はほぼ十分であると確信しています(その後、原子耐性)。

宛先ディレクトリの代わりにソースディレクトリをfsyncする場合、それはまた、宛先ディレクトリを暗黙的にfsyncするでしょうか?

  • Posix:いいえ
  • ext3/4:両方が同じトランザクションになると本当に信じているので、どちらがあなたのfsync()に関係していません
  • 古いカーネルext3 :(それらが同じトランザクションにない場合)それほど最適でない実装は、fsync()であまりにも多くの同期を行いました。そして、はい、通常の実装により、最初に宛先にリンクしてから、ソースから削除します。したがって、FSYNC(SRCDIRFD)は、宛先のFSYNC()もトリガーします。
  • ext4/最新のext3:それらが同じトランザクションにない場合、あなたはそれらを独立して完全に同期することができるかもしれません(両方がそうする)

有用な関連するテスト/デバッグ/学習ツール(障害インジェクター、内省ツール、モックファイルシステムなど)はありますか?

実際のクラッシュのために、いいえ。ちなみに、実際のクラッシュはカーネルの視点を超えています。ハードウェアは、ファイルシステムを破損して、書き込みを再注文し(すべての書き込みに失敗します)、 Ext4は、デフォルトでBarries(Mount Options)を書き込み(Ext3にはそうではない)ことを可能にし、Journal Checksums(マウントオプション)で破損を検出できるため、これに対してよりよく準備されています。

学習のために:両方の変更が何らかの形でジャーナルにリンクされているかどうかを調べてください! :P

あなたの質問に対する答えは、使用されている特定の OS、使用されているファイルシステムの種類、ソースと宛先が同じデバイス上にあるかどうかによって大きく異なります。

まず、使用しているプラ​​ットフォームの rename(2) のマニュアル ページを読みます。

ファイルシステムの仕事をしようとしているように聞こえます。ファイルを移動すると、カーネルとファイルシステムは、コードではなく、原子動作と断層回復を担当します。

とにかく、この記事はFSYNCに関するあなたの質問に対処しているようです。http://blogs.gnome.org/alexl/2009/03/16/ext4-vs-fsync-my-take/

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top