19

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

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

私は現在(Pythonで)持っています:

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

特定の質問

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

前もって感謝します。

4

4 に答える 4

16

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

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

本当の質問は次のようになります。

POSIX APIを介してそれをサポートするシステムで永続的な名前変更を行うにはどうすればよいですか?

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

fsync(destdirfd)も暗黙的にソースディレクトリをfsyncしますか?

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

または、電源を入れ直した後(「クラッシュ」)にファイルが両方のディレクトリに表示される可能性があります。つまり、永続的なアトミック移動操作を保証することは不可能ですか。

  • 一般的なPOSIX:保証はありませんが、両方のディレクトリをfsync()することになっています。これは、アトミック耐久性がない可能性があります。
  • ext3 / 4:最低限必要なfsync()の量は、マウントオプションによって異なります。たとえば、「dirsync」でマウントされている場合、これら2つのfsync()は必要ありません。せいぜい両方のfsync()が必要ですが、ほぼ確実に1つで十分です(その場合は原子耐久性があります)。

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

  • POSIX:いいえ
  • ext3 / 4:両方が同じトランザクションになると本当に信じているので、どちらをfsync()にするかは関係ありません。
  • 古いカーネルext3:(同じトランザクションにない場合)一部のあまり最適ではない実装は、fsync()での同期が多すぎたため、以前に発生したすべてのトランザクションをコミットしたに違いありません。そして、はい、通常の実装では、最初にそれを宛先にリンクしてから、ソースから削除します。したがって、fsync(srcdirfd)は、宛先のfsync()もトリガーします。
  • ext4 /最新のext3:それらが同じトランザクションにない場合は、それらを完全に独立して同期できる可能性があります(両方を実行してください)

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

実際のクラッシュの場合、いいえ。ちなみに、実際のクラッシュはカーネルの視点を超えています。ハードウェアが書き込みを並べ替えて(すべての書き込みに失敗して)、ファイルシステムを破壊する可能性があります。Ext4は、デフォルトで書き込みバリー(マウントオプション)を有効にし(ext3は無効)、ジャーナルチェックサム(マウントオプションも)で破損を検出できるため、これに対してより適切に準備されています。

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

于 2013-05-11T18:11:56.333 に答える
14

POSIXは、名前変更関数はアトミックでなければならないと定義しています。

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

しかし、それは、rename()操作が永続的であることを確認するという問題を解決しません。 POSIXはこの質問に答えます

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

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

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

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

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

(追加情報で更新:Linux固有の動作と移植可能な動作)

于 2011-04-27T18:56:09.167 に答える
-1

あなたの質問への答えは、使用されている特定のOS、使用されているファイルシステムのタイプ、およびソースと宛先が同じデバイス上にあるかどうかに大きく依存します。

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

于 2011-04-12T17:59:45.267 に答える
-4

あなたがファイルシステムの仕事をしようとしているように私には聞こえます。ファイルを移動する場合、コードではなく、カーネルとファイルシステムがアトミック操作と障害回復を担当します。

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

于 2011-04-13T05:14:46.013 に答える