From 2e5aae04de7ba8d8b4dd67e1743d396f3d09b68c Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 20 Apr 2007 20:07:47 +1000 Subject: [PATCH] added ctdb_status tool (This used to be ctdb commit 908d6c6a936e21f70f05827ce302e966cca0132a) --- ctdb/Makefile.in | 6 +- ctdb/common/cmdline.c | 30 +++++++++ ctdb/common/ctdb.c | 3 + ctdb/common/ctdb_client.c | 85 ++++++++++++++++++++++++-- ctdb/common/ctdb_daemon.c | 75 +++++++++++++++++++++-- ctdb/common/ctdb_lockwait.c | 11 ++++ ctdb/common/ctdb_util.c | 11 ++++ ctdb/include/ctdb.h | 5 ++ ctdb/include/ctdb_private.h | 34 ++++++++++- ctdb/tools/ctdb_status.c | 117 ++++++++++++++++++++++++++++++++++++ 10 files changed, 366 insertions(+), 11 deletions(-) create mode 100644 ctdb/tools/ctdb_status.c diff --git a/ctdb/Makefile.in b/ctdb/Makefile.in index 7729875f4e3..adc1f92d0a9 100644 --- a/ctdb/Makefile.in +++ b/ctdb/Makefile.in @@ -30,7 +30,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 @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 @INFINIBAND_BINS@ DIRS = lib bin @@ -57,6 +57,10 @@ bin/ctdbd: $(OBJS) direct/ctdbd.o @echo Linking $@ @$(CC) $(CFLAGS) -o $@ direct/ctdbd.o $(OBJS) $(LIB_FLAGS) +bin/ctdb_status: $(OBJS) tools/ctdb_status.o + @echo Linking $@ + @$(CC) $(CFLAGS) -o $@ tools/ctdb_status.o $(OBJS) $(LIB_FLAGS) + bin/ctdbd_test: $(OBJS) direct/ctdbd_test.o @echo Linking $@ @$(CC) $(CFLAGS) -o $@ direct/ctdbd_test.o diff --git a/ctdb/common/cmdline.c b/ctdb/common/cmdline.c index e319d4635e3..699cb8fb220 100644 --- a/ctdb/common/cmdline.c +++ b/ctdb/common/cmdline.c @@ -22,6 +22,8 @@ #include "lib/events/events.h" #include "system/filesys.h" #include "popt.h" +#include "../include/ctdb.h" +#include "../include/ctdb_private.h" /* Handle common command line options for ctdb test progs */ @@ -110,3 +112,31 @@ struct ctdb_context *ctdb_cmdline_init(struct event_context *ev) return ctdb; } + + +/* + startup a client only ctdb context + */ +struct ctdb_context *ctdb_cmdline_client(struct event_context *ev, const char *ctdb_socket) +{ + struct ctdb_context *ctdb; + int ret; + + /* initialise ctdb */ + ctdb = ctdb_init(ev); + if (ctdb == NULL) { + printf("Failed to init ctdb\n"); + exit(1); + } + + ctdb->daemon.name = talloc_strdup(ctdb, ctdb_socket); + + ret = ctdb_socket_connect(ctdb); + if (ret != 0) { + DEBUG(0,(__location__ " Failed to connect to daemon\n")); + talloc_free(ctdb); + return NULL; + } + + return ctdb; +} diff --git a/ctdb/common/ctdb.c b/ctdb/common/ctdb.c index ac3dc6d345f..ed96df91021 100644 --- a/ctdb/common/ctdb.c +++ b/ctdb/common/ctdb.c @@ -211,6 +211,8 @@ void ctdb_recv_pkt(struct ctdb_context *ctdb, uint8_t *data, uint32_t length) struct ctdb_req_header *hdr = (struct ctdb_req_header *)data; TALLOC_CTX *tmp_ctx; + ctdb->status.node_packets_recv++; + /* place the packet as a child of the tmp_ctx. We then use talloc_free() below to free it. If any of the calls want to keep it, then they will steal it somewhere else, and the @@ -375,6 +377,7 @@ static void ctdb_defer_packet(struct ctdb_context *ctdb, struct ctdb_req_header void ctdb_queue_packet(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) { struct ctdb_node *node; + ctdb->status.node_packets_sent++; node = ctdb->nodes[hdr->destnode]; if (hdr->destnode == ctdb->vnn && !(ctdb->flags & CTDB_FLAG_SELF_CONNECT)) { ctdb_defer_packet(ctdb, hdr); diff --git a/ctdb/common/ctdb_client.c b/ctdb/common/ctdb_client.c index f09894b5555..dbed8d35851 100644 --- a/ctdb/common/ctdb_client.c +++ b/ctdb/common/ctdb_client.c @@ -84,6 +84,8 @@ static void ctdb_client_reply_call(struct ctdb_context *ctdb, struct ctdb_req_he state->state = CTDB_CALL_DONE; } +static void ctdb_reply_status(struct ctdb_context *ctdb, struct ctdb_req_header *hdr); + /* this is called in the client, when data comes in from the daemon */ @@ -138,6 +140,10 @@ static void ctdb_client_read_cb(uint8_t *data, size_t cnt, void *args) ctdb_reply_connect_wait(ctdb, hdr); break; + case CTDB_REPLY_STATUS: + ctdb_reply_status(ctdb, hdr); + break; + default: DEBUG(0,("bogus operation code:%d\n",hdr->operation)); } @@ -149,7 +155,7 @@ done: /* connect to a unix domain socket */ -static int ux_socket_connect(struct ctdb_context *ctdb) +int ctdb_socket_connect(struct ctdb_context *ctdb) { struct sockaddr_un addr; @@ -276,7 +282,7 @@ struct ctdb_client_call_state *ctdb_call_send(struct ctdb_db_context *ctdb_db, /* if the domain socket is not yet open, open it */ if (ctdb->daemon.sd==-1) { - ux_socket_connect(ctdb); + ctdb_socket_connect(ctdb); } ret = ctdb_ltdb_lock(ctdb_db, call->key); @@ -373,7 +379,7 @@ int ctdb_set_message_handler(struct ctdb_context *ctdb, uint32_t srvid, /* if the domain socket is not yet open, open it */ if (ctdb->daemon.sd==-1) { - ux_socket_connect(ctdb); + ctdb_socket_connect(ctdb); } ZERO_STRUCT(c); @@ -447,7 +453,7 @@ void ctdb_connect_wait(struct ctdb_context *ctdb) /* if the domain socket is not yet open, open it */ if (ctdb->daemon.sd==-1) { - ux_socket_connect(ctdb); + ctdb_socket_connect(ctdb); } res = ctdb_queue_send(ctdb->daemon.queue, (uint8_t *)&r.hdr, r.hdr.length); @@ -585,7 +591,7 @@ void ctdb_shutdown(struct ctdb_context *ctdb) /* if the domain socket is not yet open, open it */ if (ctdb->daemon.sd==-1) { - ux_socket_connect(ctdb); + ctdb_socket_connect(ctdb); } len = sizeof(struct ctdb_req_shutdown); @@ -604,4 +610,73 @@ void ctdb_shutdown(struct ctdb_context *ctdb) } } +enum ctdb_status_states {CTDB_STATUS_WAIT, CTDB_STATUS_DONE}; + +struct ctdb_status_state { + uint32_t reqid; + struct ctdb_status *status; + enum ctdb_status_states state; +}; + +/* + handle a ctdb_reply_status reply + */ +static void ctdb_reply_status(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) +{ + struct ctdb_reply_status *r = (struct ctdb_reply_status *)hdr; + struct ctdb_status_state *state; + + state = idr_find_type(ctdb->idr, hdr->reqid, struct ctdb_status_state); + if (state == NULL) { + DEBUG(0, ("reqid %d not found\n", hdr->reqid)); + return; + } + + *state->status = r->status; + state->state = CTDB_STATUS_DONE; +} + +/* + wait until we're the only node left. + this function never returns +*/ +int ctdb_status(struct ctdb_context *ctdb, struct ctdb_status *status) +{ + struct ctdb_req_status r; + int ret; + struct ctdb_status_state *state; + + /* if the domain socket is not yet open, open it */ + if (ctdb->daemon.sd==-1) { + ctdb_socket_connect(ctdb); + } + + state = talloc(ctdb, struct ctdb_status_state); + CTDB_NO_MEMORY(ctdb, state); + + state->reqid = idr_get_new(ctdb->idr, state, 0xFFFF); + state->status = status; + state->state = CTDB_STATUS_WAIT; + + ZERO_STRUCT(r); + r.hdr.length = sizeof(r); + r.hdr.ctdb_magic = CTDB_MAGIC; + r.hdr.ctdb_version = CTDB_VERSION; + r.hdr.operation = CTDB_REQ_STATUS; + r.hdr.reqid = state->reqid; + + ret = ctdb_client_queue_pkt(ctdb, &(r.hdr)); + if (ret != 0) { + talloc_free(state); + return -1; + } + + while (state->state == CTDB_STATUS_WAIT) { + event_loop_once(ctdb->ev); + } + + talloc_free(state); + + return 0; +} diff --git a/ctdb/common/ctdb_daemon.c b/ctdb/common/ctdb_daemon.c index be535ef5ed0..3189a8a31c6 100644 --- a/ctdb/common/ctdb_daemon.c +++ b/ctdb/common/ctdb_daemon.c @@ -74,6 +74,15 @@ static void block_signal(int signum) } +/* + send a packet to a client + */ +static int daemon_queue_send(struct ctdb_client *client, struct ctdb_req_header *hdr) +{ + client->ctdb->status.client_packets_sent++; + return ctdb_queue_send(client->queue, (uint8_t *)hdr, hdr->length); +} + /* message handler for when we are in daemon mode. This redirects the message to the right client @@ -101,7 +110,7 @@ static void daemon_message_handler(struct ctdb_context *ctdb, uint32_t srvid, r->datalen = data.dsize; memcpy(&r->data[0], data.dptr, data.dsize); - ctdb_queue_send(client->queue, (uint8_t *)&r->hdr, len); + daemon_queue_send(client, &r->hdr); talloc_free(r); } @@ -205,7 +214,34 @@ static void daemon_request_connect_wait(struct ctdb_client *client, r.vnn = ctdb_get_vnn(client->ctdb); r.num_connected = client->ctdb->num_connected; - res = ctdb_queue_send(client->queue, (uint8_t *)&r.hdr, r.hdr.length); + res = daemon_queue_send(client, &r.hdr); + if (res != 0) { + DEBUG(0,(__location__ " Failed to queue a connect wait response\n")); + return; + } +} + + +/* + called when the daemon gets a status request from a client + */ +static void daemon_request_status(struct ctdb_client *client, + struct ctdb_req_status *c) +{ + struct ctdb_reply_status r; + int res; + + /* now send the reply */ + ZERO_STRUCT(r); + + r.hdr.length = sizeof(r); + r.hdr.ctdb_magic = CTDB_MAGIC; + r.hdr.ctdb_version = CTDB_VERSION; + r.hdr.operation = CTDB_REPLY_STATUS; + r.hdr.reqid = c->hdr.reqid; + r.status = client->ctdb->status; + + res = daemon_queue_send(client, &r.hdr); if (res != 0) { DEBUG(0,(__location__ " Failed to queue a connect wait response\n")); return; @@ -255,6 +291,7 @@ struct daemon_call_state { struct ctdb_client *client; uint32_t reqid; struct ctdb_call *call; + struct timeval start_time; }; /* @@ -275,6 +312,8 @@ static void daemon_call_from_client_callback(struct ctdb_call_state *state) res = ctdb_daemon_call_recv(state, dstate->call); if (res != 0) { DEBUG(0, (__location__ " ctdbd_call_recv() returned error\n")); + client->ctdb->status.pending_calls--; + ctdb_latency(&client->ctdb->status.max_call_latency, dstate->start_time); return; } @@ -282,6 +321,8 @@ static void daemon_call_from_client_callback(struct ctdb_call_state *state) r = ctdbd_allocate_pkt(dstate, length); if (r == NULL) { DEBUG(0, (__location__ " Failed to allocate reply_call in ctdb daemon\n")); + client->ctdb->status.pending_calls--; + ctdb_latency(&client->ctdb->status.max_call_latency, dstate->start_time); return; } memset(r, 0, offsetof(struct ctdb_reply_call, data)); @@ -293,11 +334,13 @@ static void daemon_call_from_client_callback(struct ctdb_call_state *state) r->datalen = dstate->call->reply_data.dsize; memcpy(&r->data[0], dstate->call->reply_data.dptr, r->datalen); - res = ctdb_queue_send(client->queue, (uint8_t *)&r->hdr, r->hdr.length); + res = daemon_queue_send(client, &r->hdr); if (res != 0) { DEBUG(0, (__location__ "Failed to queue packet from daemon to client\n")); } talloc_free(dstate); + client->ctdb->status.pending_calls--; + ctdb_latency(&client->ctdb->status.max_call_latency, dstate->start_time); } @@ -317,10 +360,14 @@ static void daemon_request_call_from_client(struct ctdb_client *client, int ret; struct ctdb_context *ctdb = client->ctdb; + ctdb->status.total_calls++; + ctdb->status.pending_calls++; + ctdb_db = find_ctdb_db(client->ctdb, c->db_id); if (!ctdb_db) { DEBUG(0, (__location__ " Unknown database in request. db_id==0x%08x", c->db_id)); + ctdb->status.pending_calls--; return; } @@ -332,11 +379,13 @@ static void daemon_request_call_from_client(struct ctdb_client *client, daemon_incoming_packet, client); if (ret == -2) { /* will retry later */ + ctdb->status.pending_calls--; return; } if (ret != 0) { DEBUG(0,(__location__ " Unable to fetch record\n")); + ctdb->status.pending_calls--; return; } @@ -344,8 +393,10 @@ static void daemon_request_call_from_client(struct ctdb_client *client, if (dstate == NULL) { ctdb_ltdb_unlock(ctdb_db, key); DEBUG(0,(__location__ " Unable to allocate dstate\n")); + ctdb->status.pending_calls--; return; } + dstate->start_time = timeval_current(); dstate->client = client; dstate->reqid = c->hdr.reqid; talloc_steal(dstate, data.dptr); @@ -354,6 +405,8 @@ static void daemon_request_call_from_client(struct ctdb_client *client, if (call == NULL) { ctdb_ltdb_unlock(ctdb_db, key); DEBUG(0,(__location__ " Unable to allocate call\n")); + ctdb->status.pending_calls--; + ctdb_latency(&ctdb->status.max_call_latency, dstate->start_time); return; } @@ -373,6 +426,8 @@ static void daemon_request_call_from_client(struct ctdb_client *client, if (state == NULL) { DEBUG(0,(__location__ " Unable to setup call send\n")); + ctdb->status.pending_calls--; + ctdb_latency(&ctdb->status.max_call_latency, dstate->start_time); return; } talloc_steal(state, dstate); @@ -427,6 +482,10 @@ static void daemon_incoming_packet(void *p, uint8_t *data, uint32_t nread) daemon_request_shutdown(client, (struct ctdb_req_shutdown *)hdr); break; + case CTDB_REQ_STATUS: + daemon_request_status(client, (struct ctdb_req_status *)hdr); + break; + default: DEBUG(0,(__location__ " daemon: unrecognized operation %d\n", hdr->operation)); @@ -436,7 +495,9 @@ done: talloc_free(tmp_ctx); } - +/* + called when the daemon gets a incoming packet + */ static void ctdb_daemon_read_cb(uint8_t *data, size_t cnt, void *args) { struct ctdb_client *client = talloc_get_type(args, struct ctdb_client); @@ -447,6 +508,8 @@ static void ctdb_daemon_read_cb(uint8_t *data, size_t cnt, void *args) return; } + client->ctdb->status.client_packets_recv++; + if (cnt < sizeof(*hdr)) { ctdb_set_error(client->ctdb, "Bad packet length %d in daemon\n", cnt); return; @@ -468,6 +531,10 @@ static void ctdb_daemon_read_cb(uint8_t *data, size_t cnt, void *args) return; } + DEBUG(3,(__location__ " client request %d of type %d length %d from " + "node %d to %d\n", hdr->reqid, hdr->operation, hdr->length, + hdr->srcnode, hdr->destnode)); + /* it is the responsibility of the incoming packet function to free 'data' */ daemon_incoming_packet(client, data, cnt); } diff --git a/ctdb/common/ctdb_lockwait.c b/ctdb/common/ctdb_lockwait.c index d5cea7c695c..1ed6e3ab896 100644 --- a/ctdb/common/ctdb_lockwait.c +++ b/ctdb/common/ctdb_lockwait.c @@ -29,6 +29,7 @@ struct lockwait_handle { + struct ctdb_context *ctdb; struct fd_event *fde; int fd[2]; pid_t child; @@ -48,6 +49,7 @@ static void lockwait_handler(struct event_context *ev, struct fd_event *fde, talloc_set_destructor(h, NULL); close(h->fd[0]); DEBUG(3,(__location__ " lockwait took %.6f seconds\n", timeval_elapsed(&h->t))); + h->ctdb->status.pending_lockwait_calls--; talloc_free(h); callback(p); waitpid(child, NULL, 0); @@ -55,6 +57,7 @@ static void lockwait_handler(struct event_context *ev, struct fd_event *fde, static int lockwait_destructor(struct lockwait_handle *h) { + h->ctdb->status.pending_lockwait_calls--; close(h->fd[0]); kill(h->child, SIGKILL); waitpid(h->child, NULL, 0); @@ -79,7 +82,11 @@ struct lockwait_handle *ctdb_lockwait(struct ctdb_db_context *ctdb_db, struct lockwait_handle *result; int ret; + ctdb_db->ctdb->status.lockwait_calls++; + ctdb_db->ctdb->status.pending_lockwait_calls++; + if (!(result = talloc_zero(ctdb_db, struct lockwait_handle))) { + ctdb_db->ctdb->status.pending_lockwait_calls--; return NULL; } @@ -87,6 +94,7 @@ struct lockwait_handle *ctdb_lockwait(struct ctdb_db_context *ctdb_db, if (ret != 0) { talloc_free(result); + ctdb_db->ctdb->status.pending_lockwait_calls--; return NULL; } @@ -96,11 +104,13 @@ struct lockwait_handle *ctdb_lockwait(struct ctdb_db_context *ctdb_db, close(result->fd[0]); close(result->fd[1]); talloc_free(result); + ctdb_db->ctdb->status.pending_lockwait_calls--; return NULL; } result->callback = callback; result->private_data = private_data; + result->ctdb = ctdb_db->ctdb; if (result->child == 0) { close(result->fd[0]); @@ -119,6 +129,7 @@ struct lockwait_handle *ctdb_lockwait(struct ctdb_db_context *ctdb_db, (void *)result); if (result->fde == NULL) { talloc_free(result); + ctdb_db->ctdb->status.pending_lockwait_calls--; return NULL; } diff --git a/ctdb/common/ctdb_util.c b/ctdb/common/ctdb_util.c index c5215c27a5d..9a5e51bfa0b 100644 --- a/ctdb/common/ctdb_util.c +++ b/ctdb/common/ctdb_util.c @@ -117,3 +117,14 @@ void *_idr_find_type(struct idr_context *idp, int id, const char *type, const ch return p; } + +/* + update a max latency number + */ +void ctdb_latency(double *latency, struct timeval t) +{ + double l = timeval_elapsed(&t); + if (l > *latency) { + *latency = l; + } +} diff --git a/ctdb/include/ctdb.h b/ctdb/include/ctdb.h index 997bdc6e13f..cb765884b6c 100644 --- a/ctdb/include/ctdb.h +++ b/ctdb/include/ctdb.h @@ -208,4 +208,9 @@ 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_status; +int ctdb_status(struct ctdb_context *ctdb, struct ctdb_status *status); + #endif diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h index 2f42cfb88a0..c46a2c02506 100644 --- a/ctdb/include/ctdb_private.h +++ b/ctdb/include/ctdb_private.h @@ -114,6 +114,22 @@ struct ctdb_daemon_data { struct ctdb_queue *queue; }; +/* + ctdb status information + */ +struct ctdb_status { + uint32_t client_packets_sent; + uint32_t client_packets_recv; + uint32_t node_packets_sent; + uint32_t node_packets_recv; + uint32_t total_calls; + uint32_t pending_calls; + uint32_t lockwait_calls; + uint32_t pending_lockwait_calls; + double max_call_latency; + double max_lockwait_latency; +}; + /* main state of the ctdb daemon */ struct ctdb_context { struct event_context *ev; @@ -135,6 +151,7 @@ struct ctdb_context { struct ctdb_db_context *db_list; struct ctdb_message_list *message_list; struct ctdb_daemon_data daemon; + struct ctdb_status status; }; struct ctdb_db_context { @@ -225,7 +242,9 @@ enum ctdb_operation { CTDB_REQ_REGISTER = 1000, CTDB_REQ_CONNECT_WAIT = 1001, CTDB_REPLY_CONNECT_WAIT = 1002, - CTDB_REQ_SHUTDOWN = 1003 + CTDB_REQ_SHUTDOWN = 1003, + CTDB_REQ_STATUS = 1004, + CTDB_REPLY_STATUS = 1005 }; #define CTDB_MAGIC 0x43544442 /* CTDB */ @@ -318,6 +337,15 @@ struct ctdb_reply_connect_wait { uint32_t num_connected; }; +struct ctdb_req_status { + struct ctdb_req_header hdr; +}; + +struct ctdb_reply_status { + struct ctdb_req_header hdr; + struct ctdb_status status; +}; + /* 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); @@ -459,4 +487,8 @@ void *_idr_find_type(struct idr_context *idp, int id, const char *type, const ch void ctdb_recv_raw_pkt(void *p, uint8_t *data, uint32_t length); +int ctdb_socket_connect(struct ctdb_context *ctdb); + +void ctdb_latency(double *latency, struct timeval t); + #endif diff --git a/ctdb/tools/ctdb_status.c b/ctdb/tools/ctdb_status.c new file mode 100644 index 00000000000..266fb0a212f --- /dev/null +++ b/ctdb/tools/ctdb_status.c @@ -0,0 +1,117 @@ +/* + ctdb status 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" + + +/* + display status structure + */ +static void show_status(struct ctdb_status *s) +{ + printf(" client_packets_sent %u\n", s->client_packets_sent); + printf(" client_packets_recv %u\n", s->client_packets_recv); + printf(" node_packets_sent %u\n", s->node_packets_sent); + printf(" node_packets_recv %u\n", s->node_packets_recv); + printf(" total_calls %u\n", s->total_calls); + printf(" pending_calls %u\n", s->pending_calls); + printf(" lockwait_calls %u\n", s->lockwait_calls); + printf(" pending_lockwait_calls %u\n", s->pending_lockwait_calls); + printf(" max_call_latency %.6f seconds\n", s->max_call_latency); + printf(" max_lockwait_latency %.6f seconds\n", s->max_lockwait_latency); +} + +/* + show usage message + */ +static void usage(void) +{ + printf("Usage: ctdb_status \n"); + exit(1); +} + +/* + 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 *ctdb_socket; + struct ctdb_status status; + + 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(); + } + + ctdb_socket = extra_argv[0]; + + ev = event_context_init(NULL); + + /* initialise ctdb */ + ctdb = ctdb_cmdline_client(ev, ctdb_socket); + if (ctdb == NULL) { + printf("Failed to init ctdb\n"); + exit(1); + } + + ret = ctdb_status(ctdb, &status); + if (ret != 0) { + printf("Failed to get ctdb status\n"); + exit(1); + } + + show_status(&status); + + return 0; +}