トップページ⇒php
981コメント337KB

【Perl】ファイルロック(排他処理)について語ろう

■ このスレッドは過去ログ倉庫に格納されています
0001nobodyさん02/06/23 10:18ID:eY2l+Gw1
どんな環境でも使えて、軽くて、頑丈なロックを考えようじゃありません
0145nobodyさん02/07/10 03:22ID:???
>>142
DBは禁句だろ。
0146nobodyさん02/07/10 10:54ID:???
>>143
(゚Д゚)ハァ? >>142が言ってるのはファイルに直接アクセスなんかしないで
排他処理が元からきちっと実装されてるDBMS使えってことだろ。
まあDBMSが使えるサーバなんて限られてるしこのスレ的にはスレ違いだとは思うが。
0147nobodyさん02/07/10 15:23ID:???
>>146
MySQLやらPostgreSQLが〜となるとたしかにアレだろうけど、
BerkleyDB とかなら OS 標準で入っていることも非常に多いし、
Perl からでも使えるしナー。
014811502/07/10 16:43ID:???
ツッコミが入らなかった・・・UNIX板へ帰ります
0149 02/07/10 16:51ID:???
> N人の哲学者が丸いテーブルに座っています.
> テーブルの真中には大きなスパゲティの皿が置いてあります.
> またN本のフォークがあって哲学者と哲学者の席の間に置いてあります.
> 哲学者は思索を続けていますが,お腹がすくと両側のフォークを取って
> スパゲティを食べます.お腹が一杯になると食べるのを止めてフォークを返します.
> 哲学者は紳士ですから,お腹が空いていても両方のフォークが手に入るまでは待ちます.

これか。このスレとは微妙に方向性が違うような。
0150nobodyさん02/07/10 17:38ID:???
>>148
はっはっは!このスレのレベルの低さを思い知ったか!!
0151nobodyさん02/07/10 18:06ID:???
>>147
BerkleyDBは排他制御やってねーだろ。
0152nobodyさん02/07/10 18:38ID:???
>>151
MySQL が BerkleyDB の機能を使ってトランザクションを実現
しているくらいなのに、lock やってないわけなかろ。いつの
version の話してるの?

http://www.sleepycat.com/docs/reftoc.html
http://www.sleepycat.com/docs/ref/lock/intro.html
見て出直してこい。ちなみにこの document は 4.0.14 のだけど、
3.x のころからしっかり lock subsystem がある。
0153nobodyさん02/07/10 21:53ID:???
>>152
OS標準で入ってるつーと
http://www.freebsd.org/cgi/cvsweb.cgi/src/lib/libc/db/README?rev=1.1&content-type=text/x-cvsweb-markup
とかVer 1だろ。
perlのDB_Fileで2や3も使えるけど、インターフェースは1でサポートされてる部分しか使えねーはずだが。
0154nobodyさん02/07/11 02:02ID:???
>>153
http://search.cpan.org/search?dist=BerkeleyDB
使えば?

あと、FreeBSD では完全に標準な状態ではたしかにそうだけど、ふつう
ports で 3.x が入ってくるし、Debian でも完全に標準では 2.x でふつう
3.x、RedHat では完全に標準で 3.x が入る
0155nobodyさん02/07/11 04:50ID:???
どうせロッキングするならクリティカルな場合も考えないといけないし、
それなら車輪の再発明は止めて最初からDBMSを使うべきというのは
反論しようのない正論。しかも、リソースのありかまで教えてくれているし。

ただ、こういう極めて的確な回答があると、この手のスレはつまらなくなるね…。
0156nobodyさん02/07/11 06:50ID:???
>>155
それでも、ダラダラとレスしてる奴等がいるところを見るとこの板のレベルの低さが解るね
0157nobodyさん02/07/11 09:23ID:???
また釣れた(・∀・)クスクス
0158nobodyさん02/07/11 11:11ID:???
DBMSやflock等の飛び道具使えないときにどうするかというパズルじゃないの?
0159nobodyさん02/07/11 16:21ID:???
つかperlのflockてatomicじゃないだろ
0160nobodyさん02/07/11 21:02ID:???
flock(2)使うときのflockはアトミックでしょ。 lockfでエミュレートしてるのはヤヴァイの?
0161nobodyさん02/07/12 18:11ID:???
# 初心者スレから誘導されてきました。

