ファイルの追加はUNIXでアトミックですか?


106

一般に、複数のプロセスからUNIXのファイルに追加する場合、何を当然と見なすことができますか?データを失う可能性はありますか(1つのプロセスが他のプロセスの変更を上書きします)?データが壊れる可能性はありますか?(たとえば、各プロセスが追加ごとに1行をログファイルに追加していますが、2行が破損する可能性はありますか?)上記の意味で追加がアトミックでない場合、相互排除を保証する最良の方法は何ですか?

回答:


65

「PIPE_BUF」のサイズ未満の書き込みはアトミックであると想定されています。これは512バイト以上にする必要がありますが、簡単に大きくなる可能性があります(Linuxでは4096に設定されているようです)。

これは、すべて完全にPOSIX準拠のコンポーネントについて話していることを前提としています。たとえば、これはNFSでは当てはまりません。

ただし、「O_APPEND」モードで開いたログファイルに書き込み、行(改行を含む)を「PIPE_BUF」バイト以下に保つと仮定すると、破損の問題を発生させることなく、ログファイルに複数のライターを置くことができます。割り込みは書き込みの前後ではなく、途中で到着します。再起動fsync(2)後もファイルの整合性を維持したい場合は、書き込み後に毎回呼び出す必要がありますが、パフォーマンスはひどいものです。

明確化:コメントとOz Solomonの回答を読んでください。それO_APPENDがそのPIPE_BUFサイズの原子性を持っているはずだとは思いません。Linuxの実装方法write()が原因である可能性も、基礎となるファイルシステムのブロックサイズが原因である可能性もあります。


11
正気なファイルシステムでfsync(2)は、できる限りの保証がsync(2)あり、パフォーマンスに大きな影響を与えません。
ephemient 2009

4
よろしいですか?その行動についてのリンクを教えてもらえますか?記述子がパイプであるかどうかを確認しましたが、どのファイルで機能するという証拠は見つかりませんでした。通常の非NFSファイルオブジェクトを含みます。
アランフランゾーニ

6
... / write.htmlの正確な場所はどこですか?O_APPENDの場合、PIPE_BUFについての言及はなく、「ファイルオフセットの変更と書き込み操作の間にファイル変更操作が発生しない」という約束はありますが、これが書き込み操作自体であるかどうかわかりません中断されない...
akavel

6
この答えは指摘して、およそ声明PIPE_BUFそのページ上では唯一のパイプとFIFO、ではない通常のファイルに適用されます。
Greg Inozemtsev

3
シグナルが到着すると、これはさらに悪化する可能性があります:bugzilla.kernel.org/show_bug.cgi?id=55651。なぜこれが回答としてマークされているのですか?PIPE_BUFはファイルとは関係ありません。
2015

35

編集:最新のWindowsの結果で2017年8月に更新。

非同期ファイルシステムとファイルI / O C ++ライブラリを実装する提案されたBoost.AFIOの作成者として、テストコードと結果へのリンクを含む回答を提供します。

まず、WindowsでのO_APPENDまたは同等のFILE_APPEND_DATAは、最大ファイルエクステント(ファイルの「長さ」)の増分が、同時ライターの下でアトミックであることを意味します。これはPOSIXによって保証されており、Linux、FreeBSD、OS X、Windowsはすべて正しく実装されています。Sambaもそれを正しく実装します。v5より前のNFSは、アトミックに追加するワイヤーフォーマット機能がないため、これを行いません。そのため、追加のみでファイルを開いた場合、NFSが関係していない限り、主要なOS同時書き込みが互いに引き裂かれることはありません

ただし、アトミックアペンドへの同時読み取りでは、OS、ファイリングシステム、およびファイルを開いたフラグによっては、書き込みの欠落が発生する可能性があります。最大ファイルエクステントの増分はアトミックですが、読み取りに関する書き込みの可視性は異なる場合があります。アトミックであること。フラグ、OS、ファイリングシステムごとの簡単な要約を次に示します。


O_DIRECT / FILE_FLAG_NO_BUFFERINGなし:

NTFSを使用するMicrosoft Windows 10:10.0.10240までのアトミック性= 1バイト、10.0.14393から少なくとも1Mb、おそらく無限(*)。

Linux 4.2.6 with ext4:更新原子性= 1バイト

FreeBSD 10.2 with ZFS:原子性の更新=少なくとも1Mb、おそらく無限(*)

O_DIRECT / FILE_FLAG_NO_BUFFERING:

NTFSを使用するMicrosoft Windows 10:原子性を更新します。ページが揃えられている場合のみ10.0.10240まで最大4096バイト、それ以外の場合はFILE_FLAG_WRITE_THROUGHがオフの場合は512バイト、それ以外の場合は64バイト。この原子性は、設計されたものではなく、PCIe DMAの機能であることに注意してください。10.0.14393以降、少なくとも1Mb、おそらく無限(*)です。

Linux 4.2.6 with ext4:更新の原子性=少なくとも1Mb、おそらく無限(*)。ext4を備えた以前のLinuxは4096バイトを確実に超えていなかったことに注意してください。XFSは確かにカスタムロックを使用していましたが、最近のLinuxがついにこれを修正したようです。

