-static int tdb_key_compare(TDB_DATA key, TDB_DATA data, void *private_data)
-{
- return memcmp(data.dptr, key.dptr, data.dsize) == 0;
-}
-
-static void unlock_lists(struct tdb_context *tdb,
- uint64_t start, uint64_t end, int ltype)
-{
- do {
- tdb_unlock_list(tdb, start, ltype);
- start = (start + ((1ULL << tdb->header.v.hash_bits) - 1))
- & ((1ULL << tdb->header.v.hash_bits) - 1);
- } while (start != end);
-}
-
-/* FIXME: Return header copy? */
-/* Returns -1 or offset of entry (0 if not found).
- * Locks hash entried from *start to *end (where the entry was found). */
-static tdb_off_t find_bucket_and_lock(struct tdb_context *tdb,
- const struct tdb_data *key,
- uint64_t hash,
- uint64_t *start,
- uint64_t *end,
- uint64_t *room,
- int ltype)
-{
- uint64_t hextra;
- tdb_off_t off;
-
- /* hash_bits might be out of date... */
-again:
- *start = *end = hash & ((1ULL << tdb->header.v.hash_bits) - 1);
- hextra = hash >> tdb->header.v.hash_bits;
-
- /* FIXME: can we avoid locks for some fast paths? */
- if (tdb_lock_list(tdb, *end, ltype, TDB_LOCK_WAIT) == -1)
- return TDB_OFF_ERR;
-
- /* We only need to check this for first lock. */
- if (unlikely(update_header(tdb))) {
- tdb_unlock_list(tdb, *end, ltype);
- goto again;
- }
-
- while ((off = tdb_read_off(tdb, tdb->header.v.hash_off
- + *end * sizeof(tdb_off_t)))
- != TDB_OFF_ERR) {
- struct tdb_used_record pad, *r;
- uint64_t keylen, next;
-
- /* Didn't find it? */
- if (!off)
- return 0;
-
-#if 0 /* FIXME: Check other bits. */
- unsigned int bits, bitmask, hoffextra;
- /* Bottom three bits show how many extra hash bits. */
- bits = (off & ((1 << TDB_EXTRA_HASHBITS_NUM) - 1)) + 1;
- bitmask = (1 << bits)-1;
- hoffextra = ((off >> TDB_EXTRA_HASHBITS_NUM) & bitmask);
- if ((hextra & bitmask) != hoffextra)
- goto lock_next;
-#endif
-
- r = tdb_get(tdb, off, &pad, sizeof(*r));
- if (!r)
- goto unlock_err;
-
- if (rec_magic(r) != TDB_MAGIC) {
- tdb->ecode = TDB_ERR_CORRUPT;
- tdb->log(tdb, TDB_DEBUG_FATAL, tdb->log_priv,
- "find_bucket_and_lock: bad magic 0x%llx"
- " at offset %llu!\n",
- (long long)rec_magic(r), (long long)off);
- goto unlock_err;
- }
-
- /* FIXME: check extra bits in header! */
- keylen = rec_key_length(r);
- if (keylen != key->dsize)
- goto lock_next;
-
- switch (tdb_parse_data(tdb, *key, off + sizeof(*r), key->dsize,
- tdb_key_compare, NULL)) {
- case 1:
- /* Match! */
- *room = rec_data_length(r) + rec_extra_padding(r);
- return off >> TDB_EXTRA_HASHBITS_NUM;
- case 0:
- break;
- default:
- goto unlock_err;
- }
-
- lock_next:
- /* Lock next bucket. */
- /* FIXME: We can deadlock if this wraps! */
- next = (*end + 1) & ((1ULL << tdb->header.v.hash_bits) - 1);
- if (next == *start) {
- tdb->ecode = TDB_ERR_CORRUPT;
- tdb->log(tdb, TDB_DEBUG_FATAL, tdb->log_priv,
- "find_bucket_and_lock: full hash table!\n");
- goto unlock_err;
- }
- if (tdb_lock_list(tdb, next, ltype, TDB_LOCK_WAIT) == -1)
- goto unlock_err;
- *end = next;
- }
-
-unlock_err:
- TEST_IT(*end < *start);
- unlock_lists(tdb, *start, *end, ltype);
- return TDB_OFF_ERR;
-}
-