persistent-zookeeper-0.2.0: Database/Persist/Zookeeper/ZooUtil.hs
{-# LANGUAGE FlexibleContexts, UndecidableInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Database.Persist.Zookeeper.ZooUtil
where
import qualified Database.Zookeeper as Z
import qualified Data.ByteString.Char8 as B
import Control.Monad
import Data.Monoid
deriving instance Read (Z.ZKError)
deriving instance Read (Z.Stat)
zGet :: Z.Zookeeper
-> String
-> String
-> IO (Either Z.ZKError (Maybe B.ByteString, Z.Stat))
zGet zk dir key = do
let path = dir <> "/" <> key
Z.get zk path Nothing
zSet :: Z.Zookeeper
-> String
-> String
-> Maybe B.ByteString
-> Maybe Z.Version
-> IO (Either Z.ZKError Z.Stat)
zSet zk dir key dat ver = do
let path = dir <> "/" <> key
Z.set zk path dat ver
zModify :: Z.Zookeeper
-> String
-> String
-> (Maybe B.ByteString -> IO (Maybe B.ByteString))
-> IO (Either Z.ZKError Z.Stat)
zModify zk dir key f = do
v <- zGet zk dir key
case v of
Right (con,ver) -> do
v'' <- f con
v' <- zSet zk dir key v'' (Just (Z.statVersion ver))
case v' of
Right _ -> return v'
Left _ -> zModify zk dir key f
Left e -> return $ Left e
zReplace :: Z.Zookeeper
-> String
-> String
-> (Maybe B.ByteString)
-> IO (Either Z.ZKError Z.Stat)
zReplace zk dir key v'' = do
v <- zGet zk dir key
case v of
Right (_con,ver) -> do
v' <- zSet zk dir key v'' (Just (Z.statVersion ver))
case v' of
Right _ -> return v'
Left _ -> zReplace zk dir key v''
Left e -> return $ Left e
zRepSert :: Z.Zookeeper
-> String
-> String
-> (Maybe B.ByteString)
-> IO (Either Z.ZKError ())
zRepSert zk dir key v'' = do
v <- zCreate zk dir key v'' []
case v of
Right _ -> return $ Right ()
Left Z.NodeExistsError -> do
v' <- zReplace zk dir key v''
case v' of
Right _ -> return $ Right ()
Left Z.NoNodeError -> do
zRepSert zk dir key v''
Left s -> do
return $ Left s
Left v' -> return $ Left v'
zGetChildren :: Z.Zookeeper
-> String
-> IO (Either Z.ZKError [String])
zGetChildren zk dir = do
v <- Z.getChildren zk dir Nothing
case v of
Right _ -> return v
Left Z.NoNodeError -> return $ Right []
Left _ -> return v
zCreate :: Z.Zookeeper
-> String
-> String
-> Maybe B.ByteString
-> [Z.CreateFlag]
-> IO (Either Z.ZKError String)
zCreate zk dir key value flag = do
let path = dir <> "/" <> key
v <- Z.create zk path value Z.OpenAclUnsafe flag
case v of
Left Z.NoNodeError -> do
v' <- Z.create zk dir Nothing Z.OpenAclUnsafe []
case v' of
Left _ -> return $ v'
Right _ -> zCreate zk dir key value flag
Left _ -> return v
-- See https://issues.apache.org/jira/browse/ZOOKEEPER-1027
-- Do not use libzookeeper under 3.3.5, Z.create returns wrong node path
-- Use libzookeeper over 3.4.*
Right path' -> return $ Right $ drop (length ( dir <> "/" )) path'
zDelete :: Z.Zookeeper
-> String
-> String
-> Maybe Z.Version
-> IO (Either Z.ZKError ())
zDelete zk dir key mversion = do
let path = dir <> "/" <> key
Z.delete zk path mversion
zDeleteRecursive :: Z.Zookeeper
-> String
-> IO (Either Z.ZKError ())
zDeleteRecursive zk dir = do
ls <- zGetTree zk dir
res <- forM (reverse ls) $ \node ->
Z.delete zk node Nothing
return $ checkRes res
where
checkRes [] = Right ()
checkRes (Left val:_) = Left val
checkRes (Right _:xs) = checkRes xs
zGetTree :: Z.Zookeeper
-> String
-> IO [String]
zGetTree zk dir = do
ls <- Z.getChildren zk dir Nothing
case ls of
Right dir' -> do
ls' <- forM dir' $ \d -> do
zGetTree zk (dir <> "/" <> d)
return $ concat ls'
Left err' -> error ("zGetTree's error:" ++ show err')