X-Git-Url: https://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Ftdb2%2Fhash.c;h=d3a195a789f5fcdd76a957e8069e03d2eb0176e3;hp=71ede4dbffda9e6a31786a9224d1e5ec16dc042a;hb=3d10865d159072553933fb72394862c884e60079;hpb=48038e705f87e54176d76bdcb7a6512a4bfa1a4a diff --git a/ccan/tdb2/hash.c b/ccan/tdb2/hash.c index 71ede4db..d3a195a7 100644 --- a/ccan/tdb2/hash.c +++ b/ccan/tdb2/hash.c @@ -131,14 +131,15 @@ bool is_subhash(tdb_off_t val) /* 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, hinfo is filled in. + * Otherwise, hinfo is filled in (and the optional tinfo). * If not found, the return value is 0. * If found, the return value is the offset, and *rec is the record. */ tdb_off_t find_and_lock(struct tdb_context *tdb, struct tdb_data key, int ltype, struct hash_info *h, - struct tdb_used_record *rec) + struct tdb_used_record *rec, + struct traverse_info *tinfo) { uint32_t i, group; tdb_off_t hashtable; @@ -158,6 +159,14 @@ tdb_off_t find_and_lock(struct tdb_context *tdb, return TDB_OFF_ERR; hashtable = offsetof(struct tdb_header, hashtable); + if (tinfo) { + tinfo->toplevel_group = group; + tinfo->num_levels = 1; + tinfo->levels[0].entry = 0; + tinfo->levels[0].hashtable = hashtable + + (group << TDB_HASH_GROUP_BITS) * sizeof(tdb_off_t); + tinfo->levels[0].total_buckets = 1 << TDB_HASH_GROUP_BITS; + } while (likely(h->hash_used < 64)) { /* Read in the hash group. */ @@ -172,9 +181,23 @@ tdb_off_t find_and_lock(struct tdb_context *tdb, if (is_subhash(h->group[h->home_bucket])) { hashtable = (h->group[h->home_bucket] & TDB_OFF_MASK) + sizeof(struct tdb_used_record); + if (tinfo) { + /* When we come back, use *next* bucket */ + tinfo->levels[tinfo->num_levels-1].entry + += h->home_bucket + 1; + } group = use_bits(h, TDB_SUBLEVEL_HASH_BITS - TDB_HASH_GROUP_BITS); h->home_bucket = use_bits(h, TDB_HASH_GROUP_BITS); + if (tinfo) { + tinfo->levels[tinfo->num_levels].hashtable + = hashtable; + tinfo->levels[tinfo->num_levels].total_buckets + = 1 << TDB_SUBLEVEL_HASH_BITS; + tinfo->levels[tinfo->num_levels].entry + = group << TDB_HASH_GROUP_BITS; + tinfo->num_levels++; + } continue; } @@ -189,8 +212,14 @@ tdb_off_t find_and_lock(struct tdb_context *tdb, if (!h->group[h->found_bucket]) break; - if (match(tdb, h, &key, h->group[h->found_bucket], rec)) + if (match(tdb, h, &key, h->group[h->found_bucket], + rec)) { + if (tinfo) { + tinfo->levels[tinfo->num_levels-1].entry + += h->found_bucket; + } return h->group[h->found_bucket] & TDB_OFF_MASK; + } } /* Didn't find it: h indicates where it would go. */ return 0; @@ -470,17 +499,18 @@ again: if (unlikely(val == TDB_OFF_ERR)) return TDB_OFF_ERR; + off = val & TDB_OFF_MASK; + /* This makes the delete-all-in-traverse case work * (and simplifies our logic a little). */ - if (val == tinfo->prev) + if (off == tinfo->prev) continue; tlevel->entry = i; - off = val & TDB_OFF_MASK; if (!is_subhash(val)) { /* Found one. */ - tinfo->prev = val; + tinfo->prev = off; return off; } @@ -507,7 +537,7 @@ again: /* Return 1 if we find something, 0 if not, -1 on error. */ int next_in_hash(struct tdb_context *tdb, int ltype, struct traverse_info *tinfo, - TDB_DATA *kbuf, unsigned int *dlen) + TDB_DATA *kbuf, size_t *dlen) { const unsigned group_bits = TDB_TOPLEVEL_HASH_BITS-TDB_HASH_GROUP_BITS; tdb_off_t hlock_start, hlock_range, off; @@ -561,7 +591,7 @@ int next_in_hash(struct tdb_context *tdb, int ltype, /* Return 1 if we find something, 0 if not, -1 on error. */ int first_in_hash(struct tdb_context *tdb, int ltype, struct traverse_info *tinfo, - TDB_DATA *kbuf, unsigned int *dlen) + TDB_DATA *kbuf, size_t *dlen) { tinfo->prev = 0; tinfo->toplevel_group = 0;