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;
}
}
*path = talloc_strdup(mem_ctx, (const char *)tmppath);
- free(discard_const(tmppath));
+ talloc_free(discard_const(tmppath));
if (*path == NULL) {
return -1;
return 0;
}
+
+
/*
attach to a specific database - client call
*/
}
-/*
- 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 {
/*
* 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);
+
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
/*
* 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);
/*
* cancel a request/call
*/
-int ctdb_cancel(ctdb_handle *);
+int ctdb_free(ctdb_handle *);
#include <poll.h>
#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 <sys/time.h>
+#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)
{
-int ctdb_cancel(ctdb_handle *handle)
+int ctdb_free(ctdb_handle *handle)
{
talloc_free(handle);
return 0;
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 *
}
if (state->status == 0 && path != NULL) {
- *path = strdup((char *)data.dptr);
+ *path = talloc_strdup(ctdb, (char *)data.dptr);
}
talloc_free(tmp_ctx);
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 **);
+