2013年8月14日水曜日

haskellでmemcachedとお友達になれる

haskellでmemcachedにアクセスする

ここ最近pythonなどでmemcacheを触ることが多かったので、「haskellにはあるのかな?」と思い探して見たところ、
githubのbeketaさんのリポジトリにhaskell-memcachedが公開されていましたのでforkさせて頂き、Gentoo用のebuildを作らさせていただきました。
ありがとうございました。


haskell-memcacheインストール

自分の使用しているghcが7.6.3で現行のバージョンが動かなかったため、ちょっとcabalファイルにパッチを当てさせてもらいました。

インストールはGentooでしたら、
karky7 ~ # emerge -pv dev-haskell/memcached
[ebuild  N    ~] dev-haskell/memcached-9999:0/9999::karky7  USE="doc hscolour -profile" 0 kB
karky7 ~ #

直接git cloneでしたら、
cuomo@karky7 ~/blogs $ git clone https://github.com/karky7/haskell-memcached.git
Cloning into 'haskell-memcached'...
remote: Counting objects: 111, done.
remote: Compressing objects: 100% (58/58), done.
remote: Total 111 (delta 55), reused 105 (delta 51)
Receiving objects: 100% (111/111), 17.94 KiB, done.
Resolving deltas: 100% (55/55), done.
cuomo@karky7 ~/blogs $ cd haskell-memcached/
cuomo@karky7 ~/blogs/haskell-memcached $ runhaskell Setup.hs install
でいくとは思われますが、やった事はございません。

クライアントコードを書いてみる

インストールが完了したら、実際にアクセスできるか試します、テストコードを見つつ、サンプルコードを書いてみました。

処理内容は以下の3つ
  • memcachedの設定値の取得
  • Intの値の保存と取得
  • ユーザー定義型の保存と取得
を単純に実行しています

import qualified Network.Memcache as M
import Network.Memcache.Protocol as P
import Network.Memcache.Serializable(Serializable(..))
import Data.ByteString.Char8 as C (pack, unpack, words)

data User = User {
  getUsername :: String,
  getAge :: Int
} deriving Show

instance Serializable User where
  serialize (User name age) = pack $ name ++ " " ++ show(age::Int)
  deserialize str = case C.words str of
    (un:ag:[]) -> Just (User (unpack $ un) (read (unpack ag)))
    _          -> Nothing

main :: IO ()
main = do
  memcache <- P.connect "localhost" 11211
  -- Memcacheステータス表示
  putStrLn "------------------"
  putStrLn "Memcacheステータス"
  putStrLn "------------------"
  status <- stats memcache
  _ <- mapM (\tp -> do
                let name = fst tp
                    val  = snd tp
                putStr $ name ++ " = " ++ val ++ "\n") status
  putStrLn ""

  -- Int値を保存
  let foo = 8888 :: Int
  putStr "Setting foo => 3: ... " >> M.set memcache "foo" foo >>= putResult
  -- Int値を取得
  foo' <- M.get memcache "foo"
  case foo' of
    Nothing -> putStrLn "Retrieving foo: expired from cache?"
    Just v  -> putStrLn ("Cached value for foo is " ++ show (v::Int) ++ ".")

  -- ユーザー定義型を保存
  let ando = User "#Ando" 29
  putStr "#A to memcache ... " >> M.set memcache "ando" ando >>= putResult
  -- ユーザー定義型を取得
  ando' <- M.get memcache "ando"
  case ando' of
    Nothing -> putStrLn "#Aは逝ってしまいました"
    Just v  -> putStrLn $ "#A 見っけ お名前は " ++ getUsername v ++ " お年は " ++ show (getAge v)
  P.disconnect memcache

putResult :: Bool -> IO()
putResult r = case r of
  True -> putStrLn "成功じゃないの"
  _    -> putStrLn "それそれ..."

memcachedへ接続してみる

まずmemcachedデーモンを起動しましてサンプルコードの実行
karky7 ~ # /etc/init.d/memcached start
 * Starting memcached ...
 * You should edit /etc/conf.d/memcached and specify an address to listen on.
 * Listening on any address (check your firewall!)                [ ok ]
karky7 ~ #

cuomo@karky7 ~ $ runhaskell memcache_client.hs
------------------
Memcacheステータス
------------------
pid = 7704
uptime = 179
time = 1376452659
version = 1.4.5
pointer_size = 64
rusage_user = 0.016000
rusage_system = 0.000000
curr_connections = 10
total_connections = 11
connection_structures = 11
cmd_get = 0
cmd_set = 0
cmd_flush = 0
get_hits = 0
get_misses = 0
delete_misses = 0
delete_hits = 0
incr_misses = 0
incr_hits = 0
decr_misses = 0
decr_hits = 0
cas_misses = 0
cas_hits = 0
cas_badval = 0
auth_cmds = 0
auth_errors = 0
bytes_read = 7
bytes_written = 0
limit_maxbytes = 67108864
accepting_conns = 1
listen_disabled_num = 0
threads = 4
conn_yields = 0
bytes = 0
curr_items = 0
total_items = 0
evictions = 0
reclaimed = 0

Setting foo => 3: ... 成功じゃないの
Cached value for foo is 8888.
#A to memcache ... 成功じゃないの
#A 見っけ お名前は #Ando お年は 29
cuomo@karky7 ~/Code/haskell/memcached $

memcached付属のコマンドツールでメモリをdumpしてみる

cuomo@karky7 ~ $ memcached-tool localhost dump
Dumping memcache contents
  Number of buckets: 1
  Number of items  : 2
Dumping bucket 1 - 2 total items
add foo 0 1376452480 4
8888
add ando 0 1376452480 8
#Ando 29
cuomo@karky7 ~ $

#A君を突っ込んで、出したりと出きるようになりました、User型みたいのは別として、シリアライズ方法がshowとreadで概ねhaskell用になっているのでjsonとかで保存すれば汎用性が上がっていいかもしれません。
しかし、haskellは書いてて楽しい

0 件のコメント:

コメントを投稿