added a ctdb control message, and tool
authorAndrew Tridgell <tridge@samba.org>
Thu, 26 Apr 2007 12:27:49 +0000 (14:27 +0200)
committerAndrew Tridgell <tridge@samba.org>
Thu, 26 Apr 2007 12:27:49 +0000 (14:27 +0200)
(This used to be ctdb commit 0d7a71f35bb8ce95231f8ca1e8e3e4024fe657e5)

16 files changed:
ctdb/Makefile.in
ctdb/common/cmdline.c
ctdb/common/ctdb.c
ctdb/common/ctdb_client.c
ctdb/common/ctdb_control.c [new file with mode: 0644]
ctdb/common/ctdb_daemon.c
ctdb/include/ctdb.h
ctdb/include/ctdb_private.h
ctdb/tests/bench-ssh.sh
ctdb/tests/bench.sh
ctdb/tests/bench1.sh [deleted file]
ctdb/tests/fetch.sh
ctdb/tests/messaging.sh
ctdb/tests/test.sh
ctdb/tools/ctdb_control.c [new file with mode: 0644]
ctdb/tools/ctdb_status.c

index 0653c727afba16634e1ead348f0e4bb6f0e38b01..a74a52abaf7c163b243594ca97ed18e7fa34d23a 100644 (file)
@@ -20,9 +20,11 @@ LIB_FLAGS=@LDFLAGS@ -Llib @LIBS@ -lpopt @INFINIBAND_LIBS@
 
 EVENTS_OBJ = lib/events/events.o lib/events/events_standard.o
 
-CTDB_COMMON_OBJ = common/ctdb.o common/ctdb_daemon.o common/ctdb_client.o common/ctdb_io.o common/util.o common/ctdb_util.o \
-       common/ctdb_call.o common/ctdb_ltdb.o common/ctdb_lockwait.o common/ctdb_message.o \
-       common/cmdline.o lib/util/idtree.o lib/util/db_wrap.o lib/util/debug.o
+CTDB_COMMON_OBJ = common/ctdb.o common/ctdb_daemon.o common/ctdb_client.o \
+       common/ctdb_io.o common/util.o common/ctdb_util.o \
+       common/ctdb_call.o common/ctdb_ltdb.o common/ctdb_lockwait.o \
+       common/ctdb_message.o common/cmdline.o common/ctdb_control.o \
+       lib/util/idtree.o lib/util/db_wrap.o lib/util/debug.o
 
 CTDB_TCP_OBJ = tcp/tcp_connect.o tcp/tcp_io.o tcp/tcp_init.o
 
@@ -30,7 +32,7 @@ CTDB_OBJ = $(CTDB_COMMON_OBJ) $(CTDB_TCP_OBJ)
 
 OBJS = @TDBOBJ@ @TALLOCOBJ@ @LIBREPLACEOBJ@ @INFINIBAND_WRAPPER_OBJ@ $(EXTRA_OBJ) $(EVENTS_OBJ) $(CTDB_OBJ)
 
-BINS = bin/ctdbd bin/ctdbd_test bin/ctdb_test bin/ctdb_bench bin/ctdb_messaging bin/ctdb_fetch bin/ctdb_fetch1 bin/lockwait bin/ctdb_status bin/ctdb_dump @INFINIBAND_BINS@
+BINS = bin/ctdbd bin/ctdbd_test bin/ctdb_test bin/ctdb_bench bin/ctdb_messaging bin/ctdb_fetch bin/ctdb_fetch1 bin/lockwait bin/ctdb_status bin/ctdb_control bin/ctdb_dump @INFINIBAND_BINS@
 
 DIRS = lib bin
 
@@ -61,6 +63,10 @@ bin/ctdb_status: $(OBJS) tools/ctdb_status.o
        @echo Linking $@
        @$(CC) $(CFLAGS) -o $@ tools/ctdb_status.o $(OBJS) $(LIB_FLAGS)
 
+bin/ctdb_control: $(OBJS) tools/ctdb_control.o 
+       @echo Linking $@
+       @$(CC) $(CFLAGS) -o $@ tools/ctdb_control.o $(OBJS) $(LIB_FLAGS)
+
 bin/ctdb_dump: $(OBJS) tools/ctdb_dump.o 
        @echo Linking $@
        @$(CC) $(CFLAGS) -o $@ tools/ctdb_dump.o $(OBJS) $(LIB_FLAGS)
