Commit 2b5cb9bd authored by Rusty Russell's avatar Rusty Russell

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.
parent a0e0927e
...@@ -1398,7 +1398,13 @@ Status ...@@ -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
......
...@@ -116,6 +116,9 @@ typedef int tdb_bool_err; ...@@ -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 { ...@@ -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];
......
...@@ -112,6 +112,7 @@ static enum TDB_ERROR tdb_new_database(struct tdb_context *tdb, ...@@ -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, ...@@ -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);
......
...@@ -4,7 +4,7 @@ ...@@ -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
......
#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();
}
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