-/* If we fail, others will try after us. */
-static void enlarge_hash(struct tdb_context *tdb)
-{
- tdb_off_t newoff, oldoff, i;
- tdb_len_t hlen;
- uint64_t num = 1ULL << tdb->header.v.hash_bits;
- struct tdb_used_record pad, *r;
-
- /* FIXME: We should do this without holding locks throughout. */
- if (tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_WAIT, false) == -1)
- return;
-
- /* Someone else enlarged for us? Nothing to do. */
- if ((1ULL << tdb->header.v.hash_bits) != num)
- goto unlock;
-
-again:
- /* Allocate our new array. */
- hlen = num * sizeof(tdb_off_t) * 2;
- newoff = alloc(tdb, 0, hlen, 0, false);
- if (unlikely(newoff == TDB_OFF_ERR))
- goto unlock;
- if (unlikely(newoff == 0)) {
- if (tdb_expand(tdb, 0, hlen, false) == -1)
- goto unlock;
- goto again;
- }
- /* Step over record header! */
- newoff += sizeof(struct tdb_used_record);
-
- /* Starts all zero. */
- if (zero_out(tdb, newoff, hlen) == -1)
- goto unlock;
-
- /* Update header now so we can use normal routines. */
- oldoff = tdb->header.v.hash_off;
-
- tdb->header.v.hash_bits++;
- tdb->header.v.hash_off = newoff;
-
- /* FIXME: If the space before is empty, we know this is in its ideal
- * location. Or steal a bit from the pointer to avoid rehash. */
- for (i = 0; i < num; i++) {
- tdb_off_t off;
- off = tdb_read_off(tdb, oldoff + i * sizeof(tdb_off_t));
- if (unlikely(off == TDB_OFF_ERR))
- goto oldheader;
- if (off && hash_add(tdb, hash_record(tdb, off), off) == -1)
- goto oldheader;
- }
-
- /* Free up old hash. */
- r = tdb_get(tdb, oldoff - sizeof(*r), &pad, sizeof(*r));
- if (!r)
- goto oldheader;
- add_free_record(tdb, oldoff - sizeof(*r),
- sizeof(*r)+rec_data_length(r)+rec_extra_padding(r));
-
- /* Now we write the modified header. */
- write_header(tdb);
-unlock:
- tdb_allrecord_unlock(tdb, F_WRLCK);
- return;
-
-oldheader:
- tdb->header.v.hash_bits--;
- tdb->header.v.hash_off = oldoff;
- goto unlock;
-}
-
-/* This is the core routine which searches the hashtable for an entry.
- * On error, no locks are held and TDB_OFF_ERR is returned.
- * Otherwise, *num_locks locks of type ltype from *start_lock are held.
- * The bucket where the entry is (or would be) is in *bucket.
- * If not found, the return value is 0.
- * If found, the return value is the offset, and *rec is the record. */
-static tdb_off_t find_and_lock(struct tdb_context *tdb,
- struct tdb_data key,
- uint64_t h,
- int ltype,
- tdb_off_t *start_lock,
- tdb_len_t *num_locks,
- tdb_off_t *bucket,
- struct tdb_used_record *rec)
-{
- tdb_off_t off;