memcached-1.2.4で追加されたコマンドのメモ
なぜか最近になってまた動きが活発になってきた気がするmemcachedですが、ちょっと前(2007-12-06)にリリースされたmemcached 1.2.4からプロトコルコマンドが追加されました。
- append
- prepend
- gets
- cas
今回は、これら新しく追加されたコマンドについて、軽く説明してみたいと思います。
なお、クライアントライブラリが新コマンドに対応していたりいなかったりするので、今回はクライアントライブラリを使用せず、直接memcachedにつないで、プロトコルをしゃべって動作を確認したいと思います。(memcachedプロトコルは、doc/protocol.txtに詳しい解説がありますのであわせて読むといいと思います)
で、おしゃべるにはtelnetやncでもいいんですが、今回はsocatを使います。localhostの11211に繋ぎたい場合にこんな感じで実行すると、CRLFの変換や行編集や履歴参照もできちゃうすぐれものです。
$ socat READLINE,prompt='> ' TCP4:localhost:11211,crnl
append, prepend
既にデータがある場合に、データの末尾(append)や先頭(prepend)になにかをくっつけるコマンドです。
getしてsetすれば同じことはできるんですが、append, prependを使うと一息に(atomicに)できるのがミソです。
では実際に試してみましょう。
なにはともあれ、適当なデータをsetして、
> set foo 0 0 4 > val1 STORED
apeend、prependした後、getで確認してみます。元々の「val1」の前後に「PrePre」と「ApAp」がついたのが確認でできます。
> append foo 0 0 4 > ApAp STORED > prepend foo 0 0 6 > PrePre STORED > get foo VALUE foo 0 14 PrePreval1ApAp END
ちなみに、存在しないキーに対してappend、prependをすると、エラー(NOT_STORED)が返されます。
> append neeeyo 0 0 1 > X NOT_STORED
gets, cas
次はgetsとcasです。
memcachedのMLでの初出は、2007-09-08に投稿されたCAS operationというメールじゃないかと思います。
「cas」という名前は、CPU命令のCAS (Compare-and-Swap) からきているんだと思います。(参考: http://en.wikipedia.org/wiki/Compare-and-swap, http://ja.wikipedia.org/wiki/コンペア・アンド・スワップ)
「gets」という名前の由来はわかりませんが、心の中では「ゲッツ!」と発音しています。
gets, casはどういうときに使うものかというと、データを更新する場合に使います。
例えば、こんな場合にどうしたらいいか考えてみましょう。
- あるキーのデータをgetしたあとで、新しいデータを(同じキーに)setしたい。
- でももし、getとsetの間で他の人が同じキーを変更した場合はエラーにしたい。
setする直前に再度getして値が変わっていないか確認するという方法を思いつくかもしれませんが、再度getとsetの間にだれかに割り込まれる可能性があるので、それを排除するには再度getの後でsetする直前に再々度getする必要があり、再々度getとsetの間にだれかに割り込まれる可能性があるので、それを排除するには再々度getの後でsetする直前に再々々度getする必要が(ryとなり、きりがありません。
そこでgets, casの出番なんですが、説明するより実際に試してみた方が理解がはやいと思うのでいきます。
まずはgets。getとだいたい出力は同じなんですが、バイト数(下の例だと「14」)の後に、7という数値がついています。これがcas id呼ばれるものです。
> gets foo
VALUE foo 0 14 7
PrePreval1ApAp
END
次にcasなんですが、casは「指定したcas idが現在のcas idと一致するときのみ実行されるreplace」という説明でだいたいあってると思います。
> cas foo 0 0 4 6 # 最後の「6」がcas idの指定。でも、 > val6 # getsで確認したcas id(= 7)と異なるので、 EXISTS # EXISTSという応答が返り、 > get foo # データは変更されない。 VALUE foo 0 14 PrePreval1ApAp END > cas foo 0 0 4 99 # 同様に、より大きな数値をcas idと指定しても > val9 # データは更新されない。 EXISTS > cas foo 0 0 4 7 # getsで得たcas id(= 7)を指定すると、 > val7 STORED # EXISTSではなくSTOREDが返され、 > get foo VALUE foo 0 4 val7 # データは更新される。 END
> gets foo # 再度gets VALUE foo 0 4 8 val7 END 〜ここで別クライアントがキー:fooに対してデータ変更を行ったとする〜 > cas foo 0 0 4 8 > val8 EXISTS # 別クライアントが変更したことにより、 # 最新のcas idが変わったため # STOREDではなくEXISTSが返される。
つまり、データを得るときにgetではなくgets(ゲッツ!)を使い、データに加えてcas idも覚えておく。後、データを更新するときにはset,add,replaceではなくcasを使い、getsのときに得たcas idを指定する。STOREDが返れば更新成功、EXISTSが返った場合は、途中でだれかがデータを変更した、ということになります。
(ひ)