- /* Start at exact size bucket, and search up... */
- for (b = find_free_head(tdb, start_b);
- b < TDB_FREE_BUCKETS;
- b = find_free_head(tdb, b + 1)) {
- /* Try getting one from list. */
- off = lock_and_alloc(tdb, tdb->flist_off,
- b, keylen, datalen, want_extra,
- hashlow);
- if (off == TDB_OFF_ERR)
- return TDB_OFF_ERR;
- if (off != 0)
- return off;
- /* Didn't work. Try next bucket. */
+ flist_off = tdb->flist_off;
+ flist = tdb->flist;
+ while (!wrapped || flist_off != tdb->flist_off) {
+ /* Start at exact size bucket, and search up... */
+ for (b = find_free_head(tdb, flist_off, start_b);
+ b < TDB_FREE_BUCKETS;
+ b = find_free_head(tdb, flist_off, b + 1)) {
+ /* Try getting one from list. */
+ off = lock_and_alloc(tdb, flist_off,
+ b, keylen, datalen, want_extra,
+ hashlow);
+ if (off == TDB_OFF_ERR)
+ return TDB_OFF_ERR;
+ if (off != 0) {
+ if (b == start_b)
+ add_stat(tdb, alloc_bucket_exact, 1);
+ if (b == TDB_FREE_BUCKETS - 1)
+ add_stat(tdb, alloc_bucket_max, 1);
+ /* Worked? Stay using this list. */
+ tdb->flist_off = flist_off;
+ tdb->flist = flist;
+ return off;
+ }
+ /* Didn't work. Try next bucket. */
+ }
+
+ /* Hmm, try next list. */
+ flist_off = next_flist(tdb, flist_off);
+ flist++;
+
+ if (flist_off == 0) {
+ wrapped = true;
+ flist_off = first_flist(tdb);
+ flist = 0;
+ }