Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

api: add zooGetAcl #11

Merged
merged 1 commit into from
Mar 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 44 additions & 2 deletions cbits/hs_zk.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,41 @@ void hs_strings_stat_completion_fn(int rc, const string_vector_t* strings,
hs_thread_done();
}

/**
* \brief signature of a completion function that returns an ACL.
*
* This method will be invoked at the end of a asynchronous call and also as
* a result of connection loss or timeout.
* \param rc the error code of the call. Connection loss/timeout triggers
* the completion with one of the following error codes:
* ZCONNECTIONLOSS -- lost connection to the server
* ZOPERATIONTIMEOUT -- connection timed out
* Data related events trigger the completion with error codes listed the
* Exceptions section of the documentation of the function that initiated the
* call. (Zero indicates call was successful.)
* \param acl a pointer to the structure containng the ACL of a node. If a non
* zero error code is returned, the content of strings is undefined. The
* programmer is NOT responsible for freeing acl.
* \param stat a pointer to the stat information for the node involved in
* this function. If a non zero error code is returned, the content of
* stat is undefined. The programmer is NOT responsible for freeing stat.
* \param data the pointer that was passed by the caller when the function
* that this completion corresponds to was invoked. The programmer
* is responsible for any memory freeing associated with the data
* pointer.
*/
void hs_acl_completion_fn(int rc, struct ACL_vector* acl, struct Stat* stat,
const void* data) {
hs_acl_completion_t* acl_completion = (hs_acl_completion_t*)data;
acl_completion->rc = rc;
if (!rc) {
acl_completion->acl = dup_acl_vector(acl);
acl_completion->stat = dup_stat(stat);
}
hs_try_putmvar(acl_completion->cap, acl_completion->mvar);
hs_thread_done();
}

// ----------------------------------------------------------------------------

