This allows us to keep the datastructure valid after the lock has been released by the application and we can trap and warn when the application is accessing the lock after it has been released. I.e. application bugs.
*
* You MUST NOT block during holding this lock and MUST release it
* quickly by performing ctdb_release_lock(lock).
*
* You MUST NOT block during holding this lock and MUST release it
* quickly by performing ctdb_release_lock(lock).
+ * Do NOT make any system calls that may block while holding the lock.
+ *
+ * Try to release the lock as quickly as possible.
lock->held = false;
remove_lock(lock->ctdb_db->ctdb, lock);
}
lock->held = false;
remove_lock(lock->ctdb_db->ctdb, lock);
}
+}
+
+static void ctdb_free_lock(struct ctdb_lock *lock)
+{
+ if (lock->held) {
+ errno = EEXIST;
+ DEBUG(lock->ctdb_db->ctdb, LOG_ERR,
+ "Lock freed before it was released");
+ ctdb_release_lock(lock);
+ }
free(lock->hdr);
free(lock);
}
free(lock->hdr);
free(lock);
}
+static void ctdb_destroy_lock(struct ctdb_lock *lock)
+{
+ ctdb_release_lock(lock);
+ ctdb_free_lock(lock);
+}
+
/* We keep the lock if local node is the dmaster. */
static bool try_readrecordlock(struct ctdb_lock *lock, TDB_DATA *data)
{
/* We keep the lock if local node is the dmaster. */
static bool try_readrecordlock(struct ctdb_lock *lock, TDB_DATA *data)
{
static void destroy_lock(struct ctdb_connection *ctdb,
struct ctdb_request *req)
{
static void destroy_lock(struct ctdb_connection *ctdb,
struct ctdb_request *req)
{
- ctdb_release_lock(req->extra);
+ ctdb_destroy_lock(req->extra);
}
static void readrecordlock_retry(struct ctdb_connection *ctdb,
}
static void readrecordlock_retry(struct ctdb_connection *ctdb,
/* Now it's their responsibility to free lock & request! */
req->extra_destructor = NULL;
lock->callback(lock->ctdb_db, lock, data, private);
/* Now it's their responsibility to free lock & request! */
req->extra_destructor = NULL;
lock->callback(lock->ctdb_db, lock, data, private);
/* Fast path. */
if (try_readrecordlock(lock, &data)) {
callback(ctdb_db, lock, data, cbdata);
/* Fast path. */
if (try_readrecordlock(lock, &data)) {
callback(ctdb_db, lock, data, cbdata);
if (!req) {
DEBUG(ctdb_db->ctdb, LOG_ERR,
"ctdb_readrecordlock_async: allocation failed");
if (!req) {
DEBUG(ctdb_db->ctdb, LOG_ERR,
"ctdb_readrecordlock_async: allocation failed");
- ctdb_release_lock(lock);
+ ctdb_destroy_lock(lock);
return NULL;
}
req->extra = lock;
return NULL;
}
req->extra = lock;
data.dsize = strlen(tmp) + 1;
ctdb_writerecord(lock, data);
data.dsize = strlen(tmp) + 1;
ctdb_writerecord(lock, data);
+ /* Release the lock as quickly as possible */
+ ctdb_release_lock(lock);
+
printf("Wrote new record : %s\n", tmp);
printf("Wrote new record : %s\n", tmp);
- ctdb_release_lock(lock);
}
static bool registered = false;
}
static bool registered = false;