example libctdb.a and test program libctdb/tst.c
authorRonnie Sahlberg <ronniesahlberg@gmail.com>
Mon, 10 May 2010 21:23:56 +0000 (07:23 +1000)
committerRonnie Sahlberg <ronniesahlberg@gmail.com>
Mon, 10 May 2010 21:23:56 +0000 (07:23 +1000)
for evaluation.

libctdb.a contains a lot of code used in ctdbd
as well as a small libctdb wrapper that are calleable form clients
: libctdb/ctdb_connect.c

15 files changed:
Makefile.in
client/ctdb_client.c
common/ctdb_logging.c
include/ctdb_private.h
include/includes.h
include/libctdb.h [new file with mode: 0644]
lib/events/events_epoll.c
lib/util/debug.h
libctdb/ctdb_connect.c [new file with mode: 0644]
libctdb/ctdb_io.c [moved from common/ctdb_io.c with 100% similarity]
libctdb/ctdb_ltdb.c [moved from common/ctdb_ltdb.c with 100% similarity]
libctdb/ctdb_message.c [moved from common/ctdb_message.c with 100% similarity]
libctdb/ctdb_util.c [moved from common/ctdb_util.c with 98% similarity]
libctdb/tst.c [new file with mode: 0644]
server/ctdb_logging.c

index 4e70ce8e0b7cf7ee90763ee6ceb1ec230b8da5f0..cdcb394557669b80b3d3297c6f708bd1a84fa8c6 100755 (executable)
@@ -2,6 +2,9 @@
 
 
 CC = @CC@
+AR = ar
+ARFLAGS = cru
+RANLIB = ranlib
 prefix = @prefix@
 exec_prefix = @exec_prefix@
 datarootdir = @datarootdir@
@@ -38,16 +41,22 @@ UTIL_OBJ = lib/util/idtree.o lib/util/db_wrap.o lib/util/strlist.o lib/util/util
        lib/util/util_time.o lib/util/util_file.o lib/util/fault.o lib/util/substitute.o \
        lib/util/signal.o
 
-CTDB_COMMON_OBJ =  common/ctdb_io.o common/ctdb_util.o \
-       common/ctdb_ltdb.o common/ctdb_message.o common/cmdline.o  \
-       lib/util/debug.o common/rb_tree.o @CTDB_SYSTEM_OBJ@ common/system_common.o \
-       common/ctdb_logging.c
+CTDB_LIB_OBJ = libctdb/ctdb_io.o libctdb/ctdb_connect.o \
+       libctdb/ctdb_client.o libctdb/ctdb_message.o \
+       libctdb/ctdb_ltdb.o \
+       libctdb/ctdb_util.o lib/util/debug.o \
+       @EVENTS_OBJ@ @TALLOC_OBJ@ @TDB_OBJ@ $(UTIL_OBJ) \
+       @LIBREPLACEOBJ@ 
+
+CTDB_COMMON_OBJ = common/cmdline.o common/rb_tree.o @CTDB_SYSTEM_OBJ@ \
+       common/system_common.o common/ctdb_logging.c \
+       libctdb/libctdb.a
 
 CTDB_TCP_OBJ = tcp/tcp_connect.o tcp/tcp_io.o tcp/tcp_init.o
 
 CTDB_CLIENT_OBJ = client/ctdb_client.o \
-       $(CTDB_COMMON_OBJ) $(POPT_OBJ) $(UTIL_OBJ) @TALLOC_OBJ@ @TDB_OBJ@ \
-       @LIBREPLACEOBJ@ $(EXTRA_OBJ) @EVENTS_OBJ@ 
+       $(CTDB_COMMON_OBJ) $(POPT_OBJ) \
+       $(EXTRA_OBJ)
 
 CTDB_SERVER_OBJ = server/ctdbd.o server/ctdb_daemon.o server/ctdb_lockwait.o \
        server/ctdb_recoverd.o server/ctdb_recover.o server/ctdb_freeze.o \
@@ -102,6 +111,12 @@ bin/ctdbd: $(CTDB_SERVER_OBJ)
        @echo Linking $@
        @$(CC) $(CFLAGS) -o $@ $(CTDB_SERVER_OBJ) $(LIB_FLAGS)
 
+libctdb/libctdb.a: $(CTDB_LIB_OBJ)
+       @echo Linking $@
+       -rm -f libctdb.a
+       @$(AR) $(ARFLAGS) libctdb/libctdb.a $(CTDB_LIB_OBJ)
+       @$(RANLIB) libctdb/libctdb.a
+
 bin/scsi_io: $(CTDB_CLIENT_OBJ) utils/scsi_io/scsi_io.o 
        @echo Linking $@
        @$(CC) $(CFLAGS) -o $@ utils/scsi_io/scsi_io.o $(CTDB_CLIENT_OBJ) $(LIB_FLAGS)
@@ -184,7 +199,7 @@ doc: doc/ctdb.1 doc/ctdb.1.html \
        doc/onnode.1 doc/onnode.1.html
 
 clean:
-       rm -f *.o */*.o */*/*.o */*~
+       rm -f *.o */*.o */*.a */*/*.o */*~
        rm -f utils/smnotify/gen_xdr.c
        rm -f $(BINS) $(SBINS) $(TEST_BINS)
 
