X-Git-Url: http://git.ozlabs.org/?a=blobdiff_plain;f=ccan%2Ftdb2%2Ftdb.c;h=5d69eedcdc4ecf58079609628d59b902c4623b56;hb=06e0037d97f5e1d83667ec40627cef862f3b7b85;hp=3cee472cfb0ac9990ef83848bbe0455708c18b5d;hpb=39f01834db9b6a21d076e67d1e3143ab99aaf43e;p=ccan diff --git a/ccan/tdb2/tdb.c b/ccan/tdb2/tdb.c index 3cee472c..5d69eedc 100644 --- a/ccan/tdb2/tdb.c +++ b/ccan/tdb2/tdb.c @@ -1,6 +1,7 @@ #include "private.h" #include #include +#include #include #include @@ -24,13 +25,13 @@ bool update_header(struct tdb_context *tdb) { struct tdb_header_volatile pad, *v; - if (tdb->header_uptodate) { + if (!(tdb->flags & TDB_NOLOCK) && tdb->header_uptodate) { tdb->log(tdb, TDB_DEBUG_WARNING, tdb->log_priv, "warning: header uptodate already\n"); } /* We could get a partial update if we're not holding any locks. */ - assert(tdb_has_locks(tdb)); + assert((tdb->flags & TDB_NOLOCK) || tdb_has_locks(tdb)); v = tdb_get(tdb, offsetof(struct tdb_header, v), &pad, sizeof(*v)); if (!v) { @@ -48,7 +49,7 @@ bool update_header(struct tdb_context *tdb) static uint64_t jenkins_hash(const void *key, size_t length, uint64_t seed, void *arg) { - return hash64_any(key, length, seed); + return hash64_stable((const unsigned char *)key, length, seed); } uint64_t tdb_hash(struct tdb_context *tdb, const void *ptr, size_t len) @@ -77,7 +78,7 @@ static uint64_t random_number(struct tdb_context *tdb) fd = open("/dev/urandom", O_RDONLY); if (fd >= 0) { - if (read(fd, &ret, sizeof(ret)) == sizeof(ret)) { + if (tdb_read_all(fd, &ret, sizeof(ret))) { tdb->log(tdb, TDB_DEBUG_TRACE, tdb->log_priv, "tdb_open: random from /dev/urandom\n"); close(fd); @@ -130,6 +131,7 @@ static int tdb_new_database(struct tdb_context *tdb) { /* We make it up in memory, then write it out if not internal */ struct new_database newdb; + unsigned int magic_off = offsetof(struct tdb_header, magic_food); /* Fill in the header */ newdb.hdr.version = TDB_VERSION; @@ -142,6 +144,9 @@ static int tdb_new_database(struct tdb_context *tdb) newdb.hdr.v.generation = 0; + /* The initial zone must cover the initial database size! */ + BUILD_ASSERT((1ULL << INITIAL_ZONE_BITS) >= sizeof(newdb)); + /* Free array has 1 zone, 10 buckets. All buckets empty. */ newdb.hdr.v.num_zones = 1; newdb.hdr.v.zone_bits = INITIAL_ZONE_BITS; @@ -158,6 +163,17 @@ static int tdb_new_database(struct tdb_context *tdb) sizeof(newdb.hash), sizeof(newdb.hash), 0); memset(newdb.hash, 0, sizeof(newdb.hash)); + /* Magic food */ + memset(newdb.hdr.magic_food, 0, sizeof(newdb.hdr.magic_food)); + strcpy(newdb.hdr.magic_food, TDB_MAGIC_FOOD); + + /* This creates an endian-converted database, as if read from disk */ + tdb_convert(tdb, + (char *)&newdb.hdr + magic_off, + sizeof(newdb) - magic_off); + + tdb->header = newdb.hdr; + if (tdb->flags & TDB_INTERNAL) { tdb->map_size = sizeof(newdb); tdb->map_ptr = malloc(tdb->map_size); @@ -166,9 +182,6 @@ static int tdb_new_database(struct tdb_context *tdb) return -1; } memcpy(tdb->map_ptr, &newdb, tdb->map_size); - tdb->header = newdb.hdr; - /* Convert the `ondisk' version if asked. */ - tdb_convert(tdb, tdb->map_ptr, sizeof(newdb)); return 0; } if (lseek(tdb->fd, 0, SEEK_SET) == -1) @@ -177,14 +190,6 @@ static int tdb_new_database(struct tdb_context *tdb) if (ftruncate(tdb->fd, 0) == -1) return -1; - /* This creates an endian-converted header, as if read from disk */ - tdb->header = newdb.hdr; - tdb_convert(tdb, &tdb->header, sizeof(tdb->header)); - - /* Don't endian-convert the magic food! */ - memset(newdb.hdr.magic_food, 0, sizeof(newdb.hdr.magic_food)); - strcpy(newdb.hdr.magic_food, TDB_MAGIC_FOOD); - if (!tdb_pwrite_all(tdb->fd, &newdb, sizeof(newdb), 0)) { tdb->ecode = TDB_ERR_IO; return -1; @@ -202,19 +207,28 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags, uint64_t hash_test; unsigned v; - if (!(tdb = (struct tdb_context *)calloc(1, sizeof *tdb))) { + tdb = malloc(sizeof(*tdb)); + if (!tdb) { /* Can't log this */ errno = ENOMEM; goto fail; } - tdb->fd = -1; tdb->name = NULL; tdb->map_ptr = NULL; + tdb->fd = -1; + /* map_size will be set below. */ + tdb->ecode = TDB_SUCCESS; + /* header will be read in below. */ + tdb->header_uptodate = false; tdb->flags = tdb_flags; tdb->log = null_log_fn; tdb->log_priv = NULL; tdb->khash = jenkins_hash; tdb->hash_priv = NULL; + tdb->transaction = NULL; + /* last_zone will be set below. */ + tdb_io_init(tdb); + tdb_lock_init(tdb); /* FIXME */ if (attr) { @@ -232,12 +246,13 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags, } if ((open_flags & O_ACCMODE) == O_RDONLY) { - tdb->read_only = 1; + tdb->read_only = true; /* read only databases don't do locking */ tdb->flags |= TDB_NOLOCK; - } + } else + tdb->read_only = false; - /* internal databases don't mmap or lock */ + /* 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) != 0) { @@ -246,7 +261,8 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags, goto fail; } TEST_IT(tdb->flags & TDB_CONVERT); - goto internal; + tdb_convert(tdb, &tdb->header, sizeof(tdb->header)); + return tdb; } if ((tdb->fd = open(name, open_flags, mode)) == -1) { @@ -268,8 +284,7 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags, goto fail; /* errno set by tdb_brlock */ } - errno = 0; - if (read(tdb->fd, &tdb->header, sizeof(tdb->header)) != sizeof(tdb->header) + if (!tdb_pread_all(tdb->fd, &tdb->header, sizeof(tdb->header), 0) || strcmp(tdb->header.magic_food, TDB_MAGIC_FOOD) != 0) { if (!(open_flags & O_CREAT) || tdb_new_database(tdb) == -1) { if (errno == 0) { @@ -325,15 +340,10 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags, tdb->map_size = st.st_size; tdb->device = st.st_dev; tdb->inode = st.st_ino; - tdb_io_init(tdb); tdb_mmap(tdb); - - internal: - /* Internal (memory-only) databases skip all the code above to - * do with disk files, and resume here by releasing their - * open lock and hooking into the active list. */ tdb_unlock_open(tdb); - tdb->last_zone = random_free_zone(tdb); + tdb_zone_init(tdb); + tdb->next = tdbs; tdbs = tdb; return tdb; @@ -374,8 +384,7 @@ static void unlock_lists(struct tdb_context *tdb, { do { tdb_unlock_list(tdb, start, ltype); - start = (start + ((1ULL << tdb->header.v.hash_bits) - 1)) - & ((1ULL << tdb->header.v.hash_bits) - 1); + start = (start + 1) & ((1ULL << tdb->header.v.hash_bits) - 1); } while (start != end); } @@ -873,3 +882,8 @@ int tdb_close(struct tdb_context *tdb) return ret; } + +enum TDB_ERROR tdb_error(struct tdb_context *tdb) +{ + return tdb->ecode; +}