1

ファイルアクティビティをディスクにフラッシュすることに関するWindowsWin32C++の質問。

ファイルを作成する外部アプリケーション(CreateProcessを使用して実行)があります。つまり、返されるときに、いくつかのコンテンツを含むファイルが作成されます。

続行する前に、プロセスで作成されたファイルが実際にディスクにフラッシュされたことを確認するにはどうすればよいですか?

これは、C ++バッファではなく、実際にディスクをフラッシュすることを意味します(FlushFileBuffersなど)。

私はファイルHANDLEにアクセスできないことを忘れないでください。もちろん、これはすべて外部プロセス内に隠されています。

私は自分のハンドルをファイルに開いてからFlushFileBuffersを使用できると思いますが、これが機能するかどうかは明らかではありません(私のハンドルには実際にフラッシュが必要なものが含まれていないため)。

最後に、これを管理者以外のユーザースペースで実行して、ボリューム全体でFlushFileBuffersを使用できないようにします。

何か案は?


更新:なぜこれが問題だと思うのですか?

私はデータバックアップアプリケーションに取り組んでいます。基本的に、説明されているようにいくつかのファイルを作成する必要があります。次に、内部DBを更新する必要があります(SQLite組み込みDBを使用)。

最近、ブルースクリーン中にデータ破損の問題が発生しました(原因はアプリとは関係ありませんでした)。

私が懸念しているのは、システムクラッシュ時のアプリケーションの整合性です。そして、はい、このアプリはデータバックアップアプリなので、私はこれを気にします。

私が懸念しているユースケースは次のとおりです。

  1. 小さなデータファイルは、外部プロセスを使用して作成されます。この書き込みは、OSキャッシュでディスクへの書き込みを待機しています。
  2. DBを更新してコミットします。これはディスクアクティビティです。この書き込みもOSキャッシュで待機しています。
  3. システム障害が発生します。

私が見ているように、私たちは今、潜在的な競合状態にあります。「1」がフラッシュされ、「2」がフラッシュされない場合は、問題ありません(DBトランザクションがコミットされていないため)。どちらもフラッシュされないか、両方がフラッシュされる場合は、問題ありません。

私が理解しているように、書き込みは非決定論的です。つまり、OSが「2」の前に「1」を書き込むことを保証することを私は知りません。(私が間違っている?)

したがって、「2」がフラッシュされても「1」がフラッシュされない場合は、問題が発生します。

私が観察したのは、DBが正しく更新されたが、ファイルにガベージが含まれていることでした。データの最後の3分の2はバイナリの「ゼロ」でした。さて、ブルースクリーン時にファイル部分をフラッシュしたときの様子はわかりませんが、そのように見えても驚かないでしょう。

これが原因であることを保証できますか?いいえ、これを保証することはできません。私はただ推測しています。ディスク障害またはブルースクリーンの結果として、ファイルが「自然に」破損した可能性があります。

パフォーマンスに関しては、これは私が対処できると私が信じていることです。

たとえば、SQLiteのデフォルトの動作では、トランザクションをコミットするたびに(FlushFileBuffersを使用して)完全なファイルフラッシュを実行します。これを行わないと、システムクラッシュ時に、DBが破損している可能性があることは明らかです。

また、「チェックポイント」でフラッシュするだけで、パフォーマンスの低下を軽減できると思います。たとえば、50個のファイルを書き込み、ロットをフラッシュしてからDBに書き込みます。

これがすべて問題になる可能性はどのくらいありますか?私を殴る。しかし、私のアプリはシステム障害時またはその前後にアーカイブされている可能性があるため、あなたが考える可能性が高くなります。

それが私がこれをしたくない理由を説明することを願っています。

4

3 に答える 3

3

なぜあなたはこれが欲しいのですか?OSは、データが期限内にディスクにフラッシュされることを確認します。アクセスすると、キャッシュまたはディスクからデータが返されるため、これは透過的です。

災害時の安全性が必要な場合はFlushFileBuffers、たとえば、外部プロセスの実行後に管理者権限を持つプロセスを作成して、を呼び出す必要があります。しかし、それはマシン全体のパフォーマンスに深刻な影響を与える可能性があります。

他の唯一のオプションは、他のプロセスのソースを変更することです。

[編集]最も簡単な解決策は、おそらくプロセスでファイルをコピーしてから、そのコピーをフラッシュすることです(ハンドルがあるため)。「データベースにコミットされていません」という名前でコピーを保存します。

次に、データベースを更新します。データベースに「ファイルから更新...」と書き込みます。次回このエントリがすでに存在する場合は、データベースを更新せずに、この手順をスキップしてください。

データベースをディスクにフラッシュします。

ファイルの名前を「ファイルはデータベースに処理されました」に変更します。名前の変更は不可分操作です(したがって、発生するかどうかは関係ありません)。

さまざまな状態に適したファイル名が思いつかない場合は、サブフォルダーを使用してファイルをサブフォルダー間で移動します。

于 2009-11-29T16:18:08.573 に答える
2

まあ、ここには魅力的なオプションはありません。プロセスから必要なファイル ハンドルを取得する方法は文書化されていません。文書化されていないものもありますが、(DuplicateHandle を介して) 慎重に検討してください。

はい、ボリューム ハンドルで FlushFileBuffers を呼び出す方法が文書化されています。サービスに呼び出しを行わせることで、特権の問題を回避できます。標準のプロセス相互運用メカニズムの 1 つを使用して、アプリから対話します。名前の先頭に Global\ が付いた名前付きパイプは、おそらくそれを実現する最も簡単な方法です。

于 2009-11-29T18:00:23.070 に答える
0

更新後、http://sqlite.org/atomiccommit.htmlで必要な答えが得られると思います。

すべてがディスクにフラッシュされることを保証する SQLite の方法が機能します。したがって、それはあなたにも役立ちます-ソースを見てください.

于 2009-11-30T10:36:34.707 に答える