zoovisitor 0.2.4.0 → 0.2.5.0
raw patch · 6 files changed
+64/−25 lines, 6 files
Files
- README.md +13/−11
- include/hs_zk.h +0/−5
- src/ZooKeeper.hs +33/−7
- src/ZooKeeper/Internal/Types.hsc +15/−0
- src/ZooKeeper/Types.hs +1/−0
- zoovisitor.cabal +2/−2
README.md view
@@ -1,26 +1,28 @@-ZooVisitor-==========+# ZooVisitor [](https://hackage.haskell.org/package/zoovisitor) An Apache [zookeeper](https://zookeeper.apache.org/) client for Haskell. -Tested on zookeeper 3.4, a higher version should work but not guaranteed.+Tested with libzookeeper-mt [3.4, 3.6], a higher version should work but not+guaranteed. **NOTE: this library is still in development.** - ## Features - Simple- + Does not require knowledge of the C APIs- + Does not require malloc and free memory manually- + High-level api written in Haskell + - Does not require knowledge of the C APIs+ - Does not require malloc and free memory manually+ - High-level api written in Haskell+ - Safe- + Type safe- + A failure action should throw an exception + - Type safe+ - A failure action should throw an exception+ - Fast- + All underlying calls are non-blocking, you can use Haskell lightweight threads to speed up your tasks.- + The speed should be compatible to C implementation+ - All underlying calls are non-blocking, you can use Haskell lightweight+ threads to speed up your tasks.+ - The speed should be compatible to C implementation
include/hs_zk.h view
@@ -75,11 +75,6 @@ // ---------------------------------------------------------------------------- -zhandle_t* hs_zookeeper_init(HsStablePtr mvar, HsInt cap,- hs_watcher_ctx_t* watcher_ctx, const char* host,- int recv_timeout, const clientid_t* clientid,- int flags);- int hs_zoo_aget_acl(zhandle_t* zh, const char* path, HsStablePtr mvar, HsInt cap, hs_acl_completion_t* completion);
src/ZooKeeper.hs view
@@ -7,6 +7,7 @@ , U.Resource , zooCreate+ , zooCreateIfMissing , zooSet , zooGet , zooWatchGet@@ -25,8 +26,10 @@ , zooDeleteOpInit , zooSetOpInit , zooCheckOpInit+ , assertZooOpResultOK , zooClientID+ , I.peekClientId , zooState , zooRecvTimeout , isUnrecoverable@@ -36,6 +39,7 @@ , zookeeperClose ) where +import Control.Exception (catch) import Control.Monad (void, when, zipWithM, (<=<)) import Data.Bifunctor (first) import Data.Maybe (fromMaybe)@@ -73,7 +77,7 @@ -- ^ The id of a previously established session that this client will be -- reconnecting to. Pass 'Nothing' if not reconnecting to a previous -- session. Clients can access the session id of an established, valid,- -- connection by calling 'zooGetClientID'. If the session corresponding to+ -- connection by calling 'zooClientID'. If the session corresponding to -- the specified clientid has expired, or if the clientid is invalid for -- any reason, the returned 'T.ZHandle' will be invalid -- the 'T.ZHandle' -- state will indicate the reason for failure (typically 'T.ZooExpiredSession').@@ -130,6 +134,19 @@ where csize = I.csize @T.StringCompletion +-- TODO: Add option to create its parents too+-- see: https://hackage.haskell.org/package/directory-1.3.7.0/docs/System-Directory.html#v:createDirectoryIfMissing+zooCreateIfMissing+ :: T.ZHandle+ -> CBytes+ -> Maybe Bytes+ -> T.AclVector+ -> T.CreateMode+ -> IO (Maybe T.StringCompletion)+zooCreateIfMissing zh path m_value acl mode =+ catch (Just <$> zooCreate zh path m_value acl mode) $+ \(_ :: E.ZNODEEXISTS) -> pure Nothing+ -- | Sets the data associated with a node. -- -- Throw one of the following exceptions on failure:@@ -540,6 +557,13 @@ (I.c_hs_zoo_amulti zh (fromIntegral len) mbai# mbar#) zipWithM ($) (map fst res) (chunkPtr ptr_result I.zooOpResultSize) +assertZooOpResultOK :: HasCallStack => T.ZooOpResult -> IO ()+assertZooOpResultOK (T.ZooCreateOpResult ret _) = void $ E.throwZooErrorIfNotOK ret+assertZooOpResultOK (T.ZooDeleteOpResult ret) = void $ E.throwZooErrorIfNotOK ret+assertZooOpResultOK (T.ZooSetOpResult ret _) = void $ E.throwZooErrorIfNotOK ret+assertZooOpResultOK (T.ZooCheckOpResult ret) = void $ E.throwZooErrorIfNotOK ret+{-# INLINE assertZooOpResultOK #-}+ -- | Internal helper function to set zoo op. initOp :: (I.ZooOp, Ptr I.CZooOp) -> IO (Ptr I.CZooOpResult -> IO T.ZooOpResult, I.TouchListBytes)@@ -560,12 +584,14 @@ -> Maybe Bytes -- ^ The data to be stored in the node. -> CInt- -- ^ The max buffer size of the created new node path (this might be- -- different than the supplied path because of the 'T.ZooSequence' flag).- -- If this size is 0,+ -- ^ Max Size of the buffer results in 'ZooOpResult' which will be filled+ -- with the path of the new node (this might be different than the supplied+ -- path because of the 'T.ZooSequence' flag). -- -- Note: we do NOT check if the size is non-negative. --+ -- If this size is 0, you will get an empty ZooCreateOpResult.+ -- -- If the path of the new node exceeds the buffer size, the path string will -- be truncated to fit. The actual path of the new node in the server will -- not be affected by the truncation.@@ -576,7 +602,7 @@ -- or an OR of the Create Flags -> T.ZooOp zooCreateOpInit path m_value buflen acl mode = I.ZooCreateOp $ \op -> do- let buflen' = buflen + 1 -- including space for the null terminator+ let buflen' = buflen + 1 -- The path string will always be null-terminated. CBytes.withCBytesUnsafe path $ \path' -> do mba@(Z.MutableByteArray mba#) <- Z.newPinnedByteArray (fromIntegral buflen') case m_value of@@ -675,7 +701,7 @@ -- ^ The id of a previously established session that this client will be -- reconnecting to. Pass 'Nothing' if not reconnecting to a previous -- session. Clients can access the session id of an established, valid,- -- connection by calling 'zooGetClientID'. If the session corresponding to+ -- connection by calling 'zooClientID'. If the session corresponding to -- the specified clientid has expired, or if the clientid is invalid for -- any reason, the returned 'T.ZHandle' will be invalid -- the 'T.ZHandle' -- state will indicate the reason for failure (typically 'T.ZooExpiredSession').@@ -695,7 +721,7 @@ void $ E.throwZooErrorIfNotOK =<< I.c_zookeeper_close zh {-# INLINABLE zookeeperClose #-} --- | Return the client session id, only valid if the connections+-- | Return the opaque client session id, only valid if the connections -- is currently connected (ie. last watcher state is 'T.ZooConnectedState') zooClientID :: T.ZHandle -> IO T.ClientID zooClientID = I.c_zoo_client_id
src/ZooKeeper/Internal/Types.hsc view
@@ -25,8 +25,23 @@ newtype ZHandle = ZHandle { unZHandle :: Ptr () } deriving (Show, Eq) +-- | This structure holds the id and password for the session. This structure+-- should be treated as opaque. It is received from the server when a session+-- is established and needs to be sent back as-is when reconnecting a session. newtype ClientID = ClientID { unClientID :: Ptr () } deriving (Show, Eq)++data HsClientID = HsClientID+ { clientId :: {-# UNPACK #-} !Int64+ , clientPasswd :: {-# UNPACK #-} !CBytes+ } deriving (Show, Eq)++peekClientId :: ClientID -> IO HsClientID+peekClientId (ClientID ptr) = do+ client_id <- (#peek clientid_t, client_id) ptr+ -- the pointer is getting from zhandle, so here we don't need to free it+ passwd <- CBytes.fromCString =<< (#peek clientid_t, passwd) ptr+ pure $ HsClientID{clientId=client_id, clientPasswd=passwd} newtype ZooLogLevel = ZooLogLevel CInt deriving (Eq, Storable)
src/ZooKeeper/Types.hs view
@@ -1,6 +1,7 @@ module ZooKeeper.Types ( I.ZHandle , I.ClientID+ , I.HsClientID (..) , I.WatcherFn , I.ZooOp
zoovisitor.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name: zoovisitor-version: 0.2.4.0+version: 0.2.5.0 synopsis: A haskell binding to Apache Zookeeper C library(mt) using Haskell Z project. @@ -12,7 +12,7 @@ copyright: Copyright (c) author: mu maintainer: mu@laxcat.xyz-tested-with: GHC ==8.8.4 || ==8.10.7 || ==9.0.2 || ==9.2.5+tested-with: GHC ==8.10.7 || ==9.0.2 || ==9.2.8 category: Database homepage: https://github.com/ZHaskell/zoovisitor bug-reports: https://github.com/ZHaskell/zoovisitor/issues