#undef ctdb_readrecordlock_async
#undef ctdb_connect
+struct ctdb_lock {
+ struct ctdb_lock *next, *prev;
+
+ struct ctdb_db *ctdb_db;
+ TDB_DATA key;
+
+ /* This will always be true by the time user sees this. */
+ bool held;
+ struct ctdb_ltdb_header *hdr;
+
+ /* For convenience, we stash original callback here. */
+ ctdb_rrl_callback_t callback;
+};
+
+static void remove_lock(struct ctdb_connection *ctdb, struct ctdb_lock *lock)
+{
+ DLIST_REMOVE(ctdb->locks, lock);
+}
+
+/* FIXME: for thread safety, need tid info too. */
+static bool holding_lock(struct ctdb_connection *ctdb)
+{
+ /* For the moment, you can't ever hold more than 1 lock. */
+ return (ctdb->locks != NULL);
+}
+
+static void add_lock(struct ctdb_connection *ctdb, struct ctdb_lock *lock)
+{
+ DLIST_ADD(ctdb->locks, lock);
+}
+
/* FIXME: Could be in shared util code with rest of ctdb */
static void close_noerr(int fd)
{
return -1;
}
+ if (holding_lock(ctdb)) {
+ DEBUG(ctdb, LOG_WARNING, "Do not block while holding lock!");
+ }
+
if (revents & POLLOUT) {
while (ctdb->outq) {
if (real_error(write_io_elem(ctdb->fd,
uint32_t id;
struct tdb_context *tdb;
+ /* The lock we are holding, if any (we can only have one!) */
+ struct ctdb_lock *lock;
+
ctdb_callback_t callback;
void *private_data;
};
return req;
}
-struct ctdb_lock {
- struct ctdb_db *ctdb_db;
- TDB_DATA key;
-
- /* This will always be true by the time user sees this. */
- bool held;
- struct ctdb_ltdb_header *hdr;
-
- /* For convenience, we stash original callback here. */
- ctdb_rrl_callback_t callback;
-};
-
void ctdb_release_lock(struct ctdb_lock *lock)
{
if (lock->held) {
- DEBUG(lock->ctdb_db->ctdb, LOG_DEBUG,
- "ctdb_attachdb_send: ctdb_release_lock %p", lock);
tdb_chainunlock(lock->ctdb_db->tdb, lock->key);
+ DEBUG(lock->ctdb_db->ctdb, LOG_DEBUG,
+ "ctdb_release_lock %p", lock);
lock->held = false;
+ remove_lock(lock->ctdb_db->ctdb, lock);
}
-}
-
-static void ctdb_free_lock(struct ctdb_lock *lock)
-{
- if (lock->held) {
- /* FIXME: report error. Callback never released the lock */
- ctdb_release_lock(lock);
- }
-
free(lock->hdr);
free(lock);
}
"ctdb_readrecordlock_async: got local lock");
lock->held = true;
lock->hdr = hdr;
+ add_lock(lock->ctdb_db->ctdb, lock);
return true;
}
struct ctdb_request *req)
{
ctdb_release_lock(req->extra);
- ctdb_free_lock(req->extra);
}
static void readrecordlock_retry(struct ctdb_connection *ctdb,
}
lock->callback(lock->ctdb_db, NULL, tdb_null, private);
ctdb_request_free(ctdb, req); /* Also frees lock. */
- ctdb_free_lock(lock);
return;
}
/* Now it's their responsibility to free lock & request! */
req->extra_destructor = NULL;
lock->callback(lock->ctdb_db, lock, data, private);
- ctdb_free_lock(lock);
return;
}
struct ctdb_lock *lock;
TDB_DATA data;
+ if (holding_lock(ctdb_db->ctdb)) {
+ DEBUG(ctdb_db->ctdb, LOG_ERR,
+ "ctdb_readrecordlock_async: already holding lock");
+ return false;
+ }
+
/* Setup lock */
lock = malloc(sizeof(*lock) + key.dsize);
if (!lock) {
/* Fast path. */
if (try_readrecordlock(lock, &data)) {
callback(ctdb_db, lock, data, cbdata);
- ctdb_free_lock(lock);
return true;
}
DEBUG(ctdb_db->ctdb, LOG_ERR,
"ctdb_readrecordlock_async: allocation failed");
ctdb_release_lock(lock);
- ctdb_free_lock(lock);
return NULL;
}
req->extra = lock;
return -1;
}
- if (!lock->held) {
- /* FIXME: Report error. */
- return -1;
- }
-
return ctdb_local_store(lock->ctdb_db->tdb, lock->key, lock->hdr,
data);
}