OBJS = @TDB_OBJ@ @TALLOC_OBJ@ @LIBREPLACEOBJ@ @INFINIBAND_WRAPPER_OBJ@ $(EXTRA_OBJ) @EVENTS_OBJ@ $(CTDB_OBJ) $(UTIL_OBJ)
-TEST_BINS=bin/ctdbd_test bin/ctdb_bench bin/ctdb_fetch @INFINIBAND_BINS@
+TEST_BINS=bin/ctdb_bench bin/ctdb_fetch @INFINIBAND_BINS@
BINS = bin/ctdb
SBINS = bin/ctdbd
@echo Linking $@
@$(CC) $(CFLAGS) -o $@ tools/ctdb_control.o $(OBJS) $(LIB_FLAGS)
-bin/ctdbd_test: $(OBJS) direct/ctdbd_test.o
- @echo Linking $@
- @$(CC) $(CFLAGS) -o $@ direct/ctdbd_test.o
-
bin/ctdb_bench: $(OBJS) tests/ctdb_bench.o
@echo Linking $@
@$(CC) $(CFLAGS) -o $@ tests/ctdb_bench.o $(OBJS) $(LIB_FLAGS)
ctdb_request_message(ctdb, hdr);
break;
- case CTDB_REQ_FINISHED:
- ctdb->statistics.node.req_finished++;
- ctdb_request_finished(ctdb, hdr);
- break;
-
case CTDB_REQ_CONTROL:
ctdb->statistics.node.req_control++;
ctdb_request_control(ctdb, hdr);
node->ctdb->name, node->name, node->ctdb->num_connected));
}
-/*
- wait for all nodes to be connected
-*/
-void ctdb_daemon_connect_wait(struct ctdb_context *ctdb)
-{
- int expected = ctdb->num_nodes - 1;
- if (ctdb->flags & CTDB_FLAG_SELF_CONNECT) {
- expected++;
- }
- while (ctdb->num_connected != expected) {
- DEBUG(3,("ctdb_connect_wait: waiting for %u nodes (have %u)\n",
- expected, ctdb->num_connected));
- event_loop_once(ctdb->ev);
- }
- DEBUG(3,("ctdb_connect_wait: got all %u nodes\n", expected));
-}
-
struct queue_next {
struct ctdb_context *ctdb;
struct ctdb_req_header *hdr;
}
-/*
- handle a connect wait reply packet
- */
-static void ctdb_reply_connect_wait(struct ctdb_context *ctdb,
- struct ctdb_req_header *hdr)
-{
- struct ctdb_reply_connect_wait *r = (struct ctdb_reply_connect_wait *)hdr;
- ctdb->vnn = r->vnn;
- ctdb->num_connected = r->num_connected;
-}
-
/*
state of a in-progress ctdb call in client
*/
ctdb_request_message(ctdb, hdr);
break;
- case CTDB_REPLY_CONNECT_WAIT:
- ctdb_reply_connect_wait(ctdb, hdr);
- break;
-
case CTDB_REPLY_CONTROL:
ctdb_client_reply_control(ctdb, hdr);
break;
return 0;
}
-/*
- wait for all nodes to be connected - from client
- */
-void ctdb_connect_wait(struct ctdb_context *ctdb)
-{
- struct ctdb_req_connect_wait *r;
- int res;
-
- r = ctdbd_allocate_pkt(ctdb, ctdb, CTDB_REQ_CONNECT_WAIT, sizeof(*r),
- struct ctdb_req_connect_wait);
- CTDB_NO_MEMORY_VOID(ctdb, r);
-
- DEBUG(3,("ctdb_connect_wait: sending to ctdbd\n"));
-
- /* if the domain socket is not yet open, open it */
- if (ctdb->daemon.sd==-1) {
- ctdb_socket_connect(ctdb);
- }
-
- res = ctdb_queue_send(ctdb->daemon.queue, (uint8_t *)&r->hdr, r->hdr.length);
- talloc_free(r);
- if (res != 0) {
- DEBUG(0,(__location__ " Failed to queue a connect wait request\n"));
- return;
- }
-
- DEBUG(3,("ctdb_connect_wait: waiting\n"));
-
- /* now we can go into the normal wait routine, as the reply packet
- will update the ctdb->num_connected variable */
- ctdb_daemon_connect_wait(ctdb);
-}
/*
cancel a ctdb_fetch_lock operation, releasing the lock
return ctdb_ltdb_store(h->ctdb_db, h->key, &h->header, data);
}
-/*
- wait until we're the only node left.
- this function never returns
-*/
-void ctdb_shutdown(struct ctdb_context *ctdb)
-{
- struct ctdb_req_shutdown *r;
-
- /* if the domain socket is not yet open, open it */
- if (ctdb->daemon.sd==-1) {
- ctdb_socket_connect(ctdb);
- }
-
- r = ctdbd_allocate_pkt(ctdb, ctdb, CTDB_REQ_SHUTDOWN, sizeof(*r),
- struct ctdb_req_shutdown);
- CTDB_NO_MEMORY_VOID(ctdb, r);
-
- ctdb_client_queue_pkt(ctdb, &(r->hdr));
-
- talloc_free(r);
-
- /* this event loop will terminate once we receive the reply */
- while (1) {
- event_loop_once(ctdb->ev);
- }
-}
-
-
struct ctdb_client_control_state {
struct ctdb_context *ctdb;
uint32_t reqid;
}
-/*
- called when the daemon gets a shutdown request from a client
- */
-static void daemon_request_shutdown(struct ctdb_client *client,
- struct ctdb_req_shutdown *f)
-{
- struct ctdb_context *ctdb = talloc_get_type(client->ctdb, struct ctdb_context);
- int len;
- uint32_t node;
-
- /* we dont send to ourself so we can already count one daemon as
- exiting */
- ctdb->num_finished++;
-
-
- /* loop over all nodes of the cluster */
- for (node=0; node<ctdb->num_nodes;node++) {
- struct ctdb_req_finished *rf;
-
- /* dont send a message to ourself */
- if (ctdb->vnn == node) {
- continue;
- }
-
- len = sizeof(struct ctdb_req_finished);
- rf = ctdb_transport_allocate(ctdb, ctdb, CTDB_REQ_FINISHED, len,
- struct ctdb_req_finished);
- CTDB_NO_MEMORY_FATAL(ctdb, rf);
-
- rf->hdr.destnode = node;
-
- ctdb_queue_packet(ctdb, &(rf->hdr));
-
- talloc_free(rf);
- }
-
- /* wait until all nodes have are prepared to shutdown */
- while (ctdb->num_finished != ctdb->num_nodes) {
- event_loop_once(ctdb->ev);
- }
-
- /* all daemons have requested to finish - we now exit */
- DEBUG(1,("All daemons finished - exiting\n"));
- _exit(0);
-}
-
-
-
-/*
- called when the daemon gets a connect wait request from a client
- */
-static void daemon_request_connect_wait(struct ctdb_client *client,
- struct ctdb_req_connect_wait *c)
-{
- struct ctdb_reply_connect_wait *r;
- int res;
-
- /* first wait - in the daemon */
- ctdb_daemon_connect_wait(client->ctdb);
-
- /* now send the reply */
- r = ctdbd_allocate_pkt(client->ctdb, client, CTDB_REPLY_CONNECT_WAIT, sizeof(*r),
- struct ctdb_reply_connect_wait);
- CTDB_NO_MEMORY_VOID(client->ctdb, r);
- r->vnn = ctdb_get_vnn(client->ctdb);
- r->num_connected = client->ctdb->num_connected;
-
- res = daemon_queue_send(client, &r->hdr);
- talloc_free(r);
- if (res != 0) {
- DEBUG(0,(__location__ " Failed to queue a connect wait response\n"));
- return;
- }
-}
-
-
/*
destroy a ctdb_client
*/
daemon_request_message_from_client(client, (struct ctdb_req_message *)hdr);
break;
- case CTDB_REQ_CONNECT_WAIT:
- ctdb->statistics.client.req_connect_wait++;
- daemon_request_connect_wait(client, (struct ctdb_req_connect_wait *)hdr);
- break;
-
- case CTDB_REQ_SHUTDOWN:
- ctdb->statistics.client.req_shutdown++;
- daemon_request_shutdown(client, (struct ctdb_req_shutdown *)hdr);
- break;
-
case CTDB_REQ_CONTROL:
ctdb->statistics.client.req_control++;
daemon_request_control_from_client(client, (struct ctdb_req_control *)hdr);
return hdr;
}
-/*
- called when a CTDB_REQ_FINISHED packet comes in
-*/
-void ctdb_request_finished(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
-{
- ctdb->num_finished++;
-}
-
-
struct daemon_control_state {
struct daemon_control_state *next, *prev;
struct ctdb_client *client;
+++ /dev/null
-127.0.0.1
-127.0.0.2
-127.0.0.3
-127.0.0.4
+++ /dev/null
-Run ./direct/ctdbd.sh to start a cluster with two ctdb nodes
-They will listen for clients on the unix domain sockets
-/tmp/ctdb.socket.127.0.0.1
-/tmp/ctdb.socket.127.0.0.2
-
-In order for this to work you must have an interface with the address 127.0.0.2 available.
-Just create this as an alias for loopback.
-
-
-Then run ./direct/ctdbd_test to connect a client to the ctdbd daemon on /tmp/ctdb.socket.127.0.0.1 and do some commands to it across the domain socket.
-
-
+++ /dev/null
-/*
- test of messaging
-
- Copyright (C) Andrew Tridgell 2006
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program 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 General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "includes.h"
-#include "system/network.h"
-#include "../include/ctdb.h"
-#include "../include/ctdb_private.h"
-
-#define CTDB_SOCKET "/tmp/ctdb.socket.127.0.0.1"
-
-
-/*
- connect to the unix domain socket
-*/
-static int ux_socket_connect(const char *name)
-{
- struct sockaddr_un addr;
- int fd;
-
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- strncpy(addr.sun_path, name, sizeof(addr.sun_path));
-
- fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (fd == -1) {
- return -1;
- }
-
- if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
- close(fd);
- return -1;
- }
-
- return fd;
-}
-
-/* send a command to the cluster to wait until all nodes are connected
- and the cluster is fully operational
- */
-int wait_for_cluster(int fd)
-{
- struct ctdb_req_connect_wait req;
- struct ctdb_reply_connect_wait rep;
- int cnt, tot;
-
- /* send a connect wait command to the local node */
- bzero(&req, sizeof(req));
- req.hdr.length = sizeof(req);
- req.hdr.ctdb_magic = CTDB_MAGIC;
- req.hdr.ctdb_version = CTDB_VERSION;
- req.hdr.generation = 1;
- req.hdr.operation = CTDB_REQ_CONNECT_WAIT;
-
- /* XXX must deal with partial writes here */
- write(fd, &req, sizeof(req));
-
-
- /* read the 4 bytes of length for the pdu */
- cnt=0;
- tot=4;
- while(cnt!=tot){
- int numread;
- numread=read(fd, ((char *)&rep)+cnt, tot-cnt);
- if(numread>0){
- cnt+=numread;
- }
- }
- /* read the rest of the pdu */
- tot=rep.hdr.length;
- while(cnt!=tot){
- int numread;
- numread=read(fd, ((char *)&rep)+cnt, tot-cnt);
- if(numread>0){
- cnt+=numread;
- }
- }
-
- return rep.vnn;
-}
-
-
-int send_a_message(int fd, int ourvnn, int vnn, int pid, TDB_DATA data)
-{
- struct ctdb_req_message r;
- int len, cnt;
-
- len = offsetof(struct ctdb_req_message, data) + data.dsize;
- r.hdr.length = len;
- r.hdr.ctdb_magic = CTDB_MAGIC;
- r.hdr.ctdb_version = CTDB_VERSION;
- r.hdr.generation = 1;
- r.hdr.operation = CTDB_REQ_MESSAGE;
- r.hdr.destnode = vnn;
- r.hdr.srcnode = ourvnn;
- r.hdr.reqid = 0;
- r.srvid = pid;
- r.datalen = data.dsize;
-
- /* write header */
- cnt=write(fd, &r, offsetof(struct ctdb_req_message, data));
- /* write data */
- if(data.dsize){
- cnt=write(fd, data.dptr, data.dsize);
- }
- return 0;
-}
-
-int receive_a_message(int fd, struct ctdb_req_message **preply)
-{
- int cnt,tot;
- struct ctdb_req_message *rep;
- uint32_t length;
-
- /* read the 4 bytes of length for the pdu */
- cnt=0;
- tot=4;
- while(cnt!=tot){
- int numread;
- numread=read(fd, ((char *)&length)+cnt, tot-cnt);
- if(numread>0){
- cnt+=numread;
- }
- }
-
- /* read the rest of the pdu */
- rep = malloc(length);
- rep->hdr.length = length;
- cnt = 0;
- tot = length-4;
- while(cnt!=tot){
- int numread;
- numread=read(fd, ((char *)rep)+cnt, tot-cnt);
- if(numread>0){
- cnt+=numread;
- }
- }
-
- *preply = rep;
- return 0;
-}
-
-/*
- hash function for mapping data to a VNN - taken from tdb
-*/
-uint32_t ctdb_hash(const TDB_DATA *key)
-{
- uint32_t value; /* Used to compute the hash value. */
- uint32_t i; /* Used to cycle through random values. */
-
- /* Set the initial value from the key size. */
- for (value = 0x238F13AF * key->dsize, i=0; i < key->dsize; i++)
- value = (value + (key->dptr[i] << (i*5 % 24)));
-
- return (1103515243 * value + 12345);
-}
-
-/* ask the daemon to migrate a record over so that the local node is the dmaster the client must not have the record locked when performing this call.
-
- when the daemon has responded this node should be the dmaster (unless it has migrated off again)
- */
-void fetch_record(int fd, uint32_t db_id, TDB_DATA key)
-{
- struct ctdb_req_call *req;
- struct ctdb_reply_call *rep;
- uint32_t length;
- int len, cnt, tot;
-
- len = offsetof(struct ctdb_req_call, data) + key.dsize;
- req = malloc(len);
-
- req->hdr.length = len;
- req->hdr.ctdb_magic = CTDB_MAGIC;
- req->hdr.ctdb_version = CTDB_VERSION;
- req->hdr.generation = 1;
- req->hdr.operation = CTDB_REQ_CALL;
- req->hdr.reqid = 1;
-
- req->flags = CTDB_IMMEDIATE_MIGRATION;
- req->db_id = db_id;
- req->callid = CTDB_NULL_FUNC;
- req->keylen = key.dsize;
- req->calldatalen = 0;
- memcpy(&req->data[0], key.dptr, key.dsize);
-
- cnt=write(fd, req, len);
-
-
- /* wait fot the reply */
- /* read the 4 bytes of length for the pdu */
- cnt=0;
- tot=4;
- while(cnt!=tot){
- int numread;
- numread=read(fd, ((char *)&length)+cnt, tot-cnt);
- if(numread>0){
- cnt+=numread;
- }
- }
- /* read the rest of the pdu */
- rep = malloc(length);
- tot=length;
- while(cnt!=tot){
- int numread;
- numread=read(fd, ((char *)rep)+cnt, tot-cnt);
- if(numread>0){
- cnt+=numread;
- }
- }
- printf("fetch record reply: operation:%d state:%d\n",rep->hdr.operation,rep->status);
-}
-
-int main(int argc, const char *argv[])
-{
- int fd, pid=0, vnn, dstvnn, dstpid;
- TDB_DATA message;
- struct ctdb_req_message *reply;
- TDB_DATA dbname;
- uint32_t db_id;
- TDB_DATA key;
-
- /* open the socket to talk to the local ctdb daemon */
- fd=ux_socket_connect(CTDB_SOCKET);
- if (fd==-1) {
- printf("failed to open domain socket\n");
- exit(10);
- }
-
-
- /* do a connect wait to ensure that all nodes in the cluster are up
- and operational.
- this also tells us the vnn of the local cluster.
- If someone wants to send us a emssage they should send it to
- this vnn and our pid
- */
- vnn=wait_for_cluster(fd);
- printf("our address is vnn:%d pid:%d if someone wants to send us a message!\n",vnn,pid);
-
-
- /* send a message to ourself */
- dstvnn=vnn;
- dstpid=pid;
- message.dptr=discard_const("Test message");
- message.dsize=strlen((const char *)message.dptr)+1;
- printf("sending test message [%s] to ourself\n", message.dptr);
- send_a_message(fd, vnn, dstvnn, dstpid, message);
-
- /* wait for the message to come back */
- receive_a_message(fd, &reply);
- printf("received message: [%s]\n",&reply->data[0]);
-
- /* create the db id for "test.tdb" */
- dbname.dptr = discard_const("test.tdb");
- dbname.dsize = strlen((const char *)(dbname.dptr));
- db_id = ctdb_hash(&dbname);
- printf("the has for the database id is 0x%08x\n",db_id);
- printf("\n");
-
- /* send a request to migrate a record to the local node */
- key.dptr=discard_const("TestKey");
- key.dsize=strlen((const char *)(key.dptr));
- printf("fetch the test key:[%s]\n",key.dptr);
-
- fetch_record(fd, db_id, key);
- printf("\n");
-
-
- return 0;
-}
+++ /dev/null
-127.0.0.1
-127.0.0.2
*/
int ctdb_call(struct ctdb_db_context *ctdb_db, struct ctdb_call *call);
-/*
- wait for all nodes to be connected - useful for test code
-*/
-void ctdb_connect_wait(struct ctdb_context *ctdb);
-
/*
initiate an ordered ctdb cluster shutdown
this function will never return
#define CTDB_MAX_REDIRECT_COUNT 3
#define CTDB_DEFAULT_SEQNUM_FREQUENCY 1
+#define CTDB_CONTROL_TIMEOUT 60
+#define CTDB_TRAVERSE_TIMEOUT 20
+#define CTDB_MONITORING_TIMEOUT 2
+#define CTDB_MONITORING_DEAD_COUNT 3
+#define CTDB_DEFAULT_MAX_LACOUNT 7
+
+
+/* all tunable variables go in here */
+struct ctdb_tunable {
+ uint32_t max_redirect_count;
+ uint32_t seqnum_frequency;
+ uint32_t control_timeout;
+ uint32_t traverse_timeout;
+ uint32_t monitoring_timeout;
+ uint32_t monitoring_limit;
+ uint32_t max_lacount;
+};
/*
an installed ctdb remote call
uint32_t reply_dmaster;
uint32_t reply_error;
uint32_t req_message;
- uint32_t req_finished;
uint32_t req_control;
uint32_t reply_control;
} node;
struct {
uint32_t req_call;
uint32_t req_message;
- uint32_t req_finished;
- uint32_t req_connect_wait;
- uint32_t req_shutdown;
uint32_t req_control;
} client;
struct {
uint32_t vnn; /* our own vnn */
uint32_t num_nodes;
uint32_t num_connected;
- uint32_t num_finished;
unsigned flags;
struct idr_context *idr;
uint16_t idr_cnt;
ctdb_fatal(ctdb, "Out of memory in " __location__ ); \
}} while (0)
-/* maximum timeout for ctdb control calls */
-#define CTDB_CONTROL_TIMEOUT 60
-
-/* timeout for ctdb traverse calls. When this is reached we cut short
- the traverse */
-#define CTDB_TRAVERSE_TIMEOUT 20
-
-/* timeout between dead-node monitoring events */
-#define CTDB_MONITORING_TIMEOUT 2
-
-/* number of monitoring timeouts before a node is considered dead */
-#define CTDB_MONITORING_DEAD_COUNT 3
-
-
-/* number of consecutive calls from the same node before we give them
- the record */
-#define CTDB_DEFAULT_MAX_LACOUNT 7
-
/*
the extended header for records in the ltdb
*/
CTDB_REQ_CONTROL,
CTDB_REPLY_CONTROL,
CTDB_REQ_KEEPALIVE,
-
- /* only used on the domain socket */
- CTDB_REQ_CONNECT_WAIT = 1000,
- CTDB_REPLY_CONNECT_WAIT,
- CTDB_REQ_SHUTDOWN
};
#define CTDB_MAGIC 0x43544442 /* CTDB */
uint8_t data[1];
};
-struct ctdb_req_finished {
- struct ctdb_req_header hdr;
-};
-
-struct ctdb_req_shutdown {
- struct ctdb_req_header hdr;
-};
-
-struct ctdb_req_connect_wait {
- struct ctdb_req_header hdr;
-};
-
-struct ctdb_reply_connect_wait {
- struct ctdb_req_header hdr;
- uint32_t vnn;
- uint32_t num_connected;
-};
-
struct ctdb_req_getdbpath {
struct ctdb_req_header hdr;
uint32_t db_id;
uint64_t srvid, TDB_DATA data);
-/*
- wait for all nodes to be connected
-*/
-void ctdb_daemon_connect_wait(struct ctdb_context *ctdb);
-
-
struct lockwait_handle *ctdb_lockwait(struct ctdb_db_context *ctdb_db,
TDB_DATA key,
void (*callback)(void *), void *private_data);
struct ctdb_call *call,
struct ctdb_ltdb_header *header);
-void ctdb_request_finished(struct ctdb_context *ctdb, struct ctdb_req_header *hdr);
-
int ctdb_call_local(struct ctdb_db_context *ctdb_db, struct ctdb_call *call,
struct ctdb_ltdb_header *header, TALLOC_CTX *mem_ctx, TDB_DATA *data,
uint32_t caller);
killall -q ctdbd
echo "Starting 2 ctdb daemons"
-$VALGRIND bin/ctdbd --reclock=rec.lock --nlist direct/nodes.txt --event-script=tests/events --logfile=-
-$VALGRIND bin/ctdbd --reclock=rec.lock --nlist direct/nodes.txt --event-script=tests/events --logfile=- --socket=sock.2
+$VALGRIND bin/ctdbd --reclock=rec.lock --nlist tests/nodes.txt --event-script=tests/events --logfile=-
+$VALGRIND bin/ctdbd --reclock=rec.lock --nlist tests/nodes.txt --event-script=tests/events --logfile=- --socket=sock.2
while bin/ctdb status | grep RECOVERY > /dev/null; do
echo "`date` Waiting for recovery"
STATISTICS_FIELD(node.reply_dmaster),
STATISTICS_FIELD(node.reply_error),
STATISTICS_FIELD(node.req_message),
- STATISTICS_FIELD(node.req_finished),
STATISTICS_FIELD(node.req_control),
STATISTICS_FIELD(node.reply_control),
STATISTICS_FIELD(client.req_call),
STATISTICS_FIELD(client.req_message),
- STATISTICS_FIELD(client.req_finished),
- STATISTICS_FIELD(client.req_connect_wait),
- STATISTICS_FIELD(client.req_shutdown),
STATISTICS_FIELD(client.req_control),
STATISTICS_FIELD(controls.statistics),
STATISTICS_FIELD(controls.get_config),