Commit 2491b65a authored by Rusty Russell's avatar Rusty Russell

tdb2: use separate magic constants for chain, htable and ftable entries

Rather than overloading TDB_USED_MAGIC and the hash value as we do now.
We also rename "free list" to the more-accurate "free table" everywhere.
parent f5087965
...@@ -95,6 +95,13 @@ static bool check_hash_chain(struct tdb_context *tdb, ...@@ -95,6 +95,13 @@ static bool check_hash_chain(struct tdb_context *tdb,
if (tdb_read_convert(tdb, off, &rec, sizeof(rec)) == -1) if (tdb_read_convert(tdb, off, &rec, sizeof(rec)) == -1)
return false; return false;
if (rec_magic(&rec) != TDB_CHAIN_MAGIC) {
tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_DEBUG_ERROR,
"tdb_check: Bad hash chain magic %llu",
(long long)rec_magic(&rec));
return false;
}
if (rec_data_length(&rec) != sizeof(struct tdb_chain)) { if (rec_data_length(&rec) != sizeof(struct tdb_chain)) {
tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_DEBUG_ERROR, tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_DEBUG_ERROR,
"tdb_check: Bad hash chain length %llu vs %zu", "tdb_check: Bad hash chain length %llu vs %zu",
...@@ -108,7 +115,7 @@ static bool check_hash_chain(struct tdb_context *tdb, ...@@ -108,7 +115,7 @@ static bool check_hash_chain(struct tdb_context *tdb,
(long long)rec_key_length(&rec)); (long long)rec_key_length(&rec));
return false; return false;
} }
if (rec_hash(&rec) != 2) { if (rec_hash(&rec) != 0) {
tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_DEBUG_ERROR, tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_DEBUG_ERROR,
"tdb_check: Bad hash chain hash value %llu", "tdb_check: Bad hash chain hash value %llu",
(long long)rec_hash(&rec)); (long long)rec_hash(&rec));
...@@ -149,6 +156,12 @@ static bool check_hash_record(struct tdb_context *tdb, ...@@ -149,6 +156,12 @@ static bool check_hash_record(struct tdb_context *tdb,
if (tdb_read_convert(tdb, off, &rec, sizeof(rec)) == -1) if (tdb_read_convert(tdb, off, &rec, sizeof(rec)) == -1)
return false; return false;
if (rec_magic(&rec) != TDB_HTABLE_MAGIC) {
tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_DEBUG_ERROR,
"tdb_check: Bad hash table magic %llu",
(long long)rec_magic(&rec));
return false;
}
if (rec_data_length(&rec) if (rec_data_length(&rec)
!= sizeof(tdb_off_t) << TDB_SUBLEVEL_HASH_BITS) { != sizeof(tdb_off_t) << TDB_SUBLEVEL_HASH_BITS) {
tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_DEBUG_ERROR, tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_DEBUG_ERROR,
...@@ -376,12 +389,12 @@ fail: ...@@ -376,12 +389,12 @@ fail:
static bool check_hash(struct tdb_context *tdb, static bool check_hash(struct tdb_context *tdb,
tdb_off_t used[], tdb_off_t used[],
size_t num_used, size_t num_flists, size_t num_used, size_t num_ftables,
int (*check)(TDB_DATA, TDB_DATA, void *), int (*check)(TDB_DATA, TDB_DATA, void *),
void *private_data) void *private_data)
{ {
/* Free lists also show up as used. */ /* Free tables also show up as used. */
size_t num_found = num_flists; size_t num_found = num_ftables;
if (!check_hash_tree(tdb, offsetof(struct tdb_header, hashtable), if (!check_hash_tree(tdb, offsetof(struct tdb_header, hashtable),
TDB_TOPLEVEL_HASH_BITS-TDB_HASH_GROUP_BITS, TDB_TOPLEVEL_HASH_BITS-TDB_HASH_GROUP_BITS,
...@@ -400,7 +413,8 @@ static bool check_hash(struct tdb_context *tdb, ...@@ -400,7 +413,8 @@ static bool check_hash(struct tdb_context *tdb,
static bool check_free(struct tdb_context *tdb, static bool check_free(struct tdb_context *tdb,
tdb_off_t off, tdb_off_t off,
const struct tdb_free_record *frec, const struct tdb_free_record *frec,
tdb_off_t prev, unsigned int flist, unsigned int bucket) tdb_off_t prev, unsigned int ftable,
unsigned int bucket)
{ {
if (frec_magic(frec) != TDB_FREE_MAGIC) { if (frec_magic(frec) != TDB_FREE_MAGIC) {
tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_DEBUG_ERROR, tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_DEBUG_ERROR,
...@@ -408,10 +422,10 @@ static bool check_free(struct tdb_context *tdb, ...@@ -408,10 +422,10 @@ static bool check_free(struct tdb_context *tdb,
(long long)off, (long long)frec->magic_and_prev); (long long)off, (long long)frec->magic_and_prev);
return false; return false;
} }
if (frec_flist(frec) != flist) { if (frec_ftable(frec) != ftable) {
tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_DEBUG_ERROR, tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_DEBUG_ERROR,
"tdb_check: offset %llu bad freelist %u", "tdb_check: offset %llu bad freetable %u",
(long long)off, frec_flist(frec)); (long long)off, frec_ftable(frec));
return false; return false;
} }
...@@ -436,26 +450,26 @@ static bool check_free(struct tdb_context *tdb, ...@@ -436,26 +450,26 @@ static bool check_free(struct tdb_context *tdb,
return true; return true;
} }
static bool check_free_list(struct tdb_context *tdb, static bool check_free_table(struct tdb_context *tdb,
tdb_off_t flist_off, tdb_off_t ftable_off,
unsigned flist_num, unsigned ftable_num,
tdb_off_t free[], tdb_off_t free[],
size_t num_free, size_t num_free,
size_t *num_found) size_t *num_found)
{ {
struct tdb_freelist flist; struct tdb_freetable ft;
tdb_off_t h; tdb_off_t h;
unsigned int i; unsigned int i;
if (tdb_read_convert(tdb, flist_off, &flist, sizeof(flist)) == -1) if (tdb_read_convert(tdb, ftable_off, &ft, sizeof(ft)) == -1)
return false; return false;
if (rec_magic(&flist.hdr) != TDB_MAGIC if (rec_magic(&ft.hdr) != TDB_FTABLE_MAGIC
|| rec_key_length(&flist.hdr) != 0 || rec_key_length(&ft.hdr) != 0
|| rec_data_length(&flist.hdr) != sizeof(flist) - sizeof(flist.hdr) || rec_data_length(&ft.hdr) != sizeof(ft) - sizeof(ft.hdr)
|| rec_hash(&flist.hdr) != 1) { || rec_hash(&ft.hdr) != 0) {
tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_DEBUG_ERROR, tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_DEBUG_ERROR,
"tdb_check: Invalid header on free list"); "tdb_check: Invalid header on free table");
return false; return false;
} }
...@@ -463,13 +477,13 @@ static bool check_free_list(struct tdb_context *tdb, ...@@ -463,13 +477,13 @@ static bool check_free_list(struct tdb_context *tdb,
tdb_off_t off, prev = 0, *p; tdb_off_t off, prev = 0, *p;
struct tdb_free_record f; struct tdb_free_record f;
h = bucket_off(flist_off, i); h = bucket_off(ftable_off, i);
for (off = tdb_read_off(tdb, h); off; off = f.next) { for (off = tdb_read_off(tdb, h); off; off = f.next) {
if (off == TDB_OFF_ERR) if (off == TDB_OFF_ERR)
return false; return false;
if (tdb_read_convert(tdb, off, &f, sizeof(f))) if (tdb_read_convert(tdb, off, &f, sizeof(f)))
return false; return false;
if (!check_free(tdb, off, &f, prev, flist_num, i)) if (!check_free(tdb, off, &f, prev, ftable_num, i))
return false; return false;
/* FIXME: Check hash bits */ /* FIXME: Check hash bits */
...@@ -588,23 +602,16 @@ static bool check_linear(struct tdb_context *tdb, ...@@ -588,23 +602,16 @@ static bool check_linear(struct tdb_context *tdb,
return false; return false;
} }
/* This record should be in free lists. */ /* This record should be in free lists. */
if (frec_flist(&rec.f) != TDB_FLIST_NONE if (frec_ftable(&rec.f) != TDB_FTABLE_NONE
&& !append(free, num_free, off)) && !append(free, num_free, off))
return false; return false;
} else { } else if (rec_magic(&rec.u) == TDB_USED_MAGIC
|| rec_magic(&rec.u) == TDB_CHAIN_MAGIC
|| rec_magic(&rec.u) == TDB_HTABLE_MAGIC
|| rec_magic(&rec.u) == TDB_FTABLE_MAGIC) {
uint64_t klen, dlen, extra; uint64_t klen, dlen, extra;
/* This record is used! */ /* This record is used! */
if (rec_magic(&rec.u) != TDB_MAGIC) {
tdb_logerr(tdb, TDB_ERR_CORRUPT,
TDB_DEBUG_ERROR,
"tdb_check: Bad magic 0x%llx"
" at offset %zu",
(long long)rec_magic(&rec.u),
(size_t)off);
return false;
}
if (!append(used, num_used, off)) if (!append(used, num_used, off))
return false; return false;
...@@ -630,6 +637,12 @@ static bool check_linear(struct tdb_context *tdb, ...@@ -630,6 +637,12 @@ static bool check_linear(struct tdb_context *tdb,
(long long)len, (long long)off); (long long)len, (long long)off);
return false; return false;
} }
} else {
tdb_logerr(tdb, TDB_ERR_CORRUPT,
TDB_DEBUG_ERROR,
"tdb_check: Bad magic 0x%llx at offset %zu",
(long long)rec_magic(&rec.u), (size_t)off);
return false;
} }
} }
...@@ -648,8 +661,8 @@ int tdb_check(struct tdb_context *tdb, ...@@ -648,8 +661,8 @@ int tdb_check(struct tdb_context *tdb,
int (*check)(TDB_DATA key, TDB_DATA data, void *private_data), int (*check)(TDB_DATA key, TDB_DATA data, void *private_data),
void *private_data) void *private_data)
{ {
tdb_off_t *free = NULL, *used = NULL, flist, recovery; tdb_off_t *free = NULL, *used = NULL, ft, recovery;
size_t num_free = 0, num_used = 0, num_found = 0, num_flists = 0; size_t num_free = 0, num_used = 0, num_found = 0, num_ftables = 0;
if (tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_WAIT, false) != 0) if (tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_WAIT, false) != 0)
return -1; return -1;
...@@ -666,17 +679,17 @@ int tdb_check(struct tdb_context *tdb, ...@@ -666,17 +679,17 @@ int tdb_check(struct tdb_context *tdb,
if (!check_linear(tdb, &used, &num_used, &free, &num_free, recovery)) if (!check_linear(tdb, &used, &num_used, &free, &num_free, recovery))
goto fail; goto fail;
for (flist = first_flist(tdb); flist; flist = next_flist(tdb, flist)) { for (ft = first_ftable(tdb); ft; ft = next_ftable(tdb, ft)) {
if (flist == TDB_OFF_ERR) if (ft == TDB_OFF_ERR)
goto fail; goto fail;
if (!check_free_list(tdb, flist, num_flists, free, num_free, if (!check_free_table(tdb, ft, num_ftables, free, num_free,
&num_found)) &num_found))
goto fail; goto fail;
num_flists++; num_ftables++;
} }
/* FIXME: Check key uniqueness? */ /* FIXME: Check key uniqueness? */
if (!check_hash(tdb, used, num_used, num_flists, check, private_data)) if (!check_hash(tdb, used, num_used, num_ftables, check, private_data))
goto fail; goto fail;
if (num_found != num_free) { if (num_found != num_free) {
......
...@@ -49,24 +49,24 @@ unsigned int size_to_bucket(tdb_len_t data_len) ...@@ -49,24 +49,24 @@ unsigned int size_to_bucket(tdb_len_t data_len)
return bucket; return bucket;
} }
tdb_off_t first_flist(struct tdb_context *tdb) tdb_off_t first_ftable(struct tdb_context *tdb)
{ {
return tdb_read_off(tdb, offsetof(struct tdb_header, free_list)); return tdb_read_off(tdb, offsetof(struct tdb_header, free_table));
} }
tdb_off_t next_flist(struct tdb_context *tdb, tdb_off_t flist) tdb_off_t next_ftable(struct tdb_context *tdb, tdb_off_t ftable)
{ {
return tdb_read_off(tdb, flist + offsetof(struct tdb_freelist, next)); return tdb_read_off(tdb, ftable + offsetof(struct tdb_freetable,next));
} }
int tdb_flist_init(struct tdb_context *tdb) int tdb_ftable_init(struct tdb_context *tdb)
{ {
/* Use reservoir sampling algorithm to select a free list at random. */ /* Use reservoir sampling algorithm to select a free list at random. */
unsigned int rnd, max = 0, count = 0; unsigned int rnd, max = 0, count = 0;
tdb_off_t off; tdb_off_t off;
tdb->flist_off = off = first_flist(tdb); tdb->ftable_off = off = first_ftable(tdb);
tdb->flist = 0; tdb->ftable = 0;
while (off) { while (off) {
if (off == TDB_OFF_ERR) if (off == TDB_OFF_ERR)
...@@ -74,31 +74,31 @@ int tdb_flist_init(struct tdb_context *tdb) ...@@ -74,31 +74,31 @@ int tdb_flist_init(struct tdb_context *tdb)
rnd = random(); rnd = random();
if (rnd >= max) { if (rnd >= max) {
tdb->flist_off = off; tdb->ftable_off = off;
tdb->flist = count; tdb->ftable = count;
max = rnd; max = rnd;
} }
off = next_flist(tdb, off); off = next_ftable(tdb, off);
count++; count++;
} }
return 0; return 0;
} }
/* Offset of a given bucket. */ /* Offset of a given bucket. */
tdb_off_t bucket_off(tdb_off_t flist_off, unsigned bucket) tdb_off_t bucket_off(tdb_off_t ftable_off, unsigned bucket)
{ {
return flist_off + offsetof(struct tdb_freelist, buckets) return ftable_off + offsetof(struct tdb_freetable, buckets)
+ bucket * sizeof(tdb_off_t); + bucket * sizeof(tdb_off_t);
} }
/* Returns free_buckets + 1, or list number to search. */ /* Returns free_buckets + 1, or list number to search. */
static tdb_off_t find_free_head(struct tdb_context *tdb, static tdb_off_t find_free_head(struct tdb_context *tdb,
tdb_off_t flist_off, tdb_off_t ftable_off,
tdb_off_t bucket) tdb_off_t bucket)
{ {
/* Speculatively search for a non-zero bucket. */ /* Speculatively search for a non-zero bucket. */
return tdb_find_nonzero_off(tdb, bucket_off(flist_off, 0), return tdb_find_nonzero_off(tdb, bucket_off(ftable_off, 0),
bucket, TDB_FREE_BUCKETS); bucket, TDB_FREE_BUCKETS);
} }
...@@ -159,8 +159,8 @@ static int enqueue_in_free(struct tdb_context *tdb, ...@@ -159,8 +159,8 @@ static int enqueue_in_free(struct tdb_context *tdb,
struct tdb_free_record new; struct tdb_free_record new;
uint64_t magic = (TDB_FREE_MAGIC << (64 - TDB_OFF_UPPER_STEAL)); uint64_t magic = (TDB_FREE_MAGIC << (64 - TDB_OFF_UPPER_STEAL));
/* We only need to set flist_and_len; rest is set in enqueue_in_free */ /* We only need to set ftable_and_len; rest is set in enqueue_in_free */
new.flist_and_len = ((uint64_t)tdb->flist << (64 - TDB_OFF_UPPER_STEAL)) new.ftable_and_len = ((uint64_t)tdb->ftable << (64 - TDB_OFF_UPPER_STEAL))
| len; | len;
/* prev = 0. */ /* prev = 0. */
new.magic_and_prev = magic; new.magic_and_prev = magic;
...@@ -209,7 +209,7 @@ int add_free_record(struct tdb_context *tdb, ...@@ -209,7 +209,7 @@ int add_free_record(struct tdb_context *tdb,
len = len_with_header - sizeof(struct tdb_used_record); len = len_with_header - sizeof(struct tdb_used_record);
b_off = bucket_off(tdb->flist_off, size_to_bucket(len)); b_off = bucket_off(tdb->ftable_off, size_to_bucket(len));
if (tdb_lock_free_bucket(tdb, b_off, TDB_LOCK_WAIT) != 0) if (tdb_lock_free_bucket(tdb, b_off, TDB_LOCK_WAIT) != 0)
return -1; return -1;
...@@ -245,17 +245,17 @@ static size_t record_leftover(size_t keylen, size_t datalen, ...@@ -245,17 +245,17 @@ static size_t record_leftover(size_t keylen, size_t datalen,
return leftover; return leftover;
} }
static tdb_off_t flist_offset(struct tdb_context *tdb, unsigned int flist) static tdb_off_t ftable_offset(struct tdb_context *tdb, unsigned int ftable)
{ {
tdb_off_t off; tdb_off_t off;
unsigned int i; unsigned int i;
if (likely(tdb->flist == flist)) if (likely(tdb->ftable == ftable))
return tdb->flist_off; return tdb->ftable_off;
off = first_flist(tdb); off = first_ftable(tdb);
for (i = 0; i < flist; i++) for (i = 0; i < ftable; i++)
off = next_flist(tdb, off); off = next_ftable(tdb, off);
return off; return off;
} }
...@@ -272,21 +272,21 @@ static int coalesce(struct tdb_context *tdb, ...@@ -272,21 +272,21 @@ static int coalesce(struct tdb_context *tdb,
while (end < tdb->map_size) { while (end < tdb->map_size) {
const struct tdb_free_record *r; const struct tdb_free_record *r;
tdb_off_t nb_off; tdb_off_t nb_off;
unsigned flist, bucket; unsigned ftable, bucket;
r = tdb_access_read(tdb, end, sizeof(*r), true); r = tdb_access_read(tdb, end, sizeof(*r), true);
if (!r) if (!r)
goto err; goto err;
if (frec_magic(r) != TDB_FREE_MAGIC if (frec_magic(r) != TDB_FREE_MAGIC
|| frec_flist(r) == TDB_FLIST_NONE) { || frec_ftable(r) == TDB_FTABLE_NONE) {
tdb_access_release(tdb, r); tdb_access_release(tdb, r);
break; break;
} }
flist = frec_flist(r); ftable = frec_ftable(r);
bucket = size_to_bucket(frec_len(r)); bucket = size_to_bucket(frec_len(r));
nb_off = bucket_off(flist_offset(tdb, flist), bucket); nb_off = bucket_off(ftable_offset(tdb, ftable), bucket);
tdb_access_release(tdb, r); tdb_access_release(tdb, r);
/* We may be violating lock order here, so best effort. */ /* We may be violating lock order here, so best effort. */
...@@ -307,7 +307,7 @@ static int coalesce(struct tdb_context *tdb, ...@@ -307,7 +307,7 @@ static int coalesce(struct tdb_context *tdb,
break; break;
} }
if (unlikely(frec_flist(&rec) != flist) if (unlikely(frec_ftable(&rec) != ftable)
|| unlikely(size_to_bucket(frec_len(&rec)) != bucket)) { || unlikely(size_to_bucket(frec_len(&rec)) != bucket)) {
add_stat(tdb, alloc_coalesce_race, 1); add_stat(tdb, alloc_coalesce_race, 1);
tdb_unlock_free_bucket(tdb, nb_off); tdb_unlock_free_bucket(tdb, nb_off);
...@@ -344,11 +344,11 @@ static int coalesce(struct tdb_context *tdb, ...@@ -344,11 +344,11 @@ static int coalesce(struct tdb_context *tdb,
/* We have to drop this to avoid deadlocks, so make sure record /* We have to drop this to avoid deadlocks, so make sure record
* doesn't get coalesced by someone else! */ * doesn't get coalesced by someone else! */
rec.flist_and_len = (TDB_FLIST_NONE << (64 - TDB_OFF_UPPER_STEAL)) rec.ftable_and_len = (TDB_FTABLE_NONE << (64 - TDB_OFF_UPPER_STEAL))
| (end - off - sizeof(struct tdb_used_record)); | (end - off - sizeof(struct tdb_used_record));
if (tdb_write_off(tdb, off + offsetof(struct tdb_free_record, if (tdb_write_off(tdb, off + offsetof(struct tdb_free_record,
flist_and_len), ftable_and_len),
rec.flist_and_len) != 0) rec.ftable_and_len) != 0)
goto err; goto err;
add_stat(tdb, alloc_coalesce_succeeded, 1); add_stat(tdb, alloc_coalesce_succeeded, 1);
...@@ -366,10 +366,11 @@ err: ...@@ -366,10 +366,11 @@ err:
/* We need size bytes to put our key and data in. */ /* We need size bytes to put our key and data in. */
static tdb_off_t lock_and_alloc(struct tdb_context *tdb, static tdb_off_t lock_and_alloc(struct tdb_context *tdb,
tdb_off_t flist_off, tdb_off_t ftable_off,
tdb_off_t bucket, tdb_off_t bucket,
size_t keylen, size_t datalen, size_t keylen, size_t datalen,
bool want_extra, bool want_extra,
unsigned magic,
unsigned hashlow) unsigned hashlow)
{ {
tdb_off_t off, b_off,best_off; tdb_off_t off, b_off,best_off;
...@@ -379,7 +380,7 @@ static tdb_off_t lock_and_alloc(struct tdb_context *tdb, ...@@ -379,7 +380,7 @@ static tdb_off_t lock_and_alloc(struct tdb_context *tdb,
add_stat(tdb, allocs, 1); add_stat(tdb, allocs, 1);
again: again:
b_off = bucket_off(flist_off, bucket); b_off = bucket_off(ftable_off, bucket);
/* FIXME: Try non-blocking wait first, to measure contention. */ /* FIXME: Try non-blocking wait first, to measure contention. */
/* Lock this bucket. */ /* Lock this bucket. */
...@@ -387,7 +388,7 @@ again: ...@@ -387,7 +388,7 @@ again:
return TDB_OFF_ERR; return TDB_OFF_ERR;
} }
best.flist_and_len = -1ULL; best.ftable_and_len = -1ULL;
best_off = 0; best_off = 0;
/* Get slack if we're after extra. */ /* Get slack if we're after extra. */
...@@ -462,9 +463,8 @@ again: ...@@ -462,9 +463,8 @@ again:
assert(keylen + datalen + leftover <= frec_len(&best)); assert(keylen + datalen + leftover <= frec_len(&best));
/* We need to mark non-free before we drop lock, otherwise /* We need to mark non-free before we drop lock, otherwise
* coalesce() could try to merge it! */ * coalesce() could try to merge it! */
if (set_used_header(tdb, &rec, keylen, datalen, if (set_header(tdb, &rec, magic, keylen, datalen,
frec_len(&best) - leftover, frec_len(&best) - leftover, hashlow) != 0)
hashlow) != 0)
goto unlock_err; goto unlock_err;
if (tdb_write_convert(tdb, best_off, &rec, sizeof(rec)) != 0) if (tdb_write_convert(tdb, best_off, &rec, sizeof(rec)) != 0)
...@@ -496,10 +496,10 @@ unlock_err: ...@@ -496,10 +496,10 @@ unlock_err:
/* Get a free block from current free list, or 0 if none. */ /* Get a free block from current free list, or 0 if none. */
static tdb_off_t get_free(struct tdb_context *tdb, static tdb_off_t get_free(struct tdb_context *tdb,
size_t keylen, size_t datalen, bool want_extra, size_t keylen, size_t datalen, bool want_extra,
unsigned hashlow) unsigned magic, unsigned hashlow)
{ {
tdb_off_t off, flist_off; tdb_off_t off, ftable_off;
unsigned start_b, b, flist; unsigned start_b, b, ftable;
bool wrapped = false; bool wrapped = false;
/* If they are growing, add 50% to get to higher bucket. */ /* If they are growing, add 50% to get to higher bucket. */
...@@ -509,17 +509,17 @@ static tdb_off_t get_free(struct tdb_context *tdb, ...@@ -509,17 +509,17 @@ static tdb_off_t get_free(struct tdb_context *tdb,
else else
start_b = size_to_bucket(adjust_size(keylen, datalen)); start_b = size_to_bucket(adjust_size(keylen, datalen));
flist_off = tdb->flist_off; ftable_off = tdb->ftable_off;
flist = tdb->flist; ftable = tdb->ftable;
while (!wrapped || flist_off != tdb->flist_off) { while (!wrapped || ftable_off != tdb->ftable_off) {
/* Start at exact size bucket, and search up... */ /* Start at exact size bucket, and search up... */
for (b = find_free_head(tdb, flist_off, start_b); for (b = find_free_head(tdb, ftable_off, start_b);
b < TDB_FREE_BUCKETS; b < TDB_FREE_BUCKETS;
b = find_free_head(tdb, flist_off, b + 1)) { b = find_free_head(tdb, ftable_off, b + 1)) {
/* Try getting one from list. */ /* Try getting one from list. */
off = lock_and_alloc(tdb, flist_off, off = lock_and_alloc(tdb, ftable_off,
b, keylen, datalen, want_extra, b, keylen, datalen, want_extra,
hashlow); magic, hashlow);
if (off == TDB_OFF_ERR) if (off == TDB_OFF_ERR)
return TDB_OFF_ERR; return TDB_OFF_ERR;
if (off != 0) { if (off != 0) {
...@@ -528,31 +528,31 @@ static tdb_off_t get_free(struct tdb_context *tdb, ...@@ -528,31 +528,31 @@ static tdb_off_t get_free(struct tdb_context *tdb,
if (b == TDB_FREE_BUCKETS - 1) if (b == TDB_FREE_BUCKETS - 1)
add_stat(tdb, alloc_bucket_max, 1); add_stat(tdb, alloc_bucket_max, 1);
/* Worked? Stay using this list. */ /* Worked? Stay using this list. */
tdb->flist_off = flist_off; tdb->ftable_off = ftable_off;
tdb->flist = flist; tdb->ftable = ftable;
return off; return off;
} }
/* Didn't work. Try next bucket. */ /* Didn't work. Try next bucket. */
} }
/* Hmm, try next list. */ /* Hmm, try next table. */
flist_off = next_flist(tdb, flist_off); ftable_off = next_ftable(tdb, ftable_off);
flist++; ftable++;
if (flist_off == 0) { if (ftable_off == 0) {
wrapped = true; wrapped = true;
flist_off = first_flist(tdb); ftable_off = first_ftable(tdb);
flist = 0; ftable = 0;
} }
} }
return 0; return 0;
} }
int set_used_header(struct tdb_context *tdb, int set_header(struct tdb_context *tdb,
struct tdb_used_record *rec, struct tdb_used_record *rec,
uint64_t keylen, uint64_t datalen, unsigned magic, uint64_t keylen, uint64_t datalen,
uint64_t actuallen, unsigned hashlow) uint64_t actuallen, unsigned hashlow)
{ {
uint64_t keybits = (fls64(keylen) + 1) / 2; uint64_t keybits = (fls64(keylen) + 1) / 2;
...@@ -560,7 +560,7 @@ int set_used_header(struct tdb_context *tdb, ...@@ -560,7 +560,7 @@ int set_used_header(struct tdb_context *tdb,
rec->magic_and_meta = (hashlow & ((1 << 11)-1)) rec->magic_and_meta = (hashlow & ((1 << 11)-1))
| ((actuallen - (keylen + datalen)) << 11) | ((actuallen - (keylen + datalen)) << 11)
| (keybits << 43) | (keybits << 43)
| (TDB_MAGIC << 48); | ((uint64_t)magic << 48);
rec->key_and_data_len = (keylen | (datalen << (keybits*2))); rec->key_and_data_len = (keylen | (datalen << (keybits*2)));
/* Encoding can fail on big values. */ /* Encoding can fail on big values. */
...@@ -627,7 +627,7 @@ static int tdb_expand(struct tdb_context *tdb, tdb_len_t size) ...@@ -627,7 +627,7 @@ static int tdb_expand(struct tdb_context *tdb, tdb_len_t size)
/* This won't fail: it will expand the database if it has to. */ /* 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, tdb_off_t alloc(struct tdb_context *tdb, size_t keylen, size_t datalen,
uint64_t hash, bool growing) uint64_t hash, unsigned magic, bool growing)
{ {
tdb_off_t off; tdb_off_t off;
...@@ -635,7 +635,7 @@ tdb_off_t alloc(struct tdb_context *tdb, size_t keylen, size_t datalen, ...@@ -635,7 +635,7 @@ tdb_off_t alloc(struct tdb_context *tdb, size_t keylen, size_t datalen,
assert(!tdb->direct_access); assert(!tdb->direct_access);
for (;;) { for (;;) {
off = get_free(tdb, keylen, datalen, growing, hash); off = get_free(tdb, keylen, datalen, growing, magic, hash);
if (likely(off != 0)) if (likely(off != 0))
break; break;
......
...@@ -409,8 +409,8 @@ static int COLD add_to_chain(struct tdb_context *tdb, ...@@ -409,8 +409,8 @@ static int COLD add_to_chain(struct tdb_context *tdb,
return -1; return -1;
if (!next) { if (!next) {
next = alloc(tdb, 0, sizeof(struct tdb_chain), 2, next = alloc(tdb, 0, sizeof(struct tdb_chain), 0,
false); TDB_CHAIN_MAGIC, false);
if (next == TDB_OFF_ERR) if (next == TDB_OFF_ERR)
return -1; return -1;
if (zero_out(tdb, next+sizeof(struct tdb_used_record), if (zero_out(tdb, next+sizeof(struct tdb_used_record),
...@@ -457,7 +457,7 @@ static int add_to_subhash(struct tdb_context *tdb, tdb_off_t subhash, ...@@ -457,7 +457,7 @@ static int add_to_subhash(struct tdb_context *tdb, tdb_off_t subhash,
static int expand_group(struct tdb_context *tdb, struct hash_info *h) static int expand_group(struct tdb_context *tdb, struct hash_info *h)
{ {
unsigned bucket, num_vals, i, hash; unsigned bucket, num_vals, i, magic;
size_t subsize; size_t subsize;
tdb_off_t subhash; tdb_off_t subhash;
tdb_off_t vals[1 << TDB_HASH_GROUP_BITS]; tdb_off_t vals[1 << TDB_HASH_GROUP_BITS];
...@@ -468,14 +468,14 @@ static int expand_group(struct tdb_context *tdb, struct hash_info *h) ...@@ -468,14 +468,14 @@ static int expand_group(struct tdb_context *tdb, struct hash_info *h)
if (h->hash_used == 64) { if (h->hash_used == 64) {
add_stat(tdb, alloc_chain, 1); add_stat(tdb, alloc_chain, 1);
subsize = sizeof(struct tdb_chain); subsize = sizeof(struct tdb_chain);
hash = 2; magic = TDB_CHAIN_MAGIC;
} else { } else {
add_stat(tdb, alloc_subhash, 1); add_stat(tdb, alloc_subhash, 1);
subsize = (sizeof(tdb_off_t) << TDB_SUBLEVEL_HASH_BITS); subsize = (sizeof(tdb_off_t) << TDB_SUBLEVEL_HASH_BITS);
hash = 0; magic = TDB_HTABLE_MAGIC;
} }
subhash = alloc(tdb, 0, subsize, hash, false); subhash = alloc(tdb, 0, subsize, 0, magic, false);
if (subhash == TDB_OFF_ERR) if (subhash == TDB_OFF_ERR)
return -1; return -1;
...@@ -703,7 +703,7 @@ int next_in_hash(struct tdb_context *tdb, int ltype, ...@@ -703,7 +703,7 @@ int next_in_hash(struct tdb_context *tdb, int ltype,
ltype); ltype);
return -1; return -1;
} }
if (rec_magic(&rec) != TDB_MAGIC) { if (rec_magic(&rec) != TDB_USED_MAGIC) {
tdb_logerr(tdb, TDB_ERR_CORRUPT, tdb_logerr(tdb, TDB_ERR_CORRUPT,
TDB_DEBUG_FATAL, TDB_DEBUG_FATAL,
"next_in_hash:" "next_in_hash:"
......
...@@ -495,12 +495,12 @@ again: ...@@ -495,12 +495,12 @@ again:
return -1; return -1;
} }
/* Lock free lists: there to end of file. */ /* Lock free tables: there to end of file. */
if (tdb_brlock(tdb, ltype, TDB_HASH_LOCK_START + TDB_HASH_LOCK_RANGE, if (tdb_brlock(tdb, ltype, TDB_HASH_LOCK_START + TDB_HASH_LOCK_RANGE,
0, flags)) { 0, flags)) {
if (!(flags & TDB_LOCK_PROBE)) { if (!(flags & TDB_LOCK_PROBE)) {
tdb_logerr(tdb, tdb->ecode, TDB_DEBUG_ERROR, tdb_logerr(tdb, tdb->ecode, TDB_DEBUG_ERROR,
"tdb_allrecord_lock freelist failed"); "tdb_allrecord_lock freetables failed");
} }
tdb_brunlock(tdb, ltype, TDB_HASH_LOCK_START, tdb_brunlock(tdb, ltype, TDB_HASH_LOCK_START,
TDB_HASH_LOCK_RANGE); TDB_HASH_LOCK_RANGE);
......
...@@ -64,7 +64,10 @@ typedef uint64_t tdb_off_t; ...@@ -64,7 +64,10 @@ typedef uint64_t tdb_off_t;
#define TDB_MAGIC_FOOD "TDB file\n" #define TDB_MAGIC_FOOD "TDB file\n"
#define TDB_VERSION ((uint64_t)(0x26011967 + 7)) #define TDB_VERSION ((uint64_t)(0x26011967 + 7))
#define TDB_MAGIC ((uint64_t)0x1999) #define TDB_USED_MAGIC ((uint64_t)0x1999)
#define TDB_HTABLE_MAGIC ((uint64_t)0x1888)
#define TDB_CHAIN_MAGIC ((uint64_t)0x1777)
#define TDB_FTABLE_MAGIC ((uint64_t)0x1666)
#define TDB_FREE_MAGIC ((uint64_t)0xFE) #define TDB_FREE_MAGIC ((uint64_t)0xFE)
#define TDB_HASH_MAGIC (0xA1ABE11A01092008ULL) #define TDB_HASH_MAGIC (0xA1ABE11A01092008ULL)
#define TDB_RECOVERY_MAGIC (0xf53bc0e7ad124589ULL) #define TDB_RECOVERY_MAGIC (0xf53bc0e7ad124589ULL)
...@@ -119,7 +122,7 @@ typedef uint64_t tdb_off_t; ...@@ -119,7 +122,7 @@ typedef uint64_t tdb_off_t;
(sizeof(struct tdb_free_record) - sizeof(struct tdb_used_record)) (sizeof(struct tdb_free_record) - sizeof(struct tdb_used_record))
/* Indicates this entry is not on an flist (can happen during coalescing) */ /* Indicates this entry is not on an flist (can happen during coalescing) */
#define TDB_FLIST_NONE ((1ULL << TDB_OFF_UPPER_STEAL) - 1) #define TDB_FTABLE_NONE ((1ULL << TDB_OFF_UPPER_STEAL) - 1)
#if !HAVE_BSWAP_64 #if !HAVE_BSWAP_64
static inline uint64_t bswap_64(uint64_t x) static inline uint64_t bswap_64(uint64_t x)
...@@ -179,7 +182,7 @@ static inline uint16_t rec_magic(const struct tdb_used_record *r) ...@@ -179,7 +182,7 @@ static inline uint16_t rec_magic(const struct tdb_used_record *r)
struct tdb_free_record { struct tdb_free_record {
uint64_t magic_and_prev; /* TDB_OFF_UPPER_STEAL bits magic, then prev */ uint64_t magic_and_prev; /* TDB_OFF_UPPER_STEAL bits magic, then prev */
uint64_t flist_and_len; /* Len not counting these two fields. */ uint64_t ftable_and_len; /* Len not counting these two fields. */
/* This is why the minimum record size is 8 bytes. */ /* This is why the minimum record size is 8 bytes. */
uint64_t next; uint64_t next;
}; };
...@@ -196,12 +199,12 @@ static inline uint64_t frec_magic(const struct tdb_free_record *f) ...@@ -196,12 +199,12 @@ static inline uint64_t frec_magic(const struct tdb_free_record *f)
static inline uint64_t frec_len(const struct tdb_free_record *f) static inline uint64_t frec_len(const struct tdb_free_record *f)
{ {
return f->flist_and_len & ((1ULL << (64 - TDB_OFF_UPPER_STEAL))-1); return f->ftable_and_len & ((1ULL << (64 - TDB_OFF_UPPER_STEAL))-1);
} }
static inline unsigned frec_flist(const struct tdb_free_record *f) static inline unsigned frec_ftable(const struct tdb_free_record *f)
{ {
return f->flist_and_len >> (64 - TDB_OFF_UPPER_STEAL); return f->ftable_and_len >> (64 - TDB_OFF_UPPER_STEAL);
} }
struct tdb_recovery_record { struct tdb_recovery_record {
...@@ -227,7 +230,7 @@ struct tdb_header { ...@@ -227,7 +230,7 @@ struct tdb_header {
uint64_t version; /* version of the code */ uint64_t version; /* version of the code */
uint64_t hash_test; /* result of hashing HASH_MAGIC. */ uint64_t hash_test; /* result of hashing HASH_MAGIC. */
uint64_t hash_seed; /* "random" seed written at creation time. */ uint64_t hash_seed; /* "random" seed written at creation time. */
tdb_off_t free_list; /* (First) free list. */ tdb_off_t free_table; /* (First) free table. */
tdb_off_t recovery; /* Transaction recovery area. */ tdb_off_t recovery; /* Transaction recovery area. */
tdb_off_t reserved[26]; tdb_off_t reserved[26];
...@@ -236,7 +239,7 @@ struct tdb_header { ...@@ -236,7 +239,7 @@ struct tdb_header {
tdb_off_t hashtable[1ULL << TDB_TOPLEVEL_HASH_BITS]; tdb_off_t hashtable[1ULL << TDB_TOPLEVEL_HASH_BITS];
}; };
struct tdb_freelist { struct tdb_freetable {
struct tdb_used_record hdr; struct tdb_used_record hdr;
tdb_off_t next; tdb_off_t next;
tdb_off_t buckets[TDB_FREE_BUCKETS]; tdb_off_t buckets[TDB_FREE_BUCKETS];
...@@ -339,9 +342,9 @@ struct tdb_context { ...@@ -339,9 +342,9 @@ struct tdb_context {
/* Set if we are in a transaction. */ /* Set if we are in a transaction. */
struct tdb_transaction *transaction; struct tdb_transaction *transaction;
/* What freelist are we using? */ /* What free table are we using? */
uint64_t flist_off; tdb_off_t ftable_off;
unsigned int flist; unsigned int ftable;
/* IO methods: changes for transactions. */ /* IO methods: changes for transactions. */
const struct tdb_methods *methods; const struct tdb_methods *methods;
...@@ -403,29 +406,29 @@ int delete_from_hash(struct tdb_context *tdb, struct hash_info *h); ...@@ -403,29 +406,29 @@ int delete_from_hash(struct tdb_context *tdb, struct hash_info *h);
bool is_subhash(tdb_off_t val); bool is_subhash(tdb_off_t val);
/* free.c: */ /* free.c: */
int tdb_flist_init(struct tdb_context *tdb); int tdb_ftable_init(struct tdb_context *tdb);
/* check.c needs these to iterate through free lists. */ /* check.c needs these to iterate through free lists. */
tdb_off_t first_flist(struct tdb_context *tdb); tdb_off_t first_ftable(struct tdb_context *tdb);
tdb_off_t next_flist(struct tdb_context *tdb, tdb_off_t flist); tdb_off_t next_ftable(struct tdb_context *tdb, tdb_off_t ftable);
/* If this fails, try tdb_expand. */ /* This returns space or TDB_OFF_ERR. */
tdb_off_t alloc(struct tdb_context *tdb, size_t keylen, size_t datalen, tdb_off_t alloc(struct tdb_context *tdb, size_t keylen, size_t datalen,
uint64_t hash, bool growing); uint64_t hash, unsigned magic, bool growing);
/* Put this record in a free list. */ /* Put this record in a free list. */
int add_free_record(struct tdb_context *tdb, int add_free_record(struct tdb_context *tdb,
tdb_off_t off, tdb_len_t len_with_header); tdb_off_t off, tdb_len_t len_with_header);
/* Set up header for a used record. */ /* Set up header for a used/ftable/htable/chain record. */
int set_used_header(struct tdb_context *tdb, int set_header(struct tdb_context *tdb,
struct tdb_used_record *rec, struct tdb_used_record *rec,
uint64_t keylen, uint64_t datalen, unsigned magic, uint64_t keylen, uint64_t datalen,
uint64_t actuallen, unsigned hashlow); uint64_t actuallen, unsigned hashlow);
/* Used by tdb_check to verify. */ /* Used by tdb_check to verify. */
unsigned int size_to_bucket(tdb_len_t data_len); unsigned int size_to_bucket(tdb_len_t data_len);
tdb_off_t bucket_off(tdb_off_t flist_off, unsigned bucket); tdb_off_t bucket_off(tdb_off_t ftable_off, unsigned bucket);
/* Used by tdb_summary */ /* Used by tdb_summary */
size_t dead_space(struct tdb_context *tdb, tdb_off_t off); size_t dead_space(struct tdb_context *tdb, tdb_off_t off);
......
...@@ -37,7 +37,7 @@ static int count_hash(struct tdb_context *tdb, ...@@ -37,7 +37,7 @@ static int count_hash(struct tdb_context *tdb,
static bool summarize(struct tdb_context *tdb, static bool summarize(struct tdb_context *tdb,
struct tally *hashes, struct tally *hashes,
struct tally *flists, struct tally *ftables,
struct tally *free, struct tally *free,
struct tally *keys, struct tally *keys,
struct tally *data, struct tally *data,
...@@ -73,7 +73,7 @@ static bool summarize(struct tdb_context *tdb, ...@@ -73,7 +73,7 @@ static bool summarize(struct tdb_context *tdb,
tally_add(buckets, size_to_bucket(len)); tally_add(buckets, size_to_bucket(len));
len += sizeof(p->u); len += sizeof(p->u);
unc++; unc++;
} else if (rec_magic(&p->u) == TDB_MAGIC) { } else if (rec_magic(&p->u) == TDB_USED_MAGIC) {
if (unc) { if (unc) {
tally_add(uncoal, unc); tally_add(uncoal, unc);
unc = 0; unc = 0;
...@@ -83,25 +83,31 @@ static bool summarize(struct tdb_context *tdb, ...@@ -83,25 +83,31 @@ static bool summarize(struct tdb_context *tdb,
+ rec_data_length(&p->u) + rec_data_length(&p->u)
+ rec_extra_padding(&p->u); + rec_extra_padding(&p->u);
/* FIXME: Use different magic for hashes, flists. */ tally_add(keys, rec_key_length(&p->u));
if (!rec_key_length(&p->u) && rec_hash(&p->u) < 3) { tally_add(data, rec_data_length(&p->u));
if (rec_hash(&p->u) == 0) { tally_add(extra, rec_extra_padding(&p->u));
int count = count_hash(tdb, } else if (rec_magic(&p->u) == TDB_HTABLE_MAGIC) {
off + sizeof(p->u), int count = count_hash(tdb,
TDB_SUBLEVEL_HASH_BITS); off + sizeof(p->u),
if (count == -1) TDB_SUBLEVEL_HASH_BITS);
return false; if (count == -1)
tally_add(hashes, count); return false;
} else if (rec_hash(&p->u) == 1) { tally_add(hashes, count);
tally_add(flists, tally_add(extra, rec_extra_padding(&p->u));
rec_data_length(&p->u)); len = sizeof(p->u)
} else if (rec_hash(&p->u) == 2) { + rec_data_length(&p->u)
tally_add(chains, 1); + rec_extra_padding(&p->u);
} } else if (rec_magic(&p->u) == TDB_FTABLE_MAGIC) {
} else { len = sizeof(p->u)
tally_add(keys, rec_key_length(&p->u)); + rec_data_length(&p->u)
tally_add(data, rec_data_length(&p->u)); + rec_extra_padding(&p->u);
} tally_add(ftables, rec_data_length(&p->u));
tally_add(extra, rec_extra_padding(&p->u));
} else if (rec_magic(&p->u) == TDB_CHAIN_MAGIC) {
len = sizeof(p->u)
+ rec_data_length(&p->u)
+ rec_extra_padding(&p->u);
tally_add(chains, 1);
tally_add(extra, rec_extra_padding(&p->u)); tally_add(extra, rec_extra_padding(&p->u));
} else } else
len = dead_space(tdb, off); len = dead_space(tdb, off);
...@@ -142,7 +148,7 @@ static bool summarize(struct tdb_context *tdb, ...@@ -142,7 +148,7 @@ static bool summarize(struct tdb_context *tdb,
char *tdb_summary(struct tdb_context *tdb, enum tdb_summary_flags flags) char *tdb_summary(struct tdb_context *tdb, enum tdb_summary_flags flags)
{ {
tdb_len_t len; tdb_len_t len;
struct tally *flists, *hashes, *freet, *keys, *data, *extra, *uncoal, struct tally *ftables, *hashes, *freet, *keys, *data, *extra, *uncoal,
*buckets, *chains; *buckets, *chains;
char *hashesg, *freeg, *keysg, *datag, *extrag, *uncoalg, *bucketsg; char *hashesg, *freeg, *keysg, *datag, *extrag, *uncoalg, *bucketsg;
char *ret = NULL; char *ret = NULL;
...@@ -158,7 +164,7 @@ char *tdb_summary(struct tdb_context *tdb, enum tdb_summary_flags flags) ...@@ -158,7 +164,7 @@ char *tdb_summary(struct tdb_context *tdb, enum tdb_summary_flags flags)
} }
/* Start stats off empty. */ /* Start stats off empty. */
flists = tally_new(HISTO_HEIGHT); ftables = tally_new(HISTO_HEIGHT);
hashes = tally_new(HISTO_HEIGHT); hashes = tally_new(HISTO_HEIGHT);
freet = tally_new(HISTO_HEIGHT); freet = tally_new(HISTO_HEIGHT);
keys = tally_new(HISTO_HEIGHT); keys = tally_new(HISTO_HEIGHT);
...@@ -167,14 +173,14 @@ char *tdb_summary(struct tdb_context *tdb, enum tdb_summary_flags flags) ...@@ -167,14 +173,14 @@ char *tdb_summary(struct tdb_context *tdb, enum tdb_summary_flags flags)
uncoal = tally_new(HISTO_HEIGHT); uncoal = tally_new(HISTO_HEIGHT);
buckets = tally_new(HISTO_HEIGHT); buckets = tally_new(HISTO_HEIGHT);
chains = tally_new(HISTO_HEIGHT); chains = tally_new(HISTO_HEIGHT);
if (!flists || !hashes || !freet || !keys || !data || !extra if (!ftables || !hashes || !freet || !keys || !data || !extra
|| !uncoal || !buckets || !chains) { || !uncoal || !buckets || !chains) {
tdb_logerr(tdb, TDB_ERR_OOM, TDB_DEBUG_ERROR, tdb_logerr(tdb, TDB_ERR_OOM, TDB_DEBUG_ERROR,
"tdb_summary: failed to allocate tally structures"); "tdb_summary: failed to allocate tally structures");
goto unlock; goto unlock;
} }
if (!summarize(tdb, hashes, flists, freet, keys, data, extra, uncoal, if (!summarize(tdb, hashes, ftables, freet, keys, data, extra, uncoal,
buckets, chains)) buckets, chains))
goto unlock; goto unlock;
...@@ -233,7 +239,7 @@ char *tdb_summary(struct tdb_context *tdb, enum tdb_summary_flags flags) ...@@ -233,7 +239,7 @@ char *tdb_summary(struct tdb_context *tdb, enum tdb_summary_flags flags)
tally_total(freet, NULL) * 100.0 / tdb->map_size, tally_total(freet, NULL) * 100.0 / tdb->map_size,
(tally_num(keys) + tally_num(freet) + tally_num(hashes)) (tally_num(keys) + tally_num(freet) + tally_num(hashes))
* sizeof(struct tdb_used_record) * 100.0 / tdb->map_size, * sizeof(struct tdb_used_record) * 100.0 / tdb->map_size,
tally_num(flists) * sizeof(struct tdb_freelist) tally_num(ftables) * sizeof(struct tdb_freetable)
* 100.0 / tdb->map_size, * 100.0 / tdb->map_size,
(tally_num(hashes) (tally_num(hashes)
* (sizeof(tdb_off_t) << TDB_SUBLEVEL_HASH_BITS) * (sizeof(tdb_off_t) << TDB_SUBLEVEL_HASH_BITS)
...@@ -256,6 +262,7 @@ unlock: ...@@ -256,6 +262,7 @@ unlock:
free(data); free(data);
free(extra); free(extra);
free(uncoal); free(uncoal);
free(ftables);
free(chains); free(chains);
tdb_allrecord_unlock(tdb, F_RDLCK); tdb_allrecord_unlock(tdb, F_RDLCK);
......
...@@ -72,7 +72,7 @@ static uint64_t random_number(struct tdb_context *tdb) ...@@ -72,7 +72,7 @@ static uint64_t random_number(struct tdb_context *tdb)
struct new_database { struct new_database {
struct tdb_header hdr; struct tdb_header hdr;
struct tdb_freelist flist; struct tdb_freetable ftable;
}; };
/* initialise a new database */ /* initialise a new database */
...@@ -101,11 +101,11 @@ static int tdb_new_database(struct tdb_context *tdb, ...@@ -101,11 +101,11 @@ static int tdb_new_database(struct tdb_context *tdb,
memset(newdb.hdr.hashtable, 0, sizeof(newdb.hdr.hashtable)); memset(newdb.hdr.hashtable, 0, sizeof(newdb.hdr.hashtable));
/* Free is empty. */ /* Free is empty. */
newdb.hdr.free_list = offsetof(struct new_database, flist); newdb.hdr.free_table = offsetof(struct new_database, ftable);
memset(&newdb.flist, 0, sizeof(newdb.flist)); memset(&newdb.ftable, 0, sizeof(newdb.ftable));
set_used_header(NULL, &newdb.flist.hdr, 0, set_header(NULL, &newdb.ftable.hdr, TDB_FTABLE_MAGIC, 0,
sizeof(newdb.flist) - sizeof(newdb.flist.hdr), sizeof(newdb.ftable) - sizeof(newdb.ftable.hdr),
sizeof(newdb.flist) - sizeof(newdb.flist.hdr), 1); sizeof(newdb.ftable) - sizeof(newdb.ftable.hdr), 0);
/* Magic food */ /* Magic food */
memset(newdb.hdr.magic_food, 0, sizeof(newdb.hdr.magic_food)); memset(newdb.hdr.magic_food, 0, sizeof(newdb.hdr.magic_food));
...@@ -229,7 +229,7 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags, ...@@ -229,7 +229,7 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
} }
tdb_convert(tdb, &hdr.hash_seed, sizeof(hdr.hash_seed)); tdb_convert(tdb, &hdr.hash_seed, sizeof(hdr.hash_seed));
tdb->hash_seed = hdr.hash_seed; tdb->hash_seed = hdr.hash_seed;
tdb_flist_init(tdb); tdb_ftable_init(tdb);
return tdb; return tdb;
} }
...@@ -324,7 +324,7 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags, ...@@ -324,7 +324,7 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
goto fail; goto fail;
} }
if (tdb_flist_init(tdb) == -1) if (tdb_ftable_init(tdb) == -1)
goto fail; goto fail;
tdb->next = tdbs; tdb->next = tdbs;
...@@ -386,7 +386,8 @@ static int update_rec_hdr(struct tdb_context *tdb, ...@@ -386,7 +386,8 @@ static int update_rec_hdr(struct tdb_context *tdb,
{ {
uint64_t dataroom = rec_data_length(rec) + rec_extra_padding(rec); uint64_t dataroom = rec_data_length(rec) + rec_extra_padding(rec);
if (set_used_header(tdb, rec, keylen, datalen, keylen + dataroom, h)) if (set_header(tdb, rec, TDB_USED_MAGIC, keylen, datalen,
keylen + dataroom, h))
return -1; return -1;
return tdb_write_convert(tdb, off, rec, sizeof(*rec)); return tdb_write_convert(tdb, off, rec, sizeof(*rec));
...@@ -402,7 +403,8 @@ static int replace_data(struct tdb_context *tdb, ...@@ -402,7 +403,8 @@ static int replace_data(struct tdb_context *tdb,
tdb_off_t new_off; tdb_off_t new_off;
/* Allocate a new record. */ /* Allocate a new record. */
new_off = alloc(tdb, key.dsize, dbuf.dsize, h->h, growing); new_off = alloc(tdb, key.dsize, dbuf.dsize, h->h, TDB_USED_MAGIC,
growing);
if (unlikely(new_off == TDB_OFF_ERR)) if (unlikely(new_off == TDB_OFF_ERR))
return -1; return -1;
......
...@@ -23,20 +23,20 @@ static void add(struct tdb_layout *layout, union tdb_layout_elem elem) ...@@ -23,20 +23,20 @@ static void add(struct tdb_layout *layout, union tdb_layout_elem elem)
layout->elem[layout->num_elems++] = elem; layout->elem[layout->num_elems++] = elem;
} }
void tdb_layout_add_freelist(struct tdb_layout *layout) void tdb_layout_add_freetable(struct tdb_layout *layout)
{ {
union tdb_layout_elem elem; union tdb_layout_elem elem;
elem.base.type = FREELIST; elem.base.type = FREETABLE;
add(layout, elem); add(layout, elem);
} }
void tdb_layout_add_free(struct tdb_layout *layout, tdb_len_t len, void tdb_layout_add_free(struct tdb_layout *layout, tdb_len_t len,
unsigned flist) unsigned ftable)
{ {
union tdb_layout_elem elem; union tdb_layout_elem elem;
elem.base.type = FREE; elem.base.type = FREE;
elem.free.len = len; elem.free.len = len;
elem.free.flist_num = flist; elem.free.ftable_num = ftable;
add(layout, elem); add(layout, elem);
} }
...@@ -82,9 +82,9 @@ static tdb_len_t hashtable_len(struct tle_hashtable *htable) ...@@ -82,9 +82,9 @@ static tdb_len_t hashtable_len(struct tle_hashtable *htable)
+ htable->extra; + htable->extra;
} }
static tdb_len_t freelist_len(struct tle_freelist *flist) static tdb_len_t freetable_len(struct tle_freetable *ftable)
{ {
return sizeof(struct tdb_freelist); return sizeof(struct tdb_freetable);
} }
static void set_free_record(void *mem, tdb_len_t len) static void set_free_record(void *mem, tdb_len_t len)
...@@ -97,9 +97,9 @@ static void set_data_record(void *mem, struct tdb_context *tdb, ...@@ -97,9 +97,9 @@ static void set_data_record(void *mem, struct tdb_context *tdb,
{ {
struct tdb_used_record *u = mem; struct tdb_used_record *u = mem;
set_used_header(tdb, u, used->key.dsize, used->data.dsize, set_header(tdb, u, TDB_USED_MAGIC, used->key.dsize, used->data.dsize,
used->key.dsize + used->data.dsize + used->extra, used->key.dsize + used->data.dsize + used->extra,
tdb_hash(tdb, used->key.dptr, used->key.dsize)); tdb_hash(tdb, used->key.dptr, used->key.dsize));
memcpy(u + 1, used->key.dptr, used->key.dsize); memcpy(u + 1, used->key.dptr, used->key.dsize);
memcpy((char *)(u + 1) + used->key.dsize, memcpy((char *)(u + 1) + used->key.dsize,
used->data.dptr, used->data.dsize); used->data.dptr, used->data.dsize);
...@@ -111,36 +111,36 @@ static void set_hashtable(void *mem, struct tdb_context *tdb, ...@@ -111,36 +111,36 @@ static void set_hashtable(void *mem, struct tdb_context *tdb,
struct tdb_used_record *u = mem; struct tdb_used_record *u = mem;
tdb_len_t len = sizeof(tdb_off_t) << TDB_SUBLEVEL_HASH_BITS; tdb_len_t len = sizeof(tdb_off_t) << TDB_SUBLEVEL_HASH_BITS;
set_used_header(tdb, u, 0, len, len + htable->extra, 0); set_header(tdb, u, TDB_HTABLE_MAGIC, 0, len, len + htable->extra, 0);
memset(u + 1, 0, len); memset(u + 1, 0, len);
} }
static void set_freelist(void *mem, struct tdb_context *tdb, static void set_freetable(void *mem, struct tdb_context *tdb,
struct tle_freelist *freelist, struct tdb_header *hdr, struct tle_freetable *freetable, struct tdb_header *hdr,
tdb_off_t last_flist) tdb_off_t last_ftable)
{ {
struct tdb_freelist *flist = mem; struct tdb_freetable *ftable = mem;
memset(flist, 0, sizeof(*flist)); memset(ftable, 0, sizeof(*ftable));
set_used_header(tdb, &flist->hdr, 0, set_header(tdb, &ftable->hdr, TDB_FTABLE_MAGIC, 0,
sizeof(*flist) - sizeof(flist->hdr), sizeof(*ftable) - sizeof(ftable->hdr),
sizeof(*flist) - sizeof(flist->hdr), 1); sizeof(*ftable) - sizeof(ftable->hdr), 0);
if (last_flist) { if (last_ftable) {
flist = (struct tdb_freelist *)((char *)hdr + last_flist); ftable = (struct tdb_freetable *)((char *)hdr + last_ftable);
flist->next = freelist->base.off; ftable->next = freetable->base.off;
} else { } else {
hdr->free_list = freelist->base.off; hdr->free_table = freetable->base.off;
} }
} }
static void add_to_freetable(struct tdb_context *tdb, static void add_to_freetable(struct tdb_context *tdb,
tdb_off_t eoff, tdb_off_t eoff,
tdb_off_t elen, tdb_off_t elen,
unsigned flist, unsigned ftable,
struct tle_freelist *freelist) struct tle_freetable *freetable)
{ {
tdb->flist_off = freelist->base.off; tdb->ftable_off = freetable->base.off;
tdb->flist = flist; tdb->ftable = ftable;
add_free_record(tdb, eoff, sizeof(struct tdb_used_record) + elen); add_free_record(tdb, eoff, sizeof(struct tdb_used_record) + elen);
} }
...@@ -204,15 +204,15 @@ static void add_to_hashtable(struct tdb_context *tdb, ...@@ -204,15 +204,15 @@ static void add_to_hashtable(struct tdb_context *tdb,
abort(); abort();
} }
static struct tle_freelist *find_flist(struct tdb_layout *layout, unsigned num) static struct tle_freetable *find_ftable(struct tdb_layout *layout, unsigned num)
{ {
unsigned i; unsigned i;
for (i = 0; i < layout->num_elems; i++) { for (i = 0; i < layout->num_elems; i++) {
if (layout->elem[i].base.type != FREELIST) if (layout->elem[i].base.type != FREETABLE)
continue; continue;
if (num == 0) if (num == 0)
return &layout->elem[i].flist; return &layout->elem[i].ftable;
num--; num--;
} }
abort(); abort();
...@@ -222,7 +222,7 @@ static struct tle_freelist *find_flist(struct tdb_layout *layout, unsigned num) ...@@ -222,7 +222,7 @@ static struct tle_freelist *find_flist(struct tdb_layout *layout, unsigned num)
struct tdb_context *tdb_layout_get(struct tdb_layout *layout) struct tdb_context *tdb_layout_get(struct tdb_layout *layout)
{ {
unsigned int i; unsigned int i;
tdb_off_t off, len, last_flist; tdb_off_t off, len, last_ftable;
char *mem; char *mem;
struct tdb_context *tdb; struct tdb_context *tdb;
...@@ -233,8 +233,8 @@ struct tdb_context *tdb_layout_get(struct tdb_layout *layout) ...@@ -233,8 +233,8 @@ struct tdb_context *tdb_layout_get(struct tdb_layout *layout)
union tdb_layout_elem *e = &layout->elem[i]; union tdb_layout_elem *e = &layout->elem[i];
e->base.off = off; e->base.off = off;
switch (e->base.type) { switch (e->base.type) {
case FREELIST: case FREETABLE:
len = freelist_len(&e->flist); len = freetable_len(&e->ftable);
break; break;
case FREE: case FREE:
len = free_record_len(e->free.len); len = free_record_len(e->free.len);
...@@ -261,14 +261,14 @@ struct tdb_context *tdb_layout_get(struct tdb_layout *layout) ...@@ -261,14 +261,14 @@ struct tdb_context *tdb_layout_get(struct tdb_layout *layout)
tdb->map_ptr = mem; tdb->map_ptr = mem;
tdb->map_size = off; tdb->map_size = off;
last_flist = 0; last_ftable = 0;
for (i = 0; i < layout->num_elems; i++) { for (i = 0; i < layout->num_elems; i++) {
union tdb_layout_elem *e = &layout->elem[i]; union tdb_layout_elem *e = &layout->elem[i];
switch (e->base.type) { switch (e->base.type) {
case FREELIST: case FREETABLE:
set_freelist(mem + e->base.off, tdb, &e->flist, set_freetable(mem + e->base.off, tdb, &e->ftable,
(struct tdb_header *)mem, last_flist); (struct tdb_header *)mem, last_ftable);
last_flist = e->base.off; last_ftable = e->base.off;
break; break;
case FREE: case FREE:
set_free_record(mem + e->base.off, e->free.len); set_free_record(mem + e->base.off, e->free.len);
...@@ -281,8 +281,8 @@ struct tdb_context *tdb_layout_get(struct tdb_layout *layout) ...@@ -281,8 +281,8 @@ struct tdb_context *tdb_layout_get(struct tdb_layout *layout)
break; break;
} }
} }
/* Must have a free list! */ /* Must have a free table! */
assert(last_flist); assert(last_ftable);
/* Now fill the free and hash tables. */ /* Now fill the free and hash tables. */
for (i = 0; i < layout->num_elems; i++) { for (i = 0; i < layout->num_elems; i++) {
...@@ -290,8 +290,8 @@ struct tdb_context *tdb_layout_get(struct tdb_layout *layout) ...@@ -290,8 +290,8 @@ struct tdb_context *tdb_layout_get(struct tdb_layout *layout)
switch (e->base.type) { switch (e->base.type) {
case FREE: case FREE:
add_to_freetable(tdb, e->base.off, e->free.len, add_to_freetable(tdb, e->base.off, e->free.len,
e->free.flist_num, e->free.ftable_num,
find_flist(layout, e->free.flist_num)); find_ftable(layout, e->free.ftable_num));
break; break;
case DATA: case DATA:
add_to_hashtable(tdb, e->base.off, e->used.key); add_to_hashtable(tdb, e->base.off, e->used.key);
...@@ -301,7 +301,7 @@ struct tdb_context *tdb_layout_get(struct tdb_layout *layout) ...@@ -301,7 +301,7 @@ struct tdb_context *tdb_layout_get(struct tdb_layout *layout)
} }
} }
tdb->flist_off = find_flist(layout, 0)->base.off; tdb->ftable_off = find_ftable(layout, 0)->base.off;
/* Get physical if they asked for it. */ /* Get physical if they asked for it. */
if (layout->filename) { if (layout->filename) {
......
...@@ -3,9 +3,9 @@ ...@@ -3,9 +3,9 @@
#include <ccan/tdb2/private.h> #include <ccan/tdb2/private.h>
struct tdb_layout *new_tdb_layout(const char *filename); struct tdb_layout *new_tdb_layout(const char *filename);
void tdb_layout_add_freelist(struct tdb_layout *layout); void tdb_layout_add_freetable(struct tdb_layout *layout);
void tdb_layout_add_free(struct tdb_layout *layout, tdb_len_t len, void tdb_layout_add_free(struct tdb_layout *layout, tdb_len_t len,
unsigned flist); unsigned ftable);
void tdb_layout_add_used(struct tdb_layout *layout, void tdb_layout_add_used(struct tdb_layout *layout,
TDB_DATA key, TDB_DATA data, TDB_DATA key, TDB_DATA data,
tdb_len_t extra); tdb_len_t extra);
...@@ -18,7 +18,7 @@ void tdb_layout_add_hashtable(struct tdb_layout *layout, ...@@ -18,7 +18,7 @@ void tdb_layout_add_hashtable(struct tdb_layout *layout,
struct tdb_context *tdb_layout_get(struct tdb_layout *layout); struct tdb_context *tdb_layout_get(struct tdb_layout *layout);
enum layout_type { enum layout_type {
FREELIST, FREE, DATA, HASHTABLE, FREETABLE, FREE, DATA, HASHTABLE,
}; };
/* Shared by all union members. */ /* Shared by all union members. */
...@@ -27,14 +27,14 @@ struct tle_base { ...@@ -27,14 +27,14 @@ struct tle_base {
tdb_off_t off; tdb_off_t off;
}; };
struct tle_freelist { struct tle_freetable {
struct tle_base base; struct tle_base base;
}; };
struct tle_free { struct tle_free {
struct tle_base base; struct tle_base base;
tdb_len_t len; tdb_len_t len;
unsigned flist_num; unsigned ftable_num;
}; };
struct tle_used { struct tle_used {
...@@ -53,7 +53,7 @@ struct tle_hashtable { ...@@ -53,7 +53,7 @@ struct tle_hashtable {
union tdb_layout_elem { union tdb_layout_elem {
struct tle_base base; struct tle_base base;
struct tle_freelist flist; struct tle_freetable ftable;
struct tle_free free; struct tle_free free;
struct tle_used used; struct tle_used used;
struct tle_hashtable hashtable; struct tle_hashtable hashtable;
......
...@@ -18,14 +18,14 @@ int main(int argc, char *argv[]) ...@@ -18,14 +18,14 @@ int main(int argc, char *argv[])
/* We should be able to encode any data value. */ /* We should be able to encode any data value. */
for (i = 0; i < 64; i++) for (i = 0; i < 64; i++)
ok1(set_used_header(&tdb, &rec, 0, 1ULL << i, 1ULL << i, 0) ok1(set_header(&tdb, &rec, TDB_USED_MAGIC, 0, 1ULL << i,
== 0); 1ULL << i, 0) == 0);
/* And any key and data with < 64 bits between them. */ /* And any key and data with < 64 bits between them. */
for (i = 0; i < 32; i++) { for (i = 0; i < 32; i++) {
tdb_len_t dlen = 1ULL >> (63 - i), klen = 1ULL << i; tdb_len_t dlen = 1ULL >> (63 - i), klen = 1ULL << i;
ok1(set_used_header(&tdb, &rec, klen, dlen, klen + dlen, 0) ok1(set_header(&tdb, &rec, TDB_USED_MAGIC, klen, dlen,
== 0); klen + dlen, 0) == 0);
} }
/* We should neatly encode all values. */ /* We should neatly encode all values. */
...@@ -34,13 +34,13 @@ int main(int argc, char *argv[]) ...@@ -34,13 +34,13 @@ int main(int argc, char *argv[])
uint64_t klen = 1ULL << (i < 16 ? i : 15); uint64_t klen = 1ULL << (i < 16 ? i : 15);
uint64_t dlen = 1ULL << i; uint64_t dlen = 1ULL << i;
uint64_t xlen = 1ULL << (i < 32 ? i : 31); uint64_t xlen = 1ULL << (i < 32 ? i : 31);
ok1(set_used_header(&tdb, &rec, klen, dlen, klen+dlen+xlen, h) ok1(set_header(&tdb, &rec, TDB_USED_MAGIC, klen, dlen,
== 0); klen+dlen+xlen, h) == 0);
ok1(rec_key_length(&rec) == klen); ok1(rec_key_length(&rec) == klen);
ok1(rec_data_length(&rec) == dlen); ok1(rec_data_length(&rec) == dlen);
ok1(rec_extra_padding(&rec) == xlen); ok1(rec_extra_padding(&rec) == xlen);
ok1((uint64_t)rec_hash(&rec) == h); ok1((uint64_t)rec_hash(&rec) == h);
ok1(rec_magic(&rec) == TDB_MAGIC); ok1(rec_magic(&rec) == TDB_USED_MAGIC);
} }
ok1(tap_log_messages == 0); ok1(tap_log_messages == 0);
return exit_status(); return exit_status();
......
...@@ -38,7 +38,7 @@ int main(int argc, char *argv[]) ...@@ -38,7 +38,7 @@ int main(int argc, char *argv[])
/* No coalescing can be done due to EOF */ /* No coalescing can be done due to EOF */
layout = new_tdb_layout(NULL); layout = new_tdb_layout(NULL);
tdb_layout_add_freelist(layout); tdb_layout_add_freetable(layout);
len = 1024; len = 1024;
tdb_layout_add_free(layout, len, 0); tdb_layout_add_free(layout, len, 0);
tdb = tdb_layout_get(layout); tdb = tdb_layout_get(layout);
...@@ -46,7 +46,7 @@ int main(int argc, char *argv[]) ...@@ -46,7 +46,7 @@ int main(int argc, char *argv[])
ok1(free_record_length(tdb, layout->elem[1].base.off) == len); ok1(free_record_length(tdb, layout->elem[1].base.off) == len);
/* Figure out which bucket free entry is. */ /* Figure out which bucket free entry is. */
b_off = bucket_off(tdb->flist_off, size_to_bucket(len)); b_off = bucket_off(tdb->ftable_off, size_to_bucket(len));
/* Lock and fail to coalesce. */ /* Lock and fail to coalesce. */
ok1(tdb_lock_free_bucket(tdb, b_off, TDB_LOCK_WAIT) == 0); ok1(tdb_lock_free_bucket(tdb, b_off, TDB_LOCK_WAIT) == 0);
ok1(coalesce(tdb, layout->elem[1].base.off, b_off, len) == 0); ok1(coalesce(tdb, layout->elem[1].base.off, b_off, len) == 0);
...@@ -57,7 +57,7 @@ int main(int argc, char *argv[]) ...@@ -57,7 +57,7 @@ int main(int argc, char *argv[])
/* No coalescing can be done due to used record */ /* No coalescing can be done due to used record */
layout = new_tdb_layout(NULL); layout = new_tdb_layout(NULL);
tdb_layout_add_freelist(layout); tdb_layout_add_freetable(layout);
tdb_layout_add_free(layout, 1024, 0); tdb_layout_add_free(layout, 1024, 0);
tdb_layout_add_used(layout, key, data, 6); tdb_layout_add_used(layout, key, data, 6);
tdb = tdb_layout_get(layout); tdb = tdb_layout_get(layout);
...@@ -65,7 +65,7 @@ int main(int argc, char *argv[]) ...@@ -65,7 +65,7 @@ int main(int argc, char *argv[])
ok1(tdb_check(tdb, NULL, NULL) == 0); ok1(tdb_check(tdb, NULL, NULL) == 0);
/* Figure out which bucket free entry is. */ /* Figure out which bucket free entry is. */
b_off = bucket_off(tdb->flist_off, size_to_bucket(1024)); b_off = bucket_off(tdb->ftable_off, size_to_bucket(1024));
/* Lock and fail to coalesce. */ /* Lock and fail to coalesce. */
ok1(tdb_lock_free_bucket(tdb, b_off, TDB_LOCK_WAIT) == 0); ok1(tdb_lock_free_bucket(tdb, b_off, TDB_LOCK_WAIT) == 0);
ok1(coalesce(tdb, layout->elem[1].base.off, b_off, 1024) == 0); ok1(coalesce(tdb, layout->elem[1].base.off, b_off, 1024) == 0);
...@@ -76,7 +76,7 @@ int main(int argc, char *argv[]) ...@@ -76,7 +76,7 @@ int main(int argc, char *argv[])
/* Coalescing can be done due to two free records, then EOF */ /* Coalescing can be done due to two free records, then EOF */
layout = new_tdb_layout(NULL); layout = new_tdb_layout(NULL);
tdb_layout_add_freelist(layout); tdb_layout_add_freetable(layout);
tdb_layout_add_free(layout, 1024, 0); tdb_layout_add_free(layout, 1024, 0);
tdb_layout_add_free(layout, 2048, 0); tdb_layout_add_free(layout, 2048, 0);
tdb = tdb_layout_get(layout); tdb = tdb_layout_get(layout);
...@@ -85,7 +85,7 @@ int main(int argc, char *argv[]) ...@@ -85,7 +85,7 @@ int main(int argc, char *argv[])
ok1(tdb_check(tdb, NULL, NULL) == 0); ok1(tdb_check(tdb, NULL, NULL) == 0);
/* Figure out which bucket (first) free entry is. */ /* Figure out which bucket (first) free entry is. */
b_off = bucket_off(tdb->flist_off, size_to_bucket(1024)); b_off = bucket_off(tdb->ftable_off, size_to_bucket(1024));
/* Lock and coalesce. */ /* Lock and coalesce. */
ok1(tdb_lock_free_bucket(tdb, b_off, TDB_LOCK_WAIT) == 0); ok1(tdb_lock_free_bucket(tdb, b_off, TDB_LOCK_WAIT) == 0);
ok1(coalesce(tdb, layout->elem[1].base.off, b_off, 1024) == 1); ok1(coalesce(tdb, layout->elem[1].base.off, b_off, 1024) == 1);
...@@ -97,7 +97,7 @@ int main(int argc, char *argv[]) ...@@ -97,7 +97,7 @@ int main(int argc, char *argv[])
/* Coalescing can be done due to two free records, then data */ /* Coalescing can be done due to two free records, then data */
layout = new_tdb_layout(NULL); layout = new_tdb_layout(NULL);
tdb_layout_add_freelist(layout); tdb_layout_add_freetable(layout);
tdb_layout_add_free(layout, 1024, 0); tdb_layout_add_free(layout, 1024, 0);
tdb_layout_add_free(layout, 512, 0); tdb_layout_add_free(layout, 512, 0);
tdb_layout_add_used(layout, key, data, 6); tdb_layout_add_used(layout, key, data, 6);
...@@ -107,7 +107,7 @@ int main(int argc, char *argv[]) ...@@ -107,7 +107,7 @@ int main(int argc, char *argv[])
ok1(tdb_check(tdb, NULL, NULL) == 0); ok1(tdb_check(tdb, NULL, NULL) == 0);
/* Figure out which bucket free entry is. */ /* Figure out which bucket free entry is. */
b_off = bucket_off(tdb->flist_off, size_to_bucket(1024)); b_off = bucket_off(tdb->ftable_off, size_to_bucket(1024));
/* Lock and coalesce. */ /* Lock and coalesce. */
ok1(tdb_lock_free_bucket(tdb, b_off, TDB_LOCK_WAIT) == 0); ok1(tdb_lock_free_bucket(tdb, b_off, TDB_LOCK_WAIT) == 0);
ok1(coalesce(tdb, layout->elem[1].base.off, b_off, 1024) == 1); ok1(coalesce(tdb, layout->elem[1].base.off, b_off, 1024) == 1);
...@@ -119,7 +119,7 @@ int main(int argc, char *argv[]) ...@@ -119,7 +119,7 @@ int main(int argc, char *argv[])
/* Coalescing can be done due to three free records, then EOF */ /* Coalescing can be done due to three free records, then EOF */
layout = new_tdb_layout(NULL); layout = new_tdb_layout(NULL);
tdb_layout_add_freelist(layout); tdb_layout_add_freetable(layout);
tdb_layout_add_free(layout, 1024, 0); tdb_layout_add_free(layout, 1024, 0);
tdb_layout_add_free(layout, 512, 0); tdb_layout_add_free(layout, 512, 0);
tdb_layout_add_free(layout, 256, 0); tdb_layout_add_free(layout, 256, 0);
...@@ -130,7 +130,7 @@ int main(int argc, char *argv[]) ...@@ -130,7 +130,7 @@ int main(int argc, char *argv[])
ok1(tdb_check(tdb, NULL, NULL) == 0); ok1(tdb_check(tdb, NULL, NULL) == 0);
/* Figure out which bucket free entry is. */ /* Figure out which bucket free entry is. */
b_off = bucket_off(tdb->flist_off, size_to_bucket(1024)); b_off = bucket_off(tdb->ftable_off, size_to_bucket(1024));
/* Lock and coalesce. */ /* Lock and coalesce. */
ok1(tdb_lock_free_bucket(tdb, b_off, TDB_LOCK_WAIT) == 0); ok1(tdb_lock_free_bucket(tdb, b_off, TDB_LOCK_WAIT) == 0);
ok1(coalesce(tdb, layout->elem[1].base.off, b_off, 1024) == 1); ok1(coalesce(tdb, layout->elem[1].base.off, b_off, 1024) == 1);
......
...@@ -65,7 +65,8 @@ int main(int argc, char *argv[]) ...@@ -65,7 +65,8 @@ int main(int argc, char *argv[])
/* FIXME: Check lock length */ /* FIXME: Check lock length */
/* Allocate a new record. */ /* Allocate a new record. */
new_off = alloc(tdb, key.dsize, dbuf.dsize, h.h, false); new_off = alloc(tdb, key.dsize, dbuf.dsize, h.h,
TDB_USED_MAGIC, false);
ok1(new_off != TDB_OFF_ERR); ok1(new_off != TDB_OFF_ERR);
/* We should be able to add it now. */ /* We should be able to add it now. */
...@@ -225,7 +226,8 @@ int main(int argc, char *argv[]) ...@@ -225,7 +226,8 @@ int main(int argc, char *argv[])
/* We should be able to add it now. */ /* We should be able to add it now. */
/* Allocate a new record. */ /* Allocate a new record. */
new_off = alloc(tdb, key.dsize, dbuf.dsize, h.h, false); new_off = alloc(tdb, key.dsize, dbuf.dsize, h.h,
TDB_USED_MAGIC, false);
ok1(new_off != TDB_OFF_ERR); ok1(new_off != TDB_OFF_ERR);
ok1(add_to_hash(tdb, &h, new_off) == 0); ok1(add_to_hash(tdb, &h, new_off) == 0);
......
...@@ -9,13 +9,13 @@ ...@@ -9,13 +9,13 @@
#include <err.h> #include <err.h>
#include "logging.h" #include "logging.h"
static bool empty_freelist(struct tdb_context *tdb) static bool empty_freetable(struct tdb_context *tdb)
{ {
struct tdb_freelist free; struct tdb_freetable free;
unsigned int i; unsigned int i;
/* Now, free list should be completely exhausted in zone 0 */ /* Now, free table should be completely exhausted in zone 0 */
if (tdb_read_convert(tdb, tdb->flist_off, &free, sizeof(free)) != 0) if (tdb_read_convert(tdb, tdb->ftable_off, &free, sizeof(free)) != 0)
abort(); abort();
for (i = 0; i < sizeof(free.buckets)/sizeof(free.buckets[0]); i++) { for (i = 0; i < sizeof(free.buckets)/sizeof(free.buckets[0]); i++) {
...@@ -50,26 +50,26 @@ int main(int argc, char *argv[]) ...@@ -50,26 +50,26 @@ int main(int argc, char *argv[])
if (!tdb) if (!tdb)
continue; continue;
ok1(empty_freelist(tdb)); ok1(empty_freetable(tdb));
/* Need some hash lock for expand. */ /* Need some hash lock for expand. */
ok1(tdb_lock_hashes(tdb, 0, 1, F_WRLCK, TDB_LOCK_WAIT) == 0); ok1(tdb_lock_hashes(tdb, 0, 1, F_WRLCK, TDB_LOCK_WAIT) == 0);
/* Create some free space. */ /* Create some free space. */
ok1(tdb_expand(tdb, 1) == 0); ok1(tdb_expand(tdb, 1) == 0);
ok1(tdb_unlock_hashes(tdb, 0, 1, F_WRLCK) == 0); ok1(tdb_unlock_hashes(tdb, 0, 1, F_WRLCK) == 0);
ok1(tdb_check(tdb, NULL, NULL) == 0); ok1(tdb_check(tdb, NULL, NULL) == 0);
ok1(!empty_freelist(tdb)); ok1(!empty_freetable(tdb));
size = tdb->map_size; size = tdb->map_size;
/* Insert minimal-length records until we expand. */ /* Insert minimal-length records until we expand. */
for (j = 0; tdb->map_size == size; j++) { for (j = 0; tdb->map_size == size; j++) {
was_empty = empty_freelist(tdb); was_empty = empty_freetable(tdb);
if (tdb_store(tdb, k, k, TDB_INSERT) != 0) if (tdb_store(tdb, k, k, TDB_INSERT) != 0)
err(1, "Failed to store record %i", j); err(1, "Failed to store record %i", j);
} }
/* Would have been empty before expansion, but no longer. */ /* Would have been empty before expansion, but no longer. */
ok1(was_empty); ok1(was_empty);
ok1(!empty_freelist(tdb)); ok1(!empty_freetable(tdb));
tdb_close(tdb); tdb_close(tdb);
} }
......
...@@ -22,11 +22,11 @@ int main(int argc, char *argv[]) ...@@ -22,11 +22,11 @@ int main(int argc, char *argv[])
data.dsize = 5; data.dsize = 5;
key.dsize = 5; key.dsize = 5;
/* Create a TDB with three free lists. */ /* Create a TDB with three free tables. */
layout = new_tdb_layout(NULL); layout = new_tdb_layout(NULL);
tdb_layout_add_freelist(layout); tdb_layout_add_freetable(layout);
tdb_layout_add_freelist(layout); tdb_layout_add_freetable(layout);
tdb_layout_add_freelist(layout); tdb_layout_add_freetable(layout);
tdb_layout_add_free(layout, 80, 0); tdb_layout_add_free(layout, 80, 0);
/* Used record prevent coalescing. */ /* Used record prevent coalescing. */
tdb_layout_add_used(layout, key, data, 6); tdb_layout_add_used(layout, key, data, 6);
...@@ -40,24 +40,28 @@ int main(int argc, char *argv[]) ...@@ -40,24 +40,28 @@ int main(int argc, char *argv[])
tdb = tdb_layout_get(layout); tdb = tdb_layout_get(layout);
ok1(tdb_check(tdb, NULL, NULL) == 0); ok1(tdb_check(tdb, NULL, NULL) == 0);
off = get_free(tdb, 0, 80 - sizeof(struct tdb_used_record), 0, 0); off = get_free(tdb, 0, 80 - sizeof(struct tdb_used_record), 0,
TDB_USED_MAGIC, 0);
ok1(off == layout->elem[3].base.off); ok1(off == layout->elem[3].base.off);
ok1(tdb->flist_off == layout->elem[0].base.off); ok1(tdb->ftable_off == layout->elem[0].base.off);
off = get_free(tdb, 0, 160 - sizeof(struct tdb_used_record), 0, 0); off = get_free(tdb, 0, 160 - sizeof(struct tdb_used_record), 0,
TDB_USED_MAGIC, 0);
ok1(off == layout->elem[5].base.off); ok1(off == layout->elem[5].base.off);
ok1(tdb->flist_off == layout->elem[1].base.off); ok1(tdb->ftable_off == layout->elem[1].base.off);
off = get_free(tdb, 0, 320 - sizeof(struct tdb_used_record), 0, 0); off = get_free(tdb, 0, 320 - sizeof(struct tdb_used_record), 0,
TDB_USED_MAGIC, 0);
ok1(off == layout->elem[7].base.off); ok1(off == layout->elem[7].base.off);
ok1(tdb->flist_off == layout->elem[2].base.off); ok1(tdb->ftable_off == layout->elem[2].base.off);
off = get_free(tdb, 0, 40 - sizeof(struct tdb_used_record), 0, 0); off = get_free(tdb, 0, 40 - sizeof(struct tdb_used_record), 0,
TDB_USED_MAGIC, 0);
ok1(off == layout->elem[9].base.off); ok1(off == layout->elem[9].base.off);
ok1(tdb->flist_off == layout->elem[0].base.off); ok1(tdb->ftable_off == layout->elem[0].base.off);
/* Now we fail. */ /* Now we fail. */
off = get_free(tdb, 0, 0, 1, 0); off = get_free(tdb, 0, 0, 1, TDB_USED_MAGIC, 0);
ok1(off == 0); ok1(off == 0);
tdb_close(tdb); tdb_close(tdb);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment