summaryrefslogtreecommitdiffstats
path: root/ctdb/client
diff options
context:
space:
mode:
authorAmitay Isaacs <amitay@gmail.com>2013-10-04 15:38:04 +1000
committerAmitay Isaacs <amitay@gmail.com>2013-10-04 15:43:32 +1000
commit1203e82d9b81798d4ad25f19b59c8943446e0f8c (patch)
treef63e97dab28fe7916e4065f344456048e8ad8667 /ctdb/client
parent0205d52657e17246121039d5312708810e94bc73 (diff)
downloadsamba-1203e82d9b81798d4ad25f19b59c8943446e0f8c.tar.gz
samba-1203e82d9b81798d4ad25f19b59c8943446e0f8c.tar.xz
samba-1203e82d9b81798d4ad25f19b59c8943446e0f8c.zip
client: Add functions to parse g_lock.tdb records
Signed-off-by: Amitay Isaacs <amitay@gmail.com> (This used to be ctdb commit 40589ae5259880431f358250c1f0d07bcaa21d1f)
Diffstat (limited to 'ctdb/client')
-rw-r--r--ctdb/client/ctdb_client.c198
1 files changed, 198 insertions, 0 deletions
diff --git a/ctdb/client/ctdb_client.c b/ctdb/client/ctdb_client.c
index 0757246ef02..2666ca2a31e 100644
--- a/ctdb/client/ctdb_client.c
+++ b/ctdb/client/ctdb_client.c
@@ -3796,6 +3796,204 @@ static bool server_id_exists(struct ctdb_context *ctdb, struct server_id *id)
}
+enum g_lock_type {
+ G_LOCK_READ = 0,
+ G_LOCK_WRITE = 1,
+};
+
+struct g_lock_rec {
+ enum g_lock_type type;
+ struct server_id id;
+};
+
+struct g_lock_recs {
+ unsigned int num;
+ struct g_lock_rec *lock;
+};
+
+static bool g_lock_parse(TALLOC_CTX *mem_ctx, TDB_DATA data,
+ struct g_lock_recs **locks)
+{
+ struct g_lock_recs *recs;
+
+ recs = talloc_zero(mem_ctx, struct g_lock_recs);
+ if (recs == NULL) {
+ return false;
+ }
+
+ if (data.dsize == 0) {
+ goto done;
+ }
+
+ if (data.dsize % sizeof(struct g_lock_rec) != 0) {
+ DEBUG(DEBUG_ERR, (__location__ "invalid data size %lu in g_lock record\n",
+ data.dsize));
+ talloc_free(recs);
+ return false;
+ }
+
+ recs->num = data.dsize / sizeof(struct g_lock_rec);
+ recs->lock = talloc_memdup(mem_ctx, data.dptr, data.dsize);
+ if (recs->lock == NULL) {
+ talloc_free(recs);
+ return false;
+ }
+
+done:
+ if (locks != NULL) {
+ *locks = recs;
+ }
+
+ return true;
+}
+
+
+static bool g_lock_lock(TALLOC_CTX *mem_ctx,
+ struct ctdb_db_context *ctdb_db,
+ const char *keyname, uint32_t reqid)
+{
+ TDB_DATA key, data;
+ struct ctdb_record_handle *h;
+ struct g_lock_recs *locks;
+ struct server_id id;
+ int i;
+
+ key.dptr = (uint8_t *)discard_const(keyname);
+ key.dsize = strlen(keyname) + 1;
+ h = ctdb_fetch_lock(ctdb_db, mem_ctx, key, &data);
+ if (h == NULL) {
+ return false;
+ }
+
+ if (!g_lock_parse(h, data, &locks)) {
+ DEBUG(DEBUG_ERR, ("g_lock: error parsing locks\n"));
+ talloc_free(data.dptr);
+ talloc_free(h);
+ return false;
+ }
+
+ talloc_free(data.dptr);
+
+ id = server_id_get(ctdb_db->ctdb, reqid);
+
+ i = 0;
+ while (i < locks->num) {
+ if (server_id_equal(&locks->lock[i].id, &id)) {
+ /* Internal error */
+ talloc_free(h);
+ return false;
+ }
+
+ if (!server_id_exists(ctdb_db->ctdb, &locks->lock[i].id)) {
+ if (i < locks->num-1) {
+ locks->lock[i] = locks->lock[locks->num-1];
+ }
+ locks->num--;
+ continue;
+ }
+
+ /* This entry is locked. */
+ DEBUG(DEBUG_INFO, ("g_lock: lock already granted for "
+ "pid=0x%llx taskid=%x vnn=%d id=0x%llx\n",
+ (unsigned long long)id.pid,
+ id.task_id, id.vnn,
+ (unsigned long long)id.unique_id));
+ talloc_free(h);
+ return false;
+ }
+
+ locks->lock = talloc_realloc(locks, locks->lock, struct g_lock_rec,
+ locks->num+1);
+ if (locks->lock == NULL) {
+ talloc_free(h);
+ return false;
+ }
+
+ locks->lock[locks->num].type = G_LOCK_WRITE;
+ locks->lock[locks->num].id = id;
+ locks->num++;
+
+ data.dptr = (uint8_t *)locks->lock;
+ data.dsize = locks->num * sizeof(struct g_lock_rec);
+
+ if (ctdb_record_store(h, data) != 0) {
+ DEBUG(DEBUG_ERR, ("g_lock: failed to write transaction lock for "
+ "pid=0x%llx taskid=%x vnn=%d id=0x%llx\n",
+ (unsigned long long)id.pid,
+ id.task_id, id.vnn,
+ (unsigned long long)id.unique_id));
+ talloc_free(h);
+ return false;
+ }
+
+ DEBUG(DEBUG_INFO, ("g_lock: lock granted for "
+ "pid=0x%llx taskid=%x vnn=%d id=0x%llx\n",
+ (unsigned long long)id.pid,
+ id.task_id, id.vnn,
+ (unsigned long long)id.unique_id));
+
+ talloc_free(h);
+ return true;
+}
+
+static bool g_lock_unlock(TALLOC_CTX *mem_ctx,
+ struct ctdb_db_context *ctdb_db,
+ const char *keyname, uint32_t reqid)
+{
+ TDB_DATA key, data;
+ struct ctdb_record_handle *h;
+ struct g_lock_recs *locks;
+ struct server_id id;
+ int i;
+ bool found = false;
+
+ key.dptr = (uint8_t *)discard_const(keyname);
+ key.dsize = strlen(keyname) + 1;
+ h = ctdb_fetch_lock(ctdb_db, mem_ctx, key, &data);
+ if (h == NULL) {
+ return false;
+ }
+
+ if (!g_lock_parse(h, data, &locks)) {
+ DEBUG(DEBUG_ERR, ("g_lock: error parsing locks\n"));
+ talloc_free(data.dptr);
+ talloc_free(h);
+ return false;
+ }
+
+ talloc_free(data.dptr);
+
+ id = server_id_get(ctdb_db->ctdb, reqid);
+
+ for (i=0; i<locks->num; i++) {
+ if (server_id_equal(&locks->lock[i].id, &id)) {
+ if (i < locks->num-1) {
+ locks->lock[i] = locks->lock[locks->num-1];
+ }
+ locks->num--;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ DEBUG(DEBUG_ERR, ("g_lock: lock not found\n"));
+ talloc_free(h);
+ return false;
+ }
+
+ data.dptr = (uint8_t *)locks->lock;
+ data.dsize = locks->num * sizeof(struct g_lock_rec);
+
+ if (ctdb_record_store(h, data) != 0) {
+ talloc_free(h);
+ return false;
+ }
+
+ talloc_free(h);
+ return true;
+}
+
/**
* check whether a transaction is active on a given db on a given node
*/