日向夏特殊応援部隊

俺様向けメモ

KeyedMutex::Memcached ってモジュールをリリースして何も言ってなかった件

id:kazuhooku さんがかつて作った KeyedMutexmemcached でやってしまおうと言うのがこのモジュールの目的です。

KeyedMutex の場合は、keyedmutexd と言うそれ専用の daemon を立ち上げなければいけませんが、このモジュールの場合は既存のシステムに memcached があれば普通に使えます。

trial を 0 にすると timeout で lock が expire するか、誰かが lock を開放するまで延々と lock の獲得が出来るまでビジーループします。一方で trial を有限の正整数とすると、その試行回数で lock が獲得出来ない場合は即座に諦めます。

正規の使い方としては lock を獲得出来るのが同時に1クライアントのみで他はそれが開放されるまで待たせると言うのが正解ですが、ちょっと変わった使い方としては、例えば特定のユーザーがオンラインかどうかみたいな処理を、次のように

my $cache = Cache::Memcached::Fast->new( ... );
my $km = KeyedMutex::Memcached->new( cache => $cache, trial => 1, timeout => 5 * 60 );
my $key = "online:" . $user_id;

if ( $km->lock( $key, 0 ) ) {
  update_online( $user_id );
}

なんてやっておくと、5分間は update_online() と言う処理がこのユーザーに対しては走らなくなります。

なんて感じでした。これも CPAN からご利用頂ける感じですよ。

余談ですが、Semaphore も考えてその際は incr/decr で管理しようと思ってたんですが、何らかの値が入ってないと incr/decr は出来ないので一度は諦めたのですが、kazeburo さんの Cache::Isolator の実装を見てたら、なるほど Cache::Memcached::Fast の add メソッドで指定個数の key をインクリメントしてく感じ*1で作って順番*2にロックの獲得を試みるようなインターフェースにすれば Semaphore も出来るなぁなんて思いました。

*1: key:1, key:2 ... みたいな感じ

*2:あるいはランダムで先頭または末尾から探索の方が効率がよさげ