読者です 読者をやめる 読者になる 読者になる

YAMAGUCHI::weblog

土足で窓から失礼いたします。今日からあなたの息子になります。 当年とって92歳、下町の発明王、エジソンです。

OCamlからmemcachedを叩く

はじめに

最近はOCamlからいろんなものとやり取りしたいなという心持ちなんですが、とりあえずmemcachedを叩いてみようかと思って始めてみました。

書いたもの

とりあえず書いた。適当に書いただけなので動くかどうかも適当です。

全部書いてもしょうがないので、とりあえずsetだけ雰囲気で。

memcachedインストール

$ sudo port install memcached
...
--->  Fetching memcached
--->  Attempting to fetch memcached-1.4.5.tar.gz from http://memcached.googlecode.com/files/
--->  Verifying checksum(s) for memcached
--->  Extracting memcached
--->  Configuring memcached
--->  Building memcached
--->  Staging memcached into destroot
--->  Creating launchd control script
###########################################################
# A startup item has been generated that will aid in
# starting memcached with launchd. It is disabled
# by default. Execute the following command to start it,
# and to cause it to launch at startup:
#
# sudo port load memcached
###########################################################
--->  Installing memcached @1.4.5_0
--->  Activating memcached @1.4.5_0
--->  Cleaning memcached

memcachedでとりあえず遊ぶ

  • server
$ memcached -vv
slab class   1: chunk size        96 perslab   10922
slab class   2: chunk size       120 perslab    8738
slab class   3: chunk size       152 perslab    6898
...
slab class  41: chunk size    771184 perslab       1
slab class  42: chunk size   1048576 perslab       1
<16 server listening (auto-negotiate)
<17 server listening (auto-negotiate)
<18 send buffer was 9216, now 3728270
<19 send buffer was 9216, now 3728270
<18 server listening (udp)
<18 server listening (udp)
<18 server listening (udp)
<18 server listening (udp)
<19 server listening (udp)
<19 server listening (udp)
<19 server listening (udp)
<19 server listening (udp)
  • client
$ telnet localhost 11211
Trying ::1...
Connected to localhost.
Escape character is '^]'.
set foo 0 0 3
bar
STORED
get foo
VALUE foo 0 3
bar
END
quit 
Connection closed by foreign host.

とりあえずおっけー。

OCamlからmemcachedを叩く

とりあえずTCPをしゃべればいいでしょう、ということでAPIの仕様を見る。

書いたもの全体は上にあるんで、とりあえずsetの部分だけ。Socketで叩いて、テキスト渡すだけ。簡単。すげー。

let connect ?(port=11211) hostname = 
  let sock = socket PF_INET SOCK_STREAM 0 in
  let host = gethostbyname hostname in
  connect sock (ADDR_INET (host.h_addr_list.(0), port));
  sock
;;

let sock_send sock str =
  let len = String.length str in
  send sock str 0 len []
;;

let store sock command key flags exptime msg = 
  let bytes = string_of_int (String.length msg) in
  let query = 
    [command; key; string_of_int flags; string_of_int exptime;
    bytes; endline] in
  let str = (String.concat " " query) ^ msg ^ endline in
  let _ = sock_send sock str in
  let recv = sock_recv sock in
  match recv with
  | "STORED\r\n" -> recv
  | "NOT_STORED\r\n" -> raise(Failure (command ^ ":not stored"))
  | "EXISTS\r\n" -> raise(Failure (command ^ ":not stored"))
  | "NOT_FOUND\r\n" -> raise(Failure (command ^ ":not stored"))
  | _ -> raise(Failure (command ^ ":not stored"))
;;

let set sock key flags exptime msg =
  store sock "set" key flags exptime msg
;;