# 排他処理をしたいです。
# ローカル環境(WindowsMe+Apache+Cygwin付属のPerl)では成功するのですが、
# サーバで実行するときには、必ず失敗します(エラー表示部が実行されます)。
# もし落ち度がありましたらご教授ください。以下要所の抜粋です。
sub create_lock {
  my ($lockfile, $retry) = @_;
  while (!mkdir($lockfile, 0755)) {
    if (--$retry <= 0) {
      return undef;
    }
    sleep(1);
  }
  return 1;
}

sub remove_lock {
  my ($lockfile) = @_;
  rmdir($lockfile);
}

#上記関数の利用例
my $lock_handle = &create_lock("./lockfile", 5);
if (not $lock_handle) {
  &print_error($resource{writedatafailed});
}
#ここで処理する
&remove_lock($dir_lock);
0162nobodyさん02/07/12 19:10ID:???
>>161
ディレクトリに書き込み権限がない。
既にロックされている(./lockfileが存在する)。
のどちらか。

&create_lock("./lockfile", 5);
と
&remove_lock($dir_lock);
のファイル名が…
0163nobodyさん02/07/12 19:38ID:???
>>162
ご指摘ありがとうございます。(;ワ;)
今夜さっそくディレクトリの書き込み権限のチェックをしてみます。

えーと、下の $dir_lock は貼り付け時に直し忘れました(^^;)
混乱させてしまったようで、すみません。

あとでまた結果報告しにきます。
016416102/07/13 07:51ID:???
できました〜!
>>162さん、感謝です。助かりました。
0165nobodyさん02/07/18 03:33ID:???
叩かれに来ました。

open(OUT, "+< outfile.txt");
flock(OUT, 2);
truncate(OUT, 0);
seek(OUT, 0, 0);
print OUT "........";
close(OUT);

の欠点を教えてください。
お願いします。
0166nobodyさん02/07/18 05:55ID:???
>>165
いいんじゃないの?それでも別に。
0167nobodyさん02/07/18 13:34ID:???
........吐くだけならロックしなくて良いじゃん
0168nobodyさん02/07/18 14:33ID:???
>>167
じゃあ、二つのプロセスが同時に同じファイルに対して吐きにいったら
どうなる?
0169nobodyさん02/07/18 14:56ID:???
open(OUT, "+< outfile.txt");
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:???
truncateしなくて良いじゃん変数じゃ無いのに
前提が変なのに何をどうしたいのやら
0172nobodyさん02/07/18 15:41ID:???
どこに定数って書いてるんだ?
0173fusianasan02/07/18 16:45ID:???
>>172
だれに言ってるんだ? わたしの記憶が確かなら>>170に定数って書いてるYO!
0174nobodyさん02/07/18 17:11ID:???
この棘々しい会話の流れ
( > v<)ノ  タマンネー♪
0175nobodyさん02/07/18 17:30ID:???
定数だろうが変数だろうが返り値だろうが関係ないわけですが
0176nobodyさん02/07/18 17:34ID:???
>>175
は? 何言いたいのおたく?
もうちょっと日本語の文章力付けなさいよ
0177nobodyさん02/07/18 17:42ID:???
みんなあまのじゃくさん♪
0178nobodyさん02/07/18 19:10ID:???
すんげー荒れてるw
0179nobodyさん02/07/18 23:34ID:???
この程度で荒れてるって言うのか。
0180nobodyさん02/07/18 23:43ID:???
荒れてるというよりみんなすさんでるな。
漢字で書いたら一緒だけど。

ま、もう当分この板はこんな調子でしょ・・・。
0181nobodyさん02/07/19 01:05ID:???
この板ってほんと殺伐系だね。馴れ合い一切なし。さっぱりしてて気持ちいいけどね。
0182nobodyさん02/07/19 01:29ID:???
>>165
いろいろなレスがあるけど、flockつかえるなら、それでいいんだよ。
初心者板でそう言い返してこい。
0183nobodyさん02/07/19 02:38ID:???
突然ですが、読むだけのオープンでもflockが必要なの?
他のプロセスとの関係とかあります?
0184nobodyさん02/07/19 02:45ID:???
>>165

