X-Git-Url: https://git.ozlabs.org/?a=blobdiff_plain;f=ccan%2Ftdb2%2Ffree.c;h=361171902680ece2441e698a3b960df6ddb781de;hb=a1d06d55999cc5004f4a3c2c8c17638972c6fe50;hp=9af6f5d04ebf3afb6673fcaf11694e290e52d6df;hpb=1a24a8708494668c07e5c02284bfc2ef3b09603b;p=ccan diff --git a/ccan/tdb2/free.c b/ccan/tdb2/free.c index 9af6f5d0..36117190 100644 --- a/ccan/tdb2/free.c +++ b/ccan/tdb2/free.c @@ -164,13 +164,10 @@ tdb_off_t bucket_off(tdb_off_t zone_off, tdb_off_t bucket) /* Returns free_buckets + 1, or list number to search. */ static tdb_off_t find_free_head(struct tdb_context *tdb, tdb_off_t bucket) { - tdb_off_t b; - /* Speculatively search for a non-zero bucket. */ - b = tdb_find_nonzero_off(tdb, bucket_off(tdb->zone_off, bucket), - BUCKETS_FOR_ZONE(tdb->zhdr.zone_bits) + 1 - - bucket); - return bucket + b; + return tdb_find_nonzero_off(tdb, bucket_off(tdb->zone_off, 0), + bucket, + BUCKETS_FOR_ZONE(tdb->zhdr.zone_bits) + 1); } /* Remove from free bucket. */ @@ -510,10 +507,10 @@ int set_header(struct tdb_context *tdb, { uint64_t keybits = (fls64(keylen) + 1) / 2; - /* Use top bits of hash, so it's independent of hash table size. */ + /* Use bottom bits of hash, so it's independent of hash table size. */ rec->magic_and_meta = zone_bits - | ((hash >> 59) << 6) + | ((hash & ((1 << 5)-1)) << 6) | ((actuallen - (keylen + datalen)) << 11) | (keybits << 43) | (TDB_MAGIC << 48); @@ -533,53 +530,6 @@ int set_header(struct tdb_context *tdb, return 0; } -static tdb_len_t adjust_size(size_t keylen, size_t datalen, bool growing) -{ - tdb_len_t size = keylen + datalen; - - if (size < MIN_DATA_LEN) - size = MIN_DATA_LEN; - - /* Overallocate if this is coming from an enlarging store. */ - if (growing) - size += datalen / 2; - - /* Round to next uint64_t boundary. */ - return (size + (sizeof(uint64_t) - 1ULL)) & ~(sizeof(uint64_t) - 1ULL); -} - -/* If this fails, try tdb_expand. */ -tdb_off_t alloc(struct tdb_context *tdb, size_t keylen, size_t datalen, - uint64_t hash, bool growing) -{ - tdb_off_t off; - tdb_len_t size, actual; - struct tdb_used_record rec; - - /* We don't want header to change during this! */ - assert(tdb->header_uptodate); - - size = adjust_size(keylen, datalen, growing); - - off = get_free(tdb, size, &actual); - if (unlikely(off == TDB_OFF_ERR || off == 0)) - return off; - - /* Some supergiant values can't be encoded. */ - /* FIXME: Check before, and limit actual in get_free. */ - if (set_header(tdb, &rec, keylen, datalen, actual, hash, - tdb->zhdr.zone_bits) != 0) { - add_free_record(tdb, tdb->zhdr.zone_bits, off, - sizeof(rec) + actual); - return TDB_OFF_ERR; - } - - if (tdb_write_convert(tdb, off, &rec, sizeof(rec)) != 0) - return TDB_OFF_ERR; - - return off; -} - static bool zones_happy(struct tdb_context *tdb) { /* FIXME: look at distribution of zones. */ @@ -594,8 +544,7 @@ static tdb_len_t overhead(unsigned int zone_bits) } /* Expand the database (by adding a zone). */ -int tdb_expand(struct tdb_context *tdb, tdb_len_t klen, tdb_len_t dlen, - bool growing) +static int tdb_expand(struct tdb_context *tdb, tdb_len_t size) { uint64_t old_size; tdb_off_t off; @@ -606,8 +555,7 @@ int tdb_expand(struct tdb_context *tdb, tdb_len_t klen, tdb_len_t dlen, bool enlarge_zone; /* We need room for the record header too. */ - wanted = sizeof(struct tdb_used_record) - + (adjust_size(klen, dlen, growing)<map_size-1-off) == -1) goto fail; + /* Try allocating from this zone now. */ + tdb->zone_off = old_size - 1; + tdb->zhdr = zhdr; + success: tdb_unlock_expand(tdb, F_WRLCK); return 0; @@ -675,3 +627,57 @@ fail: tdb_unlock_expand(tdb, F_WRLCK); return -1; } + +static tdb_len_t adjust_size(size_t keylen, size_t datalen, bool growing) +{ + tdb_len_t size = keylen + datalen; + + if (size < MIN_DATA_LEN) + size = MIN_DATA_LEN; + + /* Overallocate if this is coming from an enlarging store. */ + if (growing) + size += datalen / 2; + + /* Round to next uint64_t boundary. */ + return (size + (sizeof(uint64_t) - 1ULL)) & ~(sizeof(uint64_t) - 1ULL); +} + +/* This won't fail: it will expand the database if it has to. */ +tdb_off_t alloc(struct tdb_context *tdb, size_t keylen, size_t datalen, + uint64_t hash, bool growing) +{ + tdb_off_t off; + tdb_len_t size, actual; + struct tdb_used_record rec; + + /* We can't hold pointers during this: we could unmap! */ + assert(!tdb->direct_access); + + size = adjust_size(keylen, datalen, growing); + +again: + off = get_free(tdb, size, &actual); + if (unlikely(off == TDB_OFF_ERR)) + return off; + + if (unlikely(off == 0)) { + if (tdb_expand(tdb, size) == -1) + return TDB_OFF_ERR; + goto again; + } + + /* Some supergiant values can't be encoded. */ + /* FIXME: Check before, and limit actual in get_free. */ + if (set_header(tdb, &rec, keylen, datalen, actual, hash, + tdb->zhdr.zone_bits) != 0) { + add_free_record(tdb, tdb->zhdr.zone_bits, off, + sizeof(rec) + actual); + return TDB_OFF_ERR; + } + + if (tdb_write_convert(tdb, off, &rec, sizeof(rec)) != 0) + return TDB_OFF_ERR; + + return off; +}