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
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
@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)
const char *nlist;
const char *transport;
const char *myaddress;
+ const char *socketname;
int self_connect;
const char *db_dir;
int torture;
.nlist = NULL,
.transport = "tcp",
.myaddress = NULL,
+ .socketname = CTDB_PATH,
.self_connect = 0,
.db_dir = NULL,
.torture = 0
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"},
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) {
/*
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;
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) {
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
*/
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));
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
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));
}
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");
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;
+}
--- /dev/null
+/*
+ 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;
+}
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)
{
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);
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));
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);
{
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));
+ }
+}
*/
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
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
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
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;
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;
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)
uint32_t lacount;
};
+enum {CTDB_CONTROL_PROCESS_EXISTS};
+
enum call_state {CTDB_CALL_WAIT, CTDB_CALL_DONE, CTDB_CALL_ERROR};
/*
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,
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);
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
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
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
+++ /dev/null
-#!/bin/sh
-
-killall -q ctdb_bench
-
-echo "Trying 1 nodes"
-bin/ctdb_bench --nlist tests/1node.txt --listen 127.0.0.2:9001 $*
-wait
#!/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
#!/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
#!/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
--- /dev/null
+/*
+ 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;
+}
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);