X-Git-Url: https://git.ozlabs.org/?a=blobdiff_plain;f=ccan%2Ftdb2%2Flock.c;h=1cb150a42bec6b334d4c747d2d3c2b9d6e3e38b0;hb=4f73f6a6dfc0d65aa9a5055683bf7baa5a7b622e;hp=c8dbf8267a8f9dab5fc92c9a3e7e810e6d8943d1;hpb=2088fa3cd72332f5517edeb9267e381fdf35db01;p=ccan diff --git a/ccan/tdb2/lock.c b/ccan/tdb2/lock.c index c8dbf826..1cb150a4 100644 --- a/ccan/tdb2/lock.c +++ b/ccan/tdb2/lock.c @@ -26,6 +26,8 @@ */ #include "private.h" +#include +#include static int fcntl_lock(struct tdb_context *tdb, int rw, off_t off, off_t len, bool waitflag) @@ -255,14 +257,14 @@ static int tdb_nest_lock(struct tdb_context *tdb, tdb_off_t offset, int ltype, { struct tdb_lock_type *new_lck; - if (offset >= TDB_HASH_LOCK_START + (1ULL << tdb->header.v.hash_bits) - + (tdb->header.v.num_zones * (tdb->header.v.free_buckets+1))) { + if (offset >= TDB_HASH_LOCK_START + (1 << 30) + tdb->map_size / 8) { tdb->ecode = TDB_ERR_LOCK; tdb->log(tdb, TDB_DEBUG_FATAL, tdb->log_priv, - "tdb_lock: invalid offset %llu for ltype=%d\n", + "tdb_lock: invalid offset %llu ltype=%d\n", (long long)offset, ltype); return -1; } + if (tdb->flags & TDB_NOLOCK) return 0; @@ -485,8 +487,8 @@ int tdb_allrecord_lock(struct tdb_context *tdb, int ltype, /* Lock all the hash buckets. */ again: hash_size = (1ULL << tdb->header.v.hash_bits); - if (tdb_lock_gradual(tdb, ltype, TDB_HASH_LOCK_START, - 1ULL << tdb->header.v.hash_bits, flags)) { + if (tdb_lock_gradual(tdb, ltype, flags, TDB_HASH_LOCK_START, + hash_size)) { if (!(flags & TDB_LOCK_PROBE)) { tdb->log(tdb, TDB_DEBUG_ERROR, tdb->log_priv, "tdb_lockall hashes failed (%s)\n", @@ -529,6 +531,16 @@ void tdb_unlock_open(struct tdb_context *tdb) tdb_nest_unlock(tdb, TDB_OPEN_LOCK, F_WRLCK); } +int tdb_lock_expand(struct tdb_context *tdb, int ltype) +{ + return tdb_nest_lock(tdb, TDB_EXPANSION_LOCK, ltype, TDB_LOCK_WAIT); +} + +void tdb_unlock_expand(struct tdb_context *tdb, int ltype) +{ + tdb_nest_unlock(tdb, TDB_EXPANSION_LOCK, ltype); +} + /* unlock entire db */ int tdb_allrecord_unlock(struct tdb_context *tdb, int ltype) { @@ -682,10 +694,21 @@ int tdb_unlock_list(struct tdb_context *tdb, tdb_off_t list, int ltype) } } -/* Free list locks come after hash locks */ -int tdb_lock_free_list(struct tdb_context *tdb, tdb_off_t flist, - enum tdb_lock_flags waitflag) +/* Hash locks use TDB_HASH_LOCK_START + the next 30 bits. + * Then we begin; bucket offsets are sizeof(tdb_len_t) apart, so we divide. + * The result is that on 32 bit systems we don't use lock values > 2^31 on + * files that are less than 4GB. + */ +static tdb_off_t free_lock_off(tdb_off_t b_off) +{ + return TDB_HASH_LOCK_START + (1 << 30) + b_off / sizeof(tdb_off_t); +} + +int tdb_lock_free_bucket(struct tdb_context *tdb, tdb_off_t b_off, + enum tdb_lock_flags waitflag) { + assert(b_off >= sizeof(struct tdb_header)); + /* You're supposed to have a hash lock first! */ if (!(tdb->flags & TDB_NOLOCK) && !tdb_has_locks(tdb)) { tdb->ecode = TDB_ERR_LOCK; @@ -704,22 +727,19 @@ int tdb_lock_free_list(struct tdb_context *tdb, tdb_off_t flist, return -1; } - return tdb_nest_lock(tdb, TDB_HASH_LOCK_START - + (1ULL << tdb->header.v.hash_bits) - + flist, F_WRLCK, waitflag); + return tdb_nest_lock(tdb, free_lock_off(b_off), F_WRLCK, waitflag); } -void tdb_unlock_free_list(struct tdb_context *tdb, tdb_off_t flist) +void tdb_unlock_free_bucket(struct tdb_context *tdb, tdb_off_t b_off) { if (tdb->allrecord_lock.count) return; - tdb_nest_unlock(tdb, TDB_HASH_LOCK_START - + (1ULL << tdb->header.v.hash_bits) - + flist, F_WRLCK); + tdb_nest_unlock(tdb, free_lock_off(b_off), F_WRLCK); } -#if 0 +/* Even if the entry isn't in this hash bucket, you'd have to lock this + * bucket to find it. */ static int chainlock(struct tdb_context *tdb, const TDB_DATA *key, int ltype, enum tdb_lock_flags waitflag, const char *func) @@ -739,6 +759,14 @@ int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key) return chainlock(tdb, &key, F_WRLCK, TDB_LOCK_WAIT, "tdb_chainlock"); } +int tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key) +{ + uint64_t h = tdb_hash(tdb, key.dptr, key.dsize); + tdb_trace_1rec(tdb, "tdb_chainunlock", key); + return tdb_unlock_list(tdb, h, F_WRLCK); +} + +#if 0 /* lock/unlock one hash chain, non-blocking. This is meant to be used to reduce contention - it cannot guarantee how many records will be locked */ @@ -748,14 +776,6 @@ int tdb_chainlock_nonblock(struct tdb_context *tdb, TDB_DATA key) "tdb_chainlock_nonblock"); } -int tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key) -{ - uint64_t h = tdb_hash(tdb, key.dptr, key.dsize); - tdb_trace_1rec(tdb, "tdb_chainunlock", key); - return tdb_unlock_list(tdb, h & ((1ULL << tdb->header.v.hash_bits)-1), - F_WRLCK); -} - int tdb_chainlock_read(struct tdb_context *tdb, TDB_DATA key) { return chainlock(tdb, &key, F_RDLCK, TDB_LOCK_WAIT,