Browse Source

tdb2: feature support.

As detailed in doc/design.lyx section 2.15 "Extending The Header Is
Difficult"; we add features_used and features_offered fields to the
header, so we can identify if we add new features, and then if someone
opens it who doesn't understand that feature.
Rusty Russell 15 years ago
parent
commit
2b5cb9bd6b

+ 6 - 0
ccan/tdb2/doc/design.lyx

@@ -1398,7 +1398,13 @@ Status
 \end_layout
 \end_layout
 
 
 \begin_layout Standard
 \begin_layout Standard
+
+\change_deleted 0 1300360753
 Incomplete.
 Incomplete.
+\change_inserted 0 1300360754
+Complete.
+\change_unchanged
+
 \end_layout
 \end_layout
 
 
 \begin_layout Subsection
 \begin_layout Subsection

+ 7 - 1
ccan/tdb2/private.h

@@ -116,6 +116,9 @@ typedef int tdb_bool_err;
 #define TDB_OFF_HASH_EXTRA_BIT 57
 #define TDB_OFF_HASH_EXTRA_BIT 57
 #define TDB_OFF_UPPER_STEAL_SUBHASH_BIT 56
 #define TDB_OFF_UPPER_STEAL_SUBHASH_BIT 56
 
 
+/* Additional features we understand.  Currently: none. */
+#define TDB_FEATURE_MASK ((uint64_t)0)
+
 /* The bit number where we store the extra hash bits. */
 /* The bit number where we store the extra hash bits. */
 /* Convenience mask to get actual offset. */
 /* Convenience mask to get actual offset. */
 #define TDB_OFF_MASK \
 #define TDB_OFF_MASK \
@@ -240,7 +243,10 @@ struct tdb_header {
 	tdb_off_t free_table; /* (First) free table. */
 	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];
+	uint64_t features_used; /* Features all writers understand */
+	uint64_t features_offered; /* Features offered */
+
+	tdb_off_t reserved[24];
 
 
 	/* Top level hash table. */
 	/* Top level hash table. */
 	tdb_off_t hashtable[1ULL << TDB_TOPLEVEL_HASH_BITS];
 	tdb_off_t hashtable[1ULL << TDB_TOPLEVEL_HASH_BITS];

+ 11 - 0
ccan/tdb2/tdb.c

@@ -112,6 +112,7 @@ static enum TDB_ERROR tdb_new_database(struct tdb_context *tdb,
 					 newdb.hdr.hash_seed,
 					 newdb.hdr.hash_seed,
 					 tdb->hash_priv);
 					 tdb->hash_priv);
 	newdb.hdr.recovery = 0;
 	newdb.hdr.recovery = 0;
+	newdb.hdr.features_used = newdb.hdr.features_offered = TDB_FEATURE_MASK;
 	memset(newdb.hdr.reserved, 0, sizeof(newdb.hdr.reserved));
 	memset(newdb.hdr.reserved, 0, sizeof(newdb.hdr.reserved));
 	/* Initial hashes are empty. */
 	/* Initial hashes are empty. */
 	memset(newdb.hdr.hashtable, 0, sizeof(newdb.hdr.hashtable));
 	memset(newdb.hdr.hashtable, 0, sizeof(newdb.hdr.hashtable));
@@ -361,6 +362,16 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
 		goto fail;
 		goto fail;
 	}
 	}
 
 
+	/* Clear any features we don't understand. */
+ 	if ((open_flags & O_ACCMODE) != O_RDONLY) {
+		hdr.features_used &= TDB_FEATURE_MASK;
+		if (tdb_write_convert(tdb, offsetof(struct tdb_header,
+						    features_used),
+				      &hdr.features_used,
+				      sizeof(hdr.features_used)) == -1)
+			goto fail;
+	}
+
 	tdb->device = st.st_dev;
 	tdb->device = st.st_dev;
 	tdb->inode = st.st_ino;
 	tdb->inode = st.st_ino;
 	tdb_unlock_open(tdb);
 	tdb_unlock_open(tdb);

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

@@ -4,7 +4,7 @@
 #include <stdbool.h>
 #include <stdbool.h>
 
 
 /* FIXME: Check these! */
 /* FIXME: Check these! */
-#define INITIAL_TDB_MALLOC	"tdb.c", 190, FAILTEST_MALLOC
+#define INITIAL_TDB_MALLOC	"tdb.c", 191, FAILTEST_MALLOC
 #define URANDOM_OPEN		"tdb.c", 49, FAILTEST_OPEN
 #define URANDOM_OPEN		"tdb.c", 49, FAILTEST_OPEN
 #define URANDOM_READ		"tdb.c", 29, FAILTEST_READ
 #define URANDOM_READ		"tdb.c", 29, FAILTEST_READ
 
 

+ 71 - 0
ccan/tdb2/test/run-features.c

@@ -0,0 +1,71 @@
+#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/tdb2/summary.c>
+#include <ccan/tdb2/transaction.c>
+#include <ccan/tap/tap.h>
+#include "logging.h"
+
+int main(int argc, char *argv[])
+{
+	unsigned int i, j;
+	struct tdb_context *tdb;
+	int flags[] = { TDB_DEFAULT, TDB_NOMMAP,
+			TDB_CONVERT, TDB_NOMMAP|TDB_CONVERT };
+	struct tdb_data key = { (unsigned char *)&j, sizeof(j) };
+	struct tdb_data data = { (unsigned char *)&j, sizeof(j) };
+
+	plan_tests(sizeof(flags) / sizeof(flags[0]) * 8 + 1);
+	for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+		uint64_t features;
+		tdb = tdb_open("run-features.tdb", flags[i],
+			       O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
+		ok1(tdb);
+		if (!tdb)
+			continue;
+
+		/* Put some stuff in there. */
+		for (j = 0; j < 100; j++) {
+			if (tdb_store(tdb, key, data, TDB_REPLACE) != 0)
+				fail("Storing in tdb");
+		}
+
+		/* Mess with features fields in hdr. */
+		features = (~TDB_FEATURE_MASK ^ 1);
+		ok1(tdb_write_convert(tdb, offsetof(struct tdb_header,
+						    features_used), 
+				      &features, sizeof(features)) == 0);
+		ok1(tdb_write_convert(tdb, offsetof(struct tdb_header,
+						    features_offered), 
+				      &features, sizeof(features)) == 0);
+		tdb_close(tdb);
+
+		tdb = tdb_open("run-features.tdb", flags[i], O_RDWR, 0,
+			       &tap_log_attr);
+		ok1(tdb);
+		if (!tdb)
+			continue;
+
+		/* Should not have changed features offered. */
+		ok1(tdb_read_convert(tdb, offsetof(struct tdb_header,
+						   features_offered), 
+				     &features, sizeof(features)) == 0);
+		ok1(features == (~TDB_FEATURE_MASK ^ 1));
+
+		/* Should have cleared unknown bits in features_used. */
+		ok1(tdb_read_convert(tdb, offsetof(struct tdb_header,
+						   features_used), 
+				     &features, sizeof(features)) == 0);
+		ok1(features == (1 & TDB_FEATURE_MASK));
+
+		tdb_close(tdb);
+	}
+
+	ok1(tap_log_messages == 0);
+	return exit_status();
+}
+
+