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は書いてて楽しい