>>1参照。
どんな環境でもつかえてっていうのが、このスレの主題。
flockは環境によってはつかえない。
flockつかえるなら、それでいい。
0185行番号でるかな02/07/19 03:00ID:???
>>183
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の内容はどれか一つの
プロセスの内容しか反映されて居ないだろう。
018618302/07/19 03:17ID:???
なるほど、了解しました。
どこかのサイトに読み込みオープンでもflockすべきだと
書いてあったのが気になっていたんですが、
そういう場合のことだったんですね。
ありがとうございました。
0187nobodyさん02/07/19 14:05ID:???
ファイルロックなんでも相談室っぽい雰囲気になりそうだ
0188nobodyさん02/07/19 15:23ID:H65klWUw
http://www.din.or.jp/~ohzaki/perl.htm#File_Lock

これじゃだめか?
0189nobodyさん02/07/19 15:44ID:???
timeが全く同じだと、通常のrename式と同じ問題が生じる。
まあ、可能性ははるかに低くなると思うが。
0190nobodyさん02/07/19 15:48ID:???
>>189
???????????????????????????????????????????????????
0191nobodyさん02/07/19 19:14ID:g9uMB3Mk
>>189
同じtimeでも唯一のプロセスしかロックできないから大丈夫でない?
1秒内にロックを解除しないままプロセスが死んだ時ってこと?
0192nobodyさん02/07/20 21:32ID:???
2chはflockか?
0193nobodyさん02/07/25 16:40ID:Ong5dr5a
結局、実際の書き込みを、
1.ユニークなファイル名を作り書き込み。
2.指定のファイル名にrename
にしときなさいってこった。
0194nobodyさん02/07/25 17:54ID:???
>>193
rename時に衝突することもあるってこった。
0195nobodyさん02/07/26 01:04ID:???
ファイルロック完全にやって50点。
書き込み中のプロセス事故死に対応して100点。
0196nobodyさん02/07/26 02:18ID:???
>>195
それでは認識が甘いな。
0197nobodyさん02/07/26 03:55ID:???
&unlock if($lockkey);

sub unlock{
省略
}
この構文の意味がわからんから教えてくれ
unlock関数とif文が何で一緒になってるんだ?
0198nobodyさん02/07/26 05:36ID:???
教えてくれ、だってさ教えてくれ!!
ちょっと聞いた奥さん教えてくれ!
ぷぷぷ
0199 02/07/26 09:01ID:???
>>197はマルチポスト
0200nobodyさん02/07/26 11:19ID:???
ファイルロックって書き込み処理のときだけすればいいんですか?
読み込み処理のときにはしなくてもいいんですか?
0201nobodyさん02/07/26 11:27ID:???
>>192
2ちゃんはflockでした
0202nobodyさん02/07/26 13:35ID:NvB7dZaP
&unlock if($lockkey);
=
if($lockkey) {
  &unlock;
}
0203nobodyさん02/07/26 13:45ID:???
>>197 && >>202
ファイルロックとは関係ないぞ。
Perl初心者スレへ。
0204nobodyさん02/07/28 16:44ID:???
>>191
それでもタイムアウトまでは待つのでは?
あ、正常な処理中にタイムアウトを超えてしまった場合が問題なのかな?
完璧を追求するのなら。
0205nobodyさん02/07/29 14:41ID:???
あげてわるいか!
0206nobodyさん02/07/29 14:47ID:???
わるいっつったらどうするよ?
0207nobodyさん02/07/29 15:10ID:???
>>206
あげたもんはさがるまで待つしかしょーがねーだろ?って開き直るよ。
0208nobodyさん02/07/29 15:15ID:???
homepage1.nifty.com/glass/tom_neko/web/web_04.html
のページでロックの仕方が紹介されていたので使わせてもらおうと思いました。
で、「古いロックファイル(ディレクトリ)の削除」の項目にある、
$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ちゃんねるみたいな同時アクセスが凄い場所でない限り。
0209nobodyさん02/07/29 15:21ID:???
>>207
別にわるかねぇよ。
0210nobodyさん02/07/29 15:24ID:???
>>207
バグもあるけどキミんとこのアクセス数ならOK。
0211nobodyさん02/07/29 15:36ID:???
>>210
どういう意味なんだ?
0212nobodyさん02/07/29 15:55ID:yLhb3gGL
どこからダウンロードしたのか忘れたんだけど、
使ってるカウンター(Perl)見たら、

