From: Ronnie Sahlberg Date: Mon, 17 May 2010 02:30:22 +0000 (+1000) Subject: create an async version of ctdb_attachdb_send() for libctdb X-Git-Url: http://git.samba.org/?p=sahlberg%2Fctdb.git;a=commitdiff_plain;h=3bda422d53c481c4df638f95425e956651368819 create an async version of ctdb_attachdb_send() for libctdb --- diff --git a/client/ctdb_client.c b/client/ctdb_client.c index 0840cfd2..1552c414 100644 --- a/client/ctdb_client.c +++ b/client/ctdb_client.c @@ -808,7 +808,7 @@ int ctdb_ctrl_getdbpath(struct ctdb_context *ctdb, struct timeval timeout, uint3 if (ret != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb control for getdbpath failed\n")); if (tmppath != NULL) { - free(discard_const(tmppath)); + talloc_free(discard_const(tmppath)); } return -1; } @@ -818,7 +818,7 @@ int ctdb_ctrl_getdbpath(struct ctdb_context *ctdb, struct timeval timeout, uint3 } *path = talloc_strdup(mem_ctx, (const char *)tmppath); - free(discard_const(tmppath)); + talloc_free(discard_const(tmppath)); if (*path == NULL) { return -1; @@ -1039,6 +1039,8 @@ static int ctdb_fetch_func(struct ctdb_call_info *call) return 0; } + + /* attach to a specific database - client call */ @@ -1112,43 +1114,6 @@ struct ctdb_db_context *ctdb_attach(struct ctdb_context *ctdb, const char *name, } -/* - setup a call for a database - */ -int ctdb_set_call(struct ctdb_db_context *ctdb_db, ctdb_fn_t fn, uint32_t id) -{ - struct ctdb_registered_call *call; - -#if 0 - TDB_DATA data; - int32_t status; - struct ctdb_control_set_call c; - int ret; - - /* this is no longer valid with the separate daemon architecture */ - c.db_id = ctdb_db->db_id; - c.fn = fn; - c.id = id; - - data.dptr = (uint8_t *)&c; - data.dsize = sizeof(c); - - ret = ctdb_control(ctdb_db->ctdb, CTDB_CURRENT_NODE, 0, CTDB_CONTROL_SET_CALL, 0, - data, NULL, NULL, &status, NULL, NULL); - if (ret != 0 || status != 0) { - DEBUG(DEBUG_ERR,("ctdb_set_call failed for call %u\n", id)); - return -1; - } -#endif - - /* also register locally */ - call = talloc(ctdb_db, struct ctdb_registered_call); - call->fn = fn; - call->id = id; - - DLIST_ADD(ctdb_db->calls, call); - return 0; -} struct traverse_state { diff --git a/include/ctdb.h b/include/ctdb.h index 7b2d5c04..7ccedaaf 100644 --- a/include/ctdb.h +++ b/include/ctdb.h @@ -32,6 +32,8 @@ /* * Connect to ctdb using the specified domain socket. * Returns a ctdb context if successful or NULL. + * + * Use ctdb_free() to release the returned ctdb_context when finished. */ struct ctdb_context *ctdb_connect(const char *addr); @@ -58,9 +60,33 @@ int ctdb_service(struct ctdb_context *ctdb); + typedef void ctdb_handle; +/* + * functions to attach to a database + * if the database does not exist it will be created. + * + * Use ctdb_free() to release the returned ctdb_db_context when finished. + */ +struct ctdb_db_context; + +typedef void (*ctdb_attachdb_cb)(int32_t status, struct ctdb_db_context *ctdb_db, void *private_data); + +ctdb_handle * +ctdb_attachdb_send(struct ctdb_context *ctdb, uint32_t destnode, + const char *name, int persistent, uint32_t tdb_flags, + ctdb_attachdb_cb callback, + void *private_data); +int ctdb_attachdb_recv(struct ctdb_context *ctdb, + ctdb_handle *handle, struct ctdb_db_context **); +int ctdb_attachdb(struct ctdb_context *ctdb, uint32_t destnode, + const char *name, int persistent, uint32_t tdb_flags, + struct ctdb_db_context **); + + + /* * messaging functions * these functions provide a messaging layer for applications to communicate @@ -174,7 +200,9 @@ int ctdb_createdb(struct ctdb_context *ctdb, uint32_t destnode, /* * functions to find the filename of a database - * the caller is responsible to free() path + * + * the caller is responsible to release *path when finished with it using + * ctdb_free() */ typedef void (*ctdb_getdbpath_cb)(int32_t status, const char *path, void *private_data); @@ -193,7 +221,7 @@ int ctdb_getdbpath(struct ctdb_context *ctdb, uint32_t destnode, /* * cancel a request/call */ -int ctdb_cancel(ctdb_handle *); +int ctdb_free(ctdb_handle *); diff --git a/libctdb/ctdb_client.c b/libctdb/ctdb_client.c index 23faa4b5..864877ce 100644 --- a/libctdb/ctdb_client.c +++ b/libctdb/ctdb_client.c @@ -654,4 +654,40 @@ int ctdb_send_message(struct ctdb_context *ctdb, uint32_t pnn, +/* + setup a call for a database + */ +int ctdb_set_call(struct ctdb_db_context *ctdb_db, ctdb_fn_t fn, uint32_t id) +{ + struct ctdb_registered_call *call; + +#if 0 + TDB_DATA data; + int32_t status; + struct ctdb_control_set_call c; + int ret; + + /* this is no longer valid with the separate daemon architecture */ + c.db_id = ctdb_db->db_id; + c.fn = fn; + c.id = id; + data.dptr = (uint8_t *)&c; + data.dsize = sizeof(c); + + ret = ctdb_control(ctdb_db->ctdb, CTDB_CURRENT_NODE, 0, CTDB_CONTROL_SET_CALL, 0, + data, NULL, NULL, &status, NULL, NULL); + if (ret != 0 || status != 0) { + DEBUG(DEBUG_ERR,("ctdb_set_call failed for call %u\n", id)); + return -1; + } +#endif + + /* also register locally */ + call = talloc(ctdb_db, struct ctdb_registered_call); + call->fn = fn; + call->id = id; + + DLIST_ADD(ctdb_db->calls, call); + return 0; +} diff --git a/libctdb/libctdb.c b/libctdb/libctdb.c index fa76559a..3f8ac64f 100644 --- a/libctdb/libctdb.c +++ b/libctdb/libctdb.c @@ -21,12 +21,36 @@ #include #include "includes.h" +#include "db_wrap.h" +#include "lib/tdb/include/tdb.h" +#include "lib/util/dlinklist.h" #include "lib/events/events.h" #include "lib/events/events_internal.h" #include "include/ctdb.h" #include "include/ctdb_protocol.h" #include "include/ctdb_private.h" #include +#include "system/filesys.h" + + +/* + this is the dummy null procedure that all databases support +*/ +static int ctdb_null_func(struct ctdb_call_info *call) +{ + return 0; +} + +/* + this is a plain fetch procedure that all databases support +*/ +static int ctdb_fetch_func(struct ctdb_call_info *call) +{ + call->reply_data = &call->record_data; + return 0; +} + + struct ctdb_context *ctdb_connect(const char *addr) { @@ -134,7 +158,7 @@ int ctdb_service(struct ctdb_context *ctdb) -int ctdb_cancel(ctdb_handle *handle) +int ctdb_free(ctdb_handle *handle) { talloc_free(handle); return 0; @@ -619,7 +643,7 @@ ctdb_getdbpath_recv_cb(struct ctdb_client_control_state *state) return; } - callback(state->status, strdup((char *)state->outdata.dptr), cb_data->private_data); + callback(state->status, talloc_strdup(state->ctdb, (char *)state->outdata.dptr), cb_data->private_data); } ctdb_handle * @@ -675,7 +699,7 @@ int ctdb_getdbpath_recv(struct ctdb_context *ctdb, ctdb_handle *handle, const ch } if (state->status == 0 && path != NULL) { - *path = strdup((char *)data.dptr); + *path = talloc_strdup(ctdb, (char *)data.dptr); } talloc_free(tmp_ctx); @@ -697,3 +721,186 @@ int ctdb_getdbpath(struct ctdb_context *ctdb, uint32_t destnode, return ctdb_getdbpath_recv(ctdb, state, path); } + + +/* + * Attach to a database + */ + +struct ctdb_attachdb_state { + uint32_t destnode; + struct ctdb_context *ctdb; + struct ctdb_db_context *ctdb_db; + struct ctdb_client_control_state *cdb_state; + struct ctdb_client_control_state *gdp_state; + bool persistent; + uint32_t tdb_flags; + ctdb_attachdb_cb callback; + void *private_data; +}; + + +static void +ctdb_attachdb_recv2_cb(struct ctdb_client_control_state *state) +{ + struct ctdb_attachdb_state *adb_state = + talloc_get_type(state->async.private_data, + struct ctdb_attachdb_state); + ctdb_attachdb_cb callback = (ctdb_attachdb_cb)adb_state->callback; + + struct ctdb_db_context *ctdb_db = + talloc_get_type(adb_state->ctdb_db, + struct ctdb_db_context); + struct ctdb_context *ctdb = + talloc_get_type(ctdb_db->ctdb, + struct ctdb_context); + + uint32_t tdb_flags = adb_state->tdb_flags; + bool persistent = adb_state->persistent; + + if (state->state != CTDB_CONTROL_DONE || state->status != 0) { + DEBUG(DEBUG_ERR,(__location__ " getdbpath control failed with state:%d and status:%d\n", state->state, state->status)); + callback(-1, NULL, adb_state->private_data); + talloc_free(adb_state); + return; + } + ctdb_db->db_path = talloc_strdup(ctdb_db, (char *)state->outdata.dptr); + + tdb_flags = persistent?TDB_DEFAULT:TDB_NOSYNC; + if (ctdb->valgrinding) { + tdb_flags |= TDB_NOMMAP; + } + tdb_flags |= TDB_DISALLOW_NESTING; + + ctdb_db->ltdb = tdb_wrap_open(ctdb, ctdb_db->db_path, 0, tdb_flags, O_RDWR, 0); + if (ctdb_db->ltdb == NULL) { + DEBUG(DEBUG_ERR, (__location__ " Failed to open tdb '%s'\n", ctdb_db->db_path)); + callback(-1, NULL, adb_state->private_data); + talloc_free(adb_state); + return; + } + + ctdb_db->persistent = persistent; + + DLIST_ADD(ctdb->db_list, ctdb_db); + + /* add well known functions */ + ctdb_set_call(ctdb_db, ctdb_null_func, CTDB_NULL_FUNC); + ctdb_set_call(ctdb_db, ctdb_fetch_func, CTDB_FETCH_FUNC); + + + talloc_steal(ctdb, ctdb_db); + callback(0, ctdb_db, adb_state->private_data); + + talloc_free(adb_state); +} + +static void +ctdb_attachdb_recv1_cb(struct ctdb_client_control_state *state) +{ + struct ctdb_attachdb_state *adb_state = + talloc_get_type(state->async.private_data, + struct ctdb_attachdb_state); + ctdb_attachdb_cb callback = (ctdb_attachdb_cb)adb_state->callback; + + if (state->state != CTDB_CONTROL_DONE) { + DEBUG(DEBUG_ERR,(__location__ " createdb control failed with state:%d and status:%d\n", state->state, state->status)); + callback(-1, NULL, adb_state->private_data); + talloc_free(adb_state); + return; + } + + if (state->outdata.dsize != sizeof(uint32_t)) { + DEBUG(DEBUG_ERR, (__location__ " Wrong size of data returned for CREATEDB control. Got %zd bytes but expected %zd\n", state->outdata.dsize, sizeof(uint32_t))); + callback(-1, NULL, adb_state->private_data); + talloc_free(adb_state); + return; + } + + adb_state->ctdb_db->db_id = *(uint32_t *)state->outdata.dptr; + + adb_state->gdp_state = ctdb_getdbpath_send(adb_state->ctdb, adb_state->destnode, adb_state->ctdb_db->db_id, NULL, NULL); + if (state == NULL) { + DEBUG(DEBUG_ERR,(__location__ " ctdb_getdbpath_send() failed.\n")); + callback(-1, NULL, adb_state->private_data); + talloc_free(adb_state); + return; + } + talloc_steal(adb_state, adb_state->gdp_state); + + adb_state->gdp_state->async.fn = ctdb_attachdb_recv2_cb; + adb_state->gdp_state->async.private_data = adb_state; +} + +ctdb_handle * +ctdb_attachdb_send(struct ctdb_context *ctdb, uint32_t destnode, + const char *name, int persistent, uint32_t tdb_flags, + ctdb_attachdb_cb callback, + void *private_data) +{ + struct ctdb_attachdb_state *state; + struct ctdb_db_context *ctdb_db; + + + ctdb_db = ctdb_db_handle(ctdb, name); + if (ctdb_db != NULL) { + return ctdb_db; + } + + state = talloc_zero(ctdb, struct ctdb_attachdb_state); + if (state == NULL) { + DEBUG(DEBUG_ERR,(__location__ " Failed to allocate attachdb_state\n")); + return NULL; + } + + ctdb_db = talloc_zero(state, struct ctdb_db_context); + if (ctdb_db == NULL) { + DEBUG(DEBUG_ERR, (__location__ " Failed to allocate ctdb db context\n")); + talloc_free(state); + return NULL; + } + + state->ctdb = ctdb; + state->ctdb_db = ctdb_db; + state->destnode = destnode; + state->tdb_flags = tdb_flags; + state->persistent = persistent?True:False; + + ctdb_db->ctdb = ctdb; + ctdb_db->db_name = talloc_strdup(ctdb_db, name); + if (ctdb_db->db_name == NULL) { + DEBUG(DEBUG_ERR, (__location__ " Failed to strdup db name\n")); + talloc_free(state); + return NULL; + } + + state->cdb_state = ctdb_createdb_send(ctdb, CTDB_CURRENT_NODE, + name, persistent, tdb_flags, + NULL, NULL); + if (state->cdb_state == NULL) { + DEBUG(DEBUG_ERR, (__location__ " Failed to send CREATEDB control\n")); + talloc_free(ctdb_db); + return NULL; + } + talloc_steal(state, state->cdb_state); + + if (callback != NULL) { + state->callback = callback; + state->private_data = private_data; + + state->cdb_state->async.fn = ctdb_attachdb_recv1_cb; + state->cdb_state->async.private_data = state; + } + + return (ctdb_handle *)state; +} + + + + +int ctdb_attachdb_recv(struct ctdb_context *ctdb, + ctdb_handle *handle, struct ctdb_db_context **); +int ctdb_attachdb(struct ctdb_context *ctdb, uint32_t destnode, + const char *name, int persistent, uint32_t tdb_flags, + struct ctdb_db_context **); + diff --git a/libctdb/tst.c b/libctdb/tst.c index 821ea7f8..08d515eb 100644 --- a/libctdb/tst.c +++ b/libctdb/tst.c @@ -23,6 +23,12 @@ void rm_cb(int32_t status, int32_t recmaster, void *private_data) printf("status:%d recmaster:%d\n", status, recmaster); } +void adb_cb(int32_t status, struct ctdb_db_context *ctdb_db, void *private_data) +{ + printf("status:%d db:%p\n", status, ctdb_db); +} + + int main(int argc, char *argv[]) { struct ctdb_context *ctdb_context; @@ -65,6 +71,12 @@ int main(int argc, char *argv[]) exit(10); } + handle = ctdb_attachdb_send(ctdb_context, CTDB_CURRENT_NODE, "test_test.tdb", 0,0, adb_cb, NULL); + if (handle == NULL) { + printf("Failed to send attachdb control\n"); + exit(10); + } + pfd.fd = ctdb_get_fd(ctdb_context); for (;;) { pfd.events = ctdb_which_events(ctdb_context);