【Perl】ファイルロック(排他処理)について語ろう
■ このスレッドは過去ログ倉庫に格納されています
0001nobodyさん
02/06/23 10:18ID:eY2l+Gw10167nobodyさん
02/07/18 13:34ID:???0169nobodyさん
02/07/18 14:56ID:???flock(OUT, 2);
seek(OUT, 0, 0);
print OUT "........";
truncate(OUT, tell(OUT));
close(OUT);
書き込みが終わってからtruncate()したほうが安全でちょっと速いみたい。
truncate(FILE, tell(FILE)) : 56 wallclock secs ( 8.21 usr + 39.26 sys = 47.47 CPU) @ 210.67/s (n=10000)
truncate(FILE, 0) 60 wallclock secs ( 8.43 usr + 42.72 sys = 51.15 CPU) @ 195.49/s (n=10000)
0170nobodyさん
02/07/18 15:36ID:???正確にはsyswriteするか$|=1してバッファ使わない様にした方が良いけど
0171nobodyさん
02/07/18 15:38ID:???前提が変なのに何をどうしたいのやら
0172nobodyさん
02/07/18 15:41ID:???0173fusianasan
02/07/18 16:45ID:???だれに言ってるんだ? わたしの記憶が確かなら>>170に定数って書いてるYO!
0174nobodyさん
02/07/18 17:11ID:???( > v<)ノ タマンネー♪
0175nobodyさん
02/07/18 17:30ID:???0177nobodyさん
02/07/18 17:42ID:???0178nobodyさん
02/07/18 19:10ID:???0179nobodyさん
02/07/18 23:34ID:???0180nobodyさん
02/07/18 23:43ID:???漢字で書いたら一緒だけど。
ま、もう当分この板はこんな調子でしょ・・・。
0181nobodyさん
02/07/19 01:05ID:???0183nobodyさん
02/07/19 02:38ID:???他のプロセスとの関係とかあります?
0184nobodyさん
02/07/19 02:45ID:???>>1参照。
どんな環境でもつかえてっていうのが、このスレの主題。
flockは環境によってはつかえない。
flockつかえるなら、それでいい。
0185行番号でるかな
02/07/19 03:00ID:???01 open FH,"<./hoge";
02 my @hoge = <FH>;
03 close FH;
04 # @hogeを加工、比較的重い作業
05 open FH "+<./hoge";
06 flock (FH,2);
07 # 書き込み
2行目で配列に全部読み込んでいる、hogeの内容全部がオンメモリな状態。
今10個のプロセスが一斉に読み込みを行ったとする。
つまり10個のプロセス全てが同じ内容の@hogeを得る。
全てのプロセスが完了した時のhogeの内容はどれか一つの
プロセスの内容しか反映されて居ないだろう。
0186183
02/07/19 03:17ID:???どこかのサイトに読み込みオープンでもflockすべきだと
書いてあったのが気になっていたんですが、
そういう場合のことだったんですね。
ありがとうございました。
0187nobodyさん
02/07/19 14:05ID:???0188nobodyさん
02/07/19 15:23ID:H65klWUwこれじゃだめか?
0189nobodyさん
02/07/19 15:44ID:???まあ、可能性ははるかに低くなると思うが。
0191nobodyさん
02/07/19 19:14ID:g9uMB3Mk同じtimeでも唯一のプロセスしかロックできないから大丈夫でない?
1秒内にロックを解除しないままプロセスが死んだ時ってこと?
0192nobodyさん
02/07/20 21:32ID:???0193nobodyさん
02/07/25 16:40ID:Ong5dr5a1.ユニークなファイル名を作り書き込み。
2.指定のファイル名にrename
にしときなさいってこった。
0195nobodyさん
02/07/26 01:04ID:???書き込み中のプロセス事故死に対応して100点。
0197nobodyさん
02/07/26 03:55ID:???sub unlock{
省略
}
この構文の意味がわからんから教えてくれ
unlock関数とif文が何で一緒になってるんだ?
0198nobodyさん
02/07/26 05:36ID:???ちょっと聞いた奥さん教えてくれ!
ぷぷぷ
0200nobodyさん
02/07/26 11:19ID:???読み込み処理のときにはしなくてもいいんですか?
0202nobodyさん
02/07/26 13:35ID:NvB7dZaP=
if($lockkey) {
&unlock;
}
0204nobodyさん
02/07/28 16:44ID:???それでもタイムアウトまでは待つのでは?
あ、正常な処理中にタイムアウトを超えてしまった場合が問題なのかな?
完璧を追求するのなら。
0205nobodyさん
02/07/29 14:41ID:???0206nobodyさん
02/07/29 14:47ID:???0208nobodyさん
02/07/29 15:15ID:???のページでロックの仕方が紹介されていたので使わせてもらおうと思いました。
で、「古いロックファイル(ディレクトリ)の削除」の項目にある、
$retry = 5; # リトライ回数セット
while (!mkdir($lockdir, 0755)) { # 作成。出来なければ待つ
if (--$retry <= 0) { # 5回ダメなら
if (mkdir($lockdir2, 0755)) { # ロックを消すための排他
if ((-M $lockdir) * 86400 > 600) { # 作成時間が10分以上前なら
# ロック入れ替え
rename($lockdir2, $lockdir) or &error("LOCK ERROR");
last; # 一連の処理へ
}else{ rmdir($lockdir2); } # 部分ロック削除
}
&error("BUSY"); # あきらめる
}
sleep(1); # 1秒待つ
}
一連の処理
rmdir($lockdir); # 削除
とりあえず、これ使っておけば大丈夫なんでしょうか。
2ちゃんねるみたいな同時アクセスが凄い場所でない限り。
0212nobodyさん
02/07/29 15:55ID:yLhb3gGL使ってるカウンター(Perl)見たら、
ロックファイル作成
↓
ファイル読み込み
↓
ロックファイル消す
↓
カウントUP
↓
ロックファイル作成
↓
ファイルに書き出し
↓
ロックファイル消す
といった流れになってたんだけど、初めのファイル読み込みの時にもロックは必要なの?
0215nobodyさん
02/07/29 16:32ID:???0221nobodyさん
02/07/29 22:13ID:???0222nobodyさん
02/07/29 22:15ID:???0225nobodyさん
02/07/30 09:03ID:???0226nobodyさん
02/07/30 09:52ID:???0227nobodyさん
02/07/30 11:37ID:???0228nobodyさん
02/07/31 23:34ID:EOzgSn6U0229nobodyさん
02/08/01 02:00ID:DTOpJumx�@open直後
�Aprint直後
�Bclose
�A、�A〜�Bでしょうか?
でもopenでクリティカルな場合に吹っ飛ぶこと考えると…�@?
0230nobodyさん
02/08/01 03:58ID:???サーバの正常なタイムアウトなら、書き込みのシステムコールの
途中で止まったりしないでしょう。数回に分けて書き込んでたら、
止まるけど。サーバの容量制限に引っ掛かって止まる事もあるし。
>229
書き込むときに上書き(>)で開くと内容が消えるので、その直後に
止まったらアウト。
どうしてもログを守るんだったら、かならずtempファイルに書き
出して、書き込み成功を確認した後にrenameすることが必要。
ファイルサイズを計ってサイズが異様に小さいときは失敗だし、
内容をチェックすれば完璧。
これならrenameの瞬間に電源が切れるか、HDDがクラッシュする
くらいの事がなければ、壊れないはず。(バグは除く)
どのみち定期的なバックアップは必要かもね。
0232193
02/08/01 19:06ID:W9oFKOXJだから〜。
処理ロックのファイルロックは当然かけておいて、
書き込み時はユニークファイル名に書き出してrename
ってこったよ。
0234nobodyさん
02/08/03 18:57ID:???>>1-233
この調子でがんばれ糞ども
0235228
02/08/03 20:27ID:npWjw1lcたまにログファイルが途中でぶち切れちゃうんです
ファイルアップありだから
でかいファイルをアップロードした時に
途中でタイムアウトするのかと思ったんですが
そうでもないんですね・・・
open(DB,"+<$logdir$log_d") || &error('ファイルエラー error_24');
flock(DB, 2);
my @lines=<DB>;
unshift (@lines,$thred);
seek(DB, 0, 0);
print DB @lines;
truncate(DB, tell(DB));
close (DB);
これ問題ないですよね?
なんでだろ・・・
flock使えない鯖なんでしょうか?
他に原因は考えられます?
0237228
02/08/04 07:59ID:xc+iopog50件ずつにログを区切ってるんで
読み込んでるのは
書き込み50件分のデータです
スレッドのタイトル一覧も表示しないといけないし・・・
0238228
02/08/04 08:03ID:xc+iopogflockが使えないんでしょうか?
それかtell(DB)の値がおかしくなることがあるのかな?
0239nobodyさん
02/08/04 12:11ID:???> seek(DB, 0, 0);
> print DB @lines;
> truncate(DB, tell(DB));
先頭にseekした後に、truncate(FH, tell(FH)) したら当然ファイルサイズ0に
なるわけだが。
0240230
02/08/04 12:57ID:???my @lines=<DB> or &error('読み込みエラー');
としてみては?
読み込んだ大きなファイルの方にメモリを食われてるのかもしれず。
システムコール(ここではファイル操作)は常に失敗の可能性を考えて
おいたほうがいいかと。flockやprintもね。
0241nobodyさん
02/08/04 13:14ID:???もうちょっと問題切り分けた方が良いよ
マルチパートだと思うんだけど、変なモジュールを使って
データ千切れちゃってるとか。
Niftyはflock空振りサーバの代名詞だけど大丈夫?
適当にsleepしてウェイトかけながらテストするとか
シグナル関係全部無視するとか
基本的に共用ならサーバからkillされる様な使い方は
間違ってると思うよ
もし自分のなら、さっさとコネクション切ってじっくりと作業すれば
良いだけなんだけど
サーバのBBSとかFAQは読んでる?
>>239
それは print 〜 が有るから問題無い
と言う事で、一応。
0243nobodyさん
02/08/04 15:21ID:???0244228
02/08/04 21:59ID:etatASlj最初から書いとくべきだったんですが
説明を付け足すと
2chタイプの掲示板なんです
でログファイルへの書き込みはこの部分だけです
カウンターなんかも同じ方法で書き込みしてるんですが
それは飛んだことないんです
で、ログファイルへの書き込みが処理の最後の方なので
遅い回線でファイルアップした時にデータを送るのに
時間がかかり途中でCGIが止まる事があるのかな?
と考えてたのです(最後の方の処理のログファイルが影響受けやすいと)
でも、どういう条件でログが消えるのかは特定できてません
スレッド50件記録のうちの途中(全部じゃないです。例えば36件目とか)で
消えてしまいます(メッセージが途中までしかなかったり)・・・
(レスは別ファイルなのですが、そっちは消えません)
>読み込んだ大きなファイルの方にメモリを食われてるのかもしれず。
そういう制限もあるんですね試してみます
>もうちょっと問題切り分けた方が良いよ
でも、書き込みしてるのこの部分だけなんですよ
やっぱflockが使えなくて
他のプロセスの書き込み中のデータを読み込んでるとログが途中で消えますよね?
でも、カウンターは消えないんですよ・・・
(それともそのうち消えるんでしょうか?ファイルサイズが小さいから確率が低いだけ?)
>サーバのBBSとかFAQは読んでる?
すいません、その辺、勉強してきます
0246230
02/08/05 01:30ID:???1.flockが利かない場合は、まるっと新規発言が記録されないか、書
き込みの後のtruncateで半端な位置で切られるわけで、それぞれの
発言内容の量にさほど違いが無いなら、48〜50発言目くらいの後ろ
の方で切れるはず。
2.新規発言の処理に問題あるなら、unshiftで入れた1発言目(あとで
気が付いたなら数発言目)で切れるが、その後ろの発言まで消える事
は無い。
3.書き込みが全面的に失敗し、書き込まれて無いのに切り詰めれば
ログ丸ごと消える。(ずっとあとになって気が付けば36発言目になっ
てたりするが)
というわけで、36発言目で切れるなら問題は
1.読み込み(my @lines=<DB>)
2.書き込み(print DB @lines)
3.切り詰め(truncate(DB, tell(DB)))
の3個のどれかが失敗してると考えられるよね。それぞれ失敗時には
エラーにしないと。で、これらが失敗する原因は、メモリ使用量や
ディスク容量の制限、あるいはサーバの混雑にありそう。
途中まで書き込んでprintが失敗してるんなら、tempファイル式にす
るしか無いけど、まずは上記の対策してから。
0247228
02/08/06 00:52ID:eY1Nkha6にしたら
最初の一行しか読まないんですが・・
すいません・・・
0248nobodyさん
02/08/06 01:13ID:???(@lines=<DB>)
その他力本願ぶりじゃ先は真っ暗っぽいね
0249228
02/08/06 01:14ID:HdiBMgeWちゃんと動きました
or と || とは違うんですか?
はぁ・・
0250228
02/08/06 01:29ID:AoKqt/prありがとうございます
何が眠たいんだ?
my (@lines=<DB>) || &error('読み込みエラー');
で動いてるんだが、向学の為に教えて欲しい
orは||より優先度がずっと低いんだよ。
だから
@lines = <DB> or error;
は
(@lines = <DB>) or error;
と評価され、
@lines = <DB> || error;
は
@lines = (<DB> || error);
と評価される。
||演算子のオペランドはスカラコンテキストで評価されるから、
結果として一行しか読み込まれないことになる、というわけね。
>>252
< my(@lines = <DB>)
> (my(@lines) = <DB>)
優先度を云々するのなら、= と || および = と or について言わないと意味ナイだろ。
そういえばそうだ。肝心な所が抜けててごめん。
>>253 追記
とりあえず、代入演算子は比較的優先順位が低くなってるんだよ。
例えば、算術演算子や比較演算子などは全て代入演算子より優先度が高い。
だからこそ
$foo = 100 + 200; という式が
($foo = 100) + 200; ではなく、$foo = (100 + 200);と評価される。
で、||や&&といった演算子は代入演算子よりも優先順位が高いため、
加算演算子と同様の評価順序になるってわけ。
しかしながら、orやandといった演算子の優先順位は代入演算子のそれより低いので、
このケースの場合は期待通りに動くわけだね。
詳細についてはついてはperldoc perlopを参照のこと。
0257228
02/08/10 00:33ID:???open(LOG,"+<$log") || &error('ファイルエラー');
flock(LOG, 2) or &error('ロックエラー');
my @lines = <LOG> or &error('読み込みエラー');
〜〜〜更新処理〜〜〜
seek(LOG, 0, 0);
print LOG @lines;
truncate(LOG, tell(LOG));
close (LOG);
こんな感じです
やっぱり同時刻に書き込みが集中した時に消えるようなので
KENT式mkdirロックを少し改造したものをあわせて使ってます
そのまま使うとエラーでロックを外した瞬間に書き込みが重なってしまうようなので・・・
ありがとうございました
0258230
02/08/10 06:54ID:???>そのまま使うとエラーでロックを外した瞬間に書き込みが重なってしまう
ロックを外したら、もはやそのプロセスは書き込まないはず。
まさか&errorでexitせずに、実行続けてるとか?
mkdir式が有効なのは、flockがダメだったからかもしれないが、
処理が遅くなるのとタイムアウトがある事で、読み書きが集中
しないようになった効果かもしれない。
質問者は問題が解決しさえすればいいんだが、
flockとmkdir式の併用なんて気持ちわるい結末だなぁ。
0259228
02/08/10 18:58ID:???どんなエラーでもロックを外してしまうので
書き込み中の人がいて、それ以外の人がエラー出してロックを外してしまう
というのが問題でした
上で書いてるのはちょっと違いました。。
いろいろ教えて頂いたのに、はっきり原因を解明せずに
気持ち悪い結末にしてしまって申し訳ないですが
上のflockのみではprintで失敗したらどうしようもないのなら
mkdirを併用する方法はいいんじゃないかと思うんですが・・
0260230
02/08/10 22:16ID:???書き込み中の人がいるとしたら、その人しかロックが成功していないので、
それ以外の人がロックを外す事はありえないのが排他制御。
mkdir式の場合、ロック成功したプロセスがエラーで外すなら問題ないわけ。
通常、ロックを成功してないプロセスがロックを外すようなのはバグ。
flockの場合はロックかけたプロセス以外は外せないよ。
> printで失敗したらどうしようもない
mkdirを併用しても同じ状況だけど。
print LOG @lines or &error('書き込みエラー');
でOK。truncateする前にやめればデータは壊れない。
とにかく、mkdir式にするならflockは必要ないので消そうよ。
0261nobodyさん
02/08/11 12:39ID:???0262nobodyさん
02/08/11 12:53ID:???0263nobodyさん
02/08/11 13:45ID:???0264nobodyさん
02/08/11 13:46ID:???0265KENT
02/08/11 15:40ID:???0267nobodyさん
02/08/11 19:41ID:???だから初めにflock効いてるのか調べてと言ってるのに
空振りしてるんだよ、それ
他のファイル編集部分は時間的にロック無しでも動いてるだけだよ多分
■ このスレッドは過去ログ倉庫に格納されています