ctdb-client: Add async version for ctdb_client_init()
authorAmitay Isaacs <amitay@gmail.com>
Tue, 28 Nov 2017 10:17:37 +0000 (21:17 +1100)
committerMartin Schwenke <martins@samba.org>
Wed, 13 Dec 2017 07:48:18 +0000 (08:48 +0100)
Signed-off-by: Amitay Isaacs <amitay@gmail.com>
Reviewed-by: Martin Schwenke <martin@meltin.net>
ctdb/client/client.h
ctdb/client/client_connect.c

index 5be54b2dc0a7e18f900a2c0d09335225a69f0e59..e792047e9149606e95eef1ad275919c92fb6c517 100644 (file)
@@ -83,7 +83,7 @@ typedef void (*ctdb_tunnel_callback_func_t)(struct ctdb_tunnel_context *tctx,
                                            void *private_data);
 
 /**
- * @brief Initialize and connect to ctdb daemon
+ * @brief Async computation start to initialize a connection to ctdb daemon
  *
  * This returns a ctdb client context.  Freeing this context will free the
  * connection to ctdb daemon and any memory associated with it.
@@ -102,6 +102,31 @@ typedef void (*ctdb_tunnel_callback_func_t)(struct ctdb_tunnel_context *tctx,
  * @param[in] mem_ctx Talloc memory context
  * @param[in] ev Tevent context
  * @param[in] sockpath Path to ctdb daemon unix domain socket
+ * @return new tevent request, NULL on failure
+ */
+struct tevent_req *ctdb_client_init_send(TALLOC_CTX *mem_ctx,
+                                        struct tevent_context *ev,
+                                        const char *sockpath);
+
+/**
+ * @brief Async computation end to initialize a connection to ctdb daemon
+ *
+ * @param[in] req Tevent request
+ * @param[out] perr errno in case of failure
+ * @param[in] mem_ctx Talloc memory context
+ * @param[out] result The new ctdb client context
+ * @return true on success, false on failure
+ */
+bool ctdb_client_init_recv(struct tevent_req *req, int *perr,
+                          TALLOC_CTX *mem_ctx,
+                          struct ctdb_client_context **result);
+
+/**
+ * @brief Sync wrapper to initialize ctdb connection
+ *
+ * @param[in] mem_ctx Talloc memory context
+ * @param[in] ev Tevent context
+ * @param[in] sockpath Path to ctdb daemon unix domain socket
  * @param[out] result The new ctdb client context
  * @return 0 on succcess, errno on failure
  */
index ed4371f2c89e3b3826f23e167efca219b8477585..89a602d4030b43e74f3fe35234719cc79659541b 100644 (file)
 #include "client/client.h"
 #include "client/client_sync.h"
 
-static int ctdb_client_connect(struct ctdb_client_context *client,
-                              struct tevent_context *ev,
-                              const char *sockpath);
+static void client_read_handler(uint8_t *buf, size_t buflen,
+                               void *private_data);
+static void client_dead_handler(void *private_data);
+
+struct ctdb_client_init_state {
+       struct ctdb_client_context *client;
+};
 
 static int ctdb_client_context_destructor(struct ctdb_client_context *client);
+static void ctdb_client_init_done(struct tevent_req *subreq);
 
-int ctdb_client_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
-                    const char *sockpath, struct ctdb_client_context **out)
+struct tevent_req *ctdb_client_init_send(TALLOC_CTX *mem_ctx,
+                                        struct tevent_context *ev,
+                                        const char *sockpath)
 {
+       struct tevent_req *req, *subreq;
+       struct ctdb_client_init_state *state;
        struct ctdb_client_context *client;
+       struct ctdb_req_control request;
+       struct sockaddr_un addr;
+       size_t len;
        int ret;
 
-       client = talloc_zero(mem_ctx, struct ctdb_client_context);
-       if (client == NULL) {
-               DEBUG(DEBUG_ERR, (__location__ " memory allocation error\n"));
-               return ENOMEM;
+       req = tevent_req_create(mem_ctx, &state,
+                               struct ctdb_client_init_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       if (sockpath == NULL) {
+               D_ERR("socket path cannot be NULL\n");
+               tevent_req_error(req, EINVAL);
+               return tevent_req_post(req, ev);
+       }
+
+       client = talloc_zero(state, struct ctdb_client_context);
+       if (tevent_req_nomem(client, req)) {
+               return tevent_req_post(req, ev);
        }
 
        ret = reqid_init(client, INT_MAX-200, &client->idr);
        if (ret != 0) {
-               DEBUG(DEBUG_ERR, ("reqid_init() failed, ret=%d\n", ret));
+               D_ERR("reqid_init() failed, ret=%d\n", ret);
                talloc_free(client);
-               return ret;
+               tevent_req_error(req, ret);
+               return tevent_req_post(req, ev);
        }
 
        ret = srvid_init(client, &client->srv);
        if (ret != 0) {
                DEBUG(DEBUG_ERR, ("srvid_init() failed, ret=%d\n", ret));
                talloc_free(client);
-               return ret;
+               tevent_req_error(req, ret);
+               return tevent_req_post(req, ev);
        }
 
        ret = srvid_init(client, &client->tunnels);
        if (ret != 0) {
                DEBUG(DEBUG_ERR, ("srvid_init() failed, ret=%d\n", ret));
                talloc_free(client);
-               return ret;
+               tevent_req_error(req, ret);
+               return tevent_req_post(req, ev);
        }
 
-       client->fd = -1;
-       client->pnn = CTDB_UNKNOWN_PNN;
+       memset(&addr, 0, sizeof(addr));
+       addr.sun_family = AF_UNIX;
+       len = strlcpy(addr.sun_path, sockpath, sizeof(addr.sun_path));
+       if (len != strlen(sockpath)) {
+               D_ERR("socket path too long, len=%zu\n", strlen(sockpath));
+               talloc_free(client);
+               tevent_req_error(req, ENAMETOOLONG);
+               return tevent_req_post(req, ev);
+       }
 
-       ret = ctdb_client_connect(client, ev, sockpath);
+       client->fd = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (client->fd == -1) {
+               ret = errno;
+               D_ERR("socket() failed, errno=%d\n", ret);
+               talloc_free(client);
+               tevent_req_error(req, ret);
+               return tevent_req_post(req, ev);
+       }
+
+       ret = connect(client->fd, (struct sockaddr *)&addr, sizeof(addr));
+       if (ret == -1) {
+               ret = errno;
+               DEBUG(DEBUG_ERR, ("connect() failed, errno=%d\n", ret));
+               close(client->fd);
+               talloc_free(client);
+               tevent_req_error(req, ret);
+               return tevent_req_post(req, ev);
+       }
+
+       ret = comm_setup(client, ev, client->fd, client_read_handler, client,
+                        client_dead_handler, client, &client->comm);
        if (ret != 0) {
+               DEBUG(DEBUG_ERR, ("comm_setup() failed, ret=%d\n", ret));
+               close(client->fd);
                talloc_free(client);
-               return ret;
+               tevent_req_error(req, ret);
+               return tevent_req_post(req, ev);
        }
 
+       client->pnn = CTDB_UNKNOWN_PNN;
+
        talloc_set_destructor(client, ctdb_client_context_destructor);
 
-       *out = client;
-       return 0;
+       state->client = client;
+
+       ctdb_req_control_get_pnn(&request);
+       subreq = ctdb_client_control_send(state, ev, client,
+                                         CTDB_CURRENT_NODE,
+                                         tevent_timeval_zero(),
+                                         &request);
+       if (tevent_req_nomem(subreq, req)) {
+               TALLOC_FREE(state->client);
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, ctdb_client_init_done, req);
+
+       return req;
 }
 
 static int ctdb_client_context_destructor(struct ctdb_client_context *client)
@@ -103,63 +172,69 @@ static int ctdb_client_context_destructor(struct ctdb_client_context *client)
        return 0;
 }
 
-static void client_read_handler(uint8_t *buf, size_t buflen,
-                               void *private_data);
-static void client_dead_handler(void *private_data);
-
-static int ctdb_client_connect(struct ctdb_client_context *client,
-                              struct tevent_context *ev, const char *sockpath)
+static void ctdb_client_init_done(struct tevent_req *subreq)
 {
-       struct sockaddr_un addr;
-       size_t len;
-       int fd, ret;
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct ctdb_client_init_state *state = tevent_req_data(
+               req, struct ctdb_client_init_state);
+       struct ctdb_reply_control *reply;
+       int ret;
+       bool status;
 
-       if (sockpath == NULL) {
-               DEBUG(DEBUG_ERR, ("socket path cannot be NULL\n"));
-               return EINVAL;
+       status = ctdb_client_control_recv(subreq, &ret, state, &reply);
+       TALLOC_FREE(subreq);
+       if (! status) {
+               tevent_req_error(req, ret);
+               return;
        }
 
-       memset(&addr, 0, sizeof(addr));
-       addr.sun_family = AF_UNIX;
-       len = strlcpy(addr.sun_path, sockpath, sizeof(addr.sun_path));
-       if (len != strlen(sockpath)) {
-               DEBUG(DEBUG_ERR, ("socket path too long, len=%zu\n",
-                                 strlen(sockpath)));
-               return ENAMETOOLONG;
+       ret = ctdb_reply_control_get_pnn(reply, &state->client->pnn);
+       if (ret != 0) {
+               tevent_req_error(req, ret);
+               return;
        }
 
-       fd = socket(AF_UNIX, SOCK_STREAM, 0);
-       if (fd == -1) {
-               ret = errno;
-               DEBUG(DEBUG_ERR, ("socket() failed, errno=%d\n", ret));
-               return ret;
-       }
+       tevent_req_done(req);
+}
 
-       ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
-       if (ret == -1) {
-               ret = errno;
-               DEBUG(DEBUG_ERR, ("connect() failed, errno=%d\n", ret));
-               close(fd);
-               return ret;
+bool ctdb_client_init_recv(struct tevent_req *req, int *perr,
+                          TALLOC_CTX *mem_ctx,
+                          struct ctdb_client_context **result)
+{
+       struct ctdb_client_init_state *state = tevent_req_data(
+               req, struct ctdb_client_init_state);
+       int ret;
+
+       if (tevent_req_is_unix_error(req, &ret)) {
+               if (perr != NULL) {
+                       *perr = ret;
+               }
+               return false;
        }
-       client->fd = fd;
 
-       ret = comm_setup(client, ev, fd, client_read_handler, client,
-                        client_dead_handler, client, &client->comm);
-       if (ret != 0) {
-               DEBUG(DEBUG_ERR, ("comm_setup() failed, ret=%d\n", ret));
-               close(fd);
-               client->fd = -1;
-               return ret;
+       *result = talloc_steal(mem_ctx, state->client);
+       return true;
+}
+
+
+int ctdb_client_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+                    const char *sockpath, struct ctdb_client_context **out)
+{
+       struct tevent_req *req;
+       int ret;
+       bool status;
+
+       req = ctdb_client_init_send(mem_ctx, ev, sockpath);
+       if (req == NULL) {
+               return ENOMEM;
        }
 
-       ret = ctdb_ctrl_get_pnn(client, ev, client, CTDB_CURRENT_NODE,
-                               tevent_timeval_zero(), &client->pnn);
-       if (ret != 0) {
-               DEBUG(DEBUG_ERR, ("failed to get current node pnn\n"));
-               close(fd);
-               client->fd = -1;
-               TALLOC_FREE(client->comm);
+       tevent_req_poll(req, ev);
+
+       status = ctdb_client_init_recv(req, &ret, mem_ctx, out);
+       TALLOC_FREE(req);
+       if (! status) {
                return ret;
        }