index 946335c9ff2a26369b0a73859986f5d81d1d324e..665f61d2c42dfa728dba2402137fcb2cd3984341 100644 (file)
 #include "../include/ctdb_private.h"
 #include "lib/util/dlinklist.h"
 
-pid_t ctdbd_pid;
-
-/*
-  allocate a packet for use in client<->daemon communication
- */
-struct ctdb_req_header *_ctdbd_allocate_pkt(struct ctdb_context *ctdb,
-                                           TALLOC_CTX *mem_ctx, 
-                                           enum ctdb_operation operation, 
-                                           size_t length, size_t slength,
-                                           const char *type)
-{
-       int size;
-       struct ctdb_req_header *hdr;
-
-       length = MAX(length, slength);
-       size = (length+(CTDB_DS_ALIGNMENT-1)) & ~(CTDB_DS_ALIGNMENT-1);
-
-       hdr = (struct ctdb_req_header *)talloc_size(mem_ctx, size);
-       if (hdr == NULL) {
-               DEBUG(DEBUG_ERR,("Unable to allocate packet for operation %u of length %u\n",
-                        operation, (unsigned)length));
-               return NULL;
-       }
-       talloc_set_name_const(hdr, type);
-       memset(hdr, 0, slength);
-       hdr->length       = length;
-       hdr->operation    = operation;
-       hdr->ctdb_magic   = CTDB_MAGIC;
-       hdr->ctdb_version = CTDB_VERSION;
-       hdr->srcnode      = ctdb->pnn;
-       if (ctdb->vnn_map) {
-               hdr->generation = ctdb->vnn_map->generation;
-       }
-
-       return hdr;
-}
-
-/*
-  local version of ctdb_call
-*/
-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)
-{
-       struct ctdb_call_info *c;
-       struct ctdb_registered_call *fn;
-       struct ctdb_context *ctdb = ctdb_db->ctdb;
-       
-       c = talloc(ctdb, struct ctdb_call_info);
-       CTDB_NO_MEMORY(ctdb, c);
-
-       c->key = call->key;
-       c->call_data = &call->call_data;
-       c->record_data.dptr = talloc_memdup(c, data->dptr, data->dsize);
-       c->record_data.dsize = data->dsize;
-       CTDB_NO_MEMORY(ctdb, c->record_data.dptr);
-       c->new_data = NULL;
-       c->reply_data = NULL;
-       c->status = 0;
-
-       for (fn=ctdb_db->calls;fn;fn=fn->next) {
-               if (fn->id == call->call_id) break;
-       }
-       if (fn == NULL) {
-               ctdb_set_error(ctdb, "Unknown call id %u\n", call->call_id);
-               talloc_free(c);
-               return -1;
-       }
-
-       if (fn->fn(c) != 0) {
-               ctdb_set_error(ctdb, "ctdb_call %u failed\n", call->call_id);
-               talloc_free(c);
-               return -1;
-       }
-
-       if (header->laccessor != caller) {
-               header->lacount = 0;
-       }
-       header->laccessor = caller;
-       header->lacount++;
-
-       /* we need to force the record to be written out if this was a remote access,
-          so that the lacount is updated */
-       if (c->new_data == NULL && header->laccessor != ctdb->pnn) {
-               c->new_data = &c->record_data;
-       }
-
-       if (c->new_data) {
-               /* XXX check that we always have the lock here? */
-               if (ctdb_ltdb_store(ctdb_db, call->key, header, *c->new_data) != 0) {
-                       ctdb_set_error(ctdb, "ctdb_call tdb_store failed\n");
-                       talloc_free(c);
-                       return -1;
-               }
-       }
-
-       if (c->reply_data) {
-               call->reply_data = *c->reply_data;
-
-               talloc_steal(call, call->reply_data.dptr);
-               talloc_set_name_const(call->reply_data.dptr, __location__);
-       } else {
-               call->reply_data.dptr = NULL;
-               call->reply_data.dsize = 0;
-       }
-       call->status = c->status;
-
-       talloc_free(c);
-
-       return 0;
-}
-
-
-/*
-  queue a packet for sending from client to daemon
-*/
-static int ctdb_client_queue_pkt(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
-{
-       return ctdb_queue_send(ctdb->daemon.queue, (uint8_t *)hdr, hdr->length);
-}
-
-
-/*
-  called when a CTDB_REPLY_CALL packet comes in in the client
-
-  This packet comes in response to a CTDB_REQ_CALL request packet. It
-  contains any reply data from the call
-*/
-static void ctdb_client_reply_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr)
-{
-       struct ctdb_reply_call *c = (struct ctdb_reply_call *)hdr;
-       struct ctdb_client_call_state *state;
-
-       state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_client_call_state);
-       if (state == NULL) {
-               DEBUG(DEBUG_ERR,(__location__ " reqid %u not found\n", hdr->reqid));
-               return;
-       }
-
-       if (hdr->reqid != state->reqid) {
-               /* we found a record  but it was the wrong one */
-               DEBUG(DEBUG_ERR, ("Dropped client call reply with reqid:%u\n",hdr->reqid));
-               return;
-       }
-
-       state->call->reply_data.dptr = c->data;
-       state->call->reply_data.dsize = c->datalen;
-       state->call->status = c->status;
-
-       talloc_steal(state, c);
-
-       state->state = CTDB_CALL_DONE;
-
-       if (state->async.fn) {
-               state->async.fn(state);
-       }
-}
-
-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
- */
-static void ctdb_client_read_cb(uint8_t *data, size_t cnt, void *args)
-{
-       struct ctdb_context *ctdb = talloc_get_type(args, struct ctdb_context);
-       struct ctdb_req_header *hdr = (struct ctdb_req_header *)data;
-       TALLOC_CTX *tmp_ctx;
-
-       /* place the packet as a child of a 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
-          talloc_free() will be a no-op */
-       tmp_ctx = talloc_new(ctdb);
-       talloc_steal(tmp_ctx, hdr);
-
-       if (cnt == 0) {
-               DEBUG(DEBUG_INFO,("Daemon has exited - shutting down client\n"));
-               exit(0);
-       }
-
-       if (cnt < sizeof(*hdr)) {
-               DEBUG(DEBUG_CRIT,("Bad packet length %u in client\n", (unsigned)cnt));
-               goto done;
-       }
-       if (cnt != hdr->length) {
-               ctdb_set_error(ctdb, "Bad header length %u expected %u in client\n", 
-                              (unsigned)hdr->length, (unsigned)cnt);
-               goto done;
-       }
-
-       if (hdr->ctdb_magic != CTDB_MAGIC) {
-               ctdb_set_error(ctdb, "Non CTDB packet rejected in client\n");
-               goto done;
-       }
-
-       if (hdr->ctdb_version != CTDB_VERSION) {
-               ctdb_set_error(ctdb, "Bad CTDB version 0x%x rejected in client\n", hdr->ctdb_version);
-               goto done;
-       }
-
-       switch (hdr->operation) {
-       case CTDB_REPLY_CALL:
-               ctdb_client_reply_call(ctdb, hdr);
-               break;
-
-       case CTDB_REQ_MESSAGE:
-               ctdb_request_message(ctdb, hdr);
-               break;
-
-       case CTDB_REPLY_CONTROL:
-               ctdb_client_reply_control(ctdb, hdr);
-               break;
-
-       default:
-               DEBUG(DEBUG_CRIT,("bogus operation code:%u\n",hdr->operation));
-       }
-
-done:
-       talloc_free(tmp_ctx);
-}
-
-/*
-  connect to a unix domain socket
-*/
-int ctdb_socket_connect(struct ctdb_context *ctdb)
-{
-       struct sockaddr_un addr;
-
-       memset(&addr, 0, sizeof(addr));
-       addr.sun_family = AF_UNIX;
-       strncpy(addr.sun_path, ctdb->daemon.name, sizeof(addr.sun_path));
-
-       ctdb->daemon.sd = socket(AF_UNIX, SOCK_STREAM, 0);
-       if (ctdb->daemon.sd == -1) {
-               DEBUG(DEBUG_ERR,(__location__ " Failed to open client socket. Errno:%s(%d)\n", strerror(errno), errno));
-               return -1;
-       }
-
-       set_nonblocking(ctdb->daemon.sd);
-       set_close_on_exec(ctdb->daemon.sd);
-       
-       if (connect(ctdb->daemon.sd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
-               close(ctdb->daemon.sd);
-               ctdb->daemon.sd = -1;
-               DEBUG(DEBUG_ERR,(__location__ " Failed to connect client socket to daemon. Errno:%s(%d)\n", strerror(errno), errno));
-               return -1;
-       }
-
-       ctdb->daemon.queue = ctdb_queue_setup(ctdb, ctdb, ctdb->daemon.sd, 
-                                             CTDB_DS_ALIGNMENT, 
-                                             ctdb_client_read_cb, ctdb);
-       return 0;
-}
 
 
 struct ctdb_record_handle {
@@ -333,129 +79,7 @@ int ctdb_call_recv(struct ctdb_client_call_state *state, struct ctdb_call *call)
 
 
 
-/*
-  destroy a ctdb_call in client
-*/
-static int ctdb_client_call_destructor(struct ctdb_client_call_state *state)   
-{
-       ctdb_reqid_remove(state->ctdb_db->ctdb, state->reqid);
-       return 0;
-}
-
-/*
-  construct an event driven local ctdb_call
-
-  this is used so that locally processed ctdb_call requests are processed
-  in an event driven manner
-*/
-static struct ctdb_client_call_state *ctdb_client_call_local_send(struct ctdb_db_context *ctdb_db, 
-                                                                 struct ctdb_call *call,
-                                                                 struct ctdb_ltdb_header *header,
-                                                                 TDB_DATA *data)
-{
-       struct ctdb_client_call_state *state;
-       struct ctdb_context *ctdb = ctdb_db->ctdb;
-       int ret;
-
-       state = talloc_zero(ctdb_db, struct ctdb_client_call_state);
-       CTDB_NO_MEMORY_NULL(ctdb, state);
-       state->call = talloc_zero(state, struct ctdb_call);
-       CTDB_NO_MEMORY_NULL(ctdb, state->call);
-
-       talloc_steal(state, data->dptr);
-
-       state->state   = CTDB_CALL_DONE;
-       *(state->call) = *call;
-       state->ctdb_db = ctdb_db;
 
-       ret = ctdb_call_local(ctdb_db, state->call, header, state, data, ctdb->pnn);
-
-       return state;
-}
-
-/*
-  make a ctdb call to the local daemon - async send. Called from client context.
-
-  This constructs a ctdb_call request and queues it for processing. 
-  This call never blocks.
-*/
-struct ctdb_client_call_state *ctdb_call_send(struct ctdb_db_context *ctdb_db, 
-                                             struct ctdb_call *call)
-{
-       struct ctdb_client_call_state *state;
-       struct ctdb_context *ctdb = ctdb_db->ctdb;
-       struct ctdb_ltdb_header header;
-       TDB_DATA data;
-       int ret;
-       size_t len;
-       struct ctdb_req_call *c;
-
-       /* if the domain socket is not yet open, open it */
-       if (ctdb->daemon.sd==-1) {
-               ctdb_socket_connect(ctdb);
-       }
-
-       ret = ctdb_ltdb_lock(ctdb_db, call->key);
-       if (ret != 0) {
-               DEBUG(DEBUG_ERR,(__location__ " Failed to get chainlock\n"));
-               return NULL;
-       }
-
-       ret = ctdb_ltdb_fetch(ctdb_db, call->key, &header, ctdb_db, &data);
-
-       if (ret == 0 && header.dmaster == ctdb->pnn) {
-               state = ctdb_client_call_local_send(ctdb_db, call, &header, &data);
-               talloc_free(data.dptr);
-               ctdb_ltdb_unlock(ctdb_db, call->key);
-               return state;
-       }
-
-       ctdb_ltdb_unlock(ctdb_db, call->key);
-       talloc_free(data.dptr);
-
-       state = talloc_zero(ctdb_db, struct ctdb_client_call_state);
-       if (state == NULL) {
-               DEBUG(DEBUG_ERR, (__location__ " failed to allocate state\n"));
-               return NULL;
-       }
-       state->call = talloc_zero(state, struct ctdb_call);
-       if (state->call == NULL) {
-               DEBUG(DEBUG_ERR, (__location__ " failed to allocate state->call\n"));
-               return NULL;
-       }
-
-       len = offsetof(struct ctdb_req_call, data) + call->key.dsize + call->call_data.dsize;
-       c = ctdbd_allocate_pkt(ctdb, state, CTDB_REQ_CALL, len, struct ctdb_req_call);
-       if (c == NULL) {
-               DEBUG(DEBUG_ERR, (__location__ " failed to allocate packet\n"));
-               return NULL;
-       }
-
-       state->reqid     = ctdb_reqid_new(ctdb, state);
-       state->ctdb_db = ctdb_db;
-       talloc_set_destructor(state, ctdb_client_call_destructor);
-
-       c->hdr.reqid     = state->reqid;
-       c->flags         = call->flags;
-       c->db_id         = ctdb_db->db_id;
-       c->callid        = call->call_id;
-       c->hopcount      = 0;
-       c->keylen        = call->key.dsize;
-       c->calldatalen   = call->call_data.dsize;
-       memcpy(&c->data[0], call->key.dptr, call->key.dsize);
-       memcpy(&c->data[call->key.dsize], 
-              call->call_data.dptr, call->call_data.dsize);
-       *(state->call)              = *call;
-       state->call->call_data.dptr = &c->data[call->key.dsize];
-       state->call->key.dptr       = &c->data[0];
-
-       state->state  = CTDB_CALL_WAIT;
-
-
-       ctdb_client_queue_pkt(ctdb, &c->hdr);
-
-       return state;
-}
 
 
 /*
@@ -514,33 +138,6 @@ int ctdb_remove_message_handler(struct ctdb_context *ctdb, uint64_t srvid, void
 }
 
 
-/*
-  send a message - from client context
- */
-int ctdb_send_message(struct ctdb_context *ctdb, uint32_t pnn,
-                     uint64_t srvid, TDB_DATA data)
-{
-       struct ctdb_req_message *r;
-       int len, res;
-
-       len = offsetof(struct ctdb_req_message, data) + data.dsize;
-       r = ctdbd_allocate_pkt(ctdb, ctdb, CTDB_REQ_MESSAGE, 
-                              len, struct ctdb_req_message);
-       CTDB_NO_MEMORY(ctdb, r);
-
-       r->hdr.destnode  = pnn;
-       r->srvid         = srvid;
-       r->datalen       = data.dsize;
-       memcpy(&r->data[0], data.dptr, data.dsize);
-       
-       res = ctdb_client_queue_pkt(ctdb, &r->hdr);
-       if (res != 0) {
-               return res;
-       }
-
-       talloc_free(r);
-       return 0;
-}
 
 
 /*
@@ -679,242 +276,8 @@ int ctdb_fetch(struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx,
 
 
 
-/*
-   called when a control completes or timesout to invoke the callback
-   function the user provided
-*/
-static void invoke_control_callback(struct event_context *ev, struct timed_event *te, 
-       struct timeval t, void *private_data)
-{
-       struct ctdb_client_control_state *state;
-       TALLOC_CTX *tmp_ctx = talloc_new(NULL);
-       int ret;
-
-       state = talloc_get_type(private_data, struct ctdb_client_control_state);
-       talloc_steal(tmp_ctx, state);
-
-       ret = ctdb_control_recv(state->ctdb, state, state,
-                       NULL, 
-                       NULL, 
-                       NULL);
-
-       talloc_free(tmp_ctx);
-}
-
-/*
-  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(DEBUG_ERR,(__location__ " reqid %u not found\n", hdr->reqid));
-               return;
-       }
-
-       if (hdr->reqid != state->reqid) {
-               /* we found a record  but it was the wrong one */
-               DEBUG(DEBUG_ERR, ("Dropped orphaned reply control with reqid:%u\n",hdr->reqid));
-               return;
-       }
-
-       state->outdata.dptr = c->data;
-       state->outdata.dsize = c->datalen;
-       state->status = c->status;
-       if (c->errorlen) {
-               state->errormsg = talloc_strndup(state, 
-                                                (char *)&c->data[c->datalen], 
-                                                c->errorlen);
-       }
-
-       /* state->outdata now uses resources from c so we dont want c
-          to just dissappear from under us while state is still alive
-       */
-       talloc_steal(state, c);
-
-       state->state = CTDB_CONTROL_DONE;
-
-       /* if we had a callback registered for this control, pull the response
-          and call the callback.
-       */
-       if (state->async.fn) {
-               event_add_timed(ctdb->ev, state, timeval_zero(), invoke_control_callback, state);
-       }
-}
-
-
-/*
-  destroy a ctdb_control in client
-*/
-static int ctdb_control_destructor(struct ctdb_client_control_state *state)    
-{
-       ctdb_reqid_remove(state->ctdb, state->reqid);
-       return 0;
-}
-
-
-/* time out handler for ctdb_control */
-static void control_timeout_func(struct event_context *ev, struct timed_event *te, 
-       struct timeval t, void *private_data)
-{
-       struct ctdb_client_control_state *state = talloc_get_type(private_data, struct ctdb_client_control_state);
-
-       DEBUG(DEBUG_ERR,(__location__ " control timed out. reqid:%u opcode:%u "
-                        "dstnode:%u\n", state->reqid, state->c->opcode,
-                        state->c->hdr.destnode));
-
-       state->state = CTDB_CONTROL_TIMEOUT;
-
-       /* if we had a callback registered for this control, pull the response
-          and call the callback.
-       */
-       if (state->async.fn) {
-               event_add_timed(state->ctdb->ev, state, timeval_zero(), invoke_control_callback, state);
-       }
-}
-
-/* async version of send control request */
-struct ctdb_client_control_state *ctdb_control_send(struct ctdb_context *ctdb, 
-               uint32_t destnode, uint64_t srvid, 
-               uint32_t opcode, uint32_t flags, TDB_DATA data, 
-               TALLOC_CTX *mem_ctx,
-               struct timeval *timeout,
-               char **errormsg)
-{
-       struct ctdb_client_control_state *state;
-       size_t len;
-       struct ctdb_req_control *c;
-       int ret;
-
-       if (errormsg) {
-               *errormsg = NULL;
-       }
-
-       /* if the domain socket is not yet open, open it */
-       if (ctdb->daemon.sd==-1) {
-               ctdb_socket_connect(ctdb);
-       }
-
-       state = talloc_zero(mem_ctx, struct ctdb_client_control_state);
-       CTDB_NO_MEMORY_NULL(ctdb, state);
-
-       state->ctdb       = ctdb;
-       state->reqid      = ctdb_reqid_new(ctdb, state);
-       state->state      = CTDB_CONTROL_WAIT;
-       state->errormsg   = NULL;
-
-       talloc_set_destructor(state, ctdb_control_destructor);
-
-       len = offsetof(struct ctdb_req_control, data) + data.dsize;
-       c = ctdbd_allocate_pkt(ctdb, state, CTDB_REQ_CONTROL, 
-                              len, struct ctdb_req_control);
-       state->c            = c;        
-       CTDB_NO_MEMORY_NULL(ctdb, c);
-       c->hdr.reqid        = state->reqid;
-       c->hdr.destnode     = destnode;
-       c->opcode           = opcode;
-       c->client_id        = 0;
-       c->flags            = flags;
-       c->srvid            = srvid;
-       c->datalen          = data.dsize;
-       if (data.dsize) {
-               memcpy(&c->data[0], data.dptr, data.dsize);
-       }
-
-       /* timeout */
-       if (timeout && !timeval_is_zero(timeout)) {
-               event_add_timed(ctdb->ev, state, *timeout, control_timeout_func, state);
-       }
-
-       ret = ctdb_client_queue_pkt(ctdb, &(c->hdr));
-       if (ret != 0) {
-               talloc_free(state);
-               return NULL;
-       }
-
-       if (flags & CTDB_CTRL_FLAG_NOREPLY) {
-               talloc_free(state);
-               return NULL;
-       }
-
-       return state;
-}
-
-
-/* async version of receive control reply */
-int ctdb_control_recv(struct ctdb_context *ctdb, 
-               struct ctdb_client_control_state *state, 
-               TALLOC_CTX *mem_ctx,
-               TDB_DATA *outdata, int32_t *status, char **errormsg)
-{
-       TALLOC_CTX *tmp_ctx;
-
-       if (status != NULL) {
-               *status = -1;
-       }
-       if (errormsg != NULL) {
-               *errormsg = NULL;
-       }
-
-       if (state == NULL) {
-               return -1;
-       }
-
-       /* prevent double free of state */
-       tmp_ctx = talloc_new(ctdb);
-       talloc_steal(tmp_ctx, state);
-
-       /* loop one event at a time until we either timeout or the control
-          completes.
-       */
-       while (state->state == CTDB_CONTROL_WAIT) {
-               event_loop_once(ctdb->ev);
-       }
-
-       if (state->state != CTDB_CONTROL_DONE) {
-               DEBUG(DEBUG_ERR,(__location__ " ctdb_control_recv failed\n"));
-               if (state->async.fn) {
-                       state->async.fn(state);
-               }
-               talloc_free(tmp_ctx);
-               return -1;
-       }
-
-       if (state->errormsg) {
-               DEBUG(DEBUG_ERR,("ctdb_control error: '%s'\n", state->errormsg));
-               if (errormsg) {
-                       (*errormsg) = talloc_move(mem_ctx, &state->errormsg);
-               }
-               if (state->async.fn) {
-                       state->async.fn(state);
-               }
-               talloc_free(tmp_ctx);
-               return -1;
-       }
-
-       if (outdata) {
-               *outdata = state->outdata;
-               outdata->dptr = talloc_memdup(mem_ctx, outdata->dptr, outdata->dsize);
-       }
-
-       if (status) {
-               *status = state->status;
-       }
 
-       if (state->async.fn) {
-               state->async.fn(state);
-       }
 
-       talloc_free(tmp_ctx);
-       return 0;
-}
 
 
 
