Commit e2cb71e5 authored by Rusty Russell's avatar Rusty Russell

tdb2: add tdb_attribute_seed for setting hash seed.

Particularly useful for reproduction, like tdbtorture.
parent 7f63d84e
......@@ -94,7 +94,9 @@ struct new_database {
};
/* initialise a new database */
static int tdb_new_database(struct tdb_context *tdb, struct tdb_header *hdr)
static int tdb_new_database(struct tdb_context *tdb,
struct tdb_attribute_seed *seed,
struct tdb_header *hdr)
{
/* We make it up in memory, then write it out if not internal */
struct new_database newdb;
......@@ -105,7 +107,10 @@ static int tdb_new_database(struct tdb_context *tdb, struct tdb_header *hdr)
/* Fill in the header */
newdb.hdr.version = TDB_VERSION;
newdb.hdr.hash_seed = random_number(tdb);
if (seed)
newdb.hdr.hash_seed = seed->seed;
else
newdb.hdr.hash_seed = random_number(tdb);
newdb.hdr.hash_test = TDB_HASH_MAGIC;
newdb.hdr.hash_test = tdb->khash(&newdb.hdr.hash_test,
sizeof(newdb.hdr.hash_test),
......@@ -181,6 +186,7 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
uint64_t hash_test;
unsigned v;
struct tdb_header hdr;
struct tdb_attribute_seed *seed = NULL;
tdb = malloc(sizeof(*tdb));
if (!tdb) {
......@@ -213,6 +219,9 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
tdb->khash = attr->hash.hash_fn;
tdb->hash_priv = attr->hash.hash_private;
break;
case TDB_ATTRIBUTE_SEED:
seed = &attr->seed;
break;
default:
tdb->log(tdb, TDB_DEBUG_ERROR, tdb->log_priv,
"tdb_open: unknown attribute type %u\n",
......@@ -243,7 +252,7 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
/* internal databases don't need any of the rest. */
if (tdb->flags & TDB_INTERNAL) {
tdb->flags |= (TDB_NOLOCK | TDB_NOMMAP);
if (tdb_new_database(tdb, &hdr) != 0) {
if (tdb_new_database(tdb, seed, &hdr) != 0) {
tdb->log(tdb, TDB_DEBUG_ERROR, tdb->log_priv,
"tdb_open: tdb_new_database failed!");
goto fail;
......@@ -275,7 +284,8 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
if (!tdb_pread_all(tdb->fd, &hdr, sizeof(hdr), 0)
|| strcmp(hdr.magic_food, TDB_MAGIC_FOOD) != 0) {
if (!(open_flags & O_CREAT) || tdb_new_database(tdb, &hdr) == -1) {
if (!(open_flags & O_CREAT)
|| tdb_new_database(tdb, seed, &hdr) == -1) {
if (errno == 0) {
errno = EIO; /* ie bad format or something */
}
......
......@@ -86,7 +86,8 @@ typedef uint64_t (*tdb_hashfn_t)(const void *key, size_t len, uint64_t seed,
enum tdb_attribute_type {
TDB_ATTRIBUTE_LOG = 0,
TDB_ATTRIBUTE_HASH = 1
TDB_ATTRIBUTE_HASH = 1,
TDB_ATTRIBUTE_SEED = 2
};
struct tdb_attribute_base {
......@@ -106,10 +107,16 @@ struct tdb_attribute_hash {
void *hash_private;
};
struct tdb_attribute_seed {
struct tdb_attribute_base base; /* .attr = TDB_ATTRIBUTE_SEED */
uint64_t seed;
};
union tdb_attribute {
struct tdb_attribute_base base;
struct tdb_attribute_log log;
struct tdb_attribute_hash hash;
struct tdb_attribute_seed seed;
};
struct tdb_context *tdb_open(const char *name, int tdb_flags,
......
#include <ccan/tdb2/tdb.c>
#include <ccan/tdb2/free.c>
#include <ccan/tdb2/lock.c>
#include <ccan/tdb2/io.c>
#include <ccan/tdb2/hash.c>
#include <ccan/tdb2/check.c>
#include <ccan/tap/tap.h>
#include "logging.h"
static int log_count = 0;
/* Normally we get a log when setting random seed. */
static void my_log_fn(struct tdb_context *tdb,
enum tdb_debug_level level, void *priv,
const char *fmt, ...)
{
log_count++;
}
static union tdb_attribute log_attr = {
.log = { .base = { .attr = TDB_ATTRIBUTE_LOG },
.log_fn = my_log_fn }
};
int main(int argc, char *argv[])
{
unsigned int i;
struct tdb_context *tdb;
union tdb_attribute attr;
int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
TDB_NOMMAP|TDB_CONVERT };
attr.seed.base.attr = TDB_ATTRIBUTE_SEED;
attr.seed.base.next = &log_attr;
attr.seed.seed = 42;
plan_tests(sizeof(flags) / sizeof(flags[0]) * 4 + 4 * 3);
for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
struct tdb_header hdr;
int fd;
tdb = tdb_open("run-seed.tdb", flags[i],
O_RDWR|O_CREAT|O_TRUNC, 0600, &attr);
ok1(tdb);
if (!tdb)
continue;
ok1(tdb_check(tdb, NULL, NULL) == 0);
ok1(tdb->hash_seed == 42);
ok1(log_count == 0);
tdb_close(tdb);
if (flags[i] & TDB_INTERNAL)
continue;
fd = open("run-seed.tdb", O_RDONLY);
ok1(fd >= 0);
ok1(read(fd, &hdr, sizeof(hdr)) == sizeof(hdr));
if (flags[i] & TDB_CONVERT)
ok1(bswap_64(hdr.hash_seed) == 42);
else
ok1(hdr.hash_seed == 42);
close(fd);
}
return exit_status();
}
......@@ -41,6 +41,7 @@ static int always_transaction = 0;
static int loopnum;
static int count_pipe;
static union tdb_attribute log_attr;
static union tdb_attribute seed_attr;
#ifdef PRINTF_ATTRIBUTE
static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, void *private, const char *format, ...) PRINTF_ATTRIBUTE(4,5);
......@@ -338,7 +339,10 @@ int main(int argc, char * const *argv)
int kill_random = 0;
int *done;
log_attr.base.attr = TDB_ATTRIBUTE_LOG;
log_attr.base.next = &seed_attr;
log_attr.log.log_fn = tdb_log;
seed_attr.base.attr = TDB_ATTRIBUTE_SEED;
while ((c = getopt(argc, argv, "n:l:s:thk")) != -1) {
switch (c) {
......@@ -372,6 +376,7 @@ int main(int argc, char * const *argv)
if (seed == -1) {
seed = (getpid() + time(NULL)) & 0x7FFFFFFF;
}
seed_attr.seed.seed = (((uint64_t)seed) << 32) | seed;
if (num_procs == 1 && !kill_random) {
/* Don't fork for this case, makes debugging easier. */
......
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