FreeBSD 10.2 with ZFS:原子性の更新=少なくとも1Mb、おそらく無限(*)


https://github.com/ned14/afio/tree/master/programs/fs-probeで生の実験的テスト結果を確認できます。512バイトの倍数でのみ引き裂かれたオフセットをテストすることに注意してください。したがって、512バイトのセクターの部分的な更新が読み取り-変更-書き込みサイクル中に破損するかどうかはわかりません。

したがって、OPの質問に答えるために、O_APPENDの書き込みは相互に干渉しませんが、O_APPENDの書き込みと同時に読み取ると、O_DIRECTがオンでない限り、ext4を使用するLinuxで破損した書き込みが表示されるため、O_APPENDの書き込みはセクターサイズの倍数にする必要があります。


(*)「おそらく無限」は、POSIX仕様の次の節に由来します。

次の関数はすべて、通常のファイルまたはシンボリックリンクを操作するときに、POSIX.1-2008で指定された効果の中で互いにアトミックでなければならない... [多くの関数] ... read()... write( )... 2つのスレッドがそれぞれこれらの関数の1つを呼び出す場合、各呼び出しは、他の呼び出しの指定された効果をすべて参照するか、まったく参照しないかのいずれかになります。[ソース]

そして

書き込みは、他の読み取りおよび書き込みに関してシリアル化できます。ファイルデータのread()がデータのwrite()の後に発生したことが(何らかの手段で)証明できる場合、呼び出しが異なるプロセスで行われた場合でも、そのwrite()を反映する必要があります。[ソース]

しかし逆に:

このPOSIX.1-2008のボリュームでは、複数のプロセスからファイルへの同時書き込みの動作は指定されていません。アプリケーションは、なんらかの形の同時実行制御を使用する必要があります。[ソース]

あなたはこの答えでこれらの意味についてもっと読むことができます


29

最大のアトミック追加サイズを経験的にテストするためのスクリプトを書きました。bashで記述されたスクリプトは、複数のワーカープロセスを生成し、すべてワーカー固有の署名を同じファイルに書き込みます。次に、ファイルを読み取り、重複または破損した署名を探します。このブログ投稿でスクリプトのソースを確認できます。

実際の最大アトミック追加サイズは、OSだけでなく、ファイルシステムによっても異なります。

Linux + ext3ではサイズは4096、Windows + NTFSではサイズは1024です。その他のサイズについては、以下のコメントを参照してください。


Linuxでどのファイルシステムをテストしましたか?ファイルシステムのブロックサイズに基づいているのではないかと思います。
フライハイト2015

@freiheit私はext3でテストしたときに信じています。別のFSで実行して別の結果が得られた場合は、コメントを投稿してください。
Oz Solomon、

3
@OzSolomon、私はDebian 7.8でスクリプトを使用しましたが、ext4パーティションとtmpfsマウントの両方で、最大1008バイト(1024-16バイトのオーバーヘッド?)を含むアトミックな書き込みしか取得できませんでした。それ以上のものは毎回腐敗につながりました。
Eric Pruitt、2015

6
テストでは、のサイズecho $line >> $OUTPUT_FILEwrite関係なくが1回呼び出されると想定しているようです$line
トーマス

16

これは標準が言うことです:http : //www.opengroup.org/onlinepubs/009695399/functions/pwrite.html

場合O_APPENDファイル状態フラグのフラグがセットされ、オフセットファイルは、各書き込みに先立ってファイルの末尾に設定されるものと介在ファイル変更操作がオフセットファイル書き込み動作を変更することとの間に生じてはなりません。


20
「間」-しかし、書き込みの介入についてはどうですか、私の理解では「間」の後に起こりますか?(つまり:<change_offset_action> ... "the_between_period" ... <write_action>)-保証がないことを理解できますか?
akavel 2012年

@akavelは同意した。書き込み自体がアトミックであるという保証はありません。しかし、私は混乱しています。あなたの見積もりで提供された保証に基づいて、同じファイルを追加するマルチスレッドのアプリは、書き込まれた異なるレコードの一部を混合しないと結論付けることができるようです。ただし、OzSolomonによって報告された実験から、その仮定に違反していることがわかります。どうして?
最大

@max申し訳ありません。申し訳ありません。まず、OzSolomonの実験はマルチプロセスであり、マルチスレッド(シングルプロセス)アプリではありません。第二に、「マルチスレッドアプリ[...]はミックスされない」という結論を引き出す方法がわかりません。これは、バスティエンからの引用によって保証されていないことをコメントで述べたとおりです。質問を明確にできますか?
akavel 2017年

2
ええと、コメントを書いた時点では自分のロジックを再構築することはできません...はい、あなたの解釈が正しければ、当然、異なるレコードが混在する可能性があります。しかし、私がバスティエンの引用を読み直している今、それは誰も「書き込み中」を中断できないことを意味しているに違いないと思います-そうでなければ、標準の段落全体が役に立たず、文字通りまったく保証を提供しません最後に、「書き込み」ステップの実行中に他の誰かがオフセットを移動する可能性があるため
max
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.