index 699cb8fb2201159251f49e1f6f64a6af44c34d0a..085a1334604e75b3549e4758b9e56771e69a118e 100644 (file)
@@ -32,6 +32,7 @@ static struct {
        const char *nlist;
        const char *transport;
        const char *myaddress;
+       const char *socketname;
        int self_connect;
        const char *db_dir;
        int torture;
@@ -39,6 +40,7 @@ static struct {
        .nlist = NULL,
        .transport = "tcp",
        .myaddress = NULL,
+       .socketname = CTDB_PATH,
        .self_connect = 0,
        .db_dir = NULL,
        .torture = 0
@@ -48,6 +50,7 @@ static struct {
 struct poptOption popt_ctdb_cmdline[] = {
        { "nlist", 0, POPT_ARG_STRING, &ctdb_cmdline.nlist, 0, "node list file", "filename" },
        { "listen", 0, POPT_ARG_STRING, &ctdb_cmdline.myaddress, 0, "address to listen on", "address" },
+       { "socket", 0, POPT_ARG_STRING, &ctdb_cmdline.socketname, 0, "local socket name", "filename" },
        { "transport", 0, POPT_ARG_STRING, &ctdb_cmdline.transport, 0, "protocol transport", NULL },
        { "self-connect", 0, POPT_ARG_NONE, &ctdb_cmdline.self_connect, 0, "enable self connect", "boolean" },
        { "debug", 'd', POPT_ARG_INT, &LogLevel, 0, "debug level"},
@@ -97,6 +100,13 @@ struct ctdb_context *ctdb_cmdline_init(struct event_context *ev)
                exit(1);
        }
 
+       /* tell ctdb the socket address */
+       ret = ctdb_set_socketname(ctdb, ctdb_cmdline.socketname);
+       if (ret == -1) {
+               printf("ctdb_set_socketname failed - %s\n", ctdb_errstr(ctdb));
+               exit(1);
+       }
+
        /* tell ctdb what nodes are available */
        ret = ctdb_set_nlist(ctdb, ctdb_cmdline.nlist);
        if (ret == -1) {
@@ -117,7 +127,7 @@ struct ctdb_context *ctdb_cmdline_init(struct event_context *ev)
 /*
   startup a client only ctdb context
  */
-struct ctdb_context *ctdb_cmdline_client(struct event_context *ev, const char *ctdb_socket)
+struct ctdb_context *ctdb_cmdline_client(struct event_context *ev)
 {
        struct ctdb_context *ctdb;
        int ret;
@@ -129,7 +139,12 @@ struct ctdb_context *ctdb_cmdline_client(struct event_context *ev, const char *c
                exit(1);
        }
 
-       ctdb->daemon.name = talloc_strdup(ctdb, ctdb_socket);
+       /* tell ctdb the socket address */
+       ret = ctdb_set_socketname(ctdb, ctdb_cmdline.socketname);
+       if (ret == -1) {
+               printf("ctdb_set_socketname failed - %s\n", ctdb_errstr(ctdb));
+               exit(1);
+       }
 
        ret = ctdb_socket_connect(ctdb);
        if (ret != 0) {
index 62788d053027b15af1cb5e30d8904d00d1086c99..d7e4241250de8e6d5f9b79ba92e52d2fa9e21e85 100644 (file)
@@ -171,6 +171,16 @@ int ctdb_set_address(struct ctdb_context *ctdb, const char *address)
        return 0;
 }
 
+
+/*
+  setup the local socket name
+*/
+int ctdb_set_socketname(struct ctdb_context *ctdb, const char *socketname)
+{
+       ctdb->daemon.name = talloc_strdup(ctdb, socketname);
+       return 0;
+}
+
 /*
   add a node to the list of active nodes
 */
@@ -285,6 +295,16 @@ void ctdb_recv_pkt(struct ctdb_context *ctdb, uint8_t *data, uint32_t length)
                ctdb_request_finished(ctdb, hdr);
                break;
 
+       case CTDB_REQ_CONTROL:
+               ctdb->status.count.req_control++;
+               ctdb_request_control(ctdb, hdr);
+               break;
+
+       case CTDB_REPLY_CONTROL:
+               ctdb->status.count.reply_control++;
+               ctdb_reply_control(ctdb, hdr);
+               break;
+
        default:
                DEBUG(0,("%s: Packet with unknown operation %d\n", 
                         __location__, hdr->operation));
index 5acce1ee301c9ab6f800971e519de4f0017fad2b..e0f438c162a318f117ecf78b52d5608c558178c2 100644 (file)
@@ -93,6 +93,7 @@ static void ctdb_client_reply_call(struct ctdb_context *ctdb, struct ctdb_req_he
 
 static void ctdb_reply_status(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
 static void ctdb_reply_getdbpath(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
+static void ctdb_client_reply_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
 
 /*
   this is called in the client, when data comes in from the daemon
@@ -156,6 +157,10 @@ static void ctdb_client_read_cb(uint8_t *data, size_t cnt, void *args)
                ctdb_reply_getdbpath(ctdb, hdr);
                break;
 
+       case CTDB_REPLY_CONTROL:
+               ctdb_client_reply_control(ctdb, hdr);
+               break;
+
        default:
                DEBUG(0,("bogus operation code:%d\n",hdr->operation));
        }
@@ -422,7 +427,7 @@ int ctdb_send_message(struct ctdb_context *ctdb, uint32_t vnn,
        int len, res;
 
        len = offsetof(struct ctdb_req_message, data) + data.dsize;
-       r = ctdb->methods->allocate_pkt(ctdb, len);
+       r = ctdbd_allocate_pkt(ctdb, len);
        CTDB_NO_MEMORY(ctdb, r);
        talloc_set_name_const(r, "req_message packet");
 
@@ -771,3 +776,134 @@ int ctdb_getdbpath(struct ctdb_db_context *ctdb_db, TDB_DATA *path)
        return 0;
 }
 
+
+struct ctdb_client_control_state {
+       uint32_t reqid;
+       int32_t status;
+       TDB_DATA outdata;
+       enum call_state state;
+};
+
+/*
+  called when a CTDB_REPLY_CONTROL packet comes in in the client
+
+  This packet comes in response to a CTDB_REQ_CONTROL request packet. It
+  contains any reply data from the control
+*/
+static void ctdb_client_reply_control(struct ctdb_context *ctdb, 
+                                     struct ctdb_req_header *hdr)
+{
+       struct ctdb_reply_control *c = (struct ctdb_reply_control *)hdr;
+       struct ctdb_client_control_state *state;
+
+       state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_client_control_state);
+       if (state == NULL) {
+               DEBUG(0,(__location__ " reqid %d not found\n", hdr->reqid));
+               return;
+       }
+
+       if (hdr->reqid != state->reqid) {
+               /* we found a record  but it was the wrong one */
+               DEBUG(0, ("Dropped orphaned reply control with reqid:%d\n",hdr->reqid));
+               return;
+       }
+
+       state->outdata.dptr = c->data;
+       state->outdata.dsize = c->datalen;
+       state->status = c->status;
+
+       talloc_steal(state, c);
+
+       state->state = CTDB_CALL_DONE;
+}
+
+
+/*
+  send a ctdb control message
+ */
+int ctdb_control(struct ctdb_context *ctdb, uint32_t destnode, uint32_t srvid, 
+                uint32_t opcode, TDB_DATA data, 
+                TALLOC_CTX *mem_ctx, TDB_DATA *outdata, int32_t *status)
+{
+       struct ctdb_client_control_state *state;
+       struct ctdb_req_control *c;
+       size_t len;
+       int ret;
+
+       /* if the domain socket is not yet open, open it */
+       if (ctdb->daemon.sd==-1) {
+               ctdb_socket_connect(ctdb);
+       }
+
+       state = talloc_zero(ctdb, struct ctdb_client_control_state);
+       CTDB_NO_MEMORY(ctdb, state);
+
+       state->reqid = ctdb_reqid_new(ctdb, state);
+       state->state = CTDB_CALL_WAIT;
+
+       len = offsetof(struct ctdb_req_control, data) + data.dsize;
+       c = ctdbd_allocate_pkt(state, len);
+       
+       memset(c, 0, len);
+       c->hdr.length       = len;
+       c->hdr.ctdb_magic   = CTDB_MAGIC;
+       c->hdr.ctdb_version = CTDB_VERSION;
+       c->hdr.operation    = CTDB_REQ_CONTROL;
+       c->hdr.reqid        = state->reqid;
+       c->hdr.destnode     = destnode;
+       c->hdr.srcnode      = ctdb->vnn;
+       c->hdr.reqid        = state->reqid;
+       c->opcode           = opcode;
+       c->srvid            = srvid;
+       c->datalen          = data.dsize;
+       if (data.dsize) {
+               memcpy(&c->data[0], data.dptr, data.dsize);
+       }
+
+       ret = ctdb_client_queue_pkt(ctdb, &(c->hdr));
+       if (ret != 0) {
+               talloc_free(state);
+               return -1;
+       }
+
+       /* semi-async operation */
+       while (state->state == CTDB_CALL_WAIT) {
+               event_loop_once(ctdb->ev);
+       }
+
+       if (outdata) {
+               *outdata = state->outdata;
+               outdata->dptr = talloc_steal(mem_ctx, outdata->dptr);
+       }
+
+       *status = state->status;
+
+       talloc_free(state);
+
+       return 0;       
+}
+
+
+
+/*
+  a process exists call. Returns 0 if process exists, -1 otherwise
+ */
+int ctdb_process_exists(struct ctdb_context *ctdb, uint32_t destnode, pid_t pid)
+{
+       int ret;
+       TDB_DATA data;
+       int32_t status;
+
+       data.dptr = (uint8_t*)&pid;
+       data.dsize = sizeof(pid);
+
+       ret = ctdb_control(ctdb, destnode, 0, 
+                          CTDB_CONTROL_PROCESS_EXISTS, data, 
+                          NULL, NULL, &status);
+       if (ret != 0) {
+               DEBUG(0,(__location__ " ctdb_control failed\n"));
+               return -1;
+       }
+
+       return status;
+}
diff --git a/ctdb/common/ctdb_control.c b/ctdb/common/ctdb_control.c
new file mode 100644 (file)
index 0000000..c7af9c7
--- /dev/null
@@ -0,0 +1,182 @@
+/* 
+   ctdb_control protocol code
+
+   Copyright (C) Andrew Tridgell  2007
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+#include "includes.h"
+#include "lib/events/events.h"
+#include "lib/tdb/include/tdb.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include "../include/ctdb_private.h"
+#include "lib/util/dlinklist.h"
+
+struct ctdb_control_state {
+       struct ctdb_context *ctdb;
+       uint32_t reqid;
+       ctdb_control_callback_fn_t callback;
+       void *private_data;
+};
+
+/*
+  process a control request
+ */
+static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb, 
+                                    uint32_t opcode, TDB_DATA indata,
+                                    TDB_DATA *outdata)
+{
+       switch (opcode) {
+       case CTDB_CONTROL_PROCESS_EXISTS: {
+               pid_t pid;
+               if (indata.dsize != sizeof(pid_t)) {
+                       DEBUG(0,(__location__ " Invalid data in CTDB_CONTROL_PROCESS_EXISTS\n"));
+                       return -1;
+               }
+               pid = *(pid_t *)indata.dptr;
+               return kill(pid, 0);
+       }
+       default:
+               DEBUG(0,(__location__ " Unknown CTDB control opcode %u\n", opcode));
+               return -1;
+       }
+}
+
+/*
+  called when a CTDB_REQ_CONTROL packet comes in
+*/
+void ctdb_request_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
+{
+       struct ctdb_req_control *c = (struct ctdb_req_control *)hdr;
+       TDB_DATA data, outdata;
+       struct ctdb_reply_control *r;
+       int32_t status;
+       size_t len;
+
+       data.dptr = &c->data[0];
+       data.dsize = c->datalen;
+
+       ZERO_STRUCT(outdata);
+       status = ctdb_control_dispatch(ctdb, c->opcode, data, &outdata);
+
+       len = offsetof(struct ctdb_reply_control, data) + outdata.dsize;
+       r = ctdb->methods->allocate_pkt(ctdb, len);
+       CTDB_NO_MEMORY_VOID(ctdb, r);
+       talloc_set_name_const(r, "ctdb_reply_control packet");
+
+       r->hdr.length       = len;
+       r->hdr.ctdb_magic   = CTDB_MAGIC;
+       r->hdr.ctdb_version = CTDB_VERSION;
+       r->hdr.operation    = CTDB_REPLY_CONTROL;
+       r->hdr.destnode     = hdr->srcnode;
+       r->hdr.srcnode      = ctdb->vnn;
+       r->hdr.reqid        = hdr->reqid;
+       r->status           = status;
+       c->datalen          = outdata.dsize;
+       if (outdata.dsize) {
+               memcpy(&r->data[0], outdata.dptr, outdata.dsize);
+       }
+       
+       ctdb_queue_packet(ctdb, &r->hdr);       
+
+       talloc_free(r);
+}
+
+/*
+  called when a CTDB_REPLY_CONTROL packet comes in
+*/
+void ctdb_reply_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
+{
+       struct ctdb_reply_control *c = (struct ctdb_reply_control *)hdr;
+       TDB_DATA data;
+       struct ctdb_control_state *state;
+
+       state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_control_state);
+       if (state == NULL) {
+               return;
+       }
+
+       if (hdr->reqid != state->reqid) {
+               /* we found a record  but it was the wrong one */
+               DEBUG(0, ("Dropped orphaned control reply with reqid:%d\n", hdr->reqid));
+               return;
+       }
+
+       data.dptr = &c->data[0];
+       data.dsize = c->datalen;
+
+       state->callback(ctdb, c->status, data, state->private_data);
+       talloc_free(state);
+}
+
+static int ctdb_control_destructor(struct ctdb_control_state *state)
+{
+       ctdb_reqid_remove(state->ctdb, state->reqid);
+       return 0;
+}
+
+/*
+  send a control message to a node
+ */
+int ctdb_daemon_send_control(struct ctdb_context *ctdb, uint32_t destnode,
+                            uint32_t srvid, uint32_t opcode, TDB_DATA data,
+                            ctdb_control_callback_fn_t callback,
+                            void *private_data)
+{
+       struct ctdb_req_control *c;
+       struct ctdb_control_state *state;
+       size_t len;
+
+       state = talloc(ctdb, struct ctdb_control_state);
+       CTDB_NO_MEMORY(ctdb, state);
+
+       state->reqid = ctdb_reqid_new(ctdb, state);
+       state->callback = callback;
+       state->private_data = private_data;
+       state->ctdb = ctdb;
+
+       talloc_set_destructor(state, ctdb_control_destructor);
+
+       len = offsetof(struct ctdb_req_control, data) + data.dsize;
+       c = ctdb->methods->allocate_pkt(state, len);
+       CTDB_NO_MEMORY(ctdb, c);
+       talloc_set_name_const(c, "ctdb_req_control packet");
+
+       c->hdr.length       = len;
+       c->hdr.ctdb_magic   = CTDB_MAGIC;
+       c->hdr.ctdb_version = CTDB_VERSION;
+       c->hdr.operation    = CTDB_REQ_CONTROL;
+       c->hdr.destnode     = destnode;
+       c->hdr.srcnode      = ctdb->vnn;
+       c->hdr.reqid        = state->reqid;
+       c->opcode           = opcode;
+       c->srvid            = srvid;
+       c->datalen          = data.dsize;
+       if (data.dsize) {
+               memcpy(&c->data[0], data.dptr, data.dsize);
+       }
+       
+       ctdb_queue_packet(ctdb, &c->hdr);       
+
+#if CTDB_REQ_TIMEOUT
+       event_add_timed(ctdb->ev, state, timeval_current_ofs(CTDB_REQ_TIMEOUT, 0), 
+                       ctdb_control_timeout, state);
+#endif
+
+       talloc_free(c);
+       return 0;
+}
index 4fcaadb6bb39d46f50a034a8ed50d923f6c93354..69d1195d67af894e6e20f68fc03b4347ecaa7887 100644 (file)
@@ -482,6 +482,10 @@ static void daemon_request_call_from_client(struct ctdb_client *client,
        state->async.private_data = dstate;
 }
 
+
+static void daemon_request_control_from_client(struct ctdb_client *client, 
+                                              struct ctdb_req_control *c);
+
 /* data contains a packet from the client */
 static void daemon_incoming_packet(void *p, uint8_t *data, uint32_t nread)
 {
@@ -518,6 +522,7 @@ static void daemon_incoming_packet(void *p, uint8_t *data, uint32_t nread)
                daemon_request_register_message_handler(client, 
                                                        (struct ctdb_req_register *)hdr);
                break;
+
        case CTDB_REQ_MESSAGE:
                ctdb->status.client.req_message++;
                daemon_request_message_from_client(client, (struct ctdb_req_message *)hdr);
@@ -542,6 +547,11 @@ static void daemon_incoming_packet(void *p, uint8_t *data, uint32_t nread)
                daemon_request_getdbpath(client, (struct ctdb_req_getdbpath *)hdr);
                break;
 
+       case CTDB_REQ_CONTROL:
+               ctdb->status.client.req_control++;
+               daemon_request_control_from_client(client, (struct ctdb_req_control *)hdr);
+               break;
+
        default:
                DEBUG(0,(__location__ " daemon: unrecognized operation %d\n",
                         hdr->operation));
@@ -694,8 +704,6 @@ int ctdb_start(struct ctdb_context *ctdb)
        struct fd_event *fde;
        const char *domain_socket_name;
 
-       /* generate a name to use for our local socket */
-       ctdb->daemon.name = talloc_asprintf(ctdb, "%s.%s", CTDB_PATH, ctdb->address.address);
        /* get rid of any old sockets */
        unlink(ctdb->daemon.name);
 
@@ -758,3 +766,70 @@ void ctdb_request_finished(struct ctdb_context *ctdb, struct ctdb_req_header *hd
 {
        ctdb->num_finished++;
 }
+
+
+struct daemon_control_state {
+       struct ctdb_client *client;
+       struct ctdb_req_control *c;
+};
+
+/*
+  callback when a control reply comes in
+ */
+static void daemon_control_callback(struct ctdb_context *ctdb,
+                                   uint32_t status, TDB_DATA data, 
+                                   void *private_data)
+{
+       struct daemon_control_state *state = talloc_get_type(private_data, 
+                                                            struct daemon_control_state);
+       struct ctdb_client *client = state->client;
+       struct ctdb_reply_control *r;
+       size_t len;
+
+       /* construct a message to send to the client containing the data */
+       len = offsetof(struct ctdb_req_control, data) + data.dsize;
+       r = ctdbd_allocate_pkt(client, len);
+       talloc_set_name_const(r, "reply_control packet");
+
+       memset(r, 0, offsetof(struct ctdb_req_message, data));
+
+       r->hdr.length    = len;
+       r->hdr.ctdb_magic = CTDB_MAGIC;
+       r->hdr.ctdb_version = CTDB_VERSION;
+       r->hdr.operation = CTDB_REPLY_CONTROL;
+       r->status        = status;
+       r->datalen       = data.dsize;
+       memcpy(&r->data[0], data.dptr, data.dsize);
+
+       daemon_queue_send(client, &r->hdr);
+
+       talloc_free(state);
+}
+
+/*
+  this is called when the ctdb daemon received a ctdb request control
+  from a local client over the unix domain socket
+ */
+static void daemon_request_control_from_client(struct ctdb_client *client, 
+                                              struct ctdb_req_control *c)
+{
+       TDB_DATA data;
+       int res;
+       struct daemon_control_state *state;
+
+       state = talloc(client, struct daemon_control_state);
+       CTDB_NO_MEMORY_VOID(client->ctdb, state);
+
+       state->client = client;
+       state->c = talloc_steal(state, c);
+       
+       data.dptr = &c->data[0];
+       data.dsize = c->datalen;
+       res = ctdb_daemon_send_control(client->ctdb, c->hdr.destnode,
+                                      c->srvid, c->opcode, data, daemon_control_callback,
+                                      state);
+       if (res != 0) {
+               DEBUG(0,(__location__ " Failed to send control to remote node %u\n",
+                        c->hdr.destnode));
+       }
+}
index 79de16f33b7f8e76c0ff398fd5bad52b7a3bb19c..9691797348f27c20f5af8a108719d0e1ba1b7810 100644 (file)
@@ -95,6 +95,8 @@ void ctdb_set_max_lacount(struct ctdb_context *ctdb, unsigned count);
 */
 int ctdb_set_address(struct ctdb_context *ctdb, const char *address);
 
+int ctdb_set_socketname(struct ctdb_context *ctdb, const char *socketname);
+
 /*
   tell ctdb what nodes are available. This takes a filename, which will contain
   1 node address per line, in a transport specific format
@@ -208,11 +210,13 @@ int ctdb_register_message_handler(struct ctdb_context *ctdb,
 struct ctdb_db_context *find_ctdb_db(struct ctdb_context *ctdb, uint32_t id);
 
 
-struct ctdb_context *ctdb_cmdline_client(struct event_context *ev, const char *ctdb_socket);
+struct ctdb_context *ctdb_cmdline_client(struct event_context *ev);
 
 struct ctdb_status;
 int ctdb_status(struct ctdb_context *ctdb, struct ctdb_status *status);
 
 int ctdb_getdbpath(struct ctdb_db_context *ctdb_db, TDB_DATA *path);
 
+int ctdb_process_exists(struct ctdb_context *ctdb, uint32_t destnode, pid_t pid);
+
 #endif
index 6dec319779d992148278b1c735eebff919b4ef13..58c71d9d1b41800cef63758e3cc130052d2ef339 100644 (file)
@@ -61,6 +61,10 @@ struct ctdb_address {
 typedef void (*ctdb_queue_cb_fn_t)(uint8_t *data, size_t length,
                                   void *private_data);
 
+/* used for callbacks in ctdb_control requests */
+typedef void (*ctdb_control_callback_fn_t)(struct ctdb_context *,
+                                          uint32_t status, TDB_DATA data, 
+                                          void *private_data);
 
 /*
   state associated with one node
@@ -131,6 +135,8 @@ struct ctdb_status {
                uint32_t reply_error;
                uint32_t req_message;
                uint32_t req_finished;
+               uint32_t req_control;
+               uint32_t reply_control;
        } count;
        struct {
                uint32_t req_call;
@@ -140,6 +146,7 @@ struct ctdb_status {
                uint32_t req_connect_wait;
                uint32_t req_shutdown;
                uint32_t req_status;
+               uint32_t req_control;
        } client;
        uint32_t total_calls;
        uint32_t pending_calls;
@@ -189,6 +196,10 @@ struct ctdb_db_context {
           ctdb_set_error(ctdb, "Out of memory at %s:%d", __FILE__, __LINE__); \
          return -1; }} while (0)
 
+#define CTDB_NO_MEMORY_VOID(ctdb, p) do { if (!(p)) { \
+          ctdb_set_error(ctdb, "Out of memory at %s:%d", __FILE__, __LINE__); \
+         }} while (0)
+
 #define CTDB_NO_MEMORY_NULL(ctdb, p) do { if (!(p)) { \
           ctdb_set_error(ctdb, "Out of memory at %s:%d", __FILE__, __LINE__); \
          return NULL; }} while (0)
@@ -217,6 +228,8 @@ struct ctdb_ltdb_header {
        uint32_t lacount;
 };
 
+enum {CTDB_CONTROL_PROCESS_EXISTS};
+
 enum call_state {CTDB_CALL_WAIT, CTDB_CALL_DONE, CTDB_CALL_ERROR};
 
 /*
@@ -259,6 +272,8 @@ enum ctdb_operation {
        CTDB_REPLY_ERROR        = 5,
        CTDB_REQ_MESSAGE        = 6,
        CTDB_REQ_FINISHED       = 7,
+       CTDB_REQ_CONTROL        = 8,
+       CTDB_REPLY_CONTROL      = 9,
        
        /* only used on the domain socket */
        CTDB_REQ_REGISTER       = 1000,     
@@ -381,6 +396,22 @@ struct ctdb_reply_status {
        struct ctdb_status status;
 };
 
+struct ctdb_req_control {
+       struct ctdb_req_header hdr;
+       uint32_t opcode;
+       uint32_t srvid;
+       uint32_t datalen;
+       uint8_t data[1];
+};
+
+struct ctdb_reply_control {
+       struct ctdb_req_header hdr;
+       int32_t  status;
+       uint32_t datalen;
+       uint8_t data[1];
+};
+
+
 /* internal prototypes */
 void ctdb_set_error(struct ctdb_context *ctdb, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
 void ctdb_fatal(struct ctdb_context *ctdb, const char *msg);
@@ -529,4 +560,12 @@ uint32_t ctdb_reqid_new(struct ctdb_context *ctdb, void *state);
 void *_ctdb_reqid_find(struct ctdb_context *ctdb, uint32_t reqid, const char *type, const char *location);
 void ctdb_reqid_remove(struct ctdb_context *ctdb, uint32_t reqid);
 
+void ctdb_request_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
+void ctdb_reply_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
+
+int ctdb_daemon_send_control(struct ctdb_context *ctdb, uint32_t destnode,
+                            uint32_t srvid, uint32_t opcode, TDB_DATA data,
+                            ctdb_control_callback_fn_t callback,
+                            void *private_data);
+
 #endif
index 0d11ee9cdd8025bc0fb87358ea72ea52b19f34c0..e9b1ec28d0edc52f8e08e6aff1d027e4aef29b44 100755 (executable)
@@ -33,9 +33,9 @@ echo "Starting nodes"
 i=0
 for h in $nodes; do
     if [ $i -eq `expr $count - 1` ]; then
-       ssh $h $dir/bin/ctdb_bench --nlist $dir/nodes-ssh.txt --listen $h:9001 $options
+       ssh $h $dir/bin/ctdb_bench --nlist $dir/nodes-ssh.txt --listen $h:9001 --socket $h$options
     else
-       ssh -f $h $dir/bin/ctdb_bench --nlist $dir/nodes-ssh.txt --listen $h:9001 $options
+       ssh -f $h $dir/bin/ctdb_bench --nlist $dir/nodes-ssh.txt --listen $h:9001 --socket $h $options
     fi
     i=`expr $i + 1`
 done
index 3d0696f1710b8c13775414a056681f80574f276d..eca604c2df002968ca4aeaa322648ad6c9222bf0 100755 (executable)
@@ -2,8 +2,20 @@
 
 killall -q ctdb_bench
 
-echo "Trying 2 nodes"
-$VALGRIND bin/ctdb_bench --nlist tests/nodes.txt --listen 127.0.0.2:9001 $* &
-$VALGRIND bin/ctdb_bench --nlist tests/nodes.txt --listen 127.0.0.1:9001 $*
-wait
+NUMNODES=2
+if [ $# -gt 0 ]; then
+    NUMNODES=$1
+fi
+
+rm -f nodes.txt
+for i in `seq 1 $NUMNODES`; do
+  echo 127.0.0.$i:9001 >> nodes.txt
+done
 
+killall -9 ctdb_bench
+echo "Trying $NUMNODES nodes"
+for i in `seq 1 $NUMNODES`; do
+  $VALGRIND bin/ctdb_bench --nlist nodes.txt --listen 127.0.0.$i:9001 --socket /tmp/ctdb.127.0.0.$i $* &
+done
+
+wait
diff --git a/ctdb/tests/bench1.sh b/ctdb/tests/bench1.sh
deleted file mode 100755 (executable)
index 9adcf31..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/sh
-
-killall -q ctdb_bench
-
-echo "Trying 1 nodes"
-bin/ctdb_bench --nlist tests/1node.txt --listen 127.0.0.2:9001 $*
-wait
index 73192e70ae330ad027d0d782f069c5aede9d3897..9b611013e96654ecbbe6e1648e6a9216a2b529e9 100755 (executable)
@@ -1,15 +1,18 @@
 #!/bin/sh
 
-killall -q ctdb_fetch
+NUMNODES=2
+if [ $# -gt 0 ]; then
+    NUMNODES=$1
+fi
 
-echo "Trying 2 nodes"
-$VALGRIND bin/ctdb_fetch --nlist tests/nodes.txt --listen 127.0.0.2:9001 $* &
-$VALGRIND bin/ctdb_fetch --nlist tests/nodes.txt --listen 127.0.0.1:9001 $* 
-wait
+rm -f nodes.txt
+for i in `seq 1 $NUMNODES`; do
+  echo 127.0.0.$i:9001 >> nodes.txt
+done
 
-echo "Trying 4 nodes"
-$VALGRIND bin/ctdb_fetch --nlist tests/4nodes.txt --listen 127.0.0.4:9001 $* &
-$VALGRIND bin/ctdb_fetch --nlist tests/4nodes.txt --listen 127.0.0.3:9001 $* &
-$VALGRIND bin/ctdb_fetch --nlist tests/4nodes.txt --listen 127.0.0.2:9001 $* &
-$VALGRIND bin/ctdb_fetch --nlist tests/4nodes.txt --listen 127.0.0.1:9001 $* 
+killall -9 ctdb_fetch
+echo "Trying $NUMNODES nodes"
+for i in `seq 1 $NUMNODES`; do
+  $VALGRIND bin/ctdb_fetch --nlist nodes.txt --listen 127.0.0.$i:9001 --socket /tmp/ctdb.127.0.0.$i $* &
+done
 wait
index 46f3e4dc774b3d96d2230c8a1839251eeead2311..25f68f3bb6a08c47b06a66dd8d01f04aa0e3a82d 100755 (executable)
@@ -1,8 +1,23 @@
 #!/bin/sh
 
+#!/bin/sh
+
 killall -q ctdb_messaging
 
-echo "Trying 2 nodes"
-bin/ctdb_messaging --nlist tests/nodes.txt --listen 127.0.0.2:9001 $* &
-bin/ctdb_messaging --nlist tests/nodes.txt --listen 127.0.0.1:9001 $*
+NUMNODES=2
+if [ $# -gt 0 ]; then
+    NUMNODES=$1
+fi
+
+rm -f nodes.txt
+for i in `seq 1 $NUMNODES`; do
+  echo 127.0.0.$i:9001 >> nodes.txt
+done
+
+killall -9 ctdb_messaging
+echo "Trying $NUMNODES nodes"
+for i in `seq 1 $NUMNODES`; do
+  $VALGRIND bin/ctdb_messaging --nlist nodes.txt --listen 127.0.0.$i:9001 --socket /tmp/ctdb.127.0.0.$i $* &
+done
+
 wait
index 23fdb8d6ced8c7f1c5f1fbf68c43d917860aa9da..f95354a2d79aac0c66e134269671ca2e25f17dd2 100755 (executable)
@@ -1,17 +1,24 @@
 #!/bin/sh
 
+#!/bin/sh
+
 killall -q ctdb_test
 
+NUMNODES=2
+if [ $# -gt 0 ]; then
+    NUMNODES=$1
+    shift
+fi
 
-echo "Trying 2 nodes ..."
-$VALGRIND bin/ctdb_test --nlist tests/nodes.txt --listen 127.0.0.1:9001 &
-$VALGRIND bin/ctdb_test --nlist tests/nodes.txt --listen 127.0.0.2:9001
-wait
+rm -f nodes.txt
+for i in `seq 1 $NUMNODES`; do
+  echo 127.0.0.$i:9001 >> nodes.txt
+done
 
-echo "Trying 4 nodes ..."
-$VALGRIND bin/ctdb_test --nlist tests/4nodes.txt --listen 127.0.0.1:9001 &
-$VALGRIND bin/ctdb_test --nlist tests/4nodes.txt --listen 127.0.0.2:9001 &
-$VALGRIND bin/ctdb_test --nlist tests/4nodes.txt --listen 127.0.0.3:9001 &
-$VALGRIND bin/ctdb_test --nlist tests/4nodes.txt --listen 127.0.0.4:9001
-wait
+killall -9 ctdb_test
+echo "Trying $NUMNODES nodes"
+for i in `seq 1 $NUMNODES`; do
+  $VALGRIND bin/ctdb_test --nlist nodes.txt --listen 127.0.0.$i:9001 --socket /tmp/ctdb.127.0.0.$i $* &
+done
 
+wait
diff --git a/ctdb/tools/ctdb_control.c b/ctdb/tools/ctdb_control.c
new file mode 100644 (file)
index 0000000..6be2484
--- /dev/null
@@ -0,0 +1,119 @@
+/* 
+   ctdb control tool
+
+   Copyright (C) Andrew Tridgell  2007
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "includes.h"
+#include "lib/events/events.h"
+#include "system/filesys.h"
+#include "popt.h"
+#include "cmdline.h"
+#include "../include/ctdb_private.h"
+
+
+/*
+  show usage message
+ */
+static void usage(void)
+{
+       printf("Usage: ctdb_control [options] <control>\n");
+       exit(1);
+}
+
+static int control_process_exists(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+       uint32_t srvid;
+       pid_t pid;
+       int ret;
+       if (argc < 2) {
+               usage();
+       }
+
+       srvid = strtoul(argv[0], NULL, 0);
+       pid   = strtoul(argv[1], NULL, 0);
+
+       ret = ctdb_process_exists(ctdb, srvid, pid);
+       if (ret == 0) {
+               printf("%u:%u exists\n", srvid, pid);
+       } else {
+               printf("%u:%u does not exist\n", srvid, pid);
+       }
+       return ret;
+}
+
+/*
+  main program
+*/
+int main(int argc, const char *argv[])
+{
+       struct ctdb_context *ctdb;
+       struct poptOption popt_options[] = {
+               POPT_AUTOHELP
+               POPT_CTDB_CMDLINE
+               POPT_TABLEEND
+       };
+       int opt;
+       const char **extra_argv;
+       int extra_argc = 0;
+       int ret;
+       poptContext pc;
+       struct event_context *ev;
+       const char *control;
+
+       pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST);
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               default:
+                       fprintf(stderr, "Invalid option %s: %s\n", 
+                               poptBadOption(pc, 0), poptStrerror(opt));
+                       exit(1);
+               }
+       }
+
+       /* setup the remaining options for the main program to use */
+       extra_argv = poptGetArgs(pc);
+       if (extra_argv) {
+               extra_argv++;
+               while (extra_argv[extra_argc]) extra_argc++;
+       }
+
+       if (extra_argc < 1) {
+               usage();
+       }
+
+       control = extra_argv[0];
+
+       ev = event_context_init(NULL);
+
+       /* initialise ctdb */
+       ctdb = ctdb_cmdline_client(ev);
+       if (ctdb == NULL) {
+               printf("Failed to init ctdb\n");
+               exit(1);
+       }
+
+       if (strcmp(control, "process-exists") == 0) {
+               ret = control_process_exists(ctdb, extra_argc-1, extra_argv+1);
+       } else {
+               printf("Unknown control '%s'\n", control);
+               exit(1);
+       }
+
+       return ret;
+}
index 09159f972fc50a6a9523c01a77cf04ee731783d8..4e931d917933d0e5ae57c1bb3f574f1c0455c4b1 100644 (file)
@@ -117,7 +117,7 @@ int main(int argc, const char *argv[])
        ev = event_context_init(NULL);
 
        /* initialise ctdb */
-       ctdb = ctdb_cmdline_client(ev, ctdb_socket);
+       ctdb = ctdb_cmdline_client(ev);
        if (ctdb == NULL) {
                printf("Failed to init ctdb\n");
                exit(1);