The branch, libctdb has been updated via b28816fecc7c56a15f6027676c9557283ebc4338 (commit) via 9b78ee69040c1b28d4b9190d572795a43d5a9c57 (commit) via 0262c1a9a819f50517724ff6e1170be0fffcb7e8 (commit) from 3e9720d1dea95daf0c442eb2fbcbc1c90a0ccc47 (commit)
http://gitweb.samba.org/?p=sahlberg/ctdb.git;a=shortlog;h=libctdb - Log ----------------------------------------------------------------- commit b28816fecc7c56a15f6027676c9557283ebc4338 Author: Ronnie Sahlberg <ronniesahlb...@gmail.com> Date: Mon May 17 18:40:24 2010 +1000 add a function ctdb_writerecord() to write a record to the database. This function can only be called while hoilding a ctdb_readreacordlock*() handle. Either from the callback provided or after ctdb_readrecordlock_recv() has been called but before ctdb_free() is used to release the handle. commit 9b78ee69040c1b28d4b9190d572795a43d5a9c57 Author: Ronnie Sahlberg <ronniesahlb...@gmail.com> Date: Mon May 17 15:55:40 2010 +1000 move ctdb_call_recv to libctdb commit 0262c1a9a819f50517724ff6e1170be0fffcb7e8 Author: Ronnie Sahlberg <ronniesahlb...@gmail.com> Date: Mon May 17 15:43:37 2010 +1000 createdb and getdbpath does not need to be in the public api ----------------------------------------------------------------------- Summary of changes: client/ctdb_client.c | 175 ----------------------------------------------- include/ctdb.h | 85 ++++++++++++----------- include/ctdb_private.h | 7 ++ include/ctdb_protocol.h | 42 +++++++++++ libctdb/ctdb_client.c | 163 +++++++++++++++++++++++++++++++++++++++++++ libctdb/libctdb.c | 101 ++++++++++++++++++++++----- libctdb/tst.c | 55 +++++++++++++-- 7 files changed, 387 insertions(+), 241 deletions(-) Changeset truncated at 500 lines: diff --git a/client/ctdb_client.c b/client/ctdb_client.c index 56d8b5a..4d49293 100644 --- a/client/ctdb_client.c +++ b/client/ctdb_client.c @@ -33,181 +33,6 @@ -struct ctdb_record_handle { - struct ctdb_db_context *ctdb_db; - TDB_DATA key; - TDB_DATA *data; - struct ctdb_ltdb_header header; -}; - - -/* - make a recv call to the local ctdb daemon - called from client context - - This is called when the program wants to wait for a ctdb_call to complete and get the - results. This call will block unless the call has already completed. -*/ -int ctdb_call_recv(struct ctdb_client_call_state *state, struct ctdb_call *call) -{ - if (state == NULL) { - return -1; - } - - while (state->state < CTDB_CALL_DONE) { - event_loop_once(state->ctdb_db->ctdb->ev); - } - if (state->state != CTDB_CALL_DONE) { - DEBUG(DEBUG_ERR,(__location__ " ctdb_call_recv failed\n")); - talloc_free(state); - return -1; - } - - if (state->call->reply_data.dsize) { - call->reply_data.dptr = talloc_memdup(state->ctdb_db, - state->call->reply_data.dptr, - state->call->reply_data.dsize); - call->reply_data.dsize = state->call->reply_data.dsize; - } else { - call->reply_data.dptr = NULL; - call->reply_data.dsize = 0; - } - call->status = state->call->status; - talloc_free(state); - - return 0; -} - - - - - - - -/* - full ctdb_call. Equivalent to a ctdb_call_send() followed by a ctdb_call_recv() -*/ -int ctdb_call(struct ctdb_db_context *ctdb_db, struct ctdb_call *call) -{ - struct ctdb_client_call_state *state; - - state = ctdb_call_send(ctdb_db, call); - return ctdb_call_recv(state, call); -} - - - - - -/* - cancel a ctdb_fetch_lock operation, releasing the lock - */ -static int fetch_lock_destructor(struct ctdb_record_handle *h) -{ - ctdb_ltdb_unlock(h->ctdb_db, h->key); - return 0; -} - -/* - force the migration of a record to this node - */ -static int ctdb_client_force_migration(struct ctdb_db_context *ctdb_db, TDB_DATA key) -{ - struct ctdb_call call; - ZERO_STRUCT(call); - call.call_id = CTDB_NULL_FUNC; - call.key = key; - call.flags = CTDB_IMMEDIATE_MIGRATION; - return ctdb_call(ctdb_db, &call); -} - -/* - get a lock on a record, and return the records data. Blocks until it gets the lock - */ -struct ctdb_record_handle *ctdb_fetch_lock(struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx, - TDB_DATA key, TDB_DATA *data) -{ - int ret; - struct ctdb_record_handle *h; - - /* - procedure is as follows: - - 1) get the chain lock. - 2) check if we are dmaster - 3) if we are the dmaster then return handle - 4) if not dmaster then ask ctdb daemon to make us dmaster, and wait for - reply from ctdbd - 5) when we get the reply, goto (1) - */ - - h = talloc_zero(mem_ctx, struct ctdb_record_handle); - if (h == NULL) { - return NULL; - } - - h->ctdb_db = ctdb_db; - h->key = key; - h->key.dptr = talloc_memdup(h, key.dptr, key.dsize); - if (h->key.dptr == NULL) { - talloc_free(h); - return NULL; - } - h->data = data; - - DEBUG(DEBUG_DEBUG,("ctdb_fetch_lock: key=%*.*s\n", (int)key.dsize, (int)key.dsize, - (const char *)key.dptr)); - -again: - /* step 1 - get the chain lock */ - ret = ctdb_ltdb_lock(ctdb_db, key); - if (ret != 0) { - DEBUG(DEBUG_ERR, (__location__ " failed to lock ltdb record\n")); - talloc_free(h); - return NULL; - } - - DEBUG(DEBUG_DEBUG,("ctdb_fetch_lock: got chain lock\n")); - - talloc_set_destructor(h, fetch_lock_destructor); - - ret = ctdb_ltdb_fetch(ctdb_db, key, &h->header, h, data); - - /* when torturing, ensure we test the remote path */ - if ((ctdb_db->ctdb->flags & CTDB_FLAG_TORTURE) && - random() % 5 == 0) { - h->header.dmaster = (uint32_t)-1; - } - - - DEBUG(DEBUG_DEBUG,("ctdb_fetch_lock: done local fetch\n")); - - if (ret != 0 || h->header.dmaster != ctdb_db->ctdb->pnn) { - ctdb_ltdb_unlock(ctdb_db, key); - ret = ctdb_client_force_migration(ctdb_db, key); - if (ret != 0) { - DEBUG(DEBUG_DEBUG,("ctdb_fetch_lock: force_migration failed\n")); - talloc_free(h); - return NULL; - } - goto again; - } - - DEBUG(DEBUG_DEBUG,("ctdb_fetch_lock: we are dmaster - done\n")); - return h; -} - -/* - store some data to the record that was locked with ctdb_fetch_lock() -*/ -int ctdb_record_store(struct ctdb_record_handle *h, TDB_DATA data) -{ - if (h->ctdb_db->persistent) { - DEBUG(DEBUG_ERR, (__location__ " ctdb_record_store prohibited for persistent dbs\n")); - return -1; - } - - return ctdb_ltdb_store(h->ctdb_db, h->key, &h->header, data); -} /* non-locking fetch of a record diff --git a/include/ctdb.h b/include/ctdb.h index 678189e..d0b9507 100644 --- a/include/ctdb.h +++ b/include/ctdb.h @@ -68,11 +68,11 @@ 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. + * You have to free the handle with ctdb_free() when finished with it. */ struct ctdb_db_context; -typedef void (*ctdb_attachdb_cb)(int32_t status, struct ctdb_db_context *ctdb_db, void *private_data); +typedef void (*ctdb_attachdb_cb)(int32_t status, ctdb_handle *, struct ctdb_db_context *ctdb_db, void *private_data); ctdb_handle * ctdb_attachdb_send(struct ctdb_context *ctdb, @@ -86,6 +86,47 @@ int ctdb_attachdb(struct ctdb_context *ctdb, struct ctdb_db_context **); +/* + * functions to read a record from the database + * when the callback is invoked, the client will hold an exclusive lock + * on the record, until the handle is ctdb_free()d. + * the client MUST NOT block during holding this lock and MUST + * release it quickly by performing ctdb_free(handle). + * + * When the handle is freed, data is freed too, so make sure to copy the data + * before freeing the handle. + */ +typedef void (*ctdb_readrecordlock_cb)(int32_t status, ctdb_handle *handle, TDB_DATA data, void *private_data); + +ctdb_handle * +ctdb_readrecordlock_send(struct ctdb_context *ctdb, + struct ctdb_db_context *ctdb_db_context, + TDB_DATA key, + ctdb_readrecordlock_cb callback, + void *private_data); +int ctdb_readrecordlock_recv(struct ctdb_context *ctdb, + ctdb_handle *handle, + TDB_DATA **data); +int ctdb_readrecordlock(struct ctdb_context *ctdb, + struct ctdb_db_context *ctdb_db_context, + TDB_DATA key, + TDB_DATA **data); + + + +/* + * Function to write data to a record + * This function may ONLY be called while holding a lock to the record + * created by ctdb_readrecordlock* + * Either from the callback provided to ctdb_readrecordlock_send() + * or after calling ctdb_readrecordlock_recv() but before calling + * ctdb_free() to release the handle. + */ +int ctdb_writerecord(ctdb_handle *handle, + TDB_DATA key, + TDB_DATA data); + + /* * messaging functions @@ -179,46 +220,6 @@ int ctdb_getrecmaster(struct ctdb_context *ctdb, /* - * functions to create a database - * if the database already exists this function is a NOP - */ -typedef void (*ctdb_createdb_cb)(int32_t status, uint32_t db_id, void *private_data); - -ctdb_handle * -ctdb_createdb_send(struct ctdb_context *ctdb, uint32_t destnode, - const char *name, int persistent, uint32_t tdb_flags, - ctdb_createdb_cb callback, - void *private_data); -int ctdb_createdb_recv(struct ctdb_context *ctdb, - ctdb_handle *handle, uint32_t *db_id); -int ctdb_createdb(struct ctdb_context *ctdb, uint32_t destnode, - const char *name, int persistent, uint32_t tdb_flags, - uint32_t *db_id); - - - - -/* - * functions to find the filename of a database - * - * 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); - -ctdb_handle * -ctdb_getdbpath_send(struct ctdb_context *ctdb, uint32_t destnode, - uint32_t db_id, - ctdb_getdbpath_cb callback, - void *private_data); -int ctdb_getdbpath_recv(struct ctdb_context *ctdb, - ctdb_handle *handle, const char **path); -int ctdb_getdbpath(struct ctdb_context *ctdb, uint32_t destnode, - uint32_t db_id, - const char **path); - - -/* * cancel a request/call */ int ctdb_free(ctdb_handle *); diff --git a/include/ctdb_private.h b/include/ctdb_private.h index 90d4c13..ab60a9d 100644 --- a/include/ctdb_private.h +++ b/include/ctdb_private.h @@ -1652,4 +1652,11 @@ void ctdb_control_timeout_func(struct event_context *ev, void ctdb_invoke_control_callback(struct event_context *ev, struct timed_event *te, struct timeval t, void *private_data); +struct ctdb_record_handle { + struct ctdb_db_context *ctdb_db; + TDB_DATA key; + TDB_DATA *data; + struct ctdb_ltdb_header header; +}; + #endif diff --git a/include/ctdb_protocol.h b/include/ctdb_protocol.h index 694fdae..8eda5d4 100644 --- a/include/ctdb_protocol.h +++ b/include/ctdb_protocol.h @@ -721,4 +721,46 @@ struct ctdb_db_priority { int ctdb_ctrl_set_db_priority(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, struct ctdb_db_priority *db_prio); int ctdb_ctrl_get_db_priority(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t db_id, uint32_t *priority); + +/* + * functions to create a database + * if the database already exists this function is a NOP + */ +typedef void (*ctdb_createdb_cb)(int32_t status, uint32_t db_id, void *private_data); + +ctdb_handle * +ctdb_createdb_send(struct ctdb_context *ctdb, uint32_t destnode, + const char *name, int persistent, uint32_t tdb_flags, + ctdb_createdb_cb callback, + void *private_data); +int ctdb_createdb_recv(struct ctdb_context *ctdb, + ctdb_handle *handle, uint32_t *db_id); +int ctdb_createdb(struct ctdb_context *ctdb, uint32_t destnode, + const char *name, int persistent, uint32_t tdb_flags, + uint32_t *db_id); + + + + +/* + * functions to find the filename of a database + * + * 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); + +ctdb_handle * +ctdb_getdbpath_send(struct ctdb_context *ctdb, uint32_t destnode, + uint32_t db_id, + ctdb_getdbpath_cb callback, + void *private_data); +int ctdb_getdbpath_recv(struct ctdb_context *ctdb, + ctdb_handle *handle, const char **path); +int ctdb_getdbpath(struct ctdb_context *ctdb, uint32_t destnode, + uint32_t db_id, + const char **path); + + + #endif diff --git a/libctdb/ctdb_client.c b/libctdb/ctdb_client.c index 864877c..a7b2112 100644 --- a/libctdb/ctdb_client.c +++ b/libctdb/ctdb_client.c @@ -625,6 +625,55 @@ struct ctdb_client_call_state *ctdb_call_send(struct ctdb_db_context *ctdb_db, } /* + make a recv call to the local ctdb daemon - called from client context + + This is called when the program wants to wait for a ctdb_call to complete and get the + results. This call will block unless the call has already completed. +*/ +int ctdb_call_recv(struct ctdb_client_call_state *state, struct ctdb_call *call) +{ + if (state == NULL) { + return -1; + } + + while (state->state < CTDB_CALL_DONE) { + event_loop_once(state->ctdb_db->ctdb->ev); + } + if (state->state != CTDB_CALL_DONE) { + DEBUG(DEBUG_ERR,(__location__ " ctdb_call_recv failed\n")); + talloc_free(state); + return -1; + } + + if (state->call->reply_data.dsize) { + call->reply_data.dptr = talloc_memdup(state->ctdb_db, + state->call->reply_data.dptr, + state->call->reply_data.dsize); + call->reply_data.dsize = state->call->reply_data.dsize; + } else { + call->reply_data.dptr = NULL; + call->reply_data.dsize = 0; + } + call->status = state->call->status; + talloc_free(state); + + return 0; +} + +/* + full ctdb_call. Equivalent to a ctdb_call_send() followed by a ctdb_call_recv() +*/ +int ctdb_call(struct ctdb_db_context *ctdb_db, struct ctdb_call *call) +{ + struct ctdb_client_call_state *state; + + state = ctdb_call_send(ctdb_db, call); + return ctdb_call_recv(state, call); +} + + + +/* send a message - from client context */ int ctdb_send_message(struct ctdb_context *ctdb, uint32_t pnn, @@ -691,3 +740,117 @@ int ctdb_set_call(struct ctdb_db_context *ctdb_db, ctdb_fn_t fn, uint32_t id) DLIST_ADD(ctdb_db->calls, call); return 0; } + + + +/* + store some data to the record that was locked with ctdb_fetch_lock() +*/ +int ctdb_record_store(struct ctdb_record_handle *h, TDB_DATA data) +{ + if (h->ctdb_db->persistent) { + DEBUG(DEBUG_ERR, (__location__ " ctdb_record_store prohibited for persistent dbs\n")); + return -1; + } + + return ctdb_ltdb_store(h->ctdb_db, h->key, &h->header, data); +} + +/* + cancel a ctdb_fetch_lock operation, releasing the lock + */ +static int fetch_lock_destructor(struct ctdb_record_handle *h) +{ + ctdb_ltdb_unlock(h->ctdb_db, h->key); + return 0; +} + + +/* + force the migration of a record to this node + */ +static int ctdb_client_force_migration(struct ctdb_db_context *ctdb_db, TDB_DATA key) +{ + struct ctdb_call call; + ZERO_STRUCT(call); + call.call_id = CTDB_NULL_FUNC; + call.key = key; + call.flags = CTDB_IMMEDIATE_MIGRATION; + return ctdb_call(ctdb_db, &call); +} + +/* + get a lock on a record, and return the records data. Blocks until it gets the lock + */ +struct ctdb_record_handle *ctdb_fetch_lock(struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx, + TDB_DATA key, TDB_DATA *data) +{ + int ret; + struct ctdb_record_handle *h; + + /* + procedure is as follows: + + 1) get the chain lock. + 2) check if we are dmaster + 3) if we are the dmaster then return handle + 4) if not dmaster then ask ctdb daemon to make us dmaster, and wait for + reply from ctdbd + 5) when we get the reply, goto (1) + */ + + h = talloc_zero(mem_ctx, struct ctdb_record_handle); + if (h == NULL) { + return NULL; + } + + h->ctdb_db = ctdb_db; + h->key = key; + h->key.dptr = talloc_memdup(h, key.dptr, key.dsize); + if (h->key.dptr == NULL) { + talloc_free(h); + return NULL; -- CTDB repository