From: Andrew Tridgell Date: Thu, 26 Apr 2007 12:27:49 +0000 (+0200) Subject: added a ctdb control message, and tool X-Git-Tag: tevent-0.9.20~348^2~2844 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d955485e7be3d68554969272bfe110ebe996c360;p=thirdparty%2Fsamba.git added a ctdb control message, and tool (This used to be ctdb commit 0d7a71f35bb8ce95231f8ca1e8e3e4024fe657e5) --- diff --git a/ctdb/Makefile.in b/ctdb/Makefile.in index 0653c727afb..a74a52abaf7 100644 --- a/ctdb/Makefile.in +++ b/ctdb/Makefile.in @@ -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) diff --git a/ctdb/common/cmdline.c b/ctdb/common/cmdline.c index 699cb8fb220..085a1334604 100644 --- a/ctdb/common/cmdline.c +++ b/ctdb/common/cmdline.c @@ -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) { diff --git a/ctdb/common/ctdb.c b/ctdb/common/ctdb.c index 62788d05302..d7e4241250d 100644 --- a/ctdb/common/ctdb.c +++ b/ctdb/common/ctdb.c @@ -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)); diff --git a/ctdb/common/ctdb_client.c b/ctdb/common/ctdb_client.c index 5acce1ee301..e0f438c162a 100644 --- a/ctdb/common/ctdb_client.c +++ b/ctdb/common/ctdb_client.c @@ -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 index 00000000000..c7af9c76412 --- /dev/null +++ b/ctdb/common/ctdb_control.c @@ -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; +} diff --git a/ctdb/common/ctdb_daemon.c b/ctdb/common/ctdb_daemon.c index 4fcaadb6bb3..69d1195d67a 100644 --- a/ctdb/common/ctdb_daemon.c +++ b/ctdb/common/ctdb_daemon.c @@ -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)); + } +} diff --git a/ctdb/include/ctdb.h b/ctdb/include/ctdb.h index 79de16f33b7..9691797348f 100644 --- a/ctdb/include/ctdb.h +++ b/ctdb/include/ctdb.h @@ -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 diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h index 6dec319779d..58c71d9d1b4 100644 --- a/ctdb/include/ctdb_private.h +++ b/ctdb/include/ctdb_private.h @@ -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 diff --git a/ctdb/tests/bench-ssh.sh b/ctdb/tests/bench-ssh.sh index 0d11ee9cdd8..e9b1ec28d0e 100755 --- a/ctdb/tests/bench-ssh.sh +++ b/ctdb/tests/bench-ssh.sh @@ -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 diff --git a/ctdb/tests/bench.sh b/ctdb/tests/bench.sh index 3d0696f1710..eca604c2df0 100755 --- a/ctdb/tests/bench.sh +++ b/ctdb/tests/bench.sh @@ -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 index 9adcf3198b5..00000000000 --- a/ctdb/tests/bench1.sh +++ /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 diff --git a/ctdb/tests/fetch.sh b/ctdb/tests/fetch.sh index 73192e70ae3..9b611013e96 100755 --- a/ctdb/tests/fetch.sh +++ b/ctdb/tests/fetch.sh @@ -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 diff --git a/ctdb/tests/messaging.sh b/ctdb/tests/messaging.sh index 46f3e4dc774..25f68f3bb6a 100755 --- a/ctdb/tests/messaging.sh +++ b/ctdb/tests/messaging.sh @@ -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 diff --git a/ctdb/tests/test.sh b/ctdb/tests/test.sh index 23fdb8d6ced..f95354a2d79 100755 --- a/ctdb/tests/test.sh +++ b/ctdb/tests/test.sh @@ -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 index 00000000000..6be2484eb92 --- /dev/null +++ b/ctdb/tools/ctdb_control.c @@ -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] \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; +} diff --git a/ctdb/tools/ctdb_status.c b/ctdb/tools/ctdb_status.c index 09159f972fc..4e931d91793 100644 --- a/ctdb/tools/ctdb_status.c +++ b/ctdb/tools/ctdb_status.c @@ -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);