X-Git-Url: http://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Ftdb%2Flock.c;h=07545b345ba0c6d80af5ed541376eca195afb87b;hp=f156c0fa7b2e548640d47db23df71c9427ec73ce;hb=67aef98e2e4409b69ba668a2a4a9f0757ddc7ca7;hpb=7104b7bc2e7f9829891477dbb04a9df926a656a7 diff --git a/ccan/tdb/lock.c b/ccan/tdb/lock.c index f156c0fa..07545b34 100644 --- a/ccan/tdb/lock.c +++ b/ccan/tdb/lock.c @@ -84,7 +84,7 @@ int tdb_brlock(struct tdb_context *tdb, tdb_off_t offset, TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brlock failed (fd=%d) at offset %d rw_type=%d lck_type=%d len=%d\n", tdb->fd, offset, rw_type, lck_type, (int)len)); } - return TDB_ERRCODE(TDB_ERR_LOCK, -1); + return -1; } return 0; } @@ -133,10 +133,12 @@ static int _tdb_lock(struct tdb_context *tdb, int list, int ltype, int op) } if (tdb->global_lock.count) { - return TDB_ERRCODE(TDB_ERR_LOCK, -1); + tdb->ecode = TDB_ERR_LOCK; + return -1; } if (list < -1 || list >= (int)tdb->header.hash_size) { + tdb->ecode = TDB_ERR_LOCK; TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_lock: invalid list %d for ltype=%d\n", list, ltype)); return -1; @@ -228,7 +230,8 @@ int tdb_unlock(struct tdb_context *tdb, int list, int ltype) } if (tdb->global_lock.count) { - return TDB_ERRCODE(TDB_ERR_LOCK, -1); + tdb->ecode = TDB_ERR_LOCK; + return -1; } if (tdb->flags & TDB_NOLOCK) @@ -301,16 +304,21 @@ int tdb_unlock(struct tdb_context *tdb, int list, int ltype) */ int tdb_transaction_lock(struct tdb_context *tdb, int ltype) { - if (tdb->have_transaction_lock || tdb->global_lock.count) { + if (tdb->global_lock.count) { + return 0; + } + if (tdb->transaction_lock_count > 0) { + tdb->transaction_lock_count++; return 0; } + if (tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, ltype, F_SETLKW, 0, 1) == -1) { TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_lock: failed to get transaction lock\n")); tdb->ecode = TDB_ERR_LOCK; return -1; } - tdb->have_transaction_lock = 1; + tdb->transaction_lock_count++; return 0; } @@ -320,12 +328,16 @@ int tdb_transaction_lock(struct tdb_context *tdb, int ltype) int tdb_transaction_unlock(struct tdb_context *tdb) { int ret; - if (!tdb->have_transaction_lock) { + if (tdb->global_lock.count) { + return 0; + } + if (tdb->transaction_lock_count > 1) { + tdb->transaction_lock_count--; return 0; } ret = tdb->methods->tdb_brlock(tdb, TRANSACTION_LOCK, F_UNLCK, F_SETLKW, 0, 1); if (ret == 0) { - tdb->have_transaction_lock = 0; + tdb->transaction_lock_count = 0; } return ret; } @@ -341,8 +353,10 @@ static int _tdb_lockall(struct tdb_context *tdb, int ltype, int op) ltype &= ~TDB_MARK_LOCK; /* There are no locks on read-only dbs */ - if (tdb->read_only || tdb->traverse_read) - return TDB_ERRCODE(TDB_ERR_LOCK, -1); + if (tdb->read_only || tdb->traverse_read) { + tdb->ecode = TDB_ERR_LOCK; + return -1; + } if (tdb->global_lock.count && tdb->global_lock.ltype == ltype) { tdb->global_lock.count++; @@ -351,12 +365,14 @@ static int _tdb_lockall(struct tdb_context *tdb, int ltype, int op) if (tdb->global_lock.count) { /* a global lock of a different type exists */ - return TDB_ERRCODE(TDB_ERR_LOCK, -1); + tdb->ecode = TDB_ERR_LOCK; + return -1; } if (tdb->num_locks != 0) { /* can't combine global and chain locks */ - return TDB_ERRCODE(TDB_ERR_LOCK, -1); + tdb->ecode = TDB_ERR_LOCK; + return -1; } if (!mark_lock && @@ -385,11 +401,13 @@ static int _tdb_unlockall(struct tdb_context *tdb, int ltype) /* There are no locks on read-only dbs */ if (tdb->read_only || tdb->traverse_read) { - return TDB_ERRCODE(TDB_ERR_LOCK, -1); + tdb->ecode = TDB_ERR_LOCK; + return -1; } if (tdb->global_lock.ltype != ltype || tdb->global_lock.count == 0) { - return TDB_ERRCODE(TDB_ERR_LOCK, -1); + tdb->ecode = TDB_ERR_LOCK; + return -1; } if (tdb->global_lock.count > 1) { @@ -413,48 +431,58 @@ static int _tdb_unlockall(struct tdb_context *tdb, int ltype) /* lock entire database with write lock */ int tdb_lockall(struct tdb_context *tdb) { + tdb_trace(tdb, "tdb_lockall"); return _tdb_lockall(tdb, F_WRLCK, F_SETLKW); } /* lock entire database with write lock - mark only */ int tdb_lockall_mark(struct tdb_context *tdb) { + tdb_trace(tdb, "tdb_lockall_mark"); return _tdb_lockall(tdb, F_WRLCK | TDB_MARK_LOCK, F_SETLKW); } /* unlock entire database with write lock - unmark only */ int tdb_lockall_unmark(struct tdb_context *tdb) { + tdb_trace(tdb, "tdb_lockall_unmark"); return _tdb_unlockall(tdb, F_WRLCK | TDB_MARK_LOCK); } /* lock entire database with write lock - nonblocking varient */ int tdb_lockall_nonblock(struct tdb_context *tdb) { - return _tdb_lockall(tdb, F_WRLCK, F_SETLK); + int ret = _tdb_lockall(tdb, F_WRLCK, F_SETLK); + tdb_trace_ret(tdb, "tdb_lockall_nonblock", ret); + return ret; } /* unlock entire database with write lock */ int tdb_unlockall(struct tdb_context *tdb) { + tdb_trace(tdb, "tdb_unlockall"); return _tdb_unlockall(tdb, F_WRLCK); } /* lock entire database with read lock */ int tdb_lockall_read(struct tdb_context *tdb) { + tdb_trace(tdb, "tdb_lockall_read"); return _tdb_lockall(tdb, F_RDLCK, F_SETLKW); } /* lock entire database with read lock - nonblock varient */ int tdb_lockall_read_nonblock(struct tdb_context *tdb) { - return _tdb_lockall(tdb, F_RDLCK, F_SETLK); + int ret = _tdb_lockall(tdb, F_RDLCK, F_SETLK); + tdb_trace_ret(tdb, "tdb_lockall_read_nonblock", ret); + return ret; } /* unlock entire database with read lock */ int tdb_unlockall_read(struct tdb_context *tdb) { + tdb_trace(tdb, "tdb_unlockall_read"); return _tdb_unlockall(tdb, F_RDLCK); } @@ -462,7 +490,9 @@ int tdb_unlockall_read(struct tdb_context *tdb) contention - it cannot guarantee how many records will be locked */ int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key) { - return tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK); + int ret = tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK); + tdb_trace_1rec(tdb, "tdb_chainlock", key); + return ret; } /* lock/unlock one hash chain, non-blocking. This is meant to be used @@ -470,38 +500,46 @@ int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key) locked */ int tdb_chainlock_nonblock(struct tdb_context *tdb, TDB_DATA key) { - return tdb_lock_nonblock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK); + int ret = tdb_lock_nonblock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK); + tdb_trace_1rec_ret(tdb, "tdb_chainlock_nonblock", key, ret); + return ret; } /* mark a chain as locked without actually locking it. Warning! use with great caution! */ int tdb_chainlock_mark(struct tdb_context *tdb, TDB_DATA key) { - return tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK | TDB_MARK_LOCK); + int ret = tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK | TDB_MARK_LOCK); + tdb_trace_1rec(tdb, "tdb_chainlock_mark", key); + return ret; } /* unmark a chain as locked without actually locking it. Warning! use with great caution! */ int tdb_chainlock_unmark(struct tdb_context *tdb, TDB_DATA key) { + tdb_trace_1rec(tdb, "tdb_chainlock_unmark", key); return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK | TDB_MARK_LOCK); } int tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key) { + tdb_trace_1rec(tdb, "tdb_chainunlock", key); return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK); } int tdb_chainlock_read(struct tdb_context *tdb, TDB_DATA key) { - return tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_RDLCK); + int ret; + ret = tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_RDLCK); + tdb_trace_1rec(tdb, "tdb_chainlock_read", key); + return ret; } int tdb_chainunlock_read(struct tdb_context *tdb, TDB_DATA key) { + tdb_trace_1rec(tdb, "tdb_chainunlock_read", key); return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_RDLCK); } - - /* record lock stops delete underneath */ int tdb_lock_record(struct tdb_context *tdb, tdb_off_t off) {