既存のファイルを書き換えて、完全に一度だけ書き込まれた後、アトミックに新しいバージョンに置き換えられるようにします


18

私は漠然と、どこかで読んだことを覚えています。一部のUnicesでは、既存のファイルを書き込み用に開き、カーネルに古いバージョン(読み取り用にアクセスする他のプロセス)を使用するように要求するフラグがあり、「新しい"バージョンは完全に記述され(fdは閉じられます)、その時点からファイルは新しいバージョンとして表示されました。

言い換えると、他のプロセスは、古いバージョンまたは新しいバージョンのいずれかを認識し、不完全に記述されたバージョンは認識しませんでした。

知識のある人が私に参照を示すことができますか?


Plan 9でできることのように聞こえますが、違います。
ジル「SO-悪であるのをやめる」

2
OpenVMS上のFiles-11のように聞こえます:「既存のバージョンを上書きするのではなく、ファイルを保存するたびに、同じ名前でバージョン番号が増加した新しいファイルが作成されます。」
マット

なぜ聞いたの?その機能が必要ですか、それとも単なる好奇心でしたか?
ニルス

1
その機能があれば嬉しいですし、どこかでそれが存在していたことを思い出しました。したがって、ニーズと好奇心の両方が混在しています。
eudoxos

すべてのUnixシステムでは、これを別の方法で許可しています。同じディレクトリに新しいファイルを作成し、変更された内容を入力して、アトミックな名前変更を行います。これは小さな変更の場合ははるかに高価ですが、機能します。
-Netch

回答:


14

あなたが説明しているのは、ファイルを上書きする基本的な名前変更とまったく同じです。

あるファイルを別のファイルの上に名前変更/移動すると、古いファイルはリンク解除されます。ファイルはまだ存在していますが、ファイルシステムツリーには存在しません。したがって、古いアプリケーションは、開いたままである限り、引き続きファイルにアクセスできます。すべてのアプリケーションが古いファイルを閉じると、実際にはディスク上で未割り当てになります。

renameシステムコールはアトミック操作です。そのためには、別の名前で新しいファイルを作成してrenameから、一時ファイルの名前を変更して、一時ファイルの名前を変更します。操作はアトミックであるため、ファイルが欠落している期間は絶対にありません。すぐに古いファイルから新しいファイルに移動します。
ただし、一時ファイルと置き換えられるファイルは同じマウントポイントに存在する必要があることに注意してください。


プログラムが機能を念頭に置いて特別に記述されている場合にのみ、それを使用できます。ただし、この場合、これはOSの機能であり、通常のプログラムでさえもこのアトミックなセマンティクスを自動的に与えられていました。
eudoxos

1
@eudoxosコメントは意味がありません。あなたは、プログラムがrenameスワップの事をするために特別に書かれなければならないと言っている。たとえあなたが話しているような「OSの機能」が存在したとしても、それを利用するためにはプログラムを作成する必要があります。違いは何ですか?
パトリック

(おそらくサポートされていない)フラグをopensyscallに渡すか、手動で記述したことを行う必要がある場合には、違いがあります。
eudoxos

クラッシュした場合には、古いまたは完全に書かれた新しいバージョンのどちらかを保つためにあなたがにfsyncまたは類似してディスクに新しいファイルの同期に加えてする必要があることに注意してください
textshell

同期なしの@textshellでも、原子性は得られますが...耐久性ではありません...正しいですか?この場合、goo.gl / qfQQfyの議論は理解できません。私の場合、システムに極端な負荷がかかっており、ファイルシステムのフラッシュを避けたいので、ファイルがクラッシュしても生き残るかどうかは気にしません。
-wcochran

6

パトリックの書き込み、これを行うための通常の方法は、アトミックそれを上書きし、古いファイル名に、新しいバージョンを別のファイルに新しいバージョンを書き、そして時に完成し、リネームすることです。この2番目の操作は、overwrite-by-renameと呼ばれます

次に、いくつかの参照:


man 3p renameそれrenameは確かに原子的であり、すべてのLinuxファイルシステムを対象としていると思います。そして、あなたがリンクした最初の記事を読んだとき、私はまだBtrfsの名前変更操作はアトミックだと思います。
ハゲロ

1

これは、Allocate On Flushを思い出させます。ファイルシステムがこの機能を使用すると、ディスクに直接データを書き込むのではなく、ディスクの空き領域カウンターから書き込むデータのサイズを減算し、同期システムコールが実行されるか、カーネルが決定するまでデータをメモリに保持しますダーティバッファをフラッシュします。

この場合、ファイルが1つのプロセスによって変更され、別のプロセスによって開かれた場合、後者のプロセスはファイルの変更されていない(または「古い」)バージョンを「参照」します。

もちろん、上記は理論的なものであり、さまざまな要因に依存します。カーネルがダーティページをフラッシュするタイミングが正確にはわからないため、少し予測できないと思います。たとえば、Linuxの場合(Linuxカーネルの理解のセクション15.3を参照することもできます)、次の条件下でダーティページがディスクに書き込まれます。

  • ページキャッシュがいっぱいになり、より多くのページが必要になるか、ダーティページの数が多くなりすぎます。

  • ページが汚れたままになってから時間が経過しすぎています。

  • プロセスは、ブロックデバイスまたは特定のファイルの保留中のすべての変更をフラッシュするように要求します。これは、sync()、fsync()、またはfdatasync()システムコールを呼び出すことでこれを行います。

この機能は、HFS +、XFS、Reiser4、ZFS、Btrfs、ext4ファイルシステムに実装されていることが知られています。


2
説明するのは、POSIX(ファイル)システム上でユーザー空間から見えない(したがって、指定したことを実行しない)ファイルシステム手法です(writeを参照:「ファイルデータのread()が(何らかの手段で)データのwrite()の後に発生するには、呼び出しが異なるプロセスによって行われた場合でも、そのwrite()を反映する必要があります。他のプロセスは古いデータを表示しません(POSIXで)。
マット

修正していただきありがとうございます。このファイルシステムのテクニックの理解が間違っていたと思います。
dkaragasidis

右、これは何か別のように見えます。彼がこの機能について言及したのはRMSとのインタビューであったことを、今は漠然と思い出します。
eudoxos
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.