- 締切済み
ロックファイルが消える
ファイルロックにflockを使っているのですが、複数のファイルを扱うので、データファイルにロックをかけるのではなく別途「ロックファイル」に対してロックをかけています。 データファイルであれば読み書きモードで開く必要がありますが、ロックファイルは中身はどうでも良いので、 open(LOCK,"> $lockfile") or die ~ というように上書きモードで開いて良いとする解説を読んだので、そのようにしています。 しかし、ごくたまにロックファイルが消えてしまう現象が発生します(なかなか再現できずに条件など特定できず)。 あくまでもファイルの中身が壊れるとかいうことではなくて、ファイルそのものが消えます。 そこでお聞きしたいのですが、 1. ロックをかけたファイルが何らかの原因で消えた場合、ロック状態も消失してしまう(他プロセスがロックできてしまう)のでしょうか? 試してみたのですが、 まずプロセスAがロックをかけて プロセスBが同ファイルにロックをかけようとすると、失敗する プロセスAがロック解除せずにファイルを削除する それでもプロセスBはロックに失敗する プロセスAが(もう存在しないファイルの)ロックを解除(close)する するとプロセスBはロックに成功する ということは分かったのですが、上記を、プロセスAがファイルを削除した後にプロセスBを動かすと、どういうわけかロックに成功してしまいます。 2. 複数プロセスが同時に上書きモードでopenしようとするのが消える原因なら、ロックファイルであってもやはり読み書きモードで開くべきなのでしょうか。そしてそれなら消えることは無いのでしょうか。 (読み込みモードではロックできないという解説もありました。) 御教授のほどよろしくお願いいたします。
- みんなの回答 (4)
- 専門家の回答
みんなの回答
- hrm_mmm
- ベストアンサー率63% (292/459)
私もサイトをもってるけどそんなにアクセス数がないので、そのような状況を見たことがないので、予想ですけど、 上書きモードだと、開いてから、ファイルサイズを0にする時間帯で、別プロセスがアクセスすると存在しないかのような動作になると言うことでしょうか? とすれば、読み書きモードでのopenは、ファイルサイズ変更の手間が短縮されるので、読み書きモードにするのが最良と言うことになるでしょう。
- osamuy
- ベストアンサー率42% (1231/2878)
たんにこんな感じとか: use strict; use Fcntl ':flock'; my $fn_lock = 'a.lck'; open( LCK, $fn_lock ) or die "?! [$$]open: ${fn_lock} - $!,"; # readonlyでオープン。 flock( LCK, LOCK_EX ) or die "?! [$$]flock: $!,"; print '[',$$,']lock',"\n"; sleep( 1 ); print '[',$$,']unlock',"\n"; close( LCK ) or die "?! [$$]close: $!,"; これでファイルが消えるようだったら、なんか別のところが悪いと思われ。
お礼
ご回答ありがとうございます。 何度もすみませんが、読み込みモードで開くと排他ロックできない環境があるので・・・。 やはり open(LOCK, "+< $lockfile") のように読み書きモードが良いということですかね・・。
- hrm_mmm
- ベストアンサー率63% (292/459)
>どこかのページ(URLなど失念)で、読み込みモードでは排他ロックがかからない環境がある、というようなことが書かれていたので http://homepage1.nifty.com/glass/tom_neko/web/web_04.html ここの解説にありました。 Solarisでは、読み込み専用モードで開くと以下の書き込みロックしか出来ずに、別プロセスに読み出されてしまうらしいです。 flock(XX, 1) 読込中なので書込をロック、あとから来たら待つ。(ブロック) 同じ解説ページの「まとめてロックする」方式がロック専用ファイル利用法として有効のように思います。 >「読み込み専用(readonly)なファイル」 これは、ファイル属性を 444 =readonly にすると云うことでしょう。 こうしておけばプログラムからの削除や変更は出来ません。 でも、読み書きモードでのオープンも出来ないけど。
お礼
ご回答ありがとうございます。 Solarisということは、やはり下にも書いたようにfcntl実装の場合ということですね。 > 同じ解説ページの「まとめてロックする」方式がロック専用ファイル利用法として有効のように思います。 恐れ入りますが、これは質問文にも書いた方法と同じで、場合によってファイルが消えてしまうようでして…。それが今回させていただいた質問でした。 やはり open(LOCK, "+< $lockfile") のように読み書きモードが良いのでしょうか。
- osamuy
- ベストアンサー率42% (1231/2878)
1. 関数flock()は、ファイルハンドルを通して、ファイルにロックをかけますので、ファイルが削除されて新たなファイルが作成された場合、別物になります。 2.たんにロックをかけるだけなら、読み込み専用(readonly)なファイルでもできます。 プログラム内でのファイル削除によるロック失敗が発生しませんので、こっちがおすすめ。 ただし、あらかじめファイルを作成しておく必要があります。
お礼
ご回答ありがとうございます。 1については、つまりプロセスBがファイルハンドルを取得した時点でファイルが存在していれば、その後でプロセスAがファイルを削除しても両プロセスとも同じファイルハンドルなので、削除後もロックが有効で、ファイルハンドル取得時にファイルが削除されていたら、同じファイルパスであってもロックがかかっていても、別物になる、ということですね。 ということは、やはり削除されてしまうと問題ありということですね。 2についてなのですが、恐れ入りますが「読み込み専用(readonly)なファイル」とは、読み込みモードでオープンしたファイル、と理解して良いでしょうか。 その場合ですが、どこかのページ(URLなど失念)で、読み込みモードでは排他ロックがかからない環境がある、というようなことが書かれていたので・・・。 システムコールがflockではなくfcntlで実装されている場合なのかな?と漠然と思ったのですが、少なくともlockfなど共有ロックもサポートされている環境という前提で、やはり open(LOCK, "+< $lockfile") のように読み書きモードが良いのでしょうか。 open(LOCK, "+> $lockfile") と書くとオープン時にファイルへの影響の危険性から、より安全なのは前者ということでしょうか。
お礼
ご回答ありがとうございます。 ファイルは、「存在しないかのような動作になる」と言うより、実際に消えてしまいます。 この条件などはまだ特定できていませんが、どうやらそれらしい情報を見つけたので、とりあえず暫定的に、消える原因は「上書きモードでの同時複数オープン」のようです。 それは良いとして、いずれにしてもロック中にファイルが消えると問題が起きることが、No.1の1のご回答でわかりました。 そこで2ですが、可能性はともかく少しでも安全なものを作ろうとすれば、 ●ファイルが消えない ●排他ロックもできる という点では、やはりおっしゃるように open(LOCK, "+< $lockfile") のように読み書きモードが良さそうですね。