flockが有効に使われていない†
- ページ: BugTrack
- 投稿者: hirofummy
- 優先順位: 普通
- 状態: 完了
- カテゴリー: 本体バグ
- 投稿日: 2003-08-24 (日) 14:29:58
- バージョン: 1.4rc4
メッセージ†
file.phpのfile_write関数などいくつかの関数でflockが有効に使われていません。正しい使い方にした方がよいかと思います。
現状:
$fp = fopen($file,'w')
or die_message(/* エラーメッセージ */);
flock($fp,LOCK_EX);
fputs($fp,$str);
flock($fp,LOCK_UN);
fclose($fp);
改善案:
$fp = fopen($file,file_exists($file)?'r+':'w')
or die_message(/* エラーメッセージ */);
flock($fp,LOCK_EX);
rewind($fp);
fputs($fp,$str);
ftruncate($fp,ftell($fp));
fflush($fp);
flock($fp,LOCK_UN);
fclose($fp);
参考:
- 要件は、'w' であって、'r+' じゃない。にも関わらず、rewind しろ。というのがよく分からない。'r+' なら、そのファイルは、どういう状況なのか?分からないから、ポインタを戻すなりの考慮が必要かもねぇ。というのは納得感があるんですけど、'w' でオープンして、ロック待ちが発生している場合の 'w' の挙動は、不定となり得るということですか?まぁ、いずれにしても、要件が無い状態での改善案の 'r+' は余計でしょ。-- upk
- 質問の意味がよく分からないのですが、これは参考にならないでしょうか。 -- hirofummy
- あれ、私がひょっとして変な勘違いしてるかな… -- hirofummy
- fopen が2個ある場合と、1個の場合とは、全く異なるので、参考になり得ません。で、それはさせおき、私の知識不足からなのでしょうけど、flock をかけて、待ちが発生している状態で、fopen で捕まえたポインタは、flock の待ちが解除された際に、不定となり得るので、'w' とは言え、先頭に無い場合も想定すべき。という指摘なのだろうと思ってお聞きしたんですけどね。それなら、1つ勉強になったなぁ。と。-- upk
- あと、fflush じゃあてにならないから、明示的に ftruncate までして、全てを吐き出せ。なんですかね。fflush は、過去に、OS/2 時代の C で、同様な逃げをしたので、個人的には、理解できるんですけどね。-- upk
- 更新の衝突の検出絡みで不具合が出るかなと考えたのですがそうだとしても私の改善案では全く意味がないですね。失礼致しました。 -- hirofummy
- いやぁ、全く意味がない?ということも無いと思いますよ。コーディングして、テストし、そこで分かる逃げ道の1つ。ということもありますからね。-- upk
- 私の案はr+の場合を考えていただけでupkさんのおっしゃるような事態はあまり想定していませんでした。お恥ずかしい。 -- hirofummy
- 正しい改善案?はfile_writeの中に更新の検出を組み込む感じでしょうか。そうなると関数の仕様を変えないといけないので面倒な話になりますね。カウンタとは性質が違いますしそこまでする必要もなさそうです。 -- hirofummy
- 更新の検出を組み込むというメリットは、更新の衝突を気にしているのなら、それは意味をなさないと思いますよ。複数で利用しているシステムで、排他制御して拒否するはできません。なので衝突することを前提として、どう裁くのが良いのか?を考えて、必要なら割り切って実装することだと思っています。現状の 1.4 で、個人的には、改善されていて、使いやすくなったと思いますけどね。あと、更新の検出は、今のハッシュで十分だと思います。-- upk
- 更新の衝突が検出できないパターンがあるかと思いまして。 -- hirofummy
ソースを見ると、
$oldpagesrc = join('',get_source($post['page']));
$oldpagemd5 = md5($oldpagesrc);
if ($oldpagemd5 != $post['digest']) {
/* 衝突発生 */
}
else {
/* 書き込み */
}
という流れだったので、
md5(X(起点文書))とmd5(X(現文書))の比較 | |
Yを書き込み | |
| md5(X(起点文書))とmd5(Y(現文書))の比較 |
| 衝突 |
となるところが、
md5(X(起点文書))とmd5(X(現文書))の比較 | |
| md5(X(起点文書))とmd5(X(現文書))の比較 |
Yを書き込み | |
| Zを書き込み |
となるタイミングが生じるのではないかと考えました。。あ、get_sourceにflockのチェックをいれればいいのかな。衝突チェックから書き込みまでロックし続けないと意味ないか。 --hirofummy 2003-08-24 (日) 17:42:19
- ソースの取得がget_source(), $digestを計算するのがconvert_html(), ページを書き込むのがpage_write()/file_write()というように、現状ではそのあたりの流れがばらばらなんですよ。機能をpage_write()に集約して、page_write()の戻り値で衝突の有無を判定するようにすればいいんじゃないかなと思っています。 -- ぱんだ