zhandle_t* hs_zookeeper_init(HsStablePtr mvar, HsInt cap,
Expand All @@ -220,6 +255,8 @@ zhandle_t* hs_zookeeper_init(HsStablePtr mvar, HsInt cap,
return zh;
}

// ----------------------------------------------------------------------------

int hs_zoo_acreate(zhandle_t* zh, const char* path, const char* value,
HsInt offset, HsInt valuelen, const struct ACL_vector* acl,
int mode, HsStablePtr mvar, HsInt cap,
Expand Down Expand Up @@ -326,6 +363,13 @@ int hs_zoo_awget_children2(zhandle_t* zh, const char* path, HsStablePtr mvar_w,
hs_strings_stat_completion_fn, strings_stat);
}

int hs_zoo_aget_acl(zhandle_t* zh, const char* path, HsStablePtr mvar,
HsInt cap, hs_acl_completion_t* completion) {
completion->mvar = mvar;
completion->cap = cap;
return zoo_aget_acl(zh, path, hs_acl_completion_fn, completion);
}

int hs_zoo_amulti(zhandle_t* zh, int count, const zoo_op_t* ops,
zoo_op_result_t* results, HsStablePtr mvar, HsInt cap,
hs_void_completion_t* void_completion) {
Expand All @@ -348,5 +392,3 @@ void hs_zoo_set_op_init(zoo_op_t* op, const char* path, const char* value,
stat_t* stat) {
zoo_set_op_init(op, path, value + valoffset, valuelen, version, stat);
}

// ----------------------------------------------------------------------------
39 changes: 38 additions & 1 deletion include/hs_zk.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

typedef struct Stat stat_t;
typedef struct String_vector string_vector_t;
typedef struct ACL acl_t;
typedef struct ACL_vector acl_vector_t;

const stat_t* dup_stat(const stat_t* old_stat) {
stat_t* new_stat = (stat_t*)malloc(sizeof(stat_t));
Expand All @@ -17,9 +19,13 @@ const stat_t* dup_stat(const stat_t* old_stat) {
}

const string_vector_t* dup_string_vector(const string_vector_t* old_strings) {
int count = old_strings->count;
if (count < 0) {
fprintf(stderr, "dup_string_vector error: count %d\n", count);
return NULL;
}
string_vector_t* new_strings =
(string_vector_t*)malloc(sizeof(string_vector_t));
int count = old_strings->count;
char** vals = malloc(count * sizeof(char*));
for (int i = 0; i < count; ++i) {
vals[i] = strdup(old_strings->data[i]);
Expand All @@ -29,6 +35,26 @@ const string_vector_t* dup_string_vector(const string_vector_t* old_strings) {
return new_strings;
}

const acl_vector_t* dup_acl_vector(const acl_vector_t* old_acls) {
int count = old_acls->count;
if (count < 0) {
fprintf(stderr, "dup_acl_vector error: count %d\n", count);
return NULL;
}
acl_t* data = (acl_t*)malloc(count * sizeof(acl_t));
acl_t* old_data = old_acls->data;
for (int i = 0; i < count; ++i) {
data[i].perms = old_data[i].perms;
data[i].id.scheme = strdup(old_data[i].id.scheme);
data[i].id.id = strdup(old_data[i].id.id);
}

acl_vector_t* new_acls = (acl_vector_t*)malloc(sizeof(acl_vector_t));
new_acls->count = count;
new_acls->data = data;
return new_acls;
}

typedef struct hs_watcher_ctx_t {
HsStablePtr mvar;
HsInt cap;
Expand Down Expand Up @@ -82,13 +108,24 @@ typedef struct hs_strings_stat_completion_t {
const stat_t* stat;
} hs_strings_stat_completion_t;

typedef struct hs_acl_completion_t {
HsStablePtr mvar;
HsInt cap;
int rc;
const struct ACL_vector* acl;
const struct Stat* stat;
} hs_acl_completion_t;

// ----------------------------------------------------------------------------

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);

int hs_zoo_acreate(zhandle_t* zh, const char* path, const char* value,
HsInt offset, HsInt valuelen, const struct ACL_vector* acl,
int mode, HsStablePtr mvar, HsInt cap,
Expand Down
87 changes: 57 additions & 30 deletions src/ZooKeeper.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,6 @@ module ZooKeeper
, Res.withResource
, Res.Resource

, zooGetClientID
, zooState
, zooRecvTimeout

, isUnrecoverable

, zooCreate
, zooSet
, zooGet
Expand All @@ -23,13 +17,19 @@ module ZooKeeper
, zooDelete
, zooExists
, zooWatchExists
, zooGetAcl

, zooMulti
, zooCreateOpInit
, zooDeleteOpInit
, zooSetOpInit
, zooCheckOpInit

, zooClientID
, zooState
, zooRecvTimeout
, isUnrecoverable

, zookeeperInit
, zookeeperClose
) where
Expand Down Expand Up @@ -82,16 +82,6 @@ zookeeperResInit
zookeeperResInit host timeout mclientid flags =
Res.initResource (zookeeperInit host timeout mclientid flags) zookeeperClose

-- | Checks if the current zookeeper connection state can't be recovered.
--
-- If True, the application must close the zhandle and then try to reconnect.
isUnrecoverable
:: T.ZHandle
-- ^ The zookeeper handle obtained by a call to 'zookeeperResInit'
-> IO Bool
-- ^ Return True if connection is unrecoverable
isUnrecoverable zh = (< 0) <$> I.c_is_unrecoverable zh

-- | Create a node.
--
-- This method will create a node in ZooKeeper. A node can only be created if
Expand Down Expand Up @@ -472,22 +462,32 @@ zooWatchGetChildren2 zh path watchfn strsStatfn =
csize I.peekRet I.peekData stringsfn'
(I.c_hs_zoo_awget_children2 zh path')

-- | Return the client session id, only valid if the connections
-- is currently connected (ie. last watcher state is 'T.ZooConnectedState')
zooGetClientID :: T.ZHandle -> IO T.ClientID
zooGetClientID = I.c_zoo_client_id

-- | Get the state of the zookeeper connection
-- | Gets the acl associated with a node.
--
-- The return valud will be one of the State Consts
zooState :: T.ZHandle -> IO T.ZooState
zooState = I.c_zoo_state
-- Throw one of the following exceptions on failure:
--
-- ZBADARGUMENTS - invalid input parameters
-- ZINVALIDSTATE - zhandle state is either ZOO_SESSION_EXPIRED_STATE or ZOO_AUTH_FAILED_STATE
-- ZMARSHALLINGERROR - failed to marshall a request; possibly, out of memory
zooGetAcl
:: HasCallStack
=> T.ZHandle
-- ^ The zookeeper handle obtained by a call to 'zookeeperResInit'
-> CBytes
-- ^ The name of the node. Expressed as a file name with slashes
-- separating ancestors of the node.
-> IO T.AclCompletion
-- ^ The result when the request completes.
--
-- Throw one of the following exceptions if the request completes failed:
--
-- * ZNONODE the node does not exist.
-- * ZNOAUTH the client does not have permission.
zooGetAcl zh path = CBytes.withCBytesUnsafe path $ \path' -> do
let csize = I.csize @T.AclCompletion
cfunc = I.c_hs_zoo_aget_acl zh path'
in E.throwZooErrorIfLeft =<< I.withZKAsync csize I.peekRet I.peekData cfunc

-- | Return the timeout for this session, only valid if the connections
-- is currently connected (ie. last watcher state is ZOO_CONNECTED_STATE). This
-- value may change after a server re-connect.
zooRecvTimeout :: T.ZHandle -> IO CInt
zooRecvTimeout = I.c_zoo_recv_timeout
-------------------------------------------------------------------------------

-- | Atomically commits multiple zookeeper operations.
Expand Down Expand Up @@ -676,3 +676,30 @@ zookeeperInit host timeout mclientid flags = do
{-# INLINABLE zookeeperClose #-}
zookeeperClose :: T.ZHandle -> IO ()
zookeeperClose = void . E.throwZooErrorIfNotOK <=< I.c_zookeeper_close_safe

-- | Return the 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

-- | Checks if the current zookeeper connection state can't be recovered.
--
-- If True, the application must close the zhandle and then try to reconnect.
isUnrecoverable
:: T.ZHandle
-- ^ The zookeeper handle obtained by a call to 'zookeeperResInit'
-> IO Bool
-- ^ Return True if connection is unrecoverable
isUnrecoverable zh = (< 0) <$> I.c_is_unrecoverable zh

-- | Get the state of the zookeeper connection
--
-- The return valud will be one of the State Consts
zooState :: T.ZHandle -> IO T.ZooState
zooState = I.c_zoo_state

-- | Return the timeout for this session, only valid if the connections
-- is currently connected (ie. last watcher state is ZOO_CONNECTED_STATE). This
-- value may change after a server re-connect.
zooRecvTimeout :: T.ZHandle -> IO CInt
zooRecvTimeout = I.c_zoo_recv_timeout
6 changes: 6 additions & 0 deletions src/ZooKeeper/Internal/FFI.hsc
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ foreign import ccall unsafe "hs_zk.h zoo_state"
foreign import ccall unsafe "hs_zk.h zoo_recv_timeout"
c_zoo_recv_timeout :: ZHandle -> IO CInt

foreign import ccall unsafe "hs_zk.h hs_zoo_aget_acl"
c_hs_zoo_aget_acl
:: ZHandle -> BA## Word8
-> StablePtr PrimMVar -> Int -> Ptr AclCompletion
-> IO CInt

foreign import ccall unsafe "hs_zk.h hs_zoo_acreate"
c_hs_zoo_acreate
:: ZHandle
Expand Down
Loading