ロックファイル作成
↓
ファイル読み込み
↓
ロックファイル消す
↓
カウントUP
↓
ロックファイル作成
↓
ファイルに書き出し
↓
ロックファイル消す

といった流れになってたんだけど、初めのファイル読み込みの時にもロックは必要なの?
0213nobodyさん02/07/29 16:25ID:???
>>219
とんでもねぇロックの仕方だな
0214nobodyさん02/07/29 16:27ID:???
>>219
はとんでもないロックを出さなければいけない。
0215nobodyさん02/07/29 16:32ID:???
219に期待sage
0216nobodyさん02/07/29 17:26ID:???
>>219 はロッカー♪
0217nobodyさん02/07/29 17:33ID:???
>>219
凄い。そんなアルゴリズムがあったのか。
0218nobodyさん02/07/29 17:35ID:???
>>219ある意味で、とんでもないな。
0219 ◆JAPH9PWA 02/07/29 21:21ID:???
unless(`ps` =~ /\Q$0\E/)
{
# ロック権を取得したので処理をする
}
0220nobodyさん02/07/29 22:11ID:???
>>219
\Qと\Eの意味知らんけど、確かにとんでもないな
0221nobodyさん02/07/29 22:13ID:???
Windowsでうごかねぇよ。
0222nobodyさん02/07/29 22:15ID:???
他のプロセスを全てkillする排他制御はどうか
0223nobodyさん02/07/29 22:17ID:???
>>222
最強だな、うん
0224nobodyさん02/07/30 03:13ID:???
>>223
なんで最強なんだ? suEXEC ならどうする?
0225nobodyさん02/07/30 09:03ID:???
httpdから何から、「全て」killするからでしょ。root限定で
0226nobodyさん02/07/30 09:52ID:???
そんな真面目に考えなくても
0227nobodyさん02/07/30 11:37ID:???
木村ロック
0228nobodyさん02/07/31 23:34ID:EOzgSn6U
書き込み中にタイムアウトになるとログが壊れます?
0229nobodyさん02/08/01 02:00ID:DTOpJumx
>>228に便乗
�@open直後
�Aprint直後
�Bclose
�A、�A〜�Bでしょうか?
でもopenでクリティカルな場合に吹っ飛ぶこと考えると…�@?
0230nobodyさん02/08/01 03:58ID:???
>>228
サーバの正常なタイムアウトなら、書き込みのシステムコールの
途中で止まったりしないでしょう。数回に分けて書き込んでたら、
止まるけど。サーバの容量制限に引っ掛かって止まる事もあるし。
>229
書き込むときに上書き(>)で開くと内容が消えるので、その直後に
止まったらアウト。

どうしてもログを守るんだったら、かならずtempファイルに書き
出して、書き込み成功を確認した後にrenameすることが必要。
ファイルサイズを計ってサイズが異様に小さいときは失敗だし、
内容をチェックすれば完璧。

これならrenameの瞬間に電源が切れるか、HDDがクラッシュする
くらいの事がなければ、壊れないはず。(バグは除く)
どのみち定期的なバックアップは必要かもね。
023122902/08/01 13:35ID:???
>>230
thnx
参考になりますた
023219302/08/01 19:06ID:W9oFKOXJ
>>194
だから〜。
処理ロックのファイルロックは当然かけておいて、
書き込み時はユニークファイル名に書き出してrename
ってこったよ。
0233nobodyさん02/08/02 01:01ID:???
>>232
アマちゃんですね。
0234nobodyさん02/08/03 18:57ID:???
http://www.google.co.jp/search?hl=ja&inlang=ja&ie=Shift_JIS&as_qdr=all&q=site%3A2ch.net+perl&lr=
>>1-233
この調子でがんばれ糞ども
023522802/08/03 20:27ID:npWjw1lc
230さま
たまにログファイルが途中でぶち切れちゃうんです
ファイルアップありだから
でかいファイルをアップロードした時に
途中でタイムアウトするのかと思ったんですが
そうでもないんですね・・・

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使えない鯖なんでしょうか?
他に原因は考えられます?
0236nobodyさん02/08/03 23:45ID:???
>>235
でかいファイルを全部配列に入れるのは大問題だ
023722802/08/04 07:59ID:xc+iopog
>236
50件ずつにログを区切ってるんで
読み込んでるのは
書き込み50件分のデータです
スレッドのタイトル一覧も表示しないといけないし・・・
023822802/08/04 08:03ID:xc+iopog
やっぱ
flockが使えないんでしょうか?
それかtell(DB)の値がおかしくなることがあるのかな?
0239nobodyさん02/08/04 12:11ID:???
>>235
> seek(DB, 0, 0);
> print DB @lines;
> truncate(DB, tell(DB));

先頭にseekした後に、truncate(FH, tell(FH)) したら当然ファイルサイズ0に
なるわけだが。
024023002/08/04 12:57ID:???
データが大きくないとしても、my @lines=<DB>が失敗してるのかも。
my @lines=<DB> or &error('読み込みエラー');
としてみては?
読み込んだ大きなファイルの方にメモリを食われてるのかもしれず。
システムコール(ここではファイル操作)は常に失敗の可能性を考えて
おいたほうがいいかと。flockやprintもね。
0241nobodyさん02/08/04 13:14ID:???
>>235
もうちょっと問題切り分けた方が良いよ
マルチパートだと思うんだけど、変なモジュールを使って
データ千切れちゃってるとか。
Niftyはflock空振りサーバの代名詞だけど大丈夫?
適当にsleepしてウェイトかけながらテストするとか
シグナル関係全部無視するとか
基本的に共用ならサーバからkillされる様な使い方は
間違ってると思うよ
もし自分のなら、さっさとコネクション切ってじっくりと作業すれば
良いだけなんだけど
サーバのBBSとかFAQは読んでる?

>>239
それは print 〜 が有るから問題無い
と言う事で、一応。
024223902/08/04 14:38ID:???
>>241 正直、スマンカッタ。
0243nobodyさん02/08/04 15:21ID:???
で、なにが最強なの?
024422802/08/04 21:59ID:etatASlj
レスありがとうございます
最初から書いとくべきだったんですが
説明を付け足すと
2chタイプの掲示板なんです
でログファイルへの書き込みはこの部分だけです
カウンターなんかも同じ方法で書き込みしてるんですが
それは飛んだことないんです
で、ログファイルへの書き込みが処理の最後の方なので
遅い回線でファイルアップした時にデータを送るのに
時間がかかり途中でCGIが止まる事があるのかな?
と考えてたのです(最後の方の処理のログファイルが影響受けやすいと)

でも、どういう条件でログが消えるのかは特定できてません
スレッド50件記録のうちの途中(全部じゃないです。例えば36件目とか)で
消えてしまいます(メッセージが途中までしかなかったり)・・・
(レスは別ファイルなのですが、そっちは消えません)

>読み込んだ大きなファイルの方にメモリを食われてるのかもしれず。
そういう制限もあるんですね試してみます
>もうちょっと問題切り分けた方が良いよ
でも、書き込みしてるのこの部分だけなんですよ
やっぱflockが使えなくて
他のプロセスの書き込み中のデータを読み込んでるとログが途中で消えますよね?
でも、カウンターは消えないんですよ・・・
(それともそのうち消えるんでしょうか?ファイルサイズが小さいから確率が低いだけ?)
>サーバのBBSとかFAQは読んでる?
すいません、その辺、勉強してきます
0245nobodyさん02/08/04 22:48ID:???
>>244
一度flock以外のロックで試してみれば?
こういうのが問題を切り分けるって事じゃないのか。
■ このスレッドは過去ログ倉庫に格納されています