From e2cb71e5d46801a94a3f0f546b8dcc2b7a79b66c Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 18 Oct 2010 13:17:42 +1030 Subject: [PATCH 1/1] tdb2: add tdb_attribute_seed for setting hash seed. Particularly useful for reproduction, like tdbtorture. --- ccan/tdb2/tdb.c | 18 +++++++--- ccan/tdb2/tdb2.h | 9 ++++- ccan/tdb2/test/run-seed.c | 65 ++++++++++++++++++++++++++++++++++++ ccan/tdb2/tools/tdbtorture.c | 5 +++ 4 files changed, 92 insertions(+), 5 deletions(-) create mode 100644 ccan/tdb2/test/run-seed.c diff --git a/ccan/tdb2/tdb.c b/ccan/tdb2/tdb.c index 9468e604..4b02755c 100644 --- a/ccan/tdb2/tdb.c +++ b/ccan/tdb2/tdb.c @@ -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 */ } diff --git a/ccan/tdb2/tdb2.h b/ccan/tdb2/tdb2.h index 343264d5..adaf6710 100644 --- a/ccan/tdb2/tdb2.h +++ b/ccan/tdb2/tdb2.h @@ -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, diff --git a/ccan/tdb2/test/run-seed.c b/ccan/tdb2/test/run-seed.c new file mode 100644 index 00000000..d78e863d --- /dev/null +++ b/ccan/tdb2/test/run-seed.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include +#include +#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(); +} diff --git a/ccan/tdb2/tools/tdbtorture.c b/ccan/tdb2/tools/tdbtorture.c index 84223aa3..46dc1c72 100644 --- a/ccan/tdb2/tools/tdbtorture.c +++ b/ccan/tdb2/tools/tdbtorture.c @@ -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. */ -- 2.39.2