mirror of
https://github.com/samba-team/samba.git
synced 2024-12-22 13:34:15 +03:00
added a ctdb control message, and tool
(This used to be ctdb commit 0d7a71f35bb8ce95231f8ca1e8e3e4024fe657e5)
This commit is contained in:
parent
c1a4b3c687
commit
d955485e7b
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
}
|
||||
|
182
ctdb/common/ctdb_control.c
Normal file
182
ctdb/common/ctdb_control.c
Normal file
@ -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;
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -1,17 +1,24 @@
|
||||
#!/bin/sh
|
||||
|
||||
#!/bin/sh
|
||||
|
||||
killall -q ctdb_test
|
||||
|
||||
NUMNODES=2
|
||||
if [ $# -gt 0 ]; then
|
||||
NUMNODES=$1
|
||||
shift
|
||||
fi
|
||||
|
||||
rm -f nodes.txt
|
||||
for i in `seq 1 $NUMNODES`; do
|
||||
echo 127.0.0.$i:9001 >> nodes.txt
|
||||
done
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
|
119
ctdb/tools/ctdb_control.c
Normal file
119
ctdb/tools/ctdb_control.c
Normal file
@ -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;
|
||||
}
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user