goto unlock_err;
/* Rehash anything following. */
- for (i = old_bucket+1; i < h + num_locks; i++) {
+ for (i = hash_off(tdb, old_bucket+1);
+ i != hash_off(tdb, h + num_locks);
+ i += sizeof(tdb_off_t)) {
tdb_off_t off2;
uint64_t h2;
- off2 = tdb_read_off(tdb, hash_off(tdb, i));
+ off2 = tdb_read_off(tdb, i);
if (unlikely(off2 == TDB_OFF_ERR))
goto unlock_err;
/* Maybe use a bit to indicate it is in ideal place? */
h2 = hash_record(tdb, off2);
/* Is it happy where it is? */
- if ((h2 & ((1ULL << tdb->header.v.hash_bits)-1))
- == (i & ((1ULL << tdb->header.v.hash_bits)-1)))
+ if (hash_off(tdb, h2) == i)
continue;
/* Remove it. */
- if (tdb_write_off(tdb, hash_off(tdb, i), 0) == -1)
+ if (tdb_write_off(tdb, i, 0) == -1)
goto unlock_err;
/* Rehash it. */
#ifndef TDB2_TEST_LOGGING_H
#define TDB2_TEST_LOGGING_H
#include <ccan/tdb2/tdb2.h>
+#include <stdbool.h>
+#include <string.h>
+
unsigned tap_log_messages;
void tap_log_fn(struct tdb_context *tdb,
enum tdb_debug_level level, void *priv,
const char *fmt, ...);
+static inline bool data_equal(struct tdb_data a, struct tdb_data b)
+{
+ if (a.dsize != b.dsize)
+ return false;
+ return memcmp(a.dptr, b.dptr, a.dsize) == 0;
+}
#endif /* TDB2_TEST_LOGGING_H */
--- /dev/null
+#include <ccan/tdb2/tdb.c>
+#include <ccan/tdb2/free.c>
+#include <ccan/tdb2/lock.c>
+#include <ccan/tdb2/io.c>
+#include <ccan/tdb2/check.c>
+#include <ccan/tap/tap.h>
+#include "logging.h"
+
+int main(int argc, char *argv[])
+{
+ unsigned int i;
+ struct tdb_context *tdb;
+ int flags[] = { TDB_INTERNAL, TDB_DEFAULT,
+ TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT };
+ struct tdb_data key = { (unsigned char *)"key", 3 };
+ struct tdb_data data = { (unsigned char *)"data", 4 };
+
+ plan_tests(sizeof(flags) / sizeof(flags[0]) * 8 + 1);
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+ tdb = tdb_open("/tmp/run-new_database.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, NULL);
+ tdb->log = tap_log_fn;
+ ok1(tdb);
+ if (tdb) {
+ /* Delete should fail. */
+ ok1(tdb_delete(tdb, key) == -1);
+ ok1(tdb_error(tdb) == TDB_ERR_NOEXIST);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ /* Insert should succeed. */
+ ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ /* Delete should now work. */
+ ok1(tdb_delete(tdb, key) == 0);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ tdb_close(tdb);
+ }
+ }
+ ok1(tap_log_messages == 0);
+ return exit_status();
+}
--- /dev/null
+#include <ccan/tdb2/tdb.c>
+#include <ccan/tdb2/free.c>
+#include <ccan/tdb2/lock.c>
+#include <ccan/tdb2/io.c>
+#include <ccan/tdb2/check.c>
+#include <ccan/tap/tap.h>
+#include "logging.h"
+
+int main(int argc, char *argv[])
+{
+ unsigned int i;
+ struct tdb_context *tdb;
+ int flags[] = { TDB_INTERNAL, TDB_DEFAULT,
+ TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT };
+ struct tdb_data key = { (unsigned char *)"key", 3 };
+ struct tdb_data data = { (unsigned char *)"data", 4 };
+
+ plan_tests(sizeof(flags) / sizeof(flags[0]) * 8 + 1);
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+ tdb = tdb_open("/tmp/run-new_database.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, NULL);
+ tdb->log = tap_log_fn;
+ ok1(tdb);
+ if (tdb) {
+ struct tdb_data d;
+
+ /* fetch should fail. */
+ d = tdb_fetch(tdb, key);
+ ok1(d.dptr == NULL);
+ ok1(tdb_error(tdb) == TDB_ERR_NOEXIST);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ /* Insert should succeed. */
+ ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ /* Fetch should now work. */
+ d = tdb_fetch(tdb, key);
+ ok1(data_equal(d, data));
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ tdb_close(tdb);
+ }
+ }
+ ok1(tap_log_messages == 0);
+ return exit_status();
+}