投稿

2月, 2013の投稿を表示しています

やっぱり基礎って大事だよね

はじめに 元ネタ「プロセス間の期限付き排他ロック」が前の記事と一緒ですが、誰かを貶めたり中傷しようとしたりというのではなく、勝手に上から目線で「基礎知識が足りてないよね」とミサワ的な発言をすることを目的とした記事となっております。ご承知ください。
仕様のここがまずそう 「実装」のセクションに書いてある
シンボリックリンクを使って排他制御する 期限切れは、シンボリックリンクそのものの mtime で表現するmtime <= now なら期限切れつまり、シンボリックリンクの mtime を期限が切れる時刻(未来)にする
ですが、「ロックとは何か」とか「アトミックな操作とは何か」あたりの基礎知識がある人にとっては、ちょっと考えればまずいのがすぐに分かります。シンボリックリンクの作成symlink(2)とmtimeの変更utimeutimensat(2)は別々のシステムコールであり、両者をアトミックに行えるシステムコールがありません。
すなわちsymlink(2)が成功したとして、その次にutimeutimensat(2)が実行されるまでの「間」というものが存在し、その間に他のプロセスが色々するチャンスがあるわけです。特に、作成されたシンボリックリンクはutimeutimensat(2)が実行されるまでは「期限切れ」状態にあるとみなせます。その結果、utimeutimensat(2)の実行時点で持っているシンボリックリンクは競合するプロセスから見れば期限切れなので、そのシンボリックリンクは削除されてしまう可能性があるわけです。
この一点に関しては、symlink(2)でのリンク先としてTTLをセットするということで、期限が未来であるロックをアトミックな操作で作成できます。しかし、期限切れのロックファイルをどう取り扱うかという点にも問題があるので、そう簡単にはいかないというのは元記事のコメント欄にあるとおりです。
ちなみに、その期限切れロックファイルの扱いの問題を同じようにシステムコールレベルで見れば、statlstat(2)とunlink(2)をアトミックに実行することはできない(ので、その為に別のロック機構が必要になっちゃう)よねってな話になるかと思います。 もったいない さて超上から目線で偉そうですが、「知識が足りないのってもったい無いよね」というのが元記事に対…

関数名は大事だよね

プロセス間の期限付き排他ロックについて。

既にコメントが付いてるので、設計レベルでどうだとか、というのはおいておきます。

とにかく実装をパッと見て、これはダメそうだなというのは
52 sub lock {
中略
62             $self->unlock;
63         }
64     }
65     if (symlink $target, $self->file) { あたりで気づけるのではないでしょうか。lock関数の中で、実際にlockを獲得しているのが65行目のsymlinkなのに、その手前でunlockを呼んでます。一般的に言って、獲得してないロックを解放するのはかなりまずいでしょう(実際、このunlockの呼び出しの直前で他のプロセスがlockに成功すると、そこで生成されたロックファイルを勝手に削除しちゃうことになり、結局2重にlockが獲得できちゃいます)。
さて、標題の「関数名は大事だよね」ですが、unlockの実装は 73 sub unlock {
74     unlink $_[0]->file;
75 } だけなので、下手するとunlinkってな名前を付けちゃいそうです。が、実装がたまたまそうなってるだけで、呼び出し側から見ればやりたいことはunlockなのですから、この名前で大正解。これがunlockと命名されていたからこそ、lock関数の実装がダメそうなのがすぐに分かったわけです。
というわけで、関数名を横着しないできちんと付けてると、コードの間違にも気づきやすいよねというお話でした。