Browse Source

tdb2: add TDB_ATTRIBUTE_TDB1_HASHSIZE

This replaces the tdb1_open "hash_size" argument.  It will only be
valid when you call tdb_open() with O_CREAT in open_flags, and
TDB_VERSION1 in tdb_flags.
Rusty Russell 14 years ago
parent
commit
49475d68de

+ 34 - 2
ccan/tdb2/open.c

@@ -209,6 +209,7 @@ enum TDB_ERROR tdb_set_attribute(struct tdb_context *tdb,
 	case TDB_ATTRIBUTE_HASH:
 	case TDB_ATTRIBUTE_SEED:
 	case TDB_ATTRIBUTE_OPENHOOK:
+	case TDB_ATTRIBUTE_TDB1_HASHSIZE:
 		return tdb->last_error
 			= tdb_logerr(tdb, TDB_ERR_EINVAL,
 				     TDB_LOG_USE_ERROR,
@@ -218,7 +219,9 @@ enum TDB_ERROR tdb_set_attribute(struct tdb_context *tdb,
 				     ? "TDB_ATTRIBUTE_HASH"
 				     : attr->base.attr == TDB_ATTRIBUTE_SEED
 				     ? "TDB_ATTRIBUTE_SEED"
-				     : "TDB_ATTRIBUTE_OPENHOOK");
+				     : attr->base.attr == TDB_ATTRIBUTE_OPENHOOK
+				     ? "TDB_ATTRIBUTE_OPENHOOK"
+				     : "TDB_ATTRIBUTE_TDB1_HASHSIZE");
 	case TDB_ATTRIBUTE_STATS:
 		return tdb->last_error
 			= tdb_logerr(tdb, TDB_ERR_EINVAL,
@@ -276,6 +279,16 @@ enum TDB_ERROR tdb_get_attribute(struct tdb_context *tdb,
 		attr->flock.unlock = tdb->unlock_fn;
 		attr->flock.data = tdb->lock_data;
 		break;
+	case TDB_ATTRIBUTE_TDB1_HASHSIZE:
+		if (!(tdb->flags & TDB_VERSION1))
+			return tdb->last_error
+				= tdb_logerr(tdb, TDB_ERR_EINVAL,
+					     TDB_LOG_USE_ERROR,
+				     "tdb_get_attribute:"
+				     " cannot get TDB_ATTRIBUTE_TDB1_HASHSIZE"
+				     " on TDB2 tdb.");
+		attr->tdb1_hashsize.hsize = tdb->tdb1.header.hash_size;
+		break;
 	default:
 		return tdb->last_error
 			= tdb_logerr(tdb, TDB_ERR_EINVAL,
@@ -300,11 +313,14 @@ void tdb_unset_attribute(struct tdb_context *tdb,
 		break;
 	case TDB_ATTRIBUTE_HASH:
 	case TDB_ATTRIBUTE_SEED:
+	case TDB_ATTRIBUTE_TDB1_HASHSIZE:
 		tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR,
 			   "tdb_unset_attribute: cannot unset %s after opening",
 			   type == TDB_ATTRIBUTE_HASH
 			   ? "TDB_ATTRIBUTE_HASH"
-			   : "TDB_ATTRIBUTE_SEED");
+			   : type == TDB_ATTRIBUTE_SEED
+			   ? "TDB_ATTRIBUTE_SEED"
+			   : "TDB_ATTRIBUTE_TDB1_HASHSIZE");
 		break;
 	case TDB_ATTRIBUTE_STATS:
 		tdb_logerr(tdb, TDB_ERR_EINVAL,
@@ -336,6 +352,7 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
 	ssize_t rlen;
 	struct tdb_header hdr;
 	struct tdb_attribute_seed *seed = NULL;
+	struct tdb_attribute_tdb1_hashsize *hsize_attr = NULL;
 	tdb_bool_err berr;
 	enum TDB_ERROR ecode;
 	int openlock;
@@ -382,6 +399,9 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
 			tdb->openhook = attr->openhook.fn;
 			tdb->openhook_data = attr->openhook.data;
 			break;
+		case TDB_ATTRIBUTE_TDB1_HASHSIZE:
+			hsize_attr = &attr->tdb1_hashsize;
+			break;
 		default:
 			/* These are set as normal. */
 			ecode = tdb_set_attribute(tdb, attr);
@@ -399,6 +419,18 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
 		goto fail;
 	}
 
+	if (hsize_attr) {
+		if (!(tdb_flags & TDB_VERSION1) ||
+		    (!(tdb_flags & TDB_INTERNAL) && !(open_flags & O_CREAT))) {
+			ecode = tdb_logerr(tdb, TDB_ERR_EINVAL,
+					   TDB_LOG_USE_ERROR,
+					   "tdb_open: can only use"
+					   " TDB_ATTRIBUTE_TDB1_HASHSIZE when"
+					   " creating a TDB_VERSION1 tdb");
+			goto fail;
+		}
+	}
+
 	if ((open_flags & O_ACCMODE) == O_WRONLY) {
 		ecode = tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR,
 				   "tdb_open: can't open tdb %s write-only",

+ 1 - 3
ccan/tdb2/tdb1.h

@@ -38,7 +38,7 @@
 
 typedef int (*tdb1_traverse_func)(struct tdb_context *, TDB_DATA, TDB_DATA, void *);
 
-struct tdb_context *tdb1_open(const char *name, int hash_size, int tdb1_flags,
+struct tdb_context *tdb1_open(const char *name, int tdb1_flags,
 			      int open_flags, mode_t mode,
 			      union tdb_attribute *attributes);
 
@@ -87,8 +87,6 @@ int tdb1_transaction_cancel(struct tdb_context *tdb);
 
 int tdb1_get_seqnum(struct tdb_context *tdb);
 
-int tdb1_hash_size(struct tdb_context *tdb);
-
 void tdb1_increment_seqnum_nonblock(struct tdb_context *tdb);
 
 uint64_t tdb1_incompatible_hash(const void *key, size_t len, uint64_t seed, void *);

+ 22 - 5
ccan/tdb2/tdb1_open.c

@@ -24,7 +24,7 @@
    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, see <http://www.gnu.org/licenses/>.
 */
-
+#include <assert.h>
 #include "tdb1_private.h"
 
 /* We use two hashes to double-check they're using the right hash function. */
@@ -222,8 +222,6 @@ static struct tdb_context *tdb1_open_ex(const char *name, int hash_size, int tdb
 		goto fail;
 	}
 
-	if (hash_size == 0)
-		hash_size = TDB1_DEFAULT_HASH_SIZE;
 	if ((open_flags & O_ACCMODE) == O_RDONLY) {
 		tdb->flags |= TDB_RDONLY;
 		/* read only databases don't do locking */
@@ -359,12 +357,13 @@ static struct tdb_context *tdb1_open_ex(const char *name, int hash_size, int tdb
 }
 
 /* Temporart wrapper for transition. */
-struct tdb_context *tdb1_open(const char *name, int hash_size, int tdb1_flags,
+struct tdb_context *tdb1_open(const char *name, int tdb1_flags,
 			      int open_flags, mode_t mode,
 			      union tdb_attribute *attr)
 {
 	struct tdb1_logging_context *log_ctx = NULL, log;
 	tdb1_hash_func hash_fn = NULL;
+	struct tdb_attribute_tdb1_hashsize *hsize = NULL;
 
 	while (attr) {
 		switch (attr->base.attr) {
@@ -376,13 +375,31 @@ struct tdb_context *tdb1_open(const char *name, int hash_size, int tdb1_flags,
 			log.log_private = attr->log.data;
 			log_ctx = &log;
 			break;
+		case TDB_ATTRIBUTE_TDB1_HASHSIZE:
+			hsize = &attr->tdb1_hashsize;
+			break;
+			break;
 		default:
 			abort();
 		}
 		attr = attr->base.next;
 	}
 
-	return tdb1_open_ex(name, hash_size, tdb1_flags, open_flags, mode,
+	if (hsize && !(open_flags & O_CREAT)) {
+		if (log_ctx) {
+			log_ctx->log_fn(NULL,
+					TDB_ERR_EINVAL,
+					TDB_LOG_USE_ERROR,
+					"tdb_open: can only use"
+					" TDB_ATTRIBUTE_TDB1_HASHSIZE when"
+					" creating a tdb",
+					log_ctx->log_private);
+		}
+		errno = EINVAL;
+		return NULL;
+	}
+	return tdb1_open_ex(name, hsize ? hsize->hsize : TDB1_DEFAULT_HASH_SIZE,
+			    tdb1_flags, open_flags, mode,
 			    log_ctx, hash_fn);
 }
 

+ 6 - 6
ccan/tdb2/tdb1_tdb.c

@@ -681,11 +681,6 @@ int tdb1_get_seqnum(struct tdb_context *tdb)
 	return seqnum;
 }
 
-int tdb1_hash_size(struct tdb_context *tdb)
-{
-	return tdb->tdb1.header.hash_size;
-}
-
 
 /*
   add a region of the file to the freelist. Length is the size of the region in bytes,
@@ -836,6 +831,11 @@ int tdb1_repack(struct tdb_context *tdb)
 {
 	struct tdb_context *tmp_db;
 	struct traverse_state state;
+	union tdb_attribute hsize;
+
+	hsize.base.attr = TDB_ATTRIBUTE_TDB1_HASHSIZE;
+	hsize.base.next = NULL;
+	hsize.tdb1_hashsize.hsize = tdb->tdb1.header.hash_size;
 
 	if (tdb1_transaction_start(tdb) != 0) {
 		tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
@@ -843,7 +843,7 @@ int tdb1_repack(struct tdb_context *tdb)
 		return -1;
 	}
 
-	tmp_db = tdb1_open("tmpdb", tdb1_hash_size(tdb), TDB_INTERNAL, O_RDWR|O_CREAT, 0, NULL);
+	tmp_db = tdb1_open("tmpdb", TDB_INTERNAL, O_RDWR|O_CREAT, 0, &hsize);
 	if (tmp_db == NULL) {
 		tdb->last_error = tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
 					__location__ " Failed to create tmp_db");

+ 19 - 3
ccan/tdb2/tdb2.h

@@ -607,7 +607,8 @@ enum tdb_attribute_type {
 	TDB_ATTRIBUTE_SEED = 2,
 	TDB_ATTRIBUTE_STATS = 3,
 	TDB_ATTRIBUTE_OPENHOOK = 4,
-	TDB_ATTRIBUTE_FLOCK = 5
+	TDB_ATTRIBUTE_FLOCK = 5,
+	TDB_ATTRIBUTE_TDB1_HASHSIZE = 128,
 };
 
 /**
@@ -631,8 +632,9 @@ enum TDB_ERROR tdb_get_attribute(struct tdb_context *tdb,
  * of the same type.  It returns TDB_ERR_EINVAL if the attribute is
  * unknown or invalid.
  *
- * Note that TDB_ATTRIBUTE_HASH, TDB_ATTRIBUTE_SEED and
- * TDB_ATTRIBUTE_OPENHOOK cannot currently be set after tdb_open.
+ * Note that TDB_ATTRIBUTE_HASH, TDB_ATTRIBUTE_SEED,
+ * TDB_ATTRIBUTE_OPENHOOK and TDB_ATTRIBUTE_TDB1_HASHSIZE cannot
+ * currently be set after tdb_open.
  */
 enum TDB_ERROR tdb_set_attribute(struct tdb_context *tdb,
 				 const union tdb_attribute *attr);
@@ -838,6 +840,19 @@ struct tdb_attribute_flock {
 	void *data;
 };
 
+/**
+ * struct tdb_attribute_tdb1_hashsize - tdb1 hashsize
+ *
+ * This attribute allows setting the TDB1 hashsize; it only makes sense with
+ * O_CREAT and TDB_VERSION1.
+ *
+ * Hashsize should generally be a prime, such as 10007.
+ */
+struct tdb_attribute_tdb1_hashsize {
+	struct tdb_attribute_base base; /* .attr = TDB_ATTRIBUTE_TDB1_HASHSIZE */
+	unsigned int hsize;
+};
+
 /**
  * union tdb_attribute - tdb attributes.
  *
@@ -856,6 +871,7 @@ union tdb_attribute {
 	struct tdb_attribute_stats stats;
 	struct tdb_attribute_openhook openhook;
 	struct tdb_attribute_flock flock;
+	struct tdb_attribute_tdb1_hashsize tdb1_hashsize;
 };
 
 #ifdef  __cplusplus

+ 1 - 1
ccan/tdb2/test/failtest_helper.h

@@ -4,7 +4,7 @@
 #include <stdbool.h>
 
 /* FIXME: Check these! */
-#define INITIAL_TDB_MALLOC	"open.c", 343, FAILTEST_MALLOC
+#define INITIAL_TDB_MALLOC	"open.c", 360, FAILTEST_MALLOC
 #define URANDOM_OPEN		"open.c", 61, FAILTEST_OPEN
 #define URANDOM_READ		"open.c", 41, FAILTEST_READ
 

+ 7 - 2
ccan/tdb2/test/run-tdb1-3G-file.c

@@ -64,10 +64,15 @@ int main(int argc, char *argv[])
 	uint32_t hash;
 	tdb1_off_t rec_ptr;
 	struct tdb1_record rec;
+	union tdb_attribute hsize;
+
+	hsize.base.attr = TDB_ATTRIBUTE_TDB1_HASHSIZE;
+	hsize.base.next = &tap_log_attr;
+	hsize.tdb1_hashsize.hsize = 1024;
 
 	plan_tests(24);
-	tdb = tdb1_open("run-36-file.tdb", 1024, TDB_DEFAULT,
-			O_CREAT|O_TRUNC|O_RDWR, 0600, &tap_log_attr);
+	tdb = tdb1_open("run-36-file.tdb", TDB_DEFAULT,
+			O_CREAT|O_TRUNC|O_RDWR, 0600, &hsize);
 
 	ok1(tdb);
 	tdb->tdb1.io = &large_io_methods;

+ 12 - 8
ccan/tdb2/test/run-tdb1-bad-tdb-header.c

@@ -9,6 +9,11 @@ int main(int argc, char *argv[])
 	struct tdb_context *tdb;
 	struct tdb1_header hdr;
 	int fd;
+	union tdb_attribute hsize;
+
+	hsize.base.attr = TDB_ATTRIBUTE_TDB1_HASHSIZE;
+	hsize.base.next = &tap_log_attr;
+	hsize.tdb1_hashsize.hsize = 1024;
 
 	plan_tests(11);
 	/* Can open fine if complete crap, as long as O_CREAT. */
@@ -16,11 +21,10 @@ int main(int argc, char *argv[])
 	ok1(fd >= 0);
 	ok1(write(fd, "hello world", 11) == 11);
 	close(fd);
-	tdb = tdb1_open("run-bad-tdb-header.tdb", 1024, 0, O_RDWR, 0,
-			&tap_log_attr);
+	tdb = tdb1_open("run-bad-tdb-header.tdb", 0, O_RDWR, 0, &tap_log_attr);
 	ok1(!tdb);
-	tdb = tdb1_open("run-bad-tdb-header.tdb", 1024, 0, O_CREAT|O_RDWR,
-			0600, &tap_log_attr);
+	tdb = tdb1_open("run-bad-tdb-header.tdb", 0, O_CREAT|O_RDWR,
+			0600, &hsize);
 	ok1(tdb);
 	tdb1_close(tdb);
 
@@ -34,14 +38,14 @@ int main(int argc, char *argv[])
 	ok1(write(fd, &hdr, sizeof(hdr)) == sizeof(hdr));
 	close(fd);
 
-	tdb = tdb1_open("run-bad-tdb-header.tdb", 1024, 0, O_RDWR|O_CREAT,
-			0600, &tap_log_attr);
+	tdb = tdb1_open("run-bad-tdb-header.tdb", 0, O_RDWR|O_CREAT,
+			0600, &hsize);
 	ok1(errno == EIO);
 	ok1(!tdb);
 
 	/* With truncate, will be fine. */
-	tdb = tdb1_open("run-bad-tdb-header.tdb", 1024, 0,
-			O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
+	tdb = tdb1_open("run-bad-tdb-header.tdb", 0,
+			O_RDWR|O_CREAT|O_TRUNC, 0600, &hsize);
 	ok1(tdb);
 	tdb1_close(tdb);
 

+ 11 - 6
ccan/tdb2/test/run-tdb1-check.c

@@ -8,10 +8,15 @@ int main(int argc, char *argv[])
 {
 	struct tdb_context *tdb;
 	TDB_DATA key, data;
+	union tdb_attribute hsize;
+
+	hsize.base.attr = TDB_ATTRIBUTE_TDB1_HASHSIZE;
+	hsize.base.next = &tap_log_attr;
+	hsize.tdb1_hashsize.hsize = 1;
 
 	plan_tests(13);
-	tdb = tdb1_open("run-check.tdb", 1, TDB_DEFAULT,
-			O_CREAT|O_TRUNC|O_RDWR, 0600, &tap_log_attr);
+	tdb = tdb1_open("run-check.tdb", TDB_DEFAULT,
+			O_CREAT|O_TRUNC|O_RDWR, 0600, &hsize);
 
 	ok1(tdb);
 	ok1(tdb1_check(tdb, NULL, NULL) == 0);
@@ -25,13 +30,13 @@ int main(int argc, char *argv[])
 	ok1(tdb1_check(tdb, NULL, NULL) == 0);
 	tdb1_close(tdb);
 
-	tdb = tdb1_open("run-check.tdb", 1024, 0, O_RDWR, 0,
+	tdb = tdb1_open("run-check.tdb", 0, O_RDWR, 0,
 			&tap_log_attr);
 	ok1(tdb);
 	ok1(tdb1_check(tdb, NULL, NULL) == 0);
 	tdb1_close(tdb);
 
-	tdb = tdb1_open("test/tdb1.corrupt", 1024, 0, O_RDWR, 0,
+	tdb = tdb1_open("test/tdb1.corrupt", 0, O_RDWR, 0,
 			&tap_log_attr);
 	ok1(tdb);
 	ok1(tdb1_check(tdb, NULL, NULL) == -1);
@@ -39,13 +44,13 @@ int main(int argc, char *argv[])
 	tdb1_close(tdb);
 
 	/* Big and little endian should work! */
-	tdb = tdb1_open("test/old-nohash-le.tdb1", 1024, 0, O_RDWR, 0,
+	tdb = tdb1_open("test/old-nohash-le.tdb1", 0, O_RDWR, 0,
 			&tap_log_attr);
 	ok1(tdb);
 	ok1(tdb1_check(tdb, NULL, NULL) == 0);
 	tdb1_close(tdb);
 
-	tdb = tdb1_open("test/old-nohash-be.tdb1", 1024, 0, O_RDWR, 0,
+	tdb = tdb1_open("test/old-nohash-be.tdb1", 0, O_RDWR, 0,
 			&tap_log_attr);
 	ok1(tdb);
 	ok1(tdb1_check(tdb, NULL, NULL) == 0);

+ 9 - 4
ccan/tdb2/test/run-tdb1-corrupt.c

@@ -94,11 +94,16 @@ static void check_test(struct tdb_context *tdb)
 int main(int argc, char *argv[])
 {
 	struct tdb_context *tdb;
+	union tdb_attribute hsize;
+
+	hsize.base.attr = TDB_ATTRIBUTE_TDB1_HASHSIZE;
+	hsize.base.next = &tap_log_attr;
+	hsize.tdb1_hashsize.hsize = 2;
 
 	plan_tests(4);
 	/* This should use mmap. */
-	tdb = tdb1_open("run-corrupt.tdb", 2, TDB_DEFAULT,
-			O_CREAT|O_TRUNC|O_RDWR, 0600, &tap_log_attr);
+	tdb = tdb1_open("run-corrupt.tdb", TDB_DEFAULT,
+			O_CREAT|O_TRUNC|O_RDWR, 0600, &hsize);
 
 	if (!tdb)
 		abort();
@@ -106,8 +111,8 @@ int main(int argc, char *argv[])
 	tdb1_close(tdb);
 
 	/* This should not. */
-	tdb = tdb1_open("run-corrupt.tdb", 2, TDB_NOMMAP,
-			O_CREAT|O_TRUNC|O_RDWR, 0600, &tap_log_attr);
+	tdb = tdb1_open("run-corrupt.tdb", TDB_NOMMAP,
+			O_CREAT|O_TRUNC|O_RDWR, 0600, &hsize);
 
 	if (!tdb)
 		abort();

+ 7 - 2
ccan/tdb2/test/run-tdb1-die-during-transaction.c

@@ -85,12 +85,17 @@ static bool test_death(enum operation op, struct agent *agent)
 	TDB_DATA key;
 	enum agent_return ret;
 	int needed_recovery = 0;
+	union tdb_attribute hsize;
+
+	hsize.base.attr = TDB_ATTRIBUTE_TDB1_HASHSIZE;
+	hsize.base.next = &tap_log_attr;
+	hsize.tdb1_hashsize.hsize = 1024;
 
 	current = target = 0;
 reset:
 	unlink(TEST_DBNAME);
-	tdb = tdb1_open(TEST_DBNAME, 1024, TDB_NOMMAP,
-			O_CREAT|O_TRUNC|O_RDWR, 0600, &tap_log_attr);
+	tdb = tdb1_open(TEST_DBNAME, TDB_NOMMAP,
+			O_CREAT|O_TRUNC|O_RDWR, 0600, &hsize);
 
 	if (setjmp(jmpbuf) != 0) {
 		/* We're partway through.  Simulate our death. */

+ 8 - 4
ccan/tdb2/test/run-tdb1-endian.c

@@ -8,11 +8,16 @@ int main(int argc, char *argv[])
 {
 	struct tdb_context *tdb;
 	TDB_DATA key, data;
+	union tdb_attribute hsize;
+
+	hsize.base.attr = TDB_ATTRIBUTE_TDB1_HASHSIZE;
+	hsize.base.next = &tap_log_attr;
+	hsize.tdb1_hashsize.hsize = 1024;
 
 	plan_tests(13);
-	tdb = tdb1_open("run-endian.tdb", 1024,
+	tdb = tdb1_open("run-endian.tdb",
 			TDB_CONVERT,
-			O_CREAT|O_TRUNC|O_RDWR, 0600, &tap_log_attr);
+			O_CREAT|O_TRUNC|O_RDWR, 0600, &hsize);
 
 	ok1(tdb);
 	key.dsize = strlen("hi");
@@ -38,8 +43,7 @@ int main(int argc, char *argv[])
 	tdb1_close(tdb);
 
 	/* Reopen: should read it */
-	tdb = tdb1_open("run-endian.tdb", 1024, 0, O_RDWR, 0,
-			&tap_log_attr);
+	tdb = tdb1_open("run-endian.tdb", 0, O_RDWR, 0, NULL);
 	ok1(tdb);
 
 	key.dsize = strlen("hi");

+ 61 - 0
ccan/tdb2/test/run-tdb1-hashsize.c

@@ -0,0 +1,61 @@
+#include "tdb2-source.h"
+#include <ccan/tap/tap.h>
+#include <stdlib.h>
+#include <err.h>
+#include "logging.h"
+
+int main(int argc, char *argv[])
+{
+	struct tdb_context *tdb;
+	union tdb_attribute hsize, h2;
+
+	hsize.base.attr = TDB_ATTRIBUTE_TDB1_HASHSIZE;
+	hsize.base.next = &tap_log_attr;
+	hsize.tdb1_hashsize.hsize = 1024;
+
+	plan_tests(14);
+	tdb = tdb1_open("run-tdb1-hashsize.tdb1", TDB_DEFAULT,
+			O_CREAT|O_TRUNC|O_RDWR, 0600, &hsize);
+	ok1(tdb);
+	h2.base.attr = TDB_ATTRIBUTE_TDB1_HASHSIZE;
+	ok1(tdb_get_attribute(tdb, &h2) == TDB_SUCCESS);
+	ok1(h2.tdb1_hashsize.hsize == hsize.tdb1_hashsize.hsize);
+	tdb_close(tdb);
+
+	/* Can't specify TDB_ATTRIBUTE_TDB1_HASHSIZE without O_CREAT */
+	tdb = tdb1_open("run-tdb1-hashsize.tdb1", TDB_DEFAULT,
+			O_RDWR, 0600, &hsize);
+	ok1(!tdb);
+	ok1(tap_log_messages == 1);
+
+	/* Can't specify TDB_ATTRIBUTE_TDB1_HASHSIZE for version2. */
+	tdb = tdb_open("run-tdb1-hashsize.tdb", TDB_DEFAULT,
+			O_CREAT|O_TRUNC|O_RDWR, 0600, &hsize);
+	ok1(!tdb);
+	ok1(tap_log_messages == 2);
+
+	/* We can get attribute even if we didn't set it though. */
+	tdb = tdb1_open("run-tdb1-hashsize.tdb1", TDB_DEFAULT,
+			O_RDWR, 0600, &tap_log_attr);
+
+	ok1(tdb);
+	memset(&h2, 0, sizeof(h2));
+	h2.base.attr = TDB_ATTRIBUTE_TDB1_HASHSIZE;
+	ok1(tdb_get_attribute(tdb, &h2) == TDB_SUCCESS);
+	ok1(h2.tdb1_hashsize.hsize == hsize.tdb1_hashsize.hsize);
+	tdb_close(tdb);
+
+	/* Check for default hash size. */
+	tdb = tdb1_open("run-tdb1-hashsize.tdb1", TDB_DEFAULT,
+			O_CREAT|O_TRUNC|O_RDWR, 0600, &tap_log_attr);
+
+	ok1(tdb);
+	memset(&h2, 0, sizeof(h2));
+	h2.base.attr = TDB_ATTRIBUTE_TDB1_HASHSIZE;
+	ok1(tdb_get_attribute(tdb, &h2) == TDB_SUCCESS);
+	ok1(h2.tdb1_hashsize.hsize == TDB1_DEFAULT_HASH_SIZE);
+	tdb_close(tdb);
+	ok1(tap_log_messages == 2);
+
+	return exit_status();
+}

+ 11 - 11
ccan/tdb2/test/run-tdb1-incompatible.c

@@ -83,7 +83,7 @@ int main(int argc, char *argv[])
 
 		/* Create an old-style hash. */
 		log_count = 0;
-		tdb = tdb1_open("run-incompatible.tdb", 0, flags,
+		tdb = tdb1_open("run-incompatible.tdb", flags,
 				O_CREAT|O_RDWR|O_TRUNC, 0600, &log_attr);
 		ok1(tdb);
 		ok1(log_count == 0);
@@ -97,7 +97,7 @@ int main(int argc, char *argv[])
 
 		/* We can still open any old-style with incompat hash. */
 		log_count = 0;
-		tdb = tdb1_open("run-incompatible.tdb", 0,
+		tdb = tdb1_open("run-incompatible.tdb",
 				TDB_DEFAULT,
 				O_RDWR, 0600, &incompat_hash_attr);
 		ok1(tdb);
@@ -109,7 +109,7 @@ int main(int argc, char *argv[])
 		tdb1_close(tdb);
 
 		log_count = 0;
-		tdb = tdb1_open("test/jenkins-le-hash.tdb1", 0, 0, O_RDONLY,
+		tdb = tdb1_open("test/jenkins-le-hash.tdb1", 0, O_RDONLY,
 				0, &jhash_attr);
 		ok1(tdb);
 		ok1(log_count == 0);
@@ -117,7 +117,7 @@ int main(int argc, char *argv[])
 		tdb1_close(tdb);
 
 		log_count = 0;
-		tdb = tdb1_open("test/jenkins-be-hash.tdb1", 0, 0, O_RDONLY,
+		tdb = tdb1_open("test/jenkins-be-hash.tdb1", 0, O_RDONLY,
 				0, &jhash_attr);
 		ok1(tdb);
 		ok1(log_count == 0);
@@ -126,7 +126,7 @@ int main(int argc, char *argv[])
 
 		/* OK, now create with incompatible hash. */
 		log_count = 0;
-		tdb = tdb1_open("run-incompatible.tdb", 0,
+		tdb = tdb1_open("run-incompatible.tdb",
 				flags,
 				O_CREAT|O_RDWR|O_TRUNC, 0600,
 				&incompat_hash_attr);
@@ -142,14 +142,14 @@ int main(int argc, char *argv[])
 
 		/* Cannot open with old hash. */
 		log_count = 0;
-		tdb = tdb1_open("run-incompatible.tdb", 0, 0,
+		tdb = tdb1_open("run-incompatible.tdb", 0,
 				O_RDWR, 0600, &ohash_attr);
 		ok1(!tdb);
 		ok1(log_count == 1);
 
 		/* Can open with jenkins hash. */
 		log_count = 0;
-		tdb = tdb1_open("run-incompatible.tdb", 0, 0,
+		tdb = tdb1_open("run-incompatible.tdb", 0,
 				O_RDWR, 0600, &jhash_attr);
 		ok1(tdb);
 		ok1(log_count == 0);
@@ -161,7 +161,7 @@ int main(int argc, char *argv[])
 
 		/* Can open by letting it figure it out itself. */
 		log_count = 0;
-		tdb = tdb1_open("run-incompatible.tdb", 0, 0,
+		tdb = tdb1_open("run-incompatible.tdb", 0,
 				O_RDWR, 0600, &log_attr);
 		ok1(tdb);
 		ok1(log_count == 0);
@@ -176,7 +176,7 @@ int main(int argc, char *argv[])
 		/* FIXME: Not possible with TDB2 :( */
 		/* We can also use incompatible hash with other hashes. */
 		log_count = 0;
-		tdb = tdb1_open("run-incompatible.tdb", 0,
+		tdb = tdb1_open("run-incompatible.tdb",
 				flags,
 				O_CREAT|O_RDWR|O_TRUNC, 0600, &dumbhash_attr);
 		ok1(tdb);
@@ -191,14 +191,14 @@ int main(int argc, char *argv[])
 
 		/* It should not open if we don't specify. */
 		log_count = 0;
-		tdb = tdb1_open("run-incompatible.tdb", 0, 0, O_RDWR, 0,
+		tdb = tdb1_open("run-incompatible.tdb", 0, O_RDWR, 0,
 				&log_attr);
 		ok1(!tdb);
 		ok1(log_count == 1);
 
 		/* Should reopen with correct hash. */
 		log_count = 0;
-		tdb = tdb1_open("run-incompatible.tdb", 0, 0, O_RDWR, 0,
+		tdb = tdb1_open("run-incompatible.tdb", 0, O_RDWR, 0,
 				&dumbhash_attr);
 		ok1(tdb);
 		ok1(log_count == 0);

+ 8 - 3
ccan/tdb2/test/run-tdb1-nested-transactions.c

@@ -9,14 +9,19 @@ int main(int argc, char *argv[])
 {
 	struct tdb_context *tdb;
 	TDB_DATA key, data;
+	union tdb_attribute hsize;
+
+	hsize.base.attr = TDB_ATTRIBUTE_TDB1_HASHSIZE;
+	hsize.base.next = &tap_log_attr;
+	hsize.tdb1_hashsize.hsize = 1024;
 
 	plan_tests(27);
 	key.dsize = strlen("hi");
 	key.dptr = (void *)"hi";
 
 	tdb = tdb1_open("run-nested-transactions.tdb",
-			1024, TDB_DEFAULT,
-			O_CREAT|O_TRUNC|O_RDWR, 0600, &tap_log_attr);
+			TDB_DEFAULT,
+			O_CREAT|O_TRUNC|O_RDWR, 0600, &hsize);
 	ok1(tdb);
 
 	/* No nesting by default. */
@@ -43,7 +48,7 @@ int main(int argc, char *argv[])
 	tdb1_close(tdb);
 
 	tdb = tdb1_open("run-nested-transactions.tdb",
-			1024, TDB_ALLOW_NESTING, O_RDWR, 0, &tap_log_attr);
+			TDB_ALLOW_NESTING, O_RDWR, 0, &tap_log_attr);
 	ok1(tdb);
 
 	ok1(tdb1_transaction_start(tdb) == 0);

+ 7 - 2
ccan/tdb2/test/run-tdb1-nested-traverse.c

@@ -50,14 +50,19 @@ int main(int argc, char *argv[])
 {
 	struct tdb_context *tdb;
 	TDB_DATA key, data;
+	union tdb_attribute hsize;
+
+	hsize.base.attr = TDB_ATTRIBUTE_TDB1_HASHSIZE;
+	hsize.base.next = &tap_log_attr;
+	hsize.tdb1_hashsize.hsize = 1024;
 
 	plan_tests(17);
 	agent = prepare_external_agent1();
 	if (!agent)
 		err(1, "preparing agent");
 
-	tdb = tdb1_open("run-nested-traverse.tdb", 1024, TDB_DEFAULT,
-			O_CREAT|O_TRUNC|O_RDWR, 0600, &tap_log_attr);
+	tdb = tdb1_open("run-nested-traverse.tdb", TDB_DEFAULT,
+			O_CREAT|O_TRUNC|O_RDWR, 0600, &hsize);
 	ok1(tdb);
 
 	ok1(external_agent_operation1(agent, OPEN, tdb->name) == SUCCESS);

+ 7 - 2
ccan/tdb2/test/run-tdb1-no-lock-during-traverse.c

@@ -68,11 +68,16 @@ int main(int argc, char *argv[])
 {
 	struct tdb_context *tdb;
 	int errors = 0;
+	union tdb_attribute hsize;
+
+	hsize.base.attr = TDB_ATTRIBUTE_TDB1_HASHSIZE;
+	hsize.base.next = &tap_log_attr;
+	hsize.tdb1_hashsize.hsize = 1024;
 
 	plan_tests(41);
 	tdb = tdb1_open("run-no-lock-during-traverse.tdb",
-			1024, TDB_DEFAULT, O_CREAT|O_TRUNC|O_RDWR,
-			0600, &tap_log_attr);
+			TDB_DEFAULT, O_CREAT|O_TRUNC|O_RDWR,
+			0600, &hsize);
 
 	ok1(tdb);
 	ok1(prepare_entries(tdb));

+ 4 - 4
ccan/tdb2/test/run-tdb1-oldhash.c

@@ -17,25 +17,25 @@ int main(int argc, char *argv[])
 
 	/* Old format (with zeroes in the hash magic fields) should
 	 * open with any hash (since we don't know what hash they used). */
-	tdb = tdb1_open("test/old-nohash-le.tdb1", 0, 0, O_RDWR, 0,
+	tdb = tdb1_open("test/old-nohash-le.tdb1", 0, O_RDWR, 0,
 			&tap_log_attr);
 	ok1(tdb);
 	ok1(tdb1_check(tdb, NULL, NULL) == 0);
 	tdb1_close(tdb);
 
-	tdb = tdb1_open("test/old-nohash-be.tdb1", 0, 0, O_RDWR, 0,
+	tdb = tdb1_open("test/old-nohash-be.tdb1", 0, O_RDWR, 0,
 			&tap_log_attr);
 	ok1(tdb);
 	ok1(tdb1_check(tdb, NULL, NULL) == 0);
 	tdb1_close(tdb);
 
-	tdb = tdb1_open("test/old-nohash-le.tdb1", 0, 0, O_RDWR, 0,
+	tdb = tdb1_open("test/old-nohash-le.tdb1", 0, O_RDWR, 0,
 			&incompat_hash_attr);
 	ok1(tdb);
 	ok1(tdb1_check(tdb, NULL, NULL) == 0);
 	tdb1_close(tdb);
 
-	tdb = tdb1_open("test/old-nohash-be.tdb1", 0, 0, O_RDWR, 0,
+	tdb = tdb1_open("test/old-nohash-be.tdb1", 0, O_RDWR, 0,
 			&incompat_hash_attr);
 	ok1(tdb);
 	ok1(tdb1_check(tdb, NULL, NULL) == 0);

+ 7 - 2
ccan/tdb2/test/run-tdb1-open-during-transaction.c

@@ -133,6 +133,11 @@ int main(int argc, char *argv[])
 	int i;
 	struct tdb_context *tdb;
 	TDB_DATA key, data;
+	union tdb_attribute hsize;
+
+	hsize.base.attr = TDB_ATTRIBUTE_TDB1_HASHSIZE;
+	hsize.base.next = &tap_log_attr;
+	hsize.tdb1_hashsize.hsize = 1024;
 
 	plan_tests(10);
 	agent = prepare_external_agent1();
@@ -145,9 +150,9 @@ int main(int argc, char *argv[])
 		     "DEFAULT",
 		     (flags[i] & TDB_NOMMAP) ? "no mmap" : "mmap");
 		unlink(TEST_DBNAME);
-		tdb = tdb1_open(TEST_DBNAME, 1024, flags[i],
+		tdb = tdb1_open(TEST_DBNAME, flags[i],
 				O_CREAT|O_TRUNC|O_RDWR, 0600,
-				&tap_log_attr);
+				&hsize);
 		ok1(tdb);
 
 		opened = true;

+ 8 - 3
ccan/tdb2/test/run-tdb1-readonly-check.c

@@ -10,11 +10,16 @@ int main(int argc, char *argv[])
 {
 	struct tdb_context *tdb;
 	TDB_DATA key, data;
+	union tdb_attribute hsize;
+
+	hsize.base.attr = TDB_ATTRIBUTE_TDB1_HASHSIZE;
+	hsize.base.next = &tap_log_attr;
+	hsize.tdb1_hashsize.hsize = 1024;
 
 	plan_tests(11);
-	tdb = tdb1_open("run-readonly-check.tdb", 1024,
+	tdb = tdb1_open("run-readonly-check.tdb",
 			TDB_DEFAULT,
-			O_CREAT|O_TRUNC|O_RDWR, 0600, &tap_log_attr);
+			O_CREAT|O_TRUNC|O_RDWR, 0600, &hsize);
 
 	ok1(tdb);
 	key.dsize = strlen("hi");
@@ -30,7 +35,7 @@ int main(int argc, char *argv[])
 	ok1(tdb1_check(tdb, NULL, NULL) == 0);
 	ok1(tdb1_close(tdb) == 0);
 
-	tdb = tdb1_open("run-readonly-check.tdb", 1024,
+	tdb = tdb1_open("run-readonly-check.tdb",
 			TDB_DEFAULT, O_RDONLY, 0, &tap_log_attr);
 
 	ok1(tdb);

+ 2 - 2
ccan/tdb2/test/run-tdb1-rwlock-check.c

@@ -27,13 +27,13 @@ int main(int argc, char *argv[])
 
 	/* We should fail to open rwlock-using tdbs of either endian. */
 	log_count = 0;
-	tdb = tdb1_open("test/rwlock-le.tdb1", 0, 0, O_RDWR, 0,
+	tdb = tdb1_open("test/rwlock-le.tdb1", 0, O_RDWR, 0,
 			&log_attr);
 	ok1(!tdb);
 	ok1(log_count == 1);
 
 	log_count = 0;
-	tdb = tdb1_open("test/rwlock-be.tdb1", 0, 0, O_RDWR, 0,
+	tdb = tdb1_open("test/rwlock-be.tdb1", 0, O_RDWR, 0,
 			&log_attr);
 	ok1(!tdb);
 	ok1(log_count == 1);

+ 1 - 1
ccan/tdb2/test/run-tdb1-summary.c

@@ -16,7 +16,7 @@ int main(int argc, char *argv[])
 
 	plan_tests(sizeof(flags) / sizeof(flags[0]) * 14);
 	for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
-		tdb = tdb1_open("run-summary.tdb", 131, flags[i],
+		tdb = tdb1_open("run-summary.tdb", flags[i],
 				O_RDWR|O_CREAT|O_TRUNC, 0600, NULL);
 		ok1(tdb);
 		if (!tdb)

+ 7 - 2
ccan/tdb2/test/run-tdb1-traverse-in-transaction.c

@@ -36,6 +36,11 @@ int main(int argc, char *argv[])
 {
 	struct tdb_context *tdb;
 	TDB_DATA key, data;
+	union tdb_attribute hsize;
+
+	hsize.base.attr = TDB_ATTRIBUTE_TDB1_HASHSIZE;
+	hsize.base.next = &tap_log_attr;
+	hsize.tdb1_hashsize.hsize = 1024;
 
 	plan_tests(13);
 	agent = prepare_external_agent1();
@@ -43,8 +48,8 @@ int main(int argc, char *argv[])
 		err(1, "preparing agent");
 
 	tdb = tdb1_open("run-traverse-in-transaction.tdb",
-			1024, TDB_DEFAULT, O_CREAT|O_TRUNC|O_RDWR,
-			0600, &tap_log_attr);
+			TDB_DEFAULT, O_CREAT|O_TRUNC|O_RDWR,
+			0600, &hsize);
 	ok1(tdb);
 
 	key.dsize = strlen("hi");

+ 11 - 11
ccan/tdb2/test/run-tdb1-wronghash-fail.c

@@ -54,7 +54,7 @@ int main(int argc, char *argv[])
 
 	/* Create with default hash. */
 	log_count = 0;
-	tdb = tdb1_open("run-wronghash-fail.tdb", 0, 0,
+	tdb = tdb1_open("run-wronghash-fail.tdb", 0,
 			O_CREAT|O_RDWR|O_TRUNC, 0600, &log_attr);
 	ok1(tdb);
 	ok1(log_count == 0);
@@ -64,14 +64,14 @@ int main(int argc, char *argv[])
 	tdb1_close(tdb);
 
 	/* Fail to open with different hash. */
-	tdb = tdb1_open("run-wronghash-fail.tdb", 0, 0, O_RDWR, 0,
+	tdb = tdb1_open("run-wronghash-fail.tdb", 0, O_RDWR, 0,
 			&jhash_attr);
 	ok1(!tdb);
 	ok1(log_count == 1);
 
 	/* Create with different hash. */
 	log_count = 0;
-	tdb = tdb1_open("run-wronghash-fail.tdb", 0, 0,
+	tdb = tdb1_open("run-wronghash-fail.tdb", 0,
 			O_CREAT|O_RDWR|O_TRUNC,
 			0600, &jhash_attr);
 	ok1(tdb);
@@ -80,26 +80,26 @@ int main(int argc, char *argv[])
 
 	/* Endian should be no problem. */
 	log_count = 0;
-	tdb = tdb1_open("test/jenkins-le-hash.tdb1", 0, 0, O_RDWR, 0,
+	tdb = tdb1_open("test/jenkins-le-hash.tdb1", 0, O_RDWR, 0,
 			&ohash_attr);
 	ok1(!tdb);
 	ok1(log_count == 1);
 
 	log_count = 0;
-	tdb = tdb1_open("test/jenkins-be-hash.tdb1", 0, 0, O_RDWR, 0,
+	tdb = tdb1_open("test/jenkins-be-hash.tdb1", 0, O_RDWR, 0,
 			&ohash_attr);
 	ok1(!tdb);
 	ok1(log_count == 1);
 
 	log_count = 0;
 	/* Fail to open with old default hash. */
-	tdb = tdb1_open("run-wronghash-fail.tdb", 0, 0, O_RDWR, 0,
+	tdb = tdb1_open("run-wronghash-fail.tdb", 0, O_RDWR, 0,
 			&ohash_attr);
 	ok1(!tdb);
 	ok1(log_count == 1);
 
 	log_count = 0;
-	tdb = tdb1_open("test/jenkins-le-hash.tdb1", 0, 0, O_RDONLY,
+	tdb = tdb1_open("test/jenkins-le-hash.tdb1", 0, O_RDONLY,
 			0, &incompat_hash_attr);
 	ok1(tdb);
 	ok1(log_count == 0);
@@ -107,7 +107,7 @@ int main(int argc, char *argv[])
 	tdb1_close(tdb);
 
 	log_count = 0;
-	tdb = tdb1_open("test/jenkins-be-hash.tdb1", 0, 0, O_RDONLY,
+	tdb = tdb1_open("test/jenkins-be-hash.tdb1", 0, O_RDONLY,
 			0, &incompat_hash_attr);
 	ok1(tdb);
 	ok1(log_count == 0);
@@ -116,7 +116,7 @@ int main(int argc, char *argv[])
 
 	/* It should open with jenkins hash if we don't specify. */
 	log_count = 0;
-	tdb = tdb1_open("test/jenkins-le-hash.tdb1", 0, 0, O_RDWR, 0,
+	tdb = tdb1_open("test/jenkins-le-hash.tdb1", 0, O_RDWR, 0,
 			&log_attr);
 	ok1(tdb);
 	ok1(log_count == 0);
@@ -124,7 +124,7 @@ int main(int argc, char *argv[])
 	tdb1_close(tdb);
 
 	log_count = 0;
-	tdb = tdb1_open("test/jenkins-be-hash.tdb1", 0, 0, O_RDWR, 0,
+	tdb = tdb1_open("test/jenkins-be-hash.tdb1", 0, O_RDWR, 0,
 			&log_attr);
 	ok1(tdb);
 	ok1(log_count == 0);
@@ -132,7 +132,7 @@ int main(int argc, char *argv[])
 	tdb1_close(tdb);
 
 	log_count = 0;
-	tdb = tdb1_open("run-wronghash-fail.tdb", 0, 0, O_RDONLY,
+	tdb = tdb1_open("run-wronghash-fail.tdb", 0, O_RDONLY,
 			0, &log_attr);
 	ok1(tdb);
 	ok1(log_count == 0);

+ 7 - 2
ccan/tdb2/test/run-tdb1-zero-append.c

@@ -8,10 +8,15 @@ int main(int argc, char *argv[])
 {
 	struct tdb_context *tdb;
 	TDB_DATA key, data;
+	union tdb_attribute hsize;
+
+	hsize.base.attr = TDB_ATTRIBUTE_TDB1_HASHSIZE;
+	hsize.base.next = &tap_log_attr;
+	hsize.tdb1_hashsize.hsize = 1024;
 
 	plan_tests(4);
-	tdb = tdb1_open(NULL, 1024, TDB_INTERNAL, O_CREAT|O_TRUNC|O_RDWR,
-			0600, &tap_log_attr);
+	tdb = tdb1_open(NULL, TDB_INTERNAL, O_CREAT|O_TRUNC|O_RDWR,
+			0600, &hsize);
 	ok1(tdb);
 
 	/* Tickle bug on appending zero length buffer to zero length buffer. */

+ 7 - 2
ccan/tdb2/test/run-tdb1.c

@@ -8,10 +8,15 @@ int main(int argc, char *argv[])
 {
 	struct tdb_context *tdb;
 	TDB_DATA key, data;
+	union tdb_attribute hsize;
+
+	hsize.base.attr = TDB_ATTRIBUTE_TDB1_HASHSIZE;
+	hsize.base.next = &tap_log_attr;
+	hsize.tdb1_hashsize.hsize = 1024;
 
 	plan_tests(10);
-	tdb = tdb1_open("run.tdb", 1024, TDB_DEFAULT,
-			O_CREAT|O_TRUNC|O_RDWR, 0600, &tap_log_attr);
+	tdb = tdb1_open("run.tdb", TDB_DEFAULT,
+			O_CREAT|O_TRUNC|O_RDWR, 0600, &hsize);
 
 	ok1(tdb);
 	key.dsize = strlen("hi");

+ 1 - 1
ccan/tdb2/test/tdb1-external-agent.c

@@ -39,7 +39,7 @@ static enum agent_return do_operation(enum operation op, const char *name)
 			diag("Already have tdb %s open", tdb->name);
 			return OTHER_FAILURE;
 		}
-		tdb = tdb1_open(name, 0, TDB_DEFAULT, O_RDWR, 0,
+		tdb = tdb1_open(name, TDB_DEFAULT, O_RDWR, 0,
 				&tap_log_attr);
 		if (!tdb) {
 			if (!locking_would_block1)