@@ -2937,16 +2300,6 @@ void ctdb_set_flags(struct ctdb_context *ctdb, unsigned flags)
        ctdb->flags |= flags;
 }
 
-/*
-  setup the local socket name
-*/
-int ctdb_set_socketname(struct ctdb_context *ctdb, const char *socketname)
-{
-       ctdb->daemon.name = talloc_strdup(ctdb, socketname);
-       CTDB_NO_MEMORY(ctdb, ctdb->daemon.name);
-
-       return 0;
-}
 
 /*
   return the pnn of this node
index ea4d2716302e8abd2281bd76db1a0dcdc550ec68..d0870ceb151629ad016d99109013095c9fbf6819 100644 (file)
@@ -77,7 +77,7 @@ static void log_ringbuffer_v(const char *format, va_list ap)
        }
 }
 
-void log_ringbuffer(const char *format, ...)
+static void log_ringbuffer(const char *format, ...)
 {
        va_list ap;
 
@@ -184,3 +184,8 @@ int32_t ctdb_control_clear_log(struct ctdb_context *ctdb)
        return 0;
 }
 
+int ctdb_init_log(void)
+{
+       ctdb_ringbuf_log = log_ringbuffer;
+       return 0;
+}
index cb7c165f5e663005e8cd059cfdd784bc3a58ae62..547dc5286561dbf585643694cd6b6724bae44689 100644 (file)
@@ -969,6 +969,10 @@ struct ctdb_req_header *_ctdb_transport_allocate(struct ctdb_context *ctdb,
 #define ctdb_transport_allocate(ctdb, mem_ctx, operation, length, type) \
        (type *)_ctdb_transport_allocate(ctdb, mem_ctx, operation, length, sizeof(type), #type)
 
+
+/*
+ * Get the number of PDUs currently queued for this ctdb_queue
+ */
 int ctdb_queue_length(struct ctdb_queue *queue);
 
 /*
@@ -1609,6 +1613,7 @@ struct ctdb_get_log_addr {
 };
 
 extern int log_ringbuf_size;
+int ctdb_init_log(void);
 
 int32_t ctdb_control_get_log(struct ctdb_context *ctdb, TDB_DATA addr);
 int32_t ctdb_control_clear_log(struct ctdb_context *ctdb);
index 43a6a5ff68746a6c0fe8a488ec0780e78add469e..7e1566c3bf433a6e46d6bc81f2c37c99ff8e3ff9 100644 (file)
@@ -27,8 +27,11 @@ enum debug_level {
        DEBUG_DEBUG   =  4,
 };
 
+typedef void ctdb_ringbuf_log_fn(const char *format, ...);
+extern ctdb_ringbuf_log_fn *ctdb_ringbuf_log;
+
 #define DEBUGLVL(lvl) ((lvl) <= LogLevel)
-#define DEBUG(lvl, x) do { this_log_level = (lvl); if ((lvl) < DEBUG_DEBUG) { log_ringbuffer x; } if ((lvl) <= LogLevel) { do_debug x; }} while (0)
+#define DEBUG(lvl, x) do { this_log_level = (lvl); if (ctdb_ringbuf_log && (lvl) < DEBUG_DEBUG) { ctdb_ringbuf_log x; } if ((lvl) <= LogLevel) { do_debug x; }} while (0)
 #define DEBUGADD(lvl, x) do { if ((lvl) <= LogLevel) { this_log_level = (lvl); do_debug_add x; }} while (0)
 
 #define _PUBLIC_
diff --git a/include/libctdb.h b/include/libctdb.h
new file mode 100644 (file)
index 0000000..9a14a7e
--- /dev/null
@@ -0,0 +1,57 @@
+/* 
+   ctdb database library
+
+   Copyright (C) Ronnie sahlberg 2010
+
+   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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _LIBCTDB_H
+#define _LIBCTDB_H
+
+/*
+ * initialize the l;ibctdb layer and connect to the daemon 
+ */
+struct ctdb_context *libctdb_connect(const char *addr);
+
+/*
+ * get the filedescriptor for the event system.
+ */
+int libctdb_get_fd(struct ctdb_context *ctdb);
+
+/*
+ * what events do we need to trigger on right now
+ * we always trigger on POLLIN in case ctdb has a packet for us,
+ * but we also trigger on POLLOUT in case the message queue
+ * is in use and we need to wait for the socket to become writeable
+ */
+int libctdb_which_events(struct ctdb_context *ctdb);
+
+/*
+ * called when there are events that libctdb needs to service
+ */
+int libctdb_service(struct ctdb_context *ctdb);
+
+
+
+typedef void (*get_recmaster_cb)(int32_t status, int32_t recmaster, void *private_data);
+
+struct ctdb_client_control_state *
+libctdb_getrecmaster_send_cb(struct ctdb_context *ctdb,
+                       uint32_t destnode,
+                       get_recmaster_cb callback,
+                       void *private_data);
+
+
+#endif
index 053ae6117c13f36d3c4a4c9747989cb3edec1c18..86a7d6256ecaf730aa5fbc4cfb35d9f92e31a2ed 100644 (file)
@@ -475,14 +475,14 @@ static int epoll_event_loop_wait(struct event_context *ev)
 }
 
 static const struct event_ops epoll_event_ops = {
-       .context_init   = epoll_event_context_init,
-       .add_fd         = epoll_event_add_fd,
-       .get_fd_flags   = epoll_event_get_fd_flags,
-       .set_fd_flags   = epoll_event_set_fd_flags,
-       .add_timed      = common_event_add_timed,
-       .add_signal     = common_event_add_signal,
-       .loop_once      = epoll_event_loop_once,
-       .loop_wait      = epoll_event_loop_wait,
+       .context_init           = epoll_event_context_init,
+       .add_fd                 = epoll_event_add_fd,
+       .get_fd_flags           = epoll_event_get_fd_flags,
+       .set_fd_flags           = epoll_event_set_fd_flags,
+       .add_timed              = common_event_add_timed,
+       .add_signal             = common_event_add_signal,
+       .loop_once              = epoll_event_loop_once,
+       .loop_wait              = epoll_event_loop_wait,
 };
 
 bool events_epoll_init(void)
index 11ecb19786f9907d0644bce7bb3cee28dd5ee760..bc884ae12e99b5d851be24747313560b9bfff0e9 100644 (file)
@@ -19,7 +19,6 @@
 
 void (*do_debug_v)(const char *, va_list ap);
 void (*do_debug_add_v)(const char *, va_list ap);
-void log_ringbuffer(const char *format, ...);
 void do_debug(const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
 void do_debug_add(const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
 void dump_data(int level, const uint8_t *buf1, size_t len);
diff --git a/libctdb/ctdb_connect.c b/libctdb/ctdb_connect.c
new file mode 100644 (file)
index 0000000..de0a5b3
--- /dev/null
@@ -0,0 +1,175 @@
+/* 
+   ctdb database library
+   Utility functions to connect to the ctdb daemon
+
+   Copyright (C) Andrew Tridgell  2006
+   Copyright (C) Ronnie sahlberg  2010
+
+   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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <poll.h>
+#include "includes.h"
+#include "include/libctdb.h"
+#include "lib/events/events.h"
+#include "include/ctdb_private.h"
+
+struct ctdb_context *libctdb_connect(const char *addr)
+{
+       struct event_context *ev;
+       struct ctdb_context *ctdb;
+       int ret;
+
+       ev = event_context_init(NULL);
+
+       /* initialise ctdb */
+       ctdb = ctdb_init(ev);
+       if (ctdb == NULL) {
+               fprintf(stderr, "Failed to init ctdb\n");
+               exit(1);
+       }
+
+       ret = ctdb_set_socketname(ctdb, addr);
+       if (ret == -1) {
+               fprintf(stderr, __location__ " ctdb_set_socketname failed - %s\n", ctdb_errstr(ctdb));
+               talloc_free(ctdb);
+               exit(1);
+       }
+
+       ret = ctdb_socket_connect(ctdb);
+       if (ret != 0) {
+               fprintf(stderr, __location__ " Failed to connect to daemon\n");
+               talloc_free(ctdb);
+               return NULL;
+       }
+
+       return ctdb;
+}
+
+
+int libctdb_get_fd(struct ctdb_context *ctdb)
+{
+       return ctdb->daemon.sd;
+}
+
+int libctdb_which_events(struct ctdb_context *ctdb)
+{
+       if (ctdb_queue_length(ctdb->daemon.queue) > 0) {
+               return POLLIN|POLLOUT;
+       }
+
+       return POLLIN;
+}
+
+
+
+/*
+  initialise the ctdb daemon for client applications
+*/
+struct ctdb_context *ctdb_init(struct event_context *ev)
+{
+       int ret;
+       struct ctdb_context *ctdb;
+
+       ctdb = talloc_zero(ev, struct ctdb_context);
+       if (ctdb == NULL) {
+               DEBUG(DEBUG_ERR,(__location__ " talloc_zero failed.\n"));
+               return NULL;
+       }
+       ctdb->ev  = ev;
+       ctdb->idr = idr_init(ctdb);
+       CTDB_NO_MEMORY_NULL(ctdb, ctdb->idr);
+
+       ret = ctdb_set_socketname(ctdb, CTDB_PATH);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR,(__location__ " ctdb_set_socketname failed.\n"));
+               talloc_free(ctdb);
+               return NULL;
+       }
+
+
+
+       return ctdb;
+}
+
+
+
+/* Ouch.
+ * This is a bit hairy. due to the way ctdbd uses events.
+ * ctdbd quite frequently uses 
+ *     event_add_timed(... timeval_zero() ...)
+ *
+ * for example once it has finished reading off a full pdu off the
+ * domain socket, before calling the actual recdeive function.
+ *
+ * we probably need a new event function to handle these timed events
+ * event_loop_all_queued() or similar
+ */
+int libctdb_service(struct ctdb_context *ctdb)
+{
+       int ret;
+
+       ret = event_loop_once(ctdb->ev);
+       ret = event_loop_once(ctdb->ev);
+
+       return 0;
+}
+
+
+
+struct libctdb_control_cb_data {
+       void *callback;
+       void *private_data;
+};
+
+
+static void
+libctdb_getrecmaster_recv_cb(struct ctdb_client_control_state *state)
+{
+       struct libctdb_control_cb_data *cb_data = state->async.private_data;
+       get_recmaster_cb callback = (get_recmaster_cb)cb_data->callback;
+
+       callback(0, state->status, cb_data->private_data);
+}
+
+/*
+  get the recovery master of a remote node
+ */
+struct ctdb_client_control_state *
+libctdb_getrecmaster_send_cb(struct ctdb_context *ctdb,
+                       uint32_t destnode,
+                       get_recmaster_cb callback,
+                       void *private_data)
+{
+       struct ctdb_client_control_state *state;
+       struct libctdb_control_cb_data *cb_data;
+
+       state = ctdb_control_send(ctdb, destnode, 0, 
+                          CTDB_CONTROL_GET_RECMASTER, 0, tdb_null, 
+                          ctdb, NULL, NULL);
+
+       cb_data = talloc(state, struct libctdb_control_cb_data);
+       cb_data->callback     = callback;
+       cb_data->private_data = private_data;
+
+       state->async.fn           = libctdb_getrecmaster_recv_cb;
+       state->async.private_data = cb_data;
+
+       return state;
+}
+
+
+
+
+
similarity index 100%
rename from common/ctdb_io.c
rename to libctdb/ctdb_io.c
similarity index 100%
rename from common/ctdb_ltdb.c
rename to libctdb/ctdb_ltdb.c
similarity index 100%
rename from common/ctdb_message.c
rename to libctdb/ctdb_message.c
similarity index 98%
rename from common/ctdb_util.c
rename to libctdb/ctdb_util.c
index 433a2ad8578b29421449984c6af44814f6666af7..d1b396d1c471e2259e035aa6410bc1f3ccdb9509 100644 (file)
 int LogLevel = DEBUG_NOTICE;
 int this_log_level = 0;
 
+ctdb_ringbuf_log_fn *ctdb_ringbuf_log = NULL;
+
+pid_t ctdbd_pid;
+
 /*
   return error string for last error
 */
@@ -685,3 +689,14 @@ const char *ctdb_eventscript_call_names[] = {
        "reload",
        "updateip"
 };
+
+/*
+  setup the local socket name
+*/
+int ctdb_set_socketname(struct ctdb_context *ctdb, const char *socketname)
+{
+       ctdb->daemon.name = talloc_strdup(ctdb, socketname);
+       CTDB_NO_MEMORY(ctdb, ctdb->daemon.name);
+
+       return 0;
+}
diff --git a/libctdb/tst.c b/libctdb/tst.c
new file mode 100644 (file)
index 0000000..6e1cd21
--- /dev/null
@@ -0,0 +1,35 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <poll.h>
+#include "include/libctdb.h"
+
+
+void rm_cb(int32_t status, int32_t recmaster, void *private_data)
+{
+       printf("recmaster:%d\n", recmaster);
+}
+
+int main(int argc, char *argv[])
+{
+       struct ctdb_context *ctdb_context;
+       struct ctdb_client_control_state *state;
+       struct pollfd pfd;
+
+       ctdb_context = libctdb_connect("/tmp/ctdb.socket");
+
+
+       pfd.fd = libctdb_get_fd(ctdb_context);
+
+       state = libctdb_getrecmaster_send_cb(ctdb_context, 0, rm_cb, NULL);
+
+       for (;;) {
+         pfd.events = libctdb_which_events(ctdb_context);
+         if (poll(&pfd, 1, -1) < 0) {
+           printf("Poll failed");
+           exit(10);
+         }
+         libctdb_service(ctdb_context);
+       }
+
+       return 0;
+}
index a7ca1a1df99aeba36437779e5872aa8622dcee2a..4bfdfea2ff3fd8ffd3143f5a953a91bc4fe5c583 100644 (file)
@@ -317,6 +317,8 @@ int ctdb_set_logfile(struct ctdb_context *ctdb, const char *logfile, bool use_sy
 {
        int ret;
 
+       ctdb_init_log();
+
        ctdb->log = talloc_zero(ctdb, struct ctdb_log_state);
        if (ctdb->log == NULL) {
                printf("talloc_zero failed\n");