6

ファイルをメモリと定期的に同期する最速の方法が必要です。

私が欲しいと思うのは、手動でディスクに同期するだけのmmapファイルを作成することです。自動同期を防ぐ方法がわかりません。

手動で指定した場合を除き、ファイルを変更することはできません。重要なのは、状態のスナップショットをメモリに保持するチェックポイントファイルを用意することです。かなり頻繁に呼び出す必要があり、速度が重要であるため、コピーはできるだけ避けたいと思います。

4

5 に答える 5

4

ファイルのマッピング内でメモリに書き込むものはMAP_SHAREDすべて、その時点でファイルに書き込まれていると見なされます。これは、を使用した場合と同じですwrite()msync()この意味では、完全に類似しています。これは、ファイルにすでに加えた変更が実際に永続ストレージにプッシュされるfsync()ことを保証するだけです。これを変更することはできません-それはどのように機能するように定義されているかです。mmap()

一般に、これを行う安全な方法は、データの完全に一貫したコピーを一時ファイルに書き込み、一時ファイルを同期してから、前のチェックポイントファイルにアトミックに名前を変更することです。これは、チェックポイント間のクラッシュによって一貫性のないファイルが残らないようにする唯一の方法です。コピーが少ないソリューションでは、より複雑なトランザクションログスタイルのファイル形式と、アプリケーションの残りの部分への煩わしさの両方が必要になります(メモリ内の状態が変更される各場所で特定のフックを呼び出す必要があります) 。

于 2010-06-30T05:16:14.077 に答える
2

他の回答者が示唆しているように、コピーせずにやりたいことを実行するためのポータブルな方法はないと思います。OSなどを制御できる特別な目的の環境でこれを実行しようとしている場合は、Linuxでbtrfsファイルシステムを使用して実行できる可能性があります。

btrfsは、reflink()本質的にコピーオンライトファイルシステムコピーである新しい操作をサポートします。reflink()ファイルを起動時に一時mmap()的に、一時的に、そしてmsync()一時reflink()的に元のチェックポイントに戻すことができます。

于 2010-07-01T13:28:12.740 に答える
2

mmapこの目的には使用できません。データがディスクに書き込まれるのを防ぐ方法はありません。実際には、メモリをスワップ不可にするために使用mlock()すると、書き込みを要求した場合を除いて、メモリがディスクに書き込まれないという副作用が発生する可能性がありますが、保証はありません。確かに、別のプロセスがファイルを開くと、物理ディスク上のコピーではなく、メモリにキャッシュされたコピー(最新の変更を含む)が表示されます。多くの点で、何をすべきかは、他のプロセスと同期しようとしているのか、クラッシュや電源障害の場合の安全のためだけにしようとしているのかによって異なります。

データサイズが小さい場合は、ディスクへのアトミック同期のために他のいくつかの方法を試すことができます。1つの方法は、データセット全体をファイル名に保存し、その名前で空のファイルを作成してから、古いファイルを削除することです。起動時に2つのファイルが存在する場合(クラッシュ時間が非常に少ないため)、古いファイルを削除して、新しいファイルから再開します。write() データサイズがファイルシステムブロック、ページサイズ、またはディスクブロックよりも小さい場合もアトミックになる可能性がありますが、その効果がすぐに保証されるかどうかはわかりません。あなたはいくつかの研究をしなければならないでしょう。

データがそれほど大きくなく、2つのコピーがディスクに収まらない限り機能する、もう1つの非常に標準的なアプローチです。一時的な名前で2つ目のコピーを作成し、rename()それを古い名前の上に重ねます。rename()常にアトミックです。そうしない理由がない限り、これはおそらく最良のアプローチです。

于 2010-06-30T04:45:34.807 に答える
2

書き込みmmap()時にコピーとしてファイルを作成して、メモリ内で行った更新がファイルに書き戻されないようにすることができます。同期する場合は、次のことができます。

A)書き込み時にコピーされない新しいメモリマッピングを作成し、変更したページだけをコピーします。

または

B)直接I / O(ブロックサイズに合わせたサイズの読み取りと書き込み)でファイルを開き(通常のファイルを開きます)、変更したページのみを書き込みます。ページ全体(メモリページサイズはディスクブロックサイズの倍数)を書き込んでおり、バッファリングがないため、ダイレクトI/Oは素晴らしく高速です。この方法には、が大きく、別の巨大なファイルmmap()を保存する余地がない場合に、アドレス空間を使用しないという利点があります。mmap()

同期後、書き込み時のコピーmmap()はディスクファイルと同じですが、カーネルには、同期に必要なページが(ディスクと)非共有としてマークされたままです。したがって、メモリ不足が発生した場合に、カーネルが必要に応じて(ページをスワップアウトする代わりに)ページを破棄できるように、閉じて再作成できますmmap()(書き込み時にコピーオンライト)。

もちろん、OSがその情報を保持している場所にアクセスする方法がわからないため、自分で変更したページを追跡する必要があります。(それは便利ではないでしょうsyscall()か?)

- 編集 -

実際、mmapのページの汚れをユーザースペースから見つけることができますか?を参照してください。どのページが汚れているかを確認する方法についてのアイデア。

于 2010-12-17T20:26:29.757 に答える
-1

これはどのOSでも利用されていない可能性が高いと思いますが、OSが次の最適化に気付く可能性があります。

int fd = open("file", O_RDWR | O_SYNC | O_DIRECT);

size_t length = get_lenght(fd);

uint8_t * map_addr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);

...

// This represents all of the changes that could possibly happen before you
// want to update the on disk file.
change_various_data(map_addr);

if (is_time_to_update()) {
   write(fd, map_addr, length);
   lseek(fd, 0, SEEK_SET);
   // you could have just used pwrite here and not seeked
}

OSがこれを利用できる可能性がある理由は、特定のページに書き込むまで(そして他の誰も書き込みを行わない限り)、OSはおそらくその場所にある実際のファイルのページをそのページのスワップとして使用するからです。

次に、それらのページのセットに書き込むと、OSはプロセスのためにそれらのページをコピー オン ライトしますが、未書き込みのページは元のファイルでバックアップされたままになります。

次に、OSを呼び出すwriteと、書き込みがメモリとディスクの両方でブロックアラインされていることに気付き、ソースメモリページの一部が、書き込み先の正確なファイルシステムページとすでに同期されていることに気付く可能性があります。変更されたページのみを書き出します。

そうは言っても、この最適化がどのOSでも行われていなくても驚かないでしょう。このタイプのコードは非常に遅くなり、「write」を呼び出すと大量のディスク書き込みが発生します。それを利用すればかっこいいでしょう。

于 2010-06-30T20:49:30.170 に答える