回答:
「PIPE_BUF」のサイズ未満の書き込みはアトミックであると想定されています。これは512バイト以上にする必要がありますが、簡単に大きくなる可能性があります(Linuxでは4096に設定されているようです)。
これは、すべて完全にPOSIX準拠のコンポーネントについて話していることを前提としています。たとえば、これはNFSでは当てはまりません。
ただし、「O_APPEND」モードで開いたログファイルに書き込み、行(改行を含む)を「PIPE_BUF」バイト以下に保つと仮定すると、破損の問題を発生させることなく、ログファイルに複数のライターを置くことができます。割り込みは書き込みの前後ではなく、途中で到着します。再起動fsync(2)
後もファイルの整合性を維持したい場合は、書き込み後に毎回呼び出す必要がありますが、パフォーマンスはひどいものです。
明確化:コメントとOz Solomonの回答を読んでください。それO_APPEND
がそのPIPE_BUF
サイズの原子性を持っているはずだとは思いません。Linuxの実装方法write()
が原因である可能性も、基礎となるファイルシステムのブロックサイズが原因である可能性もあります。
PIPE_BUF
そのページ上では唯一のパイプとFIFO、ではない通常のファイルに適用されます。
編集:最新の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、ファイリングシステムごとの簡単な要約を次に示します。
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、おそらく無限(*)
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のボリュームでは、複数のプロセスからファイルへの同時書き込みの動作は指定されていません。アプリケーションは、なんらかの形の同時実行制御を使用する必要があります。[ソース]
最大のアトミック追加サイズを経験的にテストするためのスクリプトを書きました。bashで記述されたスクリプトは、複数のワーカープロセスを生成し、すべてワーカー固有の署名を同じファイルに書き込みます。次に、ファイルを読み取り、重複または破損した署名を探します。このブログ投稿でスクリプトのソースを確認できます。
実際の最大アトミック追加サイズは、OSだけでなく、ファイルシステムによっても異なります。
Linux + ext3ではサイズは4096、Windows + NTFSではサイズは1024です。その他のサイズについては、以下のコメントを参照してください。
echo $line >> $OUTPUT_FILE
にwrite
関係なくが1回呼び出されると想定しているようです$line
。
これは標準が言うことです:http : //www.opengroup.org/onlinepubs/009695399/functions/pwrite.html。
場合
O_APPEND
ファイル状態フラグのフラグがセットされ、オフセットファイルは、各書き込みに先立ってファイルの末尾に設定されるものと介在ファイル変更操作がオフセットファイル書き込み動作を変更することとの間に生じてはなりません。
fsync(2)
は、できる限りの保証がsync(2)
あり、パフォーマンスに大きな影響を与えません。