ctdb-common: Add async version of reconfigure in sock_daemon
authorAmitay Isaacs <amitay@gmail.com>
Fri, 17 Nov 2017 01:38:18 +0000 (12:38 +1100)
committerMartin Schwenke <martins@samba.org>
Tue, 21 Nov 2017 04:03:17 +0000 (05:03 +0100)
Signed-off-by: Amitay Isaacs <amitay@gmail.com>
Reviewed-by: Martin Schwenke <martin@meltin.net>
ctdb/common/sock_daemon.c
ctdb/common/sock_daemon.h
ctdb/tests/cunit/sock_daemon_test_001.sh
ctdb/tests/src/sock_daemon_test.c

index 6b05e2462f90e19e2e77099128fdd98ce3d77e1a..ce6f9230a6d34c4969e445589a4197cca51921cb 100644 (file)
@@ -533,6 +533,7 @@ static void sock_daemon_run_signal_handler(struct tevent_context *ev,
                                           int signum, int count, void *siginfo,
                                           void *private_data);
 static void sock_daemon_run_reconfigure(struct tevent_req *req);
+static void sock_daemon_run_reconfigure_done(struct tevent_req *subreq);
 static void sock_daemon_run_shutdown(struct tevent_req *req);
 static bool sock_daemon_run_socket_listen(struct tevent_req *req);
 static void sock_daemon_run_socket_fail(struct tevent_req *subreq);
@@ -717,10 +718,23 @@ static void sock_daemon_run_signal_handler(struct tevent_context *ev,
 
 static void sock_daemon_run_reconfigure(struct tevent_req *req)
 {
+       struct tevent_req *subreq;
        struct sock_daemon_run_state *state = tevent_req_data(
                req, struct sock_daemon_run_state);
        struct sock_daemon_context *sockd = state->sockd;
 
+       if (sockd->funcs != NULL && sockd->funcs->reconfigure_send != NULL &&
+           sockd->funcs->reconfigure_recv != NULL) {
+               subreq = sockd->funcs->reconfigure_send(state, state->ev,
+                                                       sockd->private_data);
+               if (tevent_req_nomem(subreq, req)) {
+                       return;
+               }
+               tevent_req_set_callback(subreq,
+                                       sock_daemon_run_reconfigure_done, req);
+               return;
+       }
+
        if (sockd->funcs != NULL && sockd->funcs->reconfigure != NULL) {
                int ret;
 
@@ -734,6 +748,26 @@ static void sock_daemon_run_reconfigure(struct tevent_req *req)
        }
 }
 
+static void sock_daemon_run_reconfigure_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct sock_daemon_run_state *state = tevent_req_data(
+               req, struct sock_daemon_run_state);
+       struct sock_daemon_context *sockd = state->sockd;
+       int ret;
+       bool status;
+
+       status = sockd->funcs->reconfigure_recv(subreq, &ret);
+       TALLOC_FREE(subreq);
+       if (! status) {
+               D_ERR("reconfigure failed, ret=%d\n", ret);
+               return;
+       }
+
+       D_NOTICE("reconfigure completed successfully\n");
+}
+
 static void sock_daemon_run_shutdown(struct tevent_req *req)
 {
        struct sock_daemon_run_state *state = tevent_req_data(
index 7f19b32dcd4d2885f08accfa54870dabcdc6efbd..2cc94c6bf5dd38d5de9dcf0d8871d9de74e0b2e6 100644 (file)
@@ -58,6 +58,8 @@ struct sock_client_context;
  *     reconfigure() should return 0 for success, non-zero value on failure
  *     On failure, sock_daemon_run() will continue to run.
  *
+ * reconfigure_send()/reconfigure_recv() is the async version of reconfigure()
+ *
  * shutdown() is called when process receives SIGINT or SIGTERM or
  *             when wait computation has finished
  *
@@ -76,6 +78,12 @@ struct sock_daemon_funcs {
        bool (*startup_recv)(struct tevent_req *req, int *perr);
 
        int (*reconfigure)(void *private_data);
+
+       struct tevent_req * (*reconfigure_send)(TALLOC_CTX *mem_ctx,
+                                               struct tevent_context *ev,
+                                               void *private_data);
+       bool (*reconfigure_recv)(struct tevent_req *req, int *perr);
+
        void (*shutdown)(void *private_data);
 
        struct tevent_req * (*wait_send)(TALLOC_CTX *mem_ctx,
index aa1d6b471db49e6dc81fdae297568fc2b690105f..e5bae38d3a0b36c97c4a65cb355cb0cc392dd9f2 100755 (executable)
@@ -44,6 +44,15 @@ test2[PID]: Received signal 10
 test2[PID]: reconfigure completed successfully
 test2[PID]: Received signal 15
 test2[PID]: Shutting down
+test2[PID]: daemon started, pid=PID
+test2[PID]: startup completed successfully
+test2[PID]: listening on $sockpath
+test2[PID]: Received signal 10
+test2[PID]: reconfigure failed, ret=2
+test2[PID]: Received signal 1
+test2[PID]: reconfigure completed successfully
+test2[PID]: Received signal 15
+test2[PID]: Shutting down
 EOF
 unit_test sock_daemon_test "$pidfile" "$sockpath" 2
 
index 72f265f0b784fd9eea31fcd7507ce05813f6c2df..05a5748fa6df191fbc5c6c95126b87c1e55453db 100644 (file)
@@ -240,6 +240,53 @@ static int test2_reconfigure(void *private_data)
        return 0;
 }
 
+struct test2_reconfigure_state {
+       int fd;
+};
+
+static struct tevent_req *test2_reconfigure_send(TALLOC_CTX *mem_ctx,
+                                                struct tevent_context *ev,
+                                                void *private_data)
+{
+       struct tevent_req *req;
+       struct test2_reconfigure_state *state;
+       static bool first_time = true;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct test2_reconfigure_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       state->fd = *(int *)private_data;
+
+       if (first_time) {
+               first_time = false;
+               tevent_req_error(req, 2);
+       } else {
+               tevent_req_done(req);
+       }
+
+       return tevent_req_post(req, ev);
+}
+
+static bool test2_reconfigure_recv(struct tevent_req *req, int *perr)
+{
+       struct test2_reconfigure_state *state = tevent_req_data(
+               req, struct test2_reconfigure_state);
+       int ret = 2;
+       ssize_t nwritten;
+
+       nwritten = write(state->fd, &ret, sizeof(ret));
+       assert(nwritten == sizeof(ret));
+
+       if (tevent_req_is_unix_error(req, perr)) {
+               return false;
+       }
+
+       return true;
+}
+
 static void test2_shutdown(void *private_data)
 {
        int fd = *(int *)private_data;
@@ -344,6 +391,69 @@ static void test2(TALLOC_CTX *mem_ctx, const char *pidfile,
 
        ret = stat(sockpath, &st);
        assert(ret == -1);
+
+       ret = pipe(fd);
+       assert(ret == 0);
+
+       pid = fork();
+       assert(pid != -1);
+
+       if (pid == 0) {
+               struct tevent_context *ev;
+               struct sock_daemon_context *sockd;
+               struct sock_daemon_funcs test2_funcs = {
+                       .startup = test2_startup,
+                       .reconfigure_send = test2_reconfigure_send,
+                       .reconfigure_recv = test2_reconfigure_recv,
+               };
+
+               close(fd[0]);
+
+               ev = tevent_context_init(mem_ctx);
+               assert(ev != NULL);
+
+               ret = sock_daemon_setup(mem_ctx, "test2", "file:", "NOTICE",
+                                       &test2_funcs, &fd[1], &sockd);
+               assert(ret == 0);
+
+               ret = sock_daemon_add_unix(sockd, sockpath,
+                                          &dummy_socket_funcs, NULL);
+               assert(ret == 0);
+
+               ret = sock_daemon_run(ev, sockd, pidfile, false, false, -1);
+               assert(ret == EINTR);
+
+               exit(0);
+       }
+
+       close(fd[1]);
+
+       n = read(fd[0], &ret, sizeof(ret));
+       assert(n == sizeof(ret));
+       assert(ret == 1);
+
+       ret = kill(pid, SIGUSR1);
+       assert(ret == 0);
+
+       n = read(fd[0], &ret, sizeof(ret));
+       assert(n == sizeof(ret));
+       assert(ret == 2);
+
+       ret = kill(pid, SIGHUP);
+       assert(ret == 0);
+
+       n = read(fd[0], &ret, sizeof(ret));
+       assert(n == sizeof(ret));
+       assert(ret == 2);
+
+       ret = kill(pid, SIGTERM);
+       assert(ret == 0);
+
+       pid2 = waitpid(pid, &ret, 0);
+       assert(pid2 == pid);
+       assert(WEXITSTATUS(ret) == 0);
+
+       close(fd[0]);
 }
 
 /*