ローカルデバイスのテストから、iOSファイルシステムにファイルを書き込むと(使用する呼び出しのレベルがどれほど低いかに関係なく)、ファイルがフラッシュに完全にコミットされる前に成功が返されることがよくあります。つまり、デバイスをハードリセットしてから再起動すると、ファイルがロールバックされるか(書き込みが完了したか、アトミックであった場合)、破損する可能性があります。この遅延の原因は何ですか(ドキュメントはありがたいですが、何も見つかりませんでした)。実際のファイルシステムの書き込みが完了したときにフィードバックを得る方法はありますか。たとえば、リモートサーバーからのデータの受信と保存を確認したいのですが、書き込みの「レポート」の成功後に確認すると、ハードクラッシュや電源障害が発生した場合にデータが失われる可能性があります。
1 に答える
これは4年前の質問なので、答えだけでなく、検索中にたどった道も示します。
公式ドキュメント「ファイルシステムプログラミングガイド」で明確な説明を見つけることができませんでした。パフォーマンスのヒントのセクションには手がかりしかありませんでした。それは次のように述べています:
アプリは、F_NOCACHEフラグを指定してBSD fcntl関数を呼び出し、ファイルのキャッシュを有効または無効にすることができます。この関数の詳細については、fcntlを参照してください。
フラグを有効にF_NOCACHE
しても、あなたが述べている問題は解決されませんが、fcntl
メソッドのマニュアルには、興味深いと思われるオプションがあると記載されています。
F_FULLFSYNC fsync(2)と同じことを行い、バッファリングされたすべてのデータを永続ストレージデバイスにフラッシュするようにドライブに要求します
(からman fcntl
、ここを参照)。
fsync
詳細については、マニュアルを確認しました。それは私に、最終的に、問題と解決策の両方の最も明確で最も理解しやすい説明を与えてくれました:
fsync()はすべてのデータをホストからドライブ(つまり「永続ストレージデバイス」)にフラッシュしますが、ドライブ自体がかなりの時間プラッターにデータを物理的に書き込まない可能性があり、出力に書き込まれる可能性があることに注意してください-順序シーケンス。
具体的には、ドライブの電源が切れたり、OSがクラッシュしたりすると、アプリケーションは、データの一部のみが書き込まれたか、まったく書き込まれなかったことを検出する場合があります。ディスクドライブは、データを並べ替えて、後の書き込みが存在するようにすることもできますが、前の書き込みは存在しません。
これは理論上のエッジケースではありません。このシナリオは、実際のワークロードとドライブの電源障害で簡単に再現できます。
データの整合性についてより厳密な保証が必要なアプリケーションの場合、MacOSXはF_FULLFSYNCfcntlを提供します。F_FULLFSYNC fcntlは、バッファリングされたすべてのデータを永続ストレージにフラッシュするようにドライブに要求します。書き込みの厳密な順序を必要とするデータベースなどのアプリケーションは、F_FULLFSYNCを使用して、データが期待どおりの順序で書き込まれるようにする必要があります。
(からman fsync
、ここを参照)。
ええ、それは間違いなく理論的なエッジケースではありません。ありがたいことに、問題がわかれば、解決策は簡単です。
let filePath: String = "your file path"
// you can use other option than read-write
let fd = open(String(path.utf8), O_RDWR)
// if fd is -1, there was an error opening file, handle it as you wish
guard fd != -1 else { return }
// syncResult is -1 if sync operation failed, handle it as you wish
let syncResult = fcntl(fd, F_FULLFSYNC)
// don't forget to close opened file
close(fd)
終了するとfcntl
、データが保存されます。
この操作は、通常のファイルへの書き込み(NSFileManager
またはwriteToURL
メソッドファミリ経由)よりも遅いことに注意してください。パフォーマンスの問題が発生した場合は、書き込みをバックグラウンドスレッドに移動することをお勧めします。