設計手順 Edit

次の点を考慮する。

ロック範囲の検討 Edit

読み出し整合性保証は必要か
読み出し内容に整合性を保証する必要がない場合がある。
例えば、リロードすれば済む単純な表示スクリプトのデータなどは、ロックする手間を省くことが出来る。

アドバイザリロックを使う限り、書き込みロック中も読み出し可能である。
書き出し内容は読み込み内容に依存するか
カウンタデータなど、読み込んだ内容をインクリメントして書き出すような場合は、
書き出しのコンフリクトを防ぐだけでなく、読み出しから書き込みまでの間に書き込もうとする他のプロセス書き込まないこと読み込まないことを保証しなければならない。

つまり、読み出しから書き出しまでの間、一貫してロックし続けなければならない。

ロックの生成 Edit

プロセスシャットダウン回避
PHPはユーザーのコネクション切断に応じて、任意のタイミングでプロセスをシャットダウンすることがある。

読み書き途中のシャットダウンによってファイル内容が破壊されることがあるため、ignore_user_abortをセットする必要がある。
シーク
ロックを取得した後、ファイルサイズが変化している場合などを考慮し、ロックした後でfseekをしておく必要がある。
書き込みロック
排他ロックを取得するまで、ファイル内容に変更を加えたり読み込んではならない。
$fp = @fopen('file.txt', 'r+b') or die();
flock($fp, LOCK_EX);
通常はこのようにr+でオープンすることで、ファイルに手を加えずにオープンする。
読み込みロック
単にオープンして共用ロックすればいい。

データ処理 Edit

バッファの考慮などは通常のファイル読み書きと変わらない。

ただし、

ロック取得前に読み込んだファイル内容を信用しない
ロックがブロックされている間に、他のプロセスが変更している可能性がある。
atimeを信用しない
アクセス時間は他のプロセスがロックにチャレンジするために、ロック中でも変更されている可能性がある。
書き込み時のエラー処理
読み込み中にreadシステムコールが失敗することでファイル整合性が壊れる。
これは基本的に起こることは少ない。しかし、読み込みが中断する可能性を考慮しなければならないシビアな用途では、次の関数の成功を確認する必要がある。
  • fread および関連関数
  • fseek および関連関数
書き込み時のエラー処理
書き込み中に、書き込み関数などが失敗するために、書き込み整合性が壊れることがある。
正しくロックが行われているなら、これは極めて高負荷なサーバー上でしか発生しない。
ただし、高負荷なカウンタプログラムなどでは、考慮すべき。エラー処理後、再試行するなどして、整合性を維持する必要がある関数は次の通り。
  • fwrite および関連関数
  • fseek および関連関数
  • ftruncate および関連関数
  • fflush
  • flock (LOCK_UN時)
  • fclose (フラッシュを任せた場合)

ロックの解除とファイルクローズ Edit

ファイルのクローズや、ロックを解除する際は、特別の注意を必要とする。

書き込みバッファの存在
プロセスレベルの書き込みバッファによって、書き込みデータがOSに渡されずに残っている可能性がある。
fflush($fp);
flock($fp, LOCK_UN);
fclose($fp);
で明示的にフラッシュするか、flock($fp,LOCK_UN)しない
fclose($fp); // LOCK_UN してはならない
をすることで、バッファがフラッシュされた後、ロックが解除される。
二重オープン時のクローズ
PHPには、 flockではなくfcntlシステムコールを利用してロックを処理するコンパイルオプション*1がある。fcntlの制限により、同じプロセスから同じファイルをオープンした場合、一つでもクローズした瞬間にロックが失われてしまう。

これは、get_file_contents等の組み込み関数が内部的にオープン・クローズした際にロックが失われてしまうことを意味する。


この制限によって、読み込みと書き込みをロックして行うような場合、読み込みにget_file_contents()を使うことが出来なくなる。

これを使うには、fcntlを使っていないか確認する必要がある。

その他のロック Edit

flockで実現できないディレクトリそのもののロックやNFS環境では、他の方法を使う必要がある。

別ファイルのロック
あらかじめ決めておいたファイルをロックすることで、対象をロックしたことにする。
  • 当然 flockのNFS問題回避には使えない。
ロックファイル・ディレクトリの生成
ファイルやディレクトリを生成することで、ロックしたことにする。
  • プロセスのシャットダウンなどでデッドロックが発生しやすく、デッドロックを明示的に検出する手段がない。
  • デッドロック時間を短くするトリックはいくつか存在するが、実時間処理の面倒を見る必要が出てくる。
データベースを用いる
全データかロック用のデータテーブルをデータベースに入れてしまう。


コンパイルオプションによっては、他の機能で代替できるが、一般的でない。

fcntlをダイレクトIO関数から用いる
セマフォ
  • 極めて柔軟で比較的高速だが、windows環境をサポートしない、あまり使われないので理解に手間取るなど、面倒が多い。
  • 同じサーバー上で動く他の種類のプロセスと干渉する・されるおそれがある。

*1 というかC定数

リロード   新規 編集 凍結 差分 添付 複製 名前変更   ホーム 一覧 単語検索 最終更新 バックアップ   ヘルプ   最終更新のRSS
Last-modified: 2009-04-26 (日) 21:20:45 (495d)