--- /dev/null
+#include <ccan/tdb2/tdb2.h>
+#include <ccan/tap/tap.h>
+#include <ccan/hash/hash.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "logging.h"
+
+/* We use the same seed which we saw a failure on. */
+static uint64_t fixedhash(const void *key, size_t len, uint64_t seed, void *p)
+{
+ return hash64_stable((const unsigned char *)key, len,
+ *(uint64_t *)p);
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned int i, j;
+ struct tdb_context *tdb;
+ uint64_t seed = 16014841315512641303ULL;
+ union tdb_attribute fixed_hattr
+ = { .hash = { .base = { TDB_ATTRIBUTE_HASH },
+ .fn = fixedhash,
+ .data = &seed } };
+ int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
+ TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
+ TDB_NOMMAP|TDB_CONVERT };
+ struct tdb_data key = { (unsigned char *)&j, sizeof(j) };
+ struct tdb_data data = { (unsigned char *)&j, sizeof(j) };
+
+ fixed_hattr.base.next = &tap_log_attr;
+
+ plan_tests(sizeof(flags) / sizeof(flags[0]) * (1 + 500 * 3) + 1);
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+ tdb = tdb_open("run-12-store.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, &fixed_hattr);
+ ok1(tdb);
+ if (!tdb)
+ continue;
+
+ /* We seemed to lose some keys.
+ * Insert and check they're in there! */
+ for (j = 0; j < 500; j++) {
+ struct tdb_data d = { NULL, 0 }; /* Bogus GCC warning */
+ ok1(tdb_store(tdb, key, data, TDB_REPLACE) == 0);
+ ok1(tdb_fetch(tdb, key, &d) == TDB_SUCCESS);
+ ok1(tdb_deq(d, data));
+ free(d.dptr);
+ }
+ tdb_close(tdb);
+ }
+
+ ok1(tap_log_messages == 0);
+ return exit_status();
+}
--- /dev/null
+#include <ccan/tdb2/private.h> // For TDB_TOPLEVEL_HASH_BITS
+#include <ccan/hash/hash.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <ccan/tdb2/tdb2.h>
+#include <ccan/tap/tap.h>
+#include "logging.h"
+
+/* We rig the hash so adjacent-numbered records always clash. */
+static uint64_t clash(const void *key, size_t len, uint64_t seed, void *priv)
+{
+ return ((uint64_t)*(const unsigned int *)key)
+ << (64 - TDB_TOPLEVEL_HASH_BITS - 1);
+}
+
+/* We use the same seed which we saw a failure on. */
+static uint64_t fixedhash(const void *key, size_t len, uint64_t seed, void *p)
+{
+ return hash64_stable((const unsigned char *)key, len,
+ *(uint64_t *)p);
+}
+
+static bool store_records(struct tdb_context *tdb)
+{
+ int i;
+ struct tdb_data key = { (unsigned char *)&i, sizeof(i) };
+ struct tdb_data d, data = { (unsigned char *)&i, sizeof(i) };
+
+ for (i = 0; i < 1000; i++) {
+ if (tdb_store(tdb, key, data, TDB_REPLACE) != 0)
+ return false;
+ tdb_fetch(tdb, key, &d);
+ if (!tdb_deq(d, data))
+ return false;
+ free(d.dptr);
+ }
+ return true;
+}
+
+static void test_val(struct tdb_context *tdb, uint64_t val)
+{
+ uint64_t v;
+ struct tdb_data key = { (unsigned char *)&v, sizeof(v) };
+ struct tdb_data d, data = { (unsigned char *)&v, sizeof(v) };
+
+ /* Insert an entry, then delete it. */
+ v = val;
+ /* Delete should fail. */
+ ok1(tdb_delete(tdb, key) == 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 succeed. */
+ ok1(tdb_delete(tdb, key) == 0);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+
+ /* Re-add it, then add collision. */
+ ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
+ v = val + 1;
+ ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+
+ /* Can find both? */
+ ok1(tdb_fetch(tdb, key, &d) == TDB_SUCCESS);
+ ok1(d.dsize == data.dsize);
+ free(d.dptr);
+ v = val;
+ ok1(tdb_fetch(tdb, key, &d) == TDB_SUCCESS);
+ ok1(d.dsize == data.dsize);
+ free(d.dptr);
+
+ /* Delete second one. */
+ v = val + 1;
+ ok1(tdb_delete(tdb, key) == 0);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+
+ /* Re-add */
+ ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+
+ /* Now, try deleting first one. */
+ v = val;
+ ok1(tdb_delete(tdb, key) == 0);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+
+ /* Can still find second? */
+ v = val + 1;
+ ok1(tdb_fetch(tdb, key, &d) == TDB_SUCCESS);
+ ok1(d.dsize == data.dsize);
+ free(d.dptr);
+
+ /* Now, this will be ideally placed. */
+ v = val + 2;
+ ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+
+ /* This will collide with both. */
+ v = val;
+ ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
+
+ /* We can still find them all, right? */
+ ok1(tdb_fetch(tdb, key, &d) == TDB_SUCCESS);
+ ok1(d.dsize == data.dsize);
+ free(d.dptr);
+ v = val + 1;
+ ok1(tdb_fetch(tdb, key, &d) == TDB_SUCCESS);
+ ok1(d.dsize == data.dsize);
+ free(d.dptr);
+ v = val + 2;
+ ok1(tdb_fetch(tdb, key, &d) == TDB_SUCCESS);
+ ok1(d.dsize == data.dsize);
+ free(d.dptr);
+
+ /* And if we delete val + 1, that val + 2 should not move! */
+ v = val + 1;
+ ok1(tdb_delete(tdb, key) == 0);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+
+ v = val;
+ ok1(tdb_fetch(tdb, key, &d) == TDB_SUCCESS);
+ ok1(d.dsize == data.dsize);
+ free(d.dptr);
+ v = val + 2;
+ ok1(tdb_fetch(tdb, key, &d) == TDB_SUCCESS);
+ ok1(d.dsize == data.dsize);
+ free(d.dptr);
+
+ /* Delete those two, so we are empty. */
+ ok1(tdb_delete(tdb, key) == 0);
+ v = val;
+ ok1(tdb_delete(tdb, key) == 0);
+
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned int i, j;
+ struct tdb_context *tdb;
+ uint64_t seed = 16014841315512641303ULL;
+ union tdb_attribute clash_hattr
+ = { .hash = { .base = { TDB_ATTRIBUTE_HASH },
+ .fn = clash } };
+ union tdb_attribute fixed_hattr
+ = { .hash = { .base = { TDB_ATTRIBUTE_HASH },
+ .fn = fixedhash,
+ .data = &seed } };
+ int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
+ TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
+ TDB_NOMMAP|TDB_CONVERT,
+ TDB_INTERNAL|TDB_VERSION1, TDB_VERSION1,
+ TDB_NOMMAP|TDB_VERSION1,
+ TDB_INTERNAL|TDB_CONVERT|TDB_VERSION1,
+ TDB_CONVERT|TDB_VERSION1,
+ TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
+ /* These two values gave trouble before. */
+ int vals[] = { 755, 837 };
+
+ clash_hattr.base.next = &tap_log_attr;
+ fixed_hattr.base.next = &tap_log_attr;
+
+ plan_tests(sizeof(flags) / sizeof(flags[0])
+ * (39 * 3 + 5 + sizeof(vals)/sizeof(vals[0])*2) + 1);
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+ tdb = tdb_open("run-13-delete.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, &clash_hattr);
+ ok1(tdb);
+ if (!tdb)
+ continue;
+
+ /* Check start of hash table. */
+ test_val(tdb, 0);
+
+ /* Check end of hash table. */
+ test_val(tdb, -1ULL);
+
+ /* Check mixed bitpattern. */
+ test_val(tdb, 0x123456789ABCDEF0ULL);
+
+ ok1(!tdb->file || (tdb->file->allrecord_lock.count == 0
+ && tdb->file->num_lockrecs == 0));
+ tdb_close(tdb);
+
+ /* Deleting these entries in the db gave problems. */
+ tdb = tdb_open("run-13-delete.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, &fixed_hattr);
+ ok1(tdb);
+ if (!tdb)
+ continue;
+
+ ok1(store_records(tdb));
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ for (j = 0; j < sizeof(vals)/sizeof(vals[0]); j++) {
+ struct tdb_data key;
+
+ key.dptr = (unsigned char *)&vals[j];
+ key.dsize = sizeof(vals[j]);
+ 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/tdb2.h>
+#include <ccan/tap/tap.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "logging.h"
+
+static bool test_records(struct tdb_context *tdb)
+{
+ int i;
+ struct tdb_data key = { (unsigned char *)&i, sizeof(i) };
+ struct tdb_data data = { (unsigned char *)&i, sizeof(i) };
+
+ for (i = 0; i < 1000; i++) {
+ if (tdb_exists(tdb, key))
+ return false;
+ if (tdb_store(tdb, key, data, TDB_REPLACE) != 0)
+ return false;
+ if (!tdb_exists(tdb, key))
+ return false;
+ }
+
+ for (i = 0; i < 1000; i++) {
+ if (!tdb_exists(tdb, key))
+ return false;
+ if (tdb_delete(tdb, key) != 0)
+ return false;
+ if (tdb_exists(tdb, key))
+ return false;
+ }
+ return true;
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned int i;
+ struct tdb_context *tdb;
+ int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
+ TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
+ TDB_NOMMAP|TDB_CONVERT,
+ TDB_INTERNAL|TDB_VERSION1, TDB_VERSION1,
+ TDB_NOMMAP|TDB_VERSION1,
+ TDB_INTERNAL|TDB_CONVERT|TDB_VERSION1,
+ TDB_CONVERT|TDB_VERSION1,
+ TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
+
+ plan_tests(sizeof(flags) / sizeof(flags[0]) * 2 + 1);
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+ tdb = tdb_open("run-14-exists.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
+ if (ok1(tdb))
+ ok1(test_records(tdb));
+ tdb_close(tdb);
+ }
+
+ ok1(tap_log_messages == 0);
+ return exit_status();
+}
--- /dev/null
+#include <ccan/tdb2/tdb2.h>
+#include <ccan/tap/tap.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "logging.h"
+
+static bool add_records(struct tdb_context *tdb)
+{
+ int i;
+ struct tdb_data key = { (unsigned char *)&i, sizeof(i) };
+ struct tdb_data data = { (unsigned char *)&i, sizeof(i) };
+
+ for (i = 0; i < 1000; i++) {
+ if (tdb_store(tdb, key, data, TDB_REPLACE) != 0)
+ return false;
+ }
+ return true;
+}
+
+
+int main(int argc, char *argv[])
+{
+ unsigned int i;
+ struct tdb_context *tdb;
+ int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
+ TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
+ TDB_NOMMAP|TDB_CONVERT,
+ TDB_INTERNAL|TDB_VERSION1, TDB_VERSION1,
+ TDB_NOMMAP|TDB_VERSION1,
+ TDB_INTERNAL|TDB_CONVERT|TDB_VERSION1,
+ TDB_CONVERT|TDB_VERSION1,
+ TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
+
+ plan_tests(sizeof(flags) / sizeof(flags[0]) * 4 + 1);
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+ tdb = tdb_open("run-16-wipe_all.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
+ if (ok1(tdb)) {
+ struct tdb_data key;
+ ok1(add_records(tdb));
+ ok1(tdb_wipe_all(tdb) == TDB_SUCCESS);
+ ok1(tdb_firstkey(tdb, &key) == TDB_ERR_NOEXIST);
+ tdb_close(tdb);
+ }
+ }
+
+ ok1(tap_log_messages == 0);
+ return exit_status();
+}
--- /dev/null
+#include <ccan/tdb2/tdb2.h>
+#include <ccan/tap/tap.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "logging.h"
+
+static enum TDB_ERROR parse(TDB_DATA key, TDB_DATA data, TDB_DATA *expected)
+{
+ if (!tdb_deq(data, *expected))
+ return TDB_ERR_EINVAL;
+ return TDB_SUCCESS;
+}
+
+static enum TDB_ERROR parse_err(TDB_DATA key, TDB_DATA data, void *unused)
+{
+ return 100;
+}
+
+static bool test_records(struct tdb_context *tdb)
+{
+ int i;
+ struct tdb_data key = { (unsigned char *)&i, sizeof(i) };
+ struct tdb_data data = { (unsigned char *)&i, sizeof(i) };
+
+ for (i = 0; i < 1000; i++) {
+ if (tdb_store(tdb, key, data, TDB_REPLACE) != 0)
+ return false;
+ }
+
+ for (i = 0; i < 1000; i++) {
+ if (tdb_parse_record(tdb, key, parse, &data) != TDB_SUCCESS)
+ return false;
+ }
+
+ if (tdb_parse_record(tdb, key, parse, &data) != TDB_ERR_NOEXIST)
+ return false;
+
+ /* Test error return from parse function. */
+ i = 0;
+ if (tdb_parse_record(tdb, key, parse_err, NULL) != 100)
+ return false;
+
+ return true;
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned int i;
+ struct tdb_context *tdb;
+ int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
+ TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
+ TDB_NOMMAP|TDB_CONVERT,
+ TDB_INTERNAL|TDB_VERSION1, TDB_VERSION1,
+ TDB_NOMMAP|TDB_VERSION1,
+ TDB_INTERNAL|TDB_CONVERT|TDB_VERSION1,
+ TDB_CONVERT|TDB_VERSION1,
+ TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
+
+ plan_tests(sizeof(flags) / sizeof(flags[0]) * 2 + 1);
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+ tdb = tdb_open("run-14-exists.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
+ if (ok1(tdb))
+ ok1(test_records(tdb));
+ tdb_close(tdb);
+ }
+
+ ok1(tap_log_messages == 0);
+ return exit_status();
+}
--- /dev/null
+#include <ccan/tdb2/private.h> // struct tdb_context
+#include <ccan/tdb2/tdb2.h>
+#include <ccan/tap/tap.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include "logging.h"
+
+int main(int argc, char *argv[])
+{
+ unsigned int i;
+ struct tdb_context *tdb;
+ unsigned char *buffer;
+ int flags[] = { TDB_DEFAULT, TDB_NOMMAP,
+ TDB_CONVERT, TDB_NOMMAP|TDB_CONVERT,
+ TDB_VERSION1, TDB_NOMMAP|TDB_VERSION1,
+ TDB_CONVERT|TDB_VERSION1,
+ TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
+ struct tdb_data key = tdb_mkdata("key", 3);
+ struct tdb_data data;
+
+ buffer = malloc(1000);
+ for (i = 0; i < 1000; i++)
+ buffer[i] = i;
+
+ plan_tests(sizeof(flags) / sizeof(flags[0]) * 20 + 1);
+
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+ tdb = tdb_open("run-55-transaction.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
+ ok1(tdb);
+ if (!tdb)
+ continue;
+
+ ok1(tdb_transaction_start(tdb) == 0);
+ data.dptr = buffer;
+ data.dsize = 1000;
+ ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
+ ok1(tdb_fetch(tdb, key, &data) == TDB_SUCCESS);
+ ok1(data.dsize == 1000);
+ ok1(memcmp(data.dptr, buffer, data.dsize) == 0);
+ free(data.dptr);
+
+ /* Cancelling a transaction means no store */
+ tdb_transaction_cancel(tdb);
+ ok1(tdb->file->allrecord_lock.count == 0
+ && tdb->file->num_lockrecs == 0);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ ok1(tdb_fetch(tdb, key, &data) == TDB_ERR_NOEXIST);
+
+ /* Commit the transaction. */
+ ok1(tdb_transaction_start(tdb) == 0);
+ data.dptr = buffer;
+ data.dsize = 1000;
+ ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
+ ok1(tdb_fetch(tdb, key, &data) == TDB_SUCCESS);
+ ok1(data.dsize == 1000);
+ ok1(memcmp(data.dptr, buffer, data.dsize) == 0);
+ free(data.dptr);
+ ok1(tdb_transaction_commit(tdb) == 0);
+ ok1(tdb->file->allrecord_lock.count == 0
+ && tdb->file->num_lockrecs == 0);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ ok1(tdb_fetch(tdb, key, &data) == TDB_SUCCESS);
+ ok1(data.dsize == 1000);
+ ok1(memcmp(data.dptr, buffer, data.dsize) == 0);
+ free(data.dptr);
+
+ tdb_close(tdb);
+ }
+
+ ok1(tap_log_messages == 0);
+ free(buffer);
+ return exit_status();
+}
--- /dev/null
+#include <ccan/tdb2/tdb2.h>
+#include <ccan/tap/tap.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "logging.h"
+
+int main(int argc, char *argv[])
+{
+ unsigned int i;
+ struct tdb_context *tdb;
+ int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
+ TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
+ TDB_NOMMAP|TDB_CONVERT,
+ TDB_INTERNAL|TDB_VERSION1, TDB_VERSION1,
+ TDB_NOMMAP|TDB_VERSION1,
+ TDB_INTERNAL|TDB_CONVERT|TDB_VERSION1,
+ TDB_CONVERT|TDB_VERSION1,
+ TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
+
+ plan_tests(sizeof(flags) / sizeof(flags[0]) * 3);
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+ tdb = tdb_open("run-new_database.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
+ if (!ok1(tdb))
+ continue;
+
+ if (flags[i] & TDB_INTERNAL)
+ ok1(tdb_fd(tdb) == -1);
+ else
+ ok1(tdb_fd(tdb) > 2);
+ tdb_close(tdb);
+ ok1(tap_log_messages == 0);
+ }
+ return exit_status();
+}
--- /dev/null
+#include <ccan/tdb2/tdb2.h>
+#include <ccan/tap/tap.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include "logging.h"
+
+int main(int argc, char *argv[])
+{
+ unsigned int i, seq;
+ struct tdb_context *tdb;
+ struct tdb_data d = { NULL, 0 }; /* Bogus GCC warning */
+ struct tdb_data key = tdb_mkdata("key", 3);
+ struct tdb_data data = tdb_mkdata("data", 4);
+ int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
+ TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
+ TDB_NOMMAP|TDB_CONVERT,
+ TDB_INTERNAL|TDB_VERSION1, TDB_VERSION1,
+ TDB_NOMMAP|TDB_VERSION1,
+ TDB_INTERNAL|TDB_CONVERT|TDB_VERSION1,
+ TDB_CONVERT|TDB_VERSION1,
+ TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
+
+ plan_tests(sizeof(flags) / sizeof(flags[0]) * 15 + 8 * 13);
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+ tdb = tdb_open("run-new_database.tdb", flags[i]|TDB_SEQNUM,
+ O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
+ if (!ok1(tdb))
+ continue;
+
+ seq = 0;
+ ok1(tdb_get_seqnum(tdb) == seq);
+ ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
+ ok1(tdb_get_seqnum(tdb) == ++seq);
+ /* Fetch doesn't change seqnum */
+ if (ok1(tdb_fetch(tdb, key, &d) == TDB_SUCCESS))
+ free(d.dptr);
+ ok1(tdb_get_seqnum(tdb) == seq);
+ ok1(tdb_append(tdb, key, data) == TDB_SUCCESS);
+ /* Append in tdb1 (or store over value) bumps twice! */
+ if (flags[i] & TDB_VERSION1)
+ seq++;
+ ok1(tdb_get_seqnum(tdb) == ++seq);
+
+ ok1(tdb_delete(tdb, key) == TDB_SUCCESS);
+ ok1(tdb_get_seqnum(tdb) == ++seq);
+ /* Empty append works */
+ ok1(tdb_append(tdb, key, data) == TDB_SUCCESS);
+ ok1(tdb_get_seqnum(tdb) == ++seq);
+
+ ok1(tdb_wipe_all(tdb) == TDB_SUCCESS);
+ ok1(tdb_get_seqnum(tdb) == ++seq);
+
+ if (!(flags[i] & TDB_INTERNAL)) {
+ ok1(tdb_transaction_start(tdb) == TDB_SUCCESS);
+ ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
+ ok1(tdb_get_seqnum(tdb) == ++seq);
+ /* Append in tdb1 (or store over value) bumps twice! */
+ if (flags[i] & TDB_VERSION1)
+ seq++;
+ ok1(tdb_append(tdb, key, data) == TDB_SUCCESS);
+ ok1(tdb_get_seqnum(tdb) == ++seq);
+ ok1(tdb_delete(tdb, key) == TDB_SUCCESS);
+ ok1(tdb_get_seqnum(tdb) == ++seq);
+ ok1(tdb_transaction_commit(tdb) == TDB_SUCCESS);
+ ok1(tdb_get_seqnum(tdb) == seq);
+
+ ok1(tdb_transaction_start(tdb) == TDB_SUCCESS);
+ ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
+ ok1(tdb_get_seqnum(tdb) == seq + 1);
+ tdb_transaction_cancel(tdb);
+ ok1(tdb_get_seqnum(tdb) == seq);
+ }
+ tdb_close(tdb);
+ ok1(tap_log_messages == 0);
+ }
+ return exit_status();
+}
--- /dev/null
+#include <ccan/tdb2/private.h> // for tdb_fcntl_unlock
+#include <ccan/tdb2/tdb2.h>
+#include <ccan/tap/tap.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "logging.h"
+
+static int mylock(int fd, int rw, off_t off, off_t len, bool waitflag,
+ void *_err)
+{
+ int *lock_err = _err;
+ struct flock fl;
+ int ret;
+
+ if (*lock_err) {
+ errno = *lock_err;
+ return -1;
+ }
+
+ do {
+ fl.l_type = rw;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = off;
+ fl.l_len = len;
+
+ if (waitflag)
+ ret = fcntl(fd, F_SETLKW, &fl);
+ else
+ ret = fcntl(fd, F_SETLK, &fl);
+ } while (ret != 0 && errno == EINTR);
+
+ return ret;
+}
+
+static int trav_err;
+static int trav(struct tdb_context *tdb, TDB_DATA k, TDB_DATA d, int *err)
+{
+ *err = trav_err;
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned int i;
+ struct tdb_context *tdb;
+ int flags[] = { TDB_DEFAULT, TDB_NOMMAP,
+ TDB_CONVERT, TDB_NOMMAP|TDB_CONVERT,
+ TDB_VERSION1, TDB_NOMMAP|TDB_VERSION1,
+ TDB_CONVERT|TDB_VERSION1,
+ TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
+ union tdb_attribute lock_attr;
+ struct tdb_data key = tdb_mkdata("key", 3);
+ struct tdb_data data = tdb_mkdata("data", 4);
+ int lock_err;
+
+ lock_attr.base.attr = TDB_ATTRIBUTE_FLOCK;
+ lock_attr.base.next = &tap_log_attr;
+ lock_attr.flock.lock = mylock;
+ lock_attr.flock.unlock = tdb_fcntl_unlock;
+ lock_attr.flock.data = &lock_err;
+
+ plan_tests(sizeof(flags) / sizeof(flags[0]) * 80);
+
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+ struct tdb_data d;
+ unsigned int num_oom_messages;
+
+ /* TDB1 double logs here. */
+ if (flags[i] & TDB_VERSION1) {
+ num_oom_messages = 2;
+ } else {
+ num_oom_messages = 1;
+ }
+
+ /* Nonblocking open; expect no error message. */
+ lock_err = EAGAIN;
+ tdb = tdb_open("run-82-lockattr.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, &lock_attr);
+ ok(errno == lock_err, "Errno is %u", errno);
+ ok1(!tdb);
+ ok1(tap_log_messages == 0);
+
+ lock_err = EINTR;
+ tdb = tdb_open("run-82-lockattr.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, &lock_attr);
+ ok(errno == lock_err, "Errno is %u", errno);
+ ok1(!tdb);
+ ok1(tap_log_messages == 0);
+
+ /* Forced fail open. */
+ lock_err = ENOMEM;
+ tdb = tdb_open("run-82-lockattr.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, &lock_attr);
+ ok1(errno == lock_err);
+ ok1(!tdb);
+ ok1(tap_log_messages == 1);
+ tap_log_messages = 0;
+
+ lock_err = 0;
+ tdb = tdb_open("run-82-lockattr.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, &lock_attr);
+ if (!ok1(tdb))
+ continue;
+ ok1(tap_log_messages == 0);
+
+ /* Nonblocking store. */
+ lock_err = EAGAIN;
+ ok1(tdb_store(tdb, key, data, TDB_REPLACE) == TDB_ERR_LOCK);
+ ok1(tap_log_messages == 0);
+ lock_err = EINTR;
+ ok1(tdb_store(tdb, key, data, TDB_REPLACE) == TDB_ERR_LOCK);
+ ok1(tap_log_messages == 0);
+ lock_err = ENOMEM;
+ ok1(tdb_store(tdb, key, data, TDB_REPLACE) == TDB_ERR_LOCK);
+ ok1(tap_log_messages == num_oom_messages);
+ tap_log_messages = 0;
+
+ /* Nonblocking fetch. */
+ lock_err = EAGAIN;
+ ok1(!tdb_exists(tdb, key));
+ ok1(tap_log_messages == 0);
+ lock_err = EINTR;
+ ok1(!tdb_exists(tdb, key));
+ ok1(tap_log_messages == 0);
+ lock_err = ENOMEM;
+ ok1(!tdb_exists(tdb, key));
+ ok1(tap_log_messages == num_oom_messages);
+ tap_log_messages = 0;
+
+ lock_err = EAGAIN;
+ ok1(tdb_fetch(tdb, key, &d) == TDB_ERR_LOCK);
+ ok1(tap_log_messages == 0);
+ lock_err = EINTR;
+ ok1(tdb_fetch(tdb, key, &d) == TDB_ERR_LOCK);
+ ok1(tap_log_messages == 0);
+ lock_err = ENOMEM;
+ ok1(tdb_fetch(tdb, key, &d) == TDB_ERR_LOCK);
+ ok1(tap_log_messages == num_oom_messages);
+ tap_log_messages = 0;
+
+ /* Nonblocking delete. */
+ lock_err = EAGAIN;
+ ok1(tdb_delete(tdb, key) == TDB_ERR_LOCK);
+ ok1(tap_log_messages == 0);
+ lock_err = EINTR;
+ ok1(tdb_delete(tdb, key) == TDB_ERR_LOCK);
+ ok1(tap_log_messages == 0);
+ lock_err = ENOMEM;
+ ok1(tdb_delete(tdb, key) == TDB_ERR_LOCK);
+ ok1(tap_log_messages == num_oom_messages);
+ tap_log_messages = 0;
+
+ /* Nonblocking locks. */
+ lock_err = EAGAIN;
+ ok1(tdb_chainlock(tdb, key) == TDB_ERR_LOCK);
+ ok1(tap_log_messages == 0);
+ lock_err = EINTR;
+ ok1(tdb_chainlock(tdb, key) == TDB_ERR_LOCK);
+ ok1(tap_log_messages == 0);
+ lock_err = ENOMEM;
+ ok1(tdb_chainlock(tdb, key) == TDB_ERR_LOCK);
+ ok1(tap_log_messages == num_oom_messages);
+ tap_log_messages = 0;
+
+ lock_err = EAGAIN;
+ ok1(tdb_chainlock_read(tdb, key) == TDB_ERR_LOCK);
+ ok1(tap_log_messages == 0);
+ lock_err = EINTR;
+ ok1(tdb_chainlock_read(tdb, key) == TDB_ERR_LOCK);
+ ok1(tap_log_messages == 0);
+ lock_err = ENOMEM;
+ ok1(tdb_chainlock_read(tdb, key) == TDB_ERR_LOCK);
+ ok1(tap_log_messages == num_oom_messages);
+ tap_log_messages = 0;
+
+ lock_err = EAGAIN;
+ ok1(tdb_lockall(tdb) == TDB_ERR_LOCK);
+ ok1(tap_log_messages == 0);
+ lock_err = EINTR;
+ ok1(tdb_lockall(tdb) == TDB_ERR_LOCK);
+ ok1(tap_log_messages == 0);
+ lock_err = ENOMEM;
+ ok1(tdb_lockall(tdb) == TDB_ERR_LOCK);
+ /* This actually does divide and conquer. */
+ ok1(tap_log_messages > 0);
+ tap_log_messages = 0;
+
+ lock_err = EAGAIN;
+ ok1(tdb_lockall_read(tdb) == TDB_ERR_LOCK);
+ ok1(tap_log_messages == 0);
+ lock_err = EINTR;
+ ok1(tdb_lockall_read(tdb) == TDB_ERR_LOCK);
+ ok1(tap_log_messages == 0);
+ lock_err = ENOMEM;
+ ok1(tdb_lockall_read(tdb) == TDB_ERR_LOCK);
+ ok1(tap_log_messages > 0);
+ tap_log_messages = 0;
+
+ /* Nonblocking traverse; go nonblock partway through. */
+ lock_err = 0;
+ ok1(tdb_store(tdb, key, data, TDB_REPLACE) == 0);
+ trav_err = EAGAIN;
+ ok1(tdb_traverse(tdb, trav, &lock_err) == TDB_ERR_LOCK);
+ ok1(tap_log_messages == 0);
+ trav_err = EINTR;
+ lock_err = 0;
+ ok1(tdb_traverse(tdb, trav, &lock_err) == TDB_ERR_LOCK);
+ ok1(tap_log_messages == 0);
+ trav_err = ENOMEM;
+ lock_err = 0;
+ ok1(tdb_traverse(tdb, trav, &lock_err) == TDB_ERR_LOCK);
+ ok1(tap_log_messages == num_oom_messages);
+ tap_log_messages = 0;
+
+ /* Nonblocking transactions. */
+ lock_err = EAGAIN;
+ ok1(tdb_transaction_start(tdb) == TDB_ERR_LOCK);
+ ok1(tap_log_messages == 0);
+ lock_err = EINTR;
+ ok1(tdb_transaction_start(tdb) == TDB_ERR_LOCK);
+ ok1(tap_log_messages == 0);
+ lock_err = ENOMEM;
+ ok1(tdb_transaction_start(tdb) == TDB_ERR_LOCK);
+ ok1(tap_log_messages == 1);
+ tap_log_messages = 0;
+
+ /* Nonblocking transaction prepare. */
+ lock_err = 0;
+ ok1(tdb_transaction_start(tdb) == 0);
+ ok1(tdb_delete(tdb, key) == 0);
+
+ lock_err = EAGAIN;
+ ok1(tdb_transaction_prepare_commit(tdb) == TDB_ERR_LOCK);
+ ok1(tap_log_messages == 0);
+
+ lock_err = 0;
+ ok1(tdb_transaction_prepare_commit(tdb) == 0);
+ ok1(tdb_transaction_commit(tdb) == 0);
+
+ /* And the transaction was committed, right? */
+ ok1(!tdb_exists(tdb, key));
+ tdb_close(tdb);
+ ok1(tap_log_messages == 0);
+ }
+ return exit_status();
+}
--- /dev/null
+#include <ccan/tdb2/tdb2.h>
+#include <ccan/tap/tap.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <err.h>
+#include <unistd.h>
+#include "external-agent.h"
+#include "logging.h"
+
+static enum TDB_ERROR clear_if_first(int fd, void *arg)
+{
+/* We hold a lock offset 4 always, so we can tell if anyone is holding it.
+ * (This is compatible with tdb1's TDB_CLEAR_IF_FIRST flag). */
+ struct flock fl;
+
+ if (arg != clear_if_first)
+ return TDB_ERR_CORRUPT;
+
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 4;
+ fl.l_len = 1;
+
+ if (fcntl(fd, F_SETLK, &fl) == 0) {
+ /* We must be first ones to open it! */
+ diag("truncating file!");
+ if (ftruncate(fd, 0) != 0) {
+ return TDB_ERR_IO;
+ }
+ }
+ fl.l_type = F_RDLCK;
+ if (fcntl(fd, F_SETLKW, &fl) != 0) {
+ return TDB_ERR_IO;
+ }
+ return TDB_SUCCESS;
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned int i;
+ struct tdb_context *tdb;
+ struct agent *agent;
+ union tdb_attribute cif;
+ struct tdb_data key = tdb_mkdata("key", 3);
+ int flags[] = { TDB_DEFAULT, TDB_NOMMAP,
+ TDB_CONVERT, TDB_NOMMAP|TDB_CONVERT,
+ TDB_VERSION1, TDB_NOMMAP|TDB_VERSION1,
+ TDB_CONVERT|TDB_VERSION1,
+ TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
+
+ cif.openhook.base.attr = TDB_ATTRIBUTE_OPENHOOK;
+ cif.openhook.base.next = &tap_log_attr;
+ cif.openhook.fn = clear_if_first;
+ cif.openhook.data = clear_if_first;
+
+ agent = prepare_external_agent();
+ plan_tests(sizeof(flags) / sizeof(flags[0]) * 13);
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+ /* Create it */
+ tdb = tdb_open("run-83-openhook.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, NULL);
+ ok1(tdb);
+ ok1(tdb_store(tdb, key, key, TDB_REPLACE) == 0);
+ tdb_close(tdb);
+
+ /* Now, open with CIF, should clear it. */
+ tdb = tdb_open("run-83-openhook.tdb", flags[i],
+ O_RDWR, 0, &cif);
+ ok1(tdb);
+ ok1(!tdb_exists(tdb, key));
+ ok1(tdb_store(tdb, key, key, TDB_REPLACE) == 0);
+
+ /* Agent should not clear it, since it's still open. */
+ ok1(external_agent_operation(agent, OPEN_WITH_HOOK,
+ "run-83-openhook.tdb") == SUCCESS);
+ ok1(external_agent_operation(agent, FETCH, "key") == SUCCESS);
+ ok1(external_agent_operation(agent, CLOSE, "") == SUCCESS);
+
+ /* Still exists for us too. */
+ ok1(tdb_exists(tdb, key));
+
+ /* Close it, now agent should clear it. */
+ tdb_close(tdb);
+
+ ok1(external_agent_operation(agent, OPEN_WITH_HOOK,
+ "run-83-openhook.tdb") == SUCCESS);
+ ok1(external_agent_operation(agent, FETCH, "key") == FAILED);
+ ok1(external_agent_operation(agent, CLOSE, "") == SUCCESS);
+
+ ok1(tap_log_messages == 0);
+ }
+
+ free_external_agent(agent);
+ return exit_status();
+}
--- /dev/null
+#include <ccan/tdb2/tdb2.h>
+#include <ccan/tap/tap.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include "logging.h"
+
+int main(int argc, char *argv[])
+{
+ unsigned int i;
+ struct tdb_context *tdb;
+ int flags[] = { TDB_DEFAULT, TDB_NOMMAP,
+ TDB_CONVERT, TDB_NOMMAP|TDB_CONVERT,
+ TDB_VERSION1, TDB_NOMMAP|TDB_VERSION1,
+ TDB_CONVERT|TDB_VERSION1,
+ TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
+
+ plan_tests(sizeof(flags) / sizeof(flags[0]) * 11);
+
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+ union tdb_attribute *attr;
+ struct tdb_data key = tdb_mkdata("key", 3);
+
+ tdb = tdb_open("run-91-get-stats.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
+ ok1(tdb);
+ ok1(tdb_store(tdb, key, key, TDB_REPLACE) == 0);
+
+ /* Use malloc so valgrind will catch overruns. */
+ attr = malloc(sizeof *attr);
+ attr->stats.base.attr = TDB_ATTRIBUTE_STATS;
+ attr->stats.size = sizeof(*attr);
+
+ ok1(tdb_get_attribute(tdb, attr) == 0);
+ ok1(attr->stats.size == sizeof(*attr));
+ ok1(attr->stats.allocs > 0);
+ ok1(attr->stats.expands > 0);
+ ok1(attr->stats.locks > 0);
+ free(attr);
+
+ /* Try short one. */
+ attr = malloc(offsetof(struct tdb_attribute_stats, allocs)
+ + sizeof(attr->stats.allocs));
+ attr->stats.base.attr = TDB_ATTRIBUTE_STATS;
+ attr->stats.size = offsetof(struct tdb_attribute_stats, allocs)
+ + sizeof(attr->stats.allocs);
+ ok1(tdb_get_attribute(tdb, attr) == 0);
+ ok1(attr->stats.size == sizeof(*attr));
+ ok1(attr->stats.allocs > 0);
+ free(attr);
+ ok1(tap_log_messages == 0);
+
+ tdb_close(tdb);
+
+ }
+ return exit_status();
+}
--- /dev/null
+#include <ccan/tdb2/tdb2.h>
+#include <ccan/tap/tap.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "logging.h"
+
+int main(int argc, char *argv[])
+{
+ unsigned int i, extra_msgs;
+ struct tdb_context *tdb;
+ struct tdb_data key = tdb_mkdata("key", 3);
+ struct tdb_data data = tdb_mkdata("data", 4);
+ int flags[] = { TDB_DEFAULT, TDB_NOMMAP,
+ TDB_CONVERT, TDB_NOMMAP|TDB_CONVERT,
+ TDB_VERSION1, TDB_NOMMAP|TDB_VERSION1,
+ TDB_CONVERT|TDB_VERSION1,
+ TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
+
+ plan_tests(sizeof(flags) / sizeof(flags[0]) * 48);
+
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+ /* RW -> R0 */
+ tdb = tdb_open("run-92-get-set-readonly.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
+ ok1(tdb);
+ ok1(!(tdb_get_flags(tdb) & TDB_RDONLY));
+
+ /* TDB1 complains multiple times. */
+ if (flags[i] & TDB_VERSION1) {
+ extra_msgs = 1;
+ } else {
+ extra_msgs = 0;
+ }
+
+ ok1(tdb_store(tdb, key, data, TDB_INSERT) == TDB_SUCCESS);
+
+ tdb_add_flag(tdb, TDB_RDONLY);
+ ok1(tdb_get_flags(tdb) & TDB_RDONLY);
+
+ /* Can't store, append, delete. */
+ ok1(tdb_store(tdb, key, data, TDB_MODIFY) == TDB_ERR_RDONLY);
+ ok1(tap_log_messages == 1);
+ ok1(tdb_append(tdb, key, data) == TDB_ERR_RDONLY);
+ tap_log_messages -= extra_msgs;
+ ok1(tap_log_messages == 2);
+ ok1(tdb_delete(tdb, key) == TDB_ERR_RDONLY);
+ tap_log_messages -= extra_msgs;
+ ok1(tap_log_messages == 3);
+
+ /* Can't start a transaction, or any write lock. */
+ ok1(tdb_transaction_start(tdb) == TDB_ERR_RDONLY);
+ ok1(tap_log_messages == 4);
+ ok1(tdb_chainlock(tdb, key) == TDB_ERR_RDONLY);
+ tap_log_messages -= extra_msgs;
+ ok1(tap_log_messages == 5);
+ ok1(tdb_lockall(tdb) == TDB_ERR_RDONLY);
+ ok1(tap_log_messages == 6);
+ ok1(tdb_wipe_all(tdb) == TDB_ERR_RDONLY);
+ ok1(tap_log_messages == 7);
+
+ /* Back to RW. */
+ tdb_remove_flag(tdb, TDB_RDONLY);
+ ok1(!(tdb_get_flags(tdb) & TDB_RDONLY));
+
+ ok1(tdb_store(tdb, key, data, TDB_MODIFY) == TDB_SUCCESS);
+ ok1(tdb_append(tdb, key, data) == TDB_SUCCESS);
+ ok1(tdb_delete(tdb, key) == TDB_SUCCESS);
+
+ ok1(tdb_transaction_start(tdb) == TDB_SUCCESS);
+ ok1(tdb_store(tdb, key, data, TDB_INSERT) == TDB_SUCCESS);
+ ok1(tdb_transaction_commit(tdb) == TDB_SUCCESS);
+
+ ok1(tdb_chainlock(tdb, key) == TDB_SUCCESS);
+ tdb_chainunlock(tdb, key);
+ ok1(tdb_lockall(tdb) == TDB_SUCCESS);
+ tdb_unlockall(tdb);
+ ok1(tdb_wipe_all(tdb) == TDB_SUCCESS);
+ ok1(tap_log_messages == 7);
+
+ tdb_close(tdb);
+
+ /* R0 -> RW */
+ tdb = tdb_open("run-92-get-set-readonly.tdb", flags[i],
+ O_RDONLY, 0600, &tap_log_attr);
+ ok1(tdb);
+ ok1(tdb_get_flags(tdb) & TDB_RDONLY);
+
+ /* Can't store, append, delete. */
+ ok1(tdb_store(tdb, key, data, TDB_INSERT) == TDB_ERR_RDONLY);
+ ok1(tap_log_messages == 8);
+ ok1(tdb_append(tdb, key, data) == TDB_ERR_RDONLY);
+ tap_log_messages -= extra_msgs;
+ ok1(tap_log_messages == 9);
+ ok1(tdb_delete(tdb, key) == TDB_ERR_RDONLY);
+ tap_log_messages -= extra_msgs;
+ ok1(tap_log_messages == 10);
+
+ /* Can't start a transaction, or any write lock. */
+ ok1(tdb_transaction_start(tdb) == TDB_ERR_RDONLY);
+ ok1(tap_log_messages == 11);
+ ok1(tdb_chainlock(tdb, key) == TDB_ERR_RDONLY);
+ tap_log_messages -= extra_msgs;
+ ok1(tap_log_messages == 12);
+ ok1(tdb_lockall(tdb) == TDB_ERR_RDONLY);
+ ok1(tap_log_messages == 13);
+ ok1(tdb_wipe_all(tdb) == TDB_ERR_RDONLY);
+ ok1(tap_log_messages == 14);
+
+ /* Can't remove TDB_RDONLY since we opened with O_RDONLY */
+ tdb_remove_flag(tdb, TDB_RDONLY);
+ ok1(tap_log_messages == 15);
+ ok1(tdb_get_flags(tdb) & TDB_RDONLY);
+ tdb_close(tdb);
+
+ ok1(tap_log_messages == 15);
+ tap_log_messages = 0;
+ }
+ return exit_status();
+}
--- /dev/null
+#include <ccan/tdb2/tdb2.h>
+#include <ccan/tap/tap.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "logging.h"
+
+#define NUM_TESTS 50000
+
+static bool store_all(struct tdb_context *tdb)
+{
+ unsigned int i;
+ struct tdb_data key = { (unsigned char *)&i, sizeof(i) };
+ struct tdb_data dbuf = { (unsigned char *)&i, sizeof(i) };
+
+ for (i = 0; i < NUM_TESTS; i++) {
+ if (tdb_store(tdb, key, dbuf, TDB_INSERT) != TDB_SUCCESS)
+ return false;
+ }
+ return true;
+}
+
+static int mark_entry(struct tdb_context *tdb,
+ TDB_DATA key, TDB_DATA data, bool found[])
+{
+ unsigned int num;
+
+ if (key.dsize != sizeof(num))
+ return -1;
+ memcpy(&num, key.dptr, key.dsize);
+ if (num >= NUM_TESTS)
+ return -1;
+ if (found[num])
+ return -1;
+ found[num] = true;
+ return 0;
+}
+
+static bool is_all_set(bool found[], unsigned int num)
+{
+ unsigned int i;
+
+ for (i = 0; i < num; i++)
+ if (!found[i])
+ return false;
+ return true;
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned int i;
+ bool found[NUM_TESTS];
+ struct tdb_context *tdb;
+ int flags[] = { TDB_DEFAULT, TDB_NOMMAP,
+ TDB_CONVERT, TDB_NOMMAP|TDB_CONVERT,
+ };
+
+ plan_tests(sizeof(flags) / sizeof(flags[0]) * 6 + 1);
+
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+ tdb = tdb_open("run-93-repack.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
+ ok1(tdb);
+ if (!tdb)
+ break;
+
+ ok1(store_all(tdb));
+
+ ok1(tdb_repack(tdb) == TDB_SUCCESS);
+ memset(found, 0, sizeof(found));
+ ok1(tdb_check(tdb, NULL, NULL) == TDB_SUCCESS);
+ ok1(tdb_traverse(tdb, mark_entry, found) == NUM_TESTS);
+ ok1(is_all_set(found, NUM_TESTS));
+ tdb_close(tdb);
+ }
+
+ ok1(tap_log_messages == 0);
+ return exit_status();
+}
--- /dev/null
+#include <ccan/tdb2/private.h> // for tdb_context
+#include <ccan/tdb2/tdb2.h>
+#include <ccan/tap/tap.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "logging.h"
+
+int main(int argc, char *argv[])
+{
+ unsigned int i;
+ struct tdb_context *tdb;
+ int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
+ TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
+ TDB_NOMMAP|TDB_CONVERT,
+ TDB_INTERNAL|TDB_VERSION1, TDB_VERSION1,
+ TDB_NOMMAP|TDB_VERSION1,
+ TDB_INTERNAL|TDB_CONVERT|TDB_VERSION1,
+ TDB_CONVERT|TDB_VERSION1,
+ TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
+
+ plan_tests(173);
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+ tdb = tdb_open("run-add-remove-flags.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
+ ok1(tdb);
+ if (!tdb)
+ continue;
+
+ ok1(tdb_get_flags(tdb) == tdb->flags);
+ tap_log_messages = 0;
+ tdb_add_flag(tdb, TDB_NOLOCK);
+ if (flags[i] & TDB_INTERNAL)
+ ok1(tap_log_messages == 1);
+ else {
+ ok1(tap_log_messages == 0);
+ ok1(tdb_get_flags(tdb) & TDB_NOLOCK);
+ }
+
+ tap_log_messages = 0;
+ tdb_add_flag(tdb, TDB_NOMMAP);
+ if (flags[i] & TDB_INTERNAL)
+ ok1(tap_log_messages == 1);
+ else {
+ ok1(tap_log_messages == 0);
+ ok1(tdb_get_flags(tdb) & TDB_NOMMAP);
+ ok1(tdb->file->map_ptr == NULL);
+ }
+
+ tap_log_messages = 0;
+ tdb_add_flag(tdb, TDB_NOSYNC);
+ if (flags[i] & TDB_INTERNAL)
+ ok1(tap_log_messages == 1);
+ else {
+ ok1(tap_log_messages == 0);
+ ok1(tdb_get_flags(tdb) & TDB_NOSYNC);
+ }
+
+ ok1(tdb_get_flags(tdb) == tdb->flags);
+
+ tap_log_messages = 0;
+ tdb_remove_flag(tdb, TDB_NOLOCK);
+ if (flags[i] & TDB_INTERNAL)
+ ok1(tap_log_messages == 1);
+ else {
+ ok1(tap_log_messages == 0);
+ ok1(!(tdb_get_flags(tdb) & TDB_NOLOCK));
+ }
+
+ tap_log_messages = 0;
+ tdb_remove_flag(tdb, TDB_NOMMAP);
+ if (flags[i] & TDB_INTERNAL)
+ ok1(tap_log_messages == 1);
+ else {
+ ok1(tap_log_messages == 0);
+ ok1(!(tdb_get_flags(tdb) & TDB_NOMMAP));
+ ok1(tdb->file->map_ptr != NULL);
+ }
+
+ tap_log_messages = 0;
+ tdb_remove_flag(tdb, TDB_NOSYNC);
+ if (flags[i] & TDB_INTERNAL)
+ ok1(tap_log_messages == 1);
+ else {
+ ok1(tap_log_messages == 0);
+ ok1(!(tdb_get_flags(tdb) & TDB_NOSYNC));
+ }
+
+ tdb_close(tdb);
+ }
+
+ ok1(tap_log_messages == 0);
+ return exit_status();
+}
--- /dev/null
+#include <ccan/tdb2/tdb2.h>
+#include <ccan/tap/tap.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "logging.h"
+
+#define NUM_RECORDS 1000
+
+static bool store_records(struct tdb_context *tdb)
+{
+ int i;
+ struct tdb_data key = { (unsigned char *)&i, sizeof(i) };
+ struct tdb_data data = { (unsigned char *)&i, sizeof(i) };
+
+ for (i = 0; i < NUM_RECORDS; i++)
+ if (tdb_store(tdb, key, data, TDB_REPLACE) != 0)
+ return false;
+ return true;
+}
+
+static enum TDB_ERROR check(struct tdb_data key,
+ struct tdb_data data,
+ bool *array)
+{
+ int val;
+
+ if (key.dsize != sizeof(val)) {
+ diag("Wrong key size: %u\n", key.dsize);
+ return TDB_ERR_CORRUPT;
+ }
+
+ if (key.dsize != data.dsize
+ || memcmp(key.dptr, data.dptr, sizeof(val)) != 0) {
+ diag("Key and data differ\n");
+ return TDB_ERR_CORRUPT;
+ }
+
+ memcpy(&val, key.dptr, sizeof(val));
+ if (val >= NUM_RECORDS || val < 0) {
+ diag("check value %i\n", val);
+ return TDB_ERR_CORRUPT;
+ }
+
+ if (array[val]) {
+ diag("Value %i already seen\n", val);
+ return TDB_ERR_CORRUPT;
+ }
+
+ array[val] = true;
+ return TDB_SUCCESS;
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned int i, j;
+ struct tdb_context *tdb;
+ int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
+ TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
+ TDB_NOMMAP|TDB_CONVERT,
+ TDB_INTERNAL|TDB_VERSION1, TDB_VERSION1,
+ TDB_NOMMAP|TDB_VERSION1,
+ TDB_INTERNAL|TDB_CONVERT|TDB_VERSION1,
+ TDB_CONVERT|TDB_VERSION1,
+ TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
+
+ plan_tests(sizeof(flags) / sizeof(flags[0]) * 4 + 1);
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+ bool array[NUM_RECORDS];
+
+ tdb = tdb_open("run-check-callback.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
+ ok1(tdb);
+ if (!tdb)
+ continue;
+
+ ok1(store_records(tdb));
+ for (j = 0; j < NUM_RECORDS; j++)
+ array[j] = false;
+ ok1(tdb_check(tdb, check, array) == TDB_SUCCESS);
+ for (j = 0; j < NUM_RECORDS; j++)
+ if (!array[j])
+ break;
+ ok1(j == NUM_RECORDS);
+ tdb_close(tdb);
+ }
+
+ ok1(tap_log_messages == 0);
+ return exit_status();
+}
--- /dev/null
+#include <ccan/tdb2/tdb2.h>
+#include <ccan/tap/tap.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include "logging.h"
+
+#define NUM_RECORDS 1000
+
+static bool store_records(struct tdb_context *tdb)
+{
+ int i;
+ struct tdb_data key = { (unsigned char *)&i, sizeof(i) };
+ struct tdb_data data = { (unsigned char *)&i, sizeof(i) };
+
+ for (i = 0; i < NUM_RECORDS; i++)
+ if (tdb_store(tdb, key, data, TDB_REPLACE) != 0)
+ return false;
+ return true;
+}
+
+struct trav_data {
+ unsigned int records[NUM_RECORDS];
+ unsigned int calls;
+};
+
+static int trav(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, void *p)
+{
+ struct trav_data *td = p;
+ int val;
+
+ memcpy(&val, dbuf.dptr, dbuf.dsize);
+ td->records[td->calls++] = val;
+ return 0;
+}
+
+/* Since tdb_nextkey frees dptr, we need to clone it. */
+static TDB_DATA dup_key(TDB_DATA key)
+{
+ void *p = malloc(key.dsize);
+ memcpy(p, key.dptr, key.dsize);
+ key.dptr = p;
+ return key;
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned int i, j;
+ int num;
+ struct trav_data td;
+ TDB_DATA k;
+ struct tdb_context *tdb;
+ union tdb_attribute seed_attr;
+ enum TDB_ERROR ecode;
+ int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
+ TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
+ TDB_NOMMAP|TDB_CONVERT,
+ TDB_INTERNAL|TDB_VERSION1, TDB_VERSION1,
+ TDB_NOMMAP|TDB_VERSION1,
+ TDB_INTERNAL|TDB_CONVERT|TDB_VERSION1,
+ TDB_CONVERT|TDB_VERSION1,
+ TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
+
+ seed_attr.base.attr = TDB_ATTRIBUTE_SEED;
+ seed_attr.base.next = &tap_log_attr;
+ seed_attr.seed.seed = 6334326220117065685ULL;
+
+ plan_tests(sizeof(flags) / sizeof(flags[0])
+ * (NUM_RECORDS*6 + (NUM_RECORDS-1)*3 + 22) + 1);
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+ tdb = tdb_open("run-traverse.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600,
+ flags[i] & TDB_VERSION1 ? NULL : &seed_attr);
+ ok1(tdb);
+ if (!tdb)
+ continue;
+
+ ok1(tdb_firstkey(tdb, &k) == TDB_ERR_NOEXIST);
+
+ /* One entry... */
+ k.dptr = (unsigned char *)#
+ k.dsize = sizeof(num);
+ num = 0;
+ ok1(tdb_store(tdb, k, k, TDB_INSERT) == 0);
+ ok1(tdb_firstkey(tdb, &k) == TDB_SUCCESS);
+ ok1(k.dsize == sizeof(num));
+ ok1(memcmp(k.dptr, &num, sizeof(num)) == 0);
+ ok1(tdb_nextkey(tdb, &k) == TDB_ERR_NOEXIST);
+
+ /* Two entries. */
+ k.dptr = (unsigned char *)#
+ k.dsize = sizeof(num);
+ num = 1;
+ ok1(tdb_store(tdb, k, k, TDB_INSERT) == 0);
+ ok1(tdb_firstkey(tdb, &k) == TDB_SUCCESS);
+ ok1(k.dsize == sizeof(num));
+ memcpy(&num, k.dptr, sizeof(num));
+ ok1(num == 0 || num == 1);
+ ok1(tdb_nextkey(tdb, &k) == TDB_SUCCESS);
+ ok1(k.dsize == sizeof(j));
+ memcpy(&j, k.dptr, sizeof(j));
+ ok1(j == 0 || j == 1);
+ ok1(j != num);
+ ok1(tdb_nextkey(tdb, &k) == TDB_ERR_NOEXIST);
+
+ /* Clean up. */
+ k.dptr = (unsigned char *)#
+ k.dsize = sizeof(num);
+ num = 0;
+ ok1(tdb_delete(tdb, k) == 0);
+ num = 1;
+ ok1(tdb_delete(tdb, k) == 0);
+
+ /* Now lots of records. */
+ ok1(store_records(tdb));
+ td.calls = 0;
+
+ num = tdb_traverse(tdb, trav, &td);
+ ok1(num == NUM_RECORDS);
+ ok1(td.calls == NUM_RECORDS);
+
+ /* Simple loop should match tdb_traverse */
+ for (j = 0, ecode = tdb_firstkey(tdb, &k); j < td.calls; j++) {
+ int val;
+
+ ok1(ecode == TDB_SUCCESS);
+ ok1(k.dsize == sizeof(val));
+ memcpy(&val, k.dptr, k.dsize);
+ ok1(td.records[j] == val);
+ ecode = tdb_nextkey(tdb, &k);
+ }
+
+ /* But arbitrary orderings should work too. */
+ for (j = td.calls-1; j > 0; j--) {
+ k.dptr = (unsigned char *)&td.records[j-1];
+ k.dsize = sizeof(td.records[j-1]);
+ k = dup_key(k);
+ ok1(tdb_nextkey(tdb, &k) == TDB_SUCCESS);
+ ok1(k.dsize == sizeof(td.records[j]));
+ ok1(memcmp(k.dptr, &td.records[j], k.dsize) == 0);
+ free(k.dptr);
+ }
+
+ /* Even delete should work. */
+ for (j = 0, ecode = tdb_firstkey(tdb, &k);
+ ecode != TDB_ERR_NOEXIST;
+ j++) {
+ ok1(ecode == TDB_SUCCESS);
+ ok1(k.dsize == 4);
+ ok1(tdb_delete(tdb, k) == 0);
+ ecode = tdb_nextkey(tdb, &k);
+ }
+
+ diag("delete using first/nextkey gave %u of %u records",
+ j, NUM_RECORDS);
+ ok1(j == NUM_RECORDS);
+ tdb_close(tdb);
+ }
+
+ ok1(tap_log_messages == 0);
+ return exit_status();
+}
--- /dev/null
+/* Test forking while holding lock.
+ *
+ * There are only five ways to do this currently:
+ * (1) grab a tdb_chainlock, then fork.
+ * (2) grab a tdb_lockall, then fork.
+ * (3) grab a tdb_lockall_read, then fork.
+ * (4) start a transaction, then fork.
+ * (5) fork from inside a tdb_parse() callback.
+ *
+ * Note that we don't hold a lock across tdb_traverse callbacks, so
+ * that doesn't matter.
+ */
+#include <ccan/tdb2/tdb2.h>
+#include <ccan/tap/tap.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "logging.h"
+
+static enum TDB_ERROR fork_in_parse(TDB_DATA key, TDB_DATA data,
+ struct tdb_context *tdb)
+{
+ int status, extra_messages;
+
+ if (tdb_get_flags(tdb) & TDB_VERSION1) {
+ extra_messages = 1;
+ } else {
+ extra_messages = 0;
+ }
+
+ if (fork() == 0) {
+ /* We expect this to fail. */
+ if (tdb_store(tdb, key, data, TDB_REPLACE) != TDB_ERR_LOCK)
+ exit(1);
+ tap_log_messages -= extra_messages;
+
+ if (tdb_fetch(tdb, key, &data) != TDB_ERR_LOCK)
+ exit(1);
+
+ tap_log_messages -= extra_messages;
+ if (tap_log_messages != 2)
+ exit(2);
+
+ tdb_close(tdb);
+ if (tap_log_messages != 2)
+ exit(3);
+ exit(0);
+ }
+ wait(&status);
+ ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
+ return TDB_SUCCESS;
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned int i;
+ struct tdb_context *tdb;
+ int flags[] = { TDB_DEFAULT, TDB_NOMMAP,
+ TDB_CONVERT, TDB_NOMMAP|TDB_CONVERT,
+ TDB_VERSION1, TDB_NOMMAP|TDB_VERSION1,
+ TDB_CONVERT|TDB_VERSION1,
+ TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
+ struct tdb_data key = tdb_mkdata("key", 3);
+ struct tdb_data data = tdb_mkdata("data", 4);
+
+ plan_tests(sizeof(flags) / sizeof(flags[0]) * 14);
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+ int status, extra_messages;
+
+ if (flags[i] & TDB_VERSION1) {
+ extra_messages = 1;
+ } else {
+ extra_messages = 0;
+ }
+
+ tap_log_messages = 0;
+
+ tdb = tdb_open("run-fork-test.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
+ if (!ok1(tdb))
+ continue;
+
+ /* Put a record in here. */
+ ok1(tdb_store(tdb, key, data, TDB_REPLACE) == TDB_SUCCESS);
+
+ ok1(tdb_chainlock(tdb, key) == TDB_SUCCESS);
+ if (fork() == 0) {
+ /* We expect this to fail. */
+ if (tdb_store(tdb, key, data, TDB_REPLACE) != TDB_ERR_LOCK)
+ return 1;
+ tap_log_messages -= extra_messages;
+
+ if (tdb_fetch(tdb, key, &data) != TDB_ERR_LOCK)
+ return 1;
+ tap_log_messages -= extra_messages;
+
+ if (tap_log_messages != 2)
+ return 2;
+
+ tdb_chainunlock(tdb, key);
+ if (tap_log_messages != 3)
+ return 3;
+ tdb_close(tdb);
+ if (tap_log_messages != 3)
+ return 4;
+ return 0;
+ }
+ wait(&status);
+ ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
+ tdb_chainunlock(tdb, key);
+
+ ok1(tdb_lockall(tdb) == TDB_SUCCESS);
+ if (fork() == 0) {
+ /* We expect this to fail. */
+ if (tdb_store(tdb, key, data, TDB_REPLACE) != TDB_ERR_LOCK)
+ return 1;
+ tap_log_messages -= extra_messages;
+
+ if (tdb_fetch(tdb, key, &data) != TDB_ERR_LOCK)
+ return 1;
+ tap_log_messages -= extra_messages;
+
+ if (tap_log_messages != 2)
+ return 2;
+
+ tdb_unlockall(tdb);
+ if (tap_log_messages != 2)
+ return 3;
+ tdb_close(tdb);
+ if (tap_log_messages != 2)
+ return 4;
+ return 0;
+ }
+ wait(&status);
+ ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
+ tdb_unlockall(tdb);
+
+ ok1(tdb_lockall_read(tdb) == TDB_SUCCESS);
+ if (fork() == 0) {
+ /* We expect this to fail. */
+ /* This would always fail anyway... */
+ if (tdb_store(tdb, key, data, TDB_REPLACE) != TDB_ERR_LOCK)
+ return 1;
+ tap_log_messages -= extra_messages;
+
+ if (tdb_fetch(tdb, key, &data) != TDB_ERR_LOCK)
+ return 1;
+ tap_log_messages -= extra_messages;
+
+ if (tap_log_messages != 2)
+ return 2;
+
+ tdb_unlockall_read(tdb);
+ if (tap_log_messages != 2)
+ return 3;
+ tdb_close(tdb);
+ if (tap_log_messages != 2)
+ return 4;
+ return 0;
+ }
+ wait(&status);
+ ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
+ tdb_unlockall_read(tdb);
+
+ ok1(tdb_transaction_start(tdb) == TDB_SUCCESS);
+ /* If transactions is empty, noop "commit" succeeds. */
+ ok1(tdb_delete(tdb, key) == TDB_SUCCESS);
+ if (fork() == 0) {
+ /* We expect this to fail. */
+ if (tdb_store(tdb, key, data, TDB_REPLACE) != TDB_ERR_LOCK)
+ return 1;
+ tap_log_messages -= extra_messages;
+
+ if (tdb_fetch(tdb, key, &data) != TDB_ERR_LOCK)
+ return 1;
+ tap_log_messages -= extra_messages;
+
+ if (tap_log_messages != 2)
+ return 2;
+
+ if (tdb_transaction_commit(tdb) != TDB_ERR_LOCK)
+ return 3;
+ tap_log_messages -= extra_messages;
+
+ tdb_close(tdb);
+ if (tap_log_messages < 3)
+ return 4;
+ return 0;
+ }
+ wait(&status);
+ ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
+ tdb_transaction_cancel(tdb);
+
+ ok1(tdb_parse_record(tdb, key, fork_in_parse, tdb)
+ == TDB_SUCCESS);
+ tdb_close(tdb);
+ ok1(tap_log_messages == 0);
+ }
+ return exit_status();
+}
--- /dev/null
+#include <ccan/tdb2/tdb2.h>
+#include <ccan/tap/tap.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <errno.h>
+#include "logging.h"
+#include "external-agent.h"
+
+#undef alarm
+#define alarm fast_alarm
+
+/* Speed things up by doing things in milliseconds. */
+static unsigned int fast_alarm(unsigned int milli_seconds)
+{
+ struct itimerval it;
+
+ it.it_interval.tv_sec = it.it_interval.tv_usec = 0;
+ it.it_value.tv_sec = milli_seconds / 1000;
+ it.it_value.tv_usec = milli_seconds * 1000;
+ setitimer(ITIMER_REAL, &it, NULL);
+ return 0;
+}
+
+#define CatchSignal(sig, handler) signal((sig), (handler))
+
+static void do_nothing(int signum)
+{
+}
+
+/* This example code is taken from SAMBA, so try not to change it. */
+static struct flock flock_struct;
+
+/* Return a value which is none of v1, v2 or v3. */
+static inline short int invalid_value(short int v1, short int v2, short int v3)
+{
+ short int try = (v1+v2+v3)^((v1+v2+v3) << 16);
+ while (try == v1 || try == v2 || try == v3)
+ try++;
+ return try;
+}
+
+/* We invalidate in as many ways as we can, so the OS rejects it */
+static void invalidate_flock_struct(int signum)
+{
+ flock_struct.l_type = invalid_value(F_RDLCK, F_WRLCK, F_UNLCK);
+ flock_struct.l_whence = invalid_value(SEEK_SET, SEEK_CUR, SEEK_END);
+ flock_struct.l_start = -1;
+ /* A large negative. */
+ flock_struct.l_len = (((off_t)1 << (sizeof(off_t)*CHAR_BIT - 1)) + 1);
+}
+
+static int timeout_lock(int fd, int rw, off_t off, off_t len, bool waitflag,
+ void *_timeout)
+{
+ int ret, saved_errno = errno;
+ unsigned int timeout = *(unsigned int *)_timeout;
+
+ flock_struct.l_type = rw;
+ flock_struct.l_whence = SEEK_SET;
+ flock_struct.l_start = off;
+ flock_struct.l_len = len;
+
+ CatchSignal(SIGALRM, invalidate_flock_struct);
+ alarm(timeout);
+
+ for (;;) {
+ if (waitflag)
+ ret = fcntl(fd, F_SETLKW, &flock_struct);
+ else
+ ret = fcntl(fd, F_SETLK, &flock_struct);
+
+ if (ret == 0)
+ break;
+
+ /* Not signalled? Something else went wrong. */
+ if (flock_struct.l_len == len) {
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+ saved_errno = errno;
+ break;
+ } else {
+ saved_errno = EINTR;
+ break;
+ }
+ }
+
+ alarm(0);
+ errno = saved_errno;
+ return ret;
+}
+
+static int tdb_chainlock_with_timeout_internal(struct tdb_context *tdb,
+ TDB_DATA key,
+ unsigned int timeout,
+ int rw_type)
+{
+ union tdb_attribute locking;
+ enum TDB_ERROR ecode;
+
+ if (timeout) {
+ locking.base.attr = TDB_ATTRIBUTE_FLOCK;
+ ecode = tdb_get_attribute(tdb, &locking);
+ if (ecode != TDB_SUCCESS)
+ return ecode;
+
+ /* Replace locking function with our own. */
+ locking.flock.data = &timeout;
+ locking.flock.lock = timeout_lock;
+
+ ecode = tdb_set_attribute(tdb, &locking);
+ if (ecode != TDB_SUCCESS)
+ return ecode;
+ }
+ if (rw_type == F_RDLCK)
+ ecode = tdb_chainlock_read(tdb, key);
+ else
+ ecode = tdb_chainlock(tdb, key);
+
+ if (timeout) {
+ tdb_unset_attribute(tdb, TDB_ATTRIBUTE_FLOCK);
+ }
+ return ecode;
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned int i;
+ struct tdb_context *tdb;
+ TDB_DATA key = tdb_mkdata("hello", 5);
+ int flags[] = { TDB_DEFAULT, TDB_NOMMAP,
+ TDB_CONVERT, TDB_NOMMAP|TDB_CONVERT,
+ TDB_VERSION1, TDB_NOMMAP|TDB_VERSION1,
+ TDB_CONVERT|TDB_VERSION1,
+ TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
+ struct agent *agent;
+
+ plan_tests(sizeof(flags) / sizeof(flags[0]) * 15);
+
+ agent = prepare_external_agent();
+
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+ enum TDB_ERROR ecode;
+ tdb = tdb_open("run-locktimeout.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
+ if (!ok1(tdb))
+ break;
+
+ /* Simple cases: should succeed. */
+ ecode = tdb_chainlock_with_timeout_internal(tdb, key, 20,
+ F_RDLCK);
+ ok1(ecode == TDB_SUCCESS);
+ ok1(tap_log_messages == 0);
+
+ tdb_chainunlock_read(tdb, key);
+ ok1(tap_log_messages == 0);
+
+ ecode = tdb_chainlock_with_timeout_internal(tdb, key, 20,
+ F_WRLCK);
+ ok1(ecode == TDB_SUCCESS);
+ ok1(tap_log_messages == 0);
+
+ tdb_chainunlock(tdb, key);
+ ok1(tap_log_messages == 0);
+
+ /* OK, get agent to start transaction, then we should time out. */
+ ok1(external_agent_operation(agent, OPEN, "run-locktimeout.tdb")
+ == SUCCESS);
+ ok1(external_agent_operation(agent, TRANSACTION_START, "")
+ == SUCCESS);
+ ecode = tdb_chainlock_with_timeout_internal(tdb, key, 20,
+ F_WRLCK);
+ ok1(ecode == TDB_ERR_LOCK);
+ ok1(tap_log_messages == 0);
+
+ /* Even if we get a different signal, should be fine. */
+ CatchSignal(SIGUSR1, do_nothing);
+ external_agent_operation(agent, SEND_SIGNAL, "");
+ ecode = tdb_chainlock_with_timeout_internal(tdb, key, 20,
+ F_WRLCK);
+ ok1(ecode == TDB_ERR_LOCK);
+ ok1(tap_log_messages == 0);
+
+ ok1(external_agent_operation(agent, TRANSACTION_COMMIT, "")
+ == SUCCESS);
+ ok1(external_agent_operation(agent, CLOSE, "")
+ == SUCCESS);
+ tdb_close(tdb);
+ }
+ free_external_agent(agent);
+ return exit_status();
+}
--- /dev/null
+/* Another test revealed that we lost an entry. This reproduces it. */
+#include <ccan/tdb2/tdb2.h>
+#include <ccan/hash/hash.h>
+#include <ccan/tap/tap.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "logging.h"
+
+#define NUM_RECORDS 1189
+
+/* We use the same seed which we saw this failure on. */
+static uint64_t failhash(const void *key, size_t len, uint64_t seed, void *p)
+{
+ seed = 699537674708983027ULL;
+ return hash64_stable((const unsigned char *)key, len, seed);
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+ struct tdb_context *tdb;
+ struct tdb_data key = { (unsigned char *)&i, sizeof(i) };
+ struct tdb_data data = { (unsigned char *)&i, sizeof(i) };
+ union tdb_attribute hattr = { .hash = { .base = { TDB_ATTRIBUTE_HASH },
+ .fn = failhash } };
+
+ hattr.base.next = &tap_log_attr;
+ plan_tests(1 + 2 * NUM_RECORDS + 1);
+
+ tdb = tdb_open("run-missing-entries.tdb", TDB_INTERNAL,
+ O_RDWR|O_CREAT|O_TRUNC, 0600, &hattr);
+ ok1(tdb);
+ if (tdb) {
+ for (i = 0; i < NUM_RECORDS; i++) {
+ ok1(tdb_store(tdb, key, data, TDB_REPLACE) == 0);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ }
+ tdb_close(tdb);
+ }
+
+ ok1(tap_log_messages == 0);
+ return exit_status();
+}
--- /dev/null
+#include <ccan/tdb2/tdb2.h>
+#include <ccan/tap/tap.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include "logging.h"
+
+int main(int argc, char *argv[])
+{
+ unsigned int i, extra_messages;
+ struct tdb_context *tdb, *tdb2;
+ struct tdb_data key = { (unsigned char *)&i, sizeof(i) };
+ struct tdb_data data = { (unsigned char *)&i, sizeof(i) };
+ struct tdb_data d = { NULL, 0 }; /* Bogus GCC warning */
+ int flags[] = { TDB_DEFAULT, TDB_NOMMAP,
+ TDB_CONVERT, TDB_NOMMAP|TDB_CONVERT,
+ TDB_VERSION1, TDB_NOMMAP|TDB_VERSION1,
+ TDB_CONVERT|TDB_VERSION1,
+ TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
+
+ plan_tests(sizeof(flags) / sizeof(flags[0]) * 28);
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+ tdb = tdb_open("run-open-multiple-times.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
+ ok1(tdb);
+ if (!tdb)
+ continue;
+
+ if (flags[i] & TDB_VERSION1) {
+ extra_messages = 1;
+ } else {
+ extra_messages = 0;
+ }
+ tdb2 = tdb_open("run-open-multiple-times.tdb", flags[i],
+ O_RDWR|O_CREAT, 0600, &tap_log_attr);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ ok1(tdb_check(tdb2, NULL, NULL) == 0);
+
+ /* Store in one, fetch in the other. */
+ ok1(tdb_store(tdb, key, data, TDB_REPLACE) == 0);
+ ok1(tdb_fetch(tdb2, key, &d) == TDB_SUCCESS);
+ ok1(tdb_deq(d, data));
+ free(d.dptr);
+
+ /* Vice versa, with delete. */
+ ok1(tdb_delete(tdb2, key) == 0);
+ ok1(tdb_fetch(tdb, key, &d) == TDB_ERR_NOEXIST);
+
+ /* OK, now close first one, check second still good. */
+ ok1(tdb_close(tdb) == 0);
+
+ ok1(tdb_store(tdb2, key, data, TDB_REPLACE) == 0);
+ ok1(tdb_fetch(tdb2, key, &d) == TDB_SUCCESS);
+ ok1(tdb_deq(d, data));
+ free(d.dptr);
+
+ /* Reopen */
+ tdb = tdb_open("run-open-multiple-times.tdb", flags[i],
+ O_RDWR|O_CREAT, 0600, &tap_log_attr);
+ ok1(tdb);
+
+ ok1(tdb_transaction_start(tdb2) == 0);
+
+ /* Anything in the other one should fail. */
+ ok1(tdb_fetch(tdb, key, &d) == TDB_ERR_LOCK);
+ tap_log_messages -= extra_messages;
+ ok1(tap_log_messages == 1);
+ ok1(tdb_store(tdb, key, data, TDB_REPLACE) == TDB_ERR_LOCK);
+ tap_log_messages -= extra_messages;
+ ok1(tap_log_messages == 2);
+ ok1(tdb_transaction_start(tdb) == TDB_ERR_LOCK);
+ ok1(tap_log_messages == 3);
+ ok1(tdb_chainlock(tdb, key) == TDB_ERR_LOCK);
+ tap_log_messages -= extra_messages;
+ ok1(tap_log_messages == 4);
+
+ /* Transaciton should work as normal. */
+ ok1(tdb_store(tdb2, key, data, TDB_REPLACE) == TDB_SUCCESS);
+
+ /* Now... try closing with locks held. */
+ ok1(tdb_close(tdb2) == 0);
+
+ ok1(tdb_fetch(tdb, key, &d) == TDB_SUCCESS);
+ ok1(tdb_deq(d, data));
+ free(d.dptr);
+ ok1(tdb_close(tdb) == 0);
+ ok1(tap_log_messages == 4);
+ tap_log_messages = 0;
+ }
+
+ return exit_status();
+}
--- /dev/null
+#include <ccan/tdb2/tdb2.h>
+#include <ccan/tap/tap.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include "logging.h"
+
+#define MAX_SIZE 10000
+#define SIZE_STEP 131
+
+int main(int argc, char *argv[])
+{
+ unsigned int i;
+ struct tdb_context *tdb;
+ int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
+ TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
+ TDB_NOMMAP|TDB_CONVERT,
+ TDB_INTERNAL|TDB_VERSION1, TDB_VERSION1,
+ TDB_NOMMAP|TDB_VERSION1,
+ TDB_INTERNAL|TDB_CONVERT|TDB_VERSION1,
+ TDB_CONVERT|TDB_VERSION1,
+ TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
+ struct tdb_data key = tdb_mkdata("key", 3);
+ struct tdb_data data;
+
+ data.dptr = malloc(MAX_SIZE);
+ memset(data.dptr, 0x24, MAX_SIZE);
+
+ plan_tests(sizeof(flags) / sizeof(flags[0])
+ * (3 + (1 + (MAX_SIZE/SIZE_STEP)) * 2) + 1);
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+ tdb = tdb_open("run-record-expand.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
+ ok1(tdb);
+ if (!tdb)
+ continue;
+
+ data.dsize = 0;
+ ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ for (data.dsize = 0;
+ data.dsize < MAX_SIZE;
+ data.dsize += SIZE_STEP) {
+ memset(data.dptr, data.dsize, data.dsize);
+ ok1(tdb_store(tdb, key, data, TDB_MODIFY) == 0);
+ ok1(tdb_check(tdb, NULL, NULL) == 0);
+ }
+ tdb_close(tdb);
+ }
+ ok1(tap_log_messages == 0);
+ free(data.dptr);
+
+ return exit_status();
+}
--- /dev/null
+#include <ccan/tdb2/tdb2.h>
+#include <ccan/tap/tap.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "logging.h"
+
+int main(int argc, char *argv[])
+{
+ unsigned int i;
+ struct tdb_context *tdb;
+ int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
+ TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
+ TDB_NOMMAP|TDB_CONVERT,
+ TDB_INTERNAL|TDB_VERSION1, TDB_VERSION1,
+ TDB_NOMMAP|TDB_VERSION1,
+ TDB_INTERNAL|TDB_CONVERT|TDB_VERSION1,
+ TDB_CONVERT|TDB_VERSION1,
+ TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
+ struct tdb_data key = tdb_mkdata("key", 3);
+ struct tdb_data data = tdb_mkdata("data", 4);
+
+ plan_tests(sizeof(flags) / sizeof(flags[0]) * 7 + 1);
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+ tdb = tdb_open("run-simple-delete.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
+ ok1(tdb);
+ if (tdb) {
+ /* Delete should fail. */
+ ok1(tdb_delete(tdb, key) == 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/tdb2.h>
+#include <ccan/tap/tap.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include "logging.h"
+
+int main(int argc, char *argv[])
+{
+ unsigned int i, j;
+ struct tdb_context *tdb;
+ int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
+ TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
+ TDB_NOMMAP|TDB_CONVERT,
+ TDB_INTERNAL|TDB_VERSION1, TDB_VERSION1,
+ TDB_NOMMAP|TDB_VERSION1,
+ TDB_INTERNAL|TDB_CONVERT|TDB_VERSION1,
+ TDB_CONVERT|TDB_VERSION1,
+ TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
+ struct tdb_data key = { (unsigned char *)&j, sizeof(j) };
+ struct tdb_data data = { (unsigned char *)&j, sizeof(j) };
+ char *summary;
+
+ plan_tests(sizeof(flags) / sizeof(flags[0]) * (1 + 2 * 5) + 1);
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+ tdb = tdb_open("run-summary.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 < 500; j++) {
+ /* Make sure padding varies to we get some graphs! */
+ data.dsize = j % (sizeof(j) + 1);
+ if (tdb_store(tdb, key, data, TDB_REPLACE) != 0)
+ fail("Storing in tdb");
+ }
+
+ for (j = 0;
+ j <= TDB_SUMMARY_HISTOGRAMS;
+ j += TDB_SUMMARY_HISTOGRAMS) {
+ ok1(tdb_summary(tdb, j, &summary) == TDB_SUCCESS);
+ ok1(strstr(summary, "Number of records: 500\n"));
+ ok1(strstr(summary, "Smallest/average/largest keys: 4/4/4\n"));
+ ok1(strstr(summary, "Smallest/average/largest data: 0/2/4\n"));
+ if (!(flags[i] & TDB_VERSION1)
+ && j == TDB_SUMMARY_HISTOGRAMS) {
+ ok1(strstr(summary, "|")
+ && strstr(summary, "*"));
+ } else {
+ ok1(!strstr(summary, "|")
+ && !strstr(summary, "*"));
+ }
+ free(summary);
+ }
+ tdb_close(tdb);
+ }
+
+ ok1(tap_log_messages == 0);
+ return exit_status();
+}
+++ /dev/null
-#include "tdb2-source.h"
-#include <ccan/tap/tap.h>
-#include "logging.h"
-
-/* We use the same seed which we saw a failure on. */
-static uint64_t fixedhash(const void *key, size_t len, uint64_t seed, void *p)
-{
- return hash64_stable((const unsigned char *)key, len,
- *(uint64_t *)p);
-}
-
-int main(int argc, char *argv[])
-{
- unsigned int i, j;
- struct tdb_context *tdb;
- uint64_t seed = 16014841315512641303ULL;
- union tdb_attribute fixed_hattr
- = { .hash = { .base = { TDB_ATTRIBUTE_HASH },
- .fn = fixedhash,
- .data = &seed } };
- int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
- TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
- TDB_NOMMAP|TDB_CONVERT };
- struct tdb_data key = { (unsigned char *)&j, sizeof(j) };
- struct tdb_data data = { (unsigned char *)&j, sizeof(j) };
-
- fixed_hattr.base.next = &tap_log_attr;
-
- plan_tests(sizeof(flags) / sizeof(flags[0]) * (1 + 500 * 3) + 1);
- for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
- tdb = tdb_open("run-12-store.tdb", flags[i],
- O_RDWR|O_CREAT|O_TRUNC, 0600, &fixed_hattr);
- ok1(tdb);
- if (!tdb)
- continue;
-
- /* We seemed to lose some keys.
- * Insert and check they're in there! */
- for (j = 0; j < 500; j++) {
- struct tdb_data d = { NULL, 0 }; /* Bogus GCC warning */
- ok1(tdb_store(tdb, key, data, TDB_REPLACE) == 0);
- ok1(tdb_fetch(tdb, key, &d) == TDB_SUCCESS);
- ok1(tdb_deq(d, data));
- free(d.dptr);
- }
- tdb_close(tdb);
- }
-
- ok1(tap_log_messages == 0);
- return exit_status();
-}
-
-
+++ /dev/null
-#include "tdb2-source.h"
-#include <ccan/tap/tap.h>
-#include "logging.h"
-
-/* We rig the hash so adjacent-numbered records always clash. */
-static uint64_t clash(const void *key, size_t len, uint64_t seed, void *priv)
-{
- return ((uint64_t)*(const unsigned int *)key)
- << (64 - TDB_TOPLEVEL_HASH_BITS - 1);
-}
-
-/* We use the same seed which we saw a failure on. */
-static uint64_t fixedhash(const void *key, size_t len, uint64_t seed, void *p)
-{
- return hash64_stable((const unsigned char *)key, len,
- *(uint64_t *)p);
-}
-
-static bool store_records(struct tdb_context *tdb)
-{
- int i;
- struct tdb_data key = { (unsigned char *)&i, sizeof(i) };
- struct tdb_data d, data = { (unsigned char *)&i, sizeof(i) };
-
- for (i = 0; i < 1000; i++) {
- if (tdb_store(tdb, key, data, TDB_REPLACE) != 0)
- return false;
- tdb_fetch(tdb, key, &d);
- if (!tdb_deq(d, data))
- return false;
- free(d.dptr);
- }
- return true;
-}
-
-static void test_val(struct tdb_context *tdb, uint64_t val)
-{
- uint64_t v;
- struct tdb_data key = { (unsigned char *)&v, sizeof(v) };
- struct tdb_data d, data = { (unsigned char *)&v, sizeof(v) };
-
- /* Insert an entry, then delete it. */
- v = val;
- /* Delete should fail. */
- ok1(tdb_delete(tdb, key) == 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 succeed. */
- ok1(tdb_delete(tdb, key) == 0);
- ok1(tdb_check(tdb, NULL, NULL) == 0);
-
- /* Re-add it, then add collision. */
- ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
- v = val + 1;
- ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
- ok1(tdb_check(tdb, NULL, NULL) == 0);
-
- /* Can find both? */
- ok1(tdb_fetch(tdb, key, &d) == TDB_SUCCESS);
- ok1(d.dsize == data.dsize);
- free(d.dptr);
- v = val;
- ok1(tdb_fetch(tdb, key, &d) == TDB_SUCCESS);
- ok1(d.dsize == data.dsize);
- free(d.dptr);
-
- /* Delete second one. */
- v = val + 1;
- ok1(tdb_delete(tdb, key) == 0);
- ok1(tdb_check(tdb, NULL, NULL) == 0);
-
- /* Re-add */
- ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
- ok1(tdb_check(tdb, NULL, NULL) == 0);
-
- /* Now, try deleting first one. */
- v = val;
- ok1(tdb_delete(tdb, key) == 0);
- ok1(tdb_check(tdb, NULL, NULL) == 0);
-
- /* Can still find second? */
- v = val + 1;
- ok1(tdb_fetch(tdb, key, &d) == TDB_SUCCESS);
- ok1(d.dsize == data.dsize);
- free(d.dptr);
-
- /* Now, this will be ideally placed. */
- v = val + 2;
- ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
- ok1(tdb_check(tdb, NULL, NULL) == 0);
-
- /* This will collide with both. */
- v = val;
- ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
-
- /* We can still find them all, right? */
- ok1(tdb_fetch(tdb, key, &d) == TDB_SUCCESS);
- ok1(d.dsize == data.dsize);
- free(d.dptr);
- v = val + 1;
- ok1(tdb_fetch(tdb, key, &d) == TDB_SUCCESS);
- ok1(d.dsize == data.dsize);
- free(d.dptr);
- v = val + 2;
- ok1(tdb_fetch(tdb, key, &d) == TDB_SUCCESS);
- ok1(d.dsize == data.dsize);
- free(d.dptr);
-
- /* And if we delete val + 1, that val + 2 should not move! */
- v = val + 1;
- ok1(tdb_delete(tdb, key) == 0);
- ok1(tdb_check(tdb, NULL, NULL) == 0);
-
- v = val;
- ok1(tdb_fetch(tdb, key, &d) == TDB_SUCCESS);
- ok1(d.dsize == data.dsize);
- free(d.dptr);
- v = val + 2;
- ok1(tdb_fetch(tdb, key, &d) == TDB_SUCCESS);
- ok1(d.dsize == data.dsize);
- free(d.dptr);
-
- /* Delete those two, so we are empty. */
- ok1(tdb_delete(tdb, key) == 0);
- v = val;
- ok1(tdb_delete(tdb, key) == 0);
-
- ok1(tdb_check(tdb, NULL, NULL) == 0);
-}
-
-int main(int argc, char *argv[])
-{
- unsigned int i, j;
- struct tdb_context *tdb;
- uint64_t seed = 16014841315512641303ULL;
- union tdb_attribute clash_hattr
- = { .hash = { .base = { TDB_ATTRIBUTE_HASH },
- .fn = clash } };
- union tdb_attribute fixed_hattr
- = { .hash = { .base = { TDB_ATTRIBUTE_HASH },
- .fn = fixedhash,
- .data = &seed } };
- int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
- TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
- TDB_NOMMAP|TDB_CONVERT,
- TDB_INTERNAL|TDB_VERSION1, TDB_VERSION1,
- TDB_NOMMAP|TDB_VERSION1,
- TDB_INTERNAL|TDB_CONVERT|TDB_VERSION1,
- TDB_CONVERT|TDB_VERSION1,
- TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
- /* These two values gave trouble before. */
- int vals[] = { 755, 837 };
-
- clash_hattr.base.next = &tap_log_attr;
- fixed_hattr.base.next = &tap_log_attr;
-
- plan_tests(sizeof(flags) / sizeof(flags[0])
- * (39 * 3 + 5 + sizeof(vals)/sizeof(vals[0])*2) + 1);
- for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
- tdb = tdb_open("run-13-delete.tdb", flags[i],
- O_RDWR|O_CREAT|O_TRUNC, 0600, &clash_hattr);
- ok1(tdb);
- if (!tdb)
- continue;
-
- /* Check start of hash table. */
- test_val(tdb, 0);
-
- /* Check end of hash table. */
- test_val(tdb, -1ULL);
-
- /* Check mixed bitpattern. */
- test_val(tdb, 0x123456789ABCDEF0ULL);
-
- ok1(!tdb->file || (tdb->file->allrecord_lock.count == 0
- && tdb->file->num_lockrecs == 0));
- tdb_close(tdb);
-
- /* Deleting these entries in the db gave problems. */
- tdb = tdb_open("run-13-delete.tdb", flags[i],
- O_RDWR|O_CREAT|O_TRUNC, 0600, &fixed_hattr);
- ok1(tdb);
- if (!tdb)
- continue;
-
- ok1(store_records(tdb));
- ok1(tdb_check(tdb, NULL, NULL) == 0);
- for (j = 0; j < sizeof(vals)/sizeof(vals[0]); j++) {
- struct tdb_data key;
-
- key.dptr = (unsigned char *)&vals[j];
- key.dsize = sizeof(vals[j]);
- 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 "tdb2-source.h"
-#include <ccan/tap/tap.h>
-#include "logging.h"
-
-static bool test_records(struct tdb_context *tdb)
-{
- int i;
- struct tdb_data key = { (unsigned char *)&i, sizeof(i) };
- struct tdb_data data = { (unsigned char *)&i, sizeof(i) };
-
- for (i = 0; i < 1000; i++) {
- if (tdb_exists(tdb, key))
- return false;
- if (tdb_store(tdb, key, data, TDB_REPLACE) != 0)
- return false;
- if (!tdb_exists(tdb, key))
- return false;
- }
-
- for (i = 0; i < 1000; i++) {
- if (!tdb_exists(tdb, key))
- return false;
- if (tdb_delete(tdb, key) != 0)
- return false;
- if (tdb_exists(tdb, key))
- return false;
- }
- return true;
-}
-
-int main(int argc, char *argv[])
-{
- unsigned int i;
- struct tdb_context *tdb;
- int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
- TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
- TDB_NOMMAP|TDB_CONVERT,
- TDB_INTERNAL|TDB_VERSION1, TDB_VERSION1,
- TDB_NOMMAP|TDB_VERSION1,
- TDB_INTERNAL|TDB_CONVERT|TDB_VERSION1,
- TDB_CONVERT|TDB_VERSION1,
- TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
-
- plan_tests(sizeof(flags) / sizeof(flags[0]) * 2 + 1);
- for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
- tdb = tdb_open("run-14-exists.tdb", flags[i],
- O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
- if (ok1(tdb))
- ok1(test_records(tdb));
- tdb_close(tdb);
- }
-
- ok1(tap_log_messages == 0);
- return exit_status();
-}
+++ /dev/null
-#include "tdb2-source.h"
-#include <ccan/tap/tap.h>
-#include "logging.h"
-
-static bool add_records(struct tdb_context *tdb)
-{
- int i;
- struct tdb_data key = { (unsigned char *)&i, sizeof(i) };
- struct tdb_data data = { (unsigned char *)&i, sizeof(i) };
-
- for (i = 0; i < 1000; i++) {
- if (tdb_store(tdb, key, data, TDB_REPLACE) != 0)
- return false;
- }
- return true;
-}
-
-
-int main(int argc, char *argv[])
-{
- unsigned int i;
- struct tdb_context *tdb;
- int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
- TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
- TDB_NOMMAP|TDB_CONVERT,
- TDB_INTERNAL|TDB_VERSION1, TDB_VERSION1,
- TDB_NOMMAP|TDB_VERSION1,
- TDB_INTERNAL|TDB_CONVERT|TDB_VERSION1,
- TDB_CONVERT|TDB_VERSION1,
- TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
-
- plan_tests(sizeof(flags) / sizeof(flags[0]) * 4 + 1);
- for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
- tdb = tdb_open("run-16-wipe_all.tdb", flags[i],
- O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
- if (ok1(tdb)) {
- struct tdb_data key;
- ok1(add_records(tdb));
- ok1(tdb_wipe_all(tdb) == TDB_SUCCESS);
- ok1(tdb_firstkey(tdb, &key) == TDB_ERR_NOEXIST);
- tdb_close(tdb);
- }
- }
-
- ok1(tap_log_messages == 0);
- return exit_status();
-}
+++ /dev/null
-#include "tdb2-source.h"
-#include <ccan/tap/tap.h>
-#include "logging.h"
-
-static enum TDB_ERROR parse(TDB_DATA key, TDB_DATA data, TDB_DATA *expected)
-{
- if (!tdb_deq(data, *expected))
- return TDB_ERR_EINVAL;
- return TDB_SUCCESS;
-}
-
-static enum TDB_ERROR parse_err(TDB_DATA key, TDB_DATA data, void *unused)
-{
- return 100;
-}
-
-static bool test_records(struct tdb_context *tdb)
-{
- int i;
- struct tdb_data key = { (unsigned char *)&i, sizeof(i) };
- struct tdb_data data = { (unsigned char *)&i, sizeof(i) };
-
- for (i = 0; i < 1000; i++) {
- if (tdb_store(tdb, key, data, TDB_REPLACE) != 0)
- return false;
- }
-
- for (i = 0; i < 1000; i++) {
- if (tdb_parse_record(tdb, key, parse, &data) != TDB_SUCCESS)
- return false;
- }
-
- if (tdb_parse_record(tdb, key, parse, &data) != TDB_ERR_NOEXIST)
- return false;
-
- /* Test error return from parse function. */
- i = 0;
- if (tdb_parse_record(tdb, key, parse_err, NULL) != 100)
- return false;
-
- return true;
-}
-
-int main(int argc, char *argv[])
-{
- unsigned int i;
- struct tdb_context *tdb;
- int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
- TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
- TDB_NOMMAP|TDB_CONVERT,
- TDB_INTERNAL|TDB_VERSION1, TDB_VERSION1,
- TDB_NOMMAP|TDB_VERSION1,
- TDB_INTERNAL|TDB_CONVERT|TDB_VERSION1,
- TDB_CONVERT|TDB_VERSION1,
- TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
-
- plan_tests(sizeof(flags) / sizeof(flags[0]) * 2 + 1);
- for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
- tdb = tdb_open("run-14-exists.tdb", flags[i],
- O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
- if (ok1(tdb))
- ok1(test_records(tdb));
- tdb_close(tdb);
- }
-
- ok1(tap_log_messages == 0);
- return exit_status();
-}
+++ /dev/null
-#include "tdb2-source.h"
-#include <ccan/tap/tap.h>
-#include "logging.h"
-
-int main(int argc, char *argv[])
-{
- unsigned int i;
- struct tdb_context *tdb;
- unsigned char *buffer;
- int flags[] = { TDB_DEFAULT, TDB_NOMMAP,
- TDB_CONVERT, TDB_NOMMAP|TDB_CONVERT,
- TDB_VERSION1, TDB_NOMMAP|TDB_VERSION1,
- TDB_CONVERT|TDB_VERSION1,
- TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
- struct tdb_data key = tdb_mkdata("key", 3);
- struct tdb_data data;
-
- buffer = malloc(1000);
- for (i = 0; i < 1000; i++)
- buffer[i] = i;
-
- plan_tests(sizeof(flags) / sizeof(flags[0]) * 20 + 1);
-
- for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
- tdb = tdb_open("run-55-transaction.tdb", flags[i],
- O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
- ok1(tdb);
- if (!tdb)
- continue;
-
- ok1(tdb_transaction_start(tdb) == 0);
- data.dptr = buffer;
- data.dsize = 1000;
- ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
- ok1(tdb_fetch(tdb, key, &data) == TDB_SUCCESS);
- ok1(data.dsize == 1000);
- ok1(memcmp(data.dptr, buffer, data.dsize) == 0);
- free(data.dptr);
-
- /* Cancelling a transaction means no store */
- tdb_transaction_cancel(tdb);
- ok1(tdb->file->allrecord_lock.count == 0
- && tdb->file->num_lockrecs == 0);
- ok1(tdb_check(tdb, NULL, NULL) == 0);
- ok1(tdb_fetch(tdb, key, &data) == TDB_ERR_NOEXIST);
-
- /* Commit the transaction. */
- ok1(tdb_transaction_start(tdb) == 0);
- data.dptr = buffer;
- data.dsize = 1000;
- ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
- ok1(tdb_fetch(tdb, key, &data) == TDB_SUCCESS);
- ok1(data.dsize == 1000);
- ok1(memcmp(data.dptr, buffer, data.dsize) == 0);
- free(data.dptr);
- ok1(tdb_transaction_commit(tdb) == 0);
- ok1(tdb->file->allrecord_lock.count == 0
- && tdb->file->num_lockrecs == 0);
- ok1(tdb_check(tdb, NULL, NULL) == 0);
- ok1(tdb_fetch(tdb, key, &data) == TDB_SUCCESS);
- ok1(data.dsize == 1000);
- ok1(memcmp(data.dptr, buffer, data.dsize) == 0);
- free(data.dptr);
-
- tdb_close(tdb);
- }
-
- ok1(tap_log_messages == 0);
- free(buffer);
- return exit_status();
-}
+++ /dev/null
-#include "tdb2-source.h"
-#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_NOMMAP,
- TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
- TDB_NOMMAP|TDB_CONVERT,
- TDB_INTERNAL|TDB_VERSION1, TDB_VERSION1,
- TDB_NOMMAP|TDB_VERSION1,
- TDB_INTERNAL|TDB_CONVERT|TDB_VERSION1,
- TDB_CONVERT|TDB_VERSION1,
- TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
-
- plan_tests(sizeof(flags) / sizeof(flags[0]) * 3);
- for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
- tdb = tdb_open("run-new_database.tdb", flags[i],
- O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
- if (!ok1(tdb))
- continue;
-
- if (flags[i] & TDB_INTERNAL)
- ok1(tdb_fd(tdb) == -1);
- else
- ok1(tdb_fd(tdb) > 2);
- tdb_close(tdb);
- ok1(tap_log_messages == 0);
- }
- return exit_status();
-}
+++ /dev/null
-#include "tdb2-source.h"
-#include <ccan/tap/tap.h>
-#include "logging.h"
-
-int main(int argc, char *argv[])
-{
- unsigned int i, seq;
- struct tdb_context *tdb;
- struct tdb_data d = { NULL, 0 }; /* Bogus GCC warning */
- struct tdb_data key = tdb_mkdata("key", 3);
- struct tdb_data data = tdb_mkdata("data", 4);
- int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
- TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
- TDB_NOMMAP|TDB_CONVERT,
- TDB_INTERNAL|TDB_VERSION1, TDB_VERSION1,
- TDB_NOMMAP|TDB_VERSION1,
- TDB_INTERNAL|TDB_CONVERT|TDB_VERSION1,
- TDB_CONVERT|TDB_VERSION1,
- TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
-
- plan_tests(sizeof(flags) / sizeof(flags[0]) * 15 + 8 * 13);
- for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
- tdb = tdb_open("run-new_database.tdb", flags[i]|TDB_SEQNUM,
- O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
- if (!ok1(tdb))
- continue;
-
- seq = 0;
- ok1(tdb_get_seqnum(tdb) == seq);
- ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
- ok1(tdb_get_seqnum(tdb) == ++seq);
- /* Fetch doesn't change seqnum */
- if (ok1(tdb_fetch(tdb, key, &d) == TDB_SUCCESS))
- free(d.dptr);
- ok1(tdb_get_seqnum(tdb) == seq);
- ok1(tdb_append(tdb, key, data) == TDB_SUCCESS);
- /* Append in tdb1 (or store over value) bumps twice! */
- if (flags[i] & TDB_VERSION1)
- seq++;
- ok1(tdb_get_seqnum(tdb) == ++seq);
-
- ok1(tdb_delete(tdb, key) == TDB_SUCCESS);
- ok1(tdb_get_seqnum(tdb) == ++seq);
- /* Empty append works */
- ok1(tdb_append(tdb, key, data) == TDB_SUCCESS);
- ok1(tdb_get_seqnum(tdb) == ++seq);
-
- ok1(tdb_wipe_all(tdb) == TDB_SUCCESS);
- ok1(tdb_get_seqnum(tdb) == ++seq);
-
- if (!(flags[i] & TDB_INTERNAL)) {
- ok1(tdb_transaction_start(tdb) == TDB_SUCCESS);
- ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
- ok1(tdb_get_seqnum(tdb) == ++seq);
- /* Append in tdb1 (or store over value) bumps twice! */
- if (flags[i] & TDB_VERSION1)
- seq++;
- ok1(tdb_append(tdb, key, data) == TDB_SUCCESS);
- ok1(tdb_get_seqnum(tdb) == ++seq);
- ok1(tdb_delete(tdb, key) == TDB_SUCCESS);
- ok1(tdb_get_seqnum(tdb) == ++seq);
- ok1(tdb_transaction_commit(tdb) == TDB_SUCCESS);
- ok1(tdb_get_seqnum(tdb) == seq);
-
- ok1(tdb_transaction_start(tdb) == TDB_SUCCESS);
- ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
- ok1(tdb_get_seqnum(tdb) == seq + 1);
- tdb_transaction_cancel(tdb);
- ok1(tdb_get_seqnum(tdb) == seq);
- }
- tdb_close(tdb);
- ok1(tap_log_messages == 0);
- }
- return exit_status();
-}
+++ /dev/null
-#include "tdb2-source.h"
-#include <ccan/tap/tap.h>
-#include "logging.h"
-
-static int mylock(int fd, int rw, off_t off, off_t len, bool waitflag,
- void *_err)
-{
- int *lock_err = _err;
- struct flock fl;
- int ret;
-
- if (*lock_err) {
- errno = *lock_err;
- return -1;
- }
-
- do {
- fl.l_type = rw;
- fl.l_whence = SEEK_SET;
- fl.l_start = off;
- fl.l_len = len;
-
- if (waitflag)
- ret = fcntl(fd, F_SETLKW, &fl);
- else
- ret = fcntl(fd, F_SETLK, &fl);
- } while (ret != 0 && errno == EINTR);
-
- return ret;
-}
-
-static int trav_err;
-static int trav(struct tdb_context *tdb, TDB_DATA k, TDB_DATA d, int *err)
-{
- *err = trav_err;
- return 0;
-}
-
-int main(int argc, char *argv[])
-{
- unsigned int i;
- struct tdb_context *tdb;
- int flags[] = { TDB_DEFAULT, TDB_NOMMAP,
- TDB_CONVERT, TDB_NOMMAP|TDB_CONVERT,
- TDB_VERSION1, TDB_NOMMAP|TDB_VERSION1,
- TDB_CONVERT|TDB_VERSION1,
- TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
- union tdb_attribute lock_attr;
- struct tdb_data key = tdb_mkdata("key", 3);
- struct tdb_data data = tdb_mkdata("data", 4);
- int lock_err;
-
- lock_attr.base.attr = TDB_ATTRIBUTE_FLOCK;
- lock_attr.base.next = &tap_log_attr;
- lock_attr.flock.lock = mylock;
- lock_attr.flock.unlock = tdb_fcntl_unlock;
- lock_attr.flock.data = &lock_err;
-
- plan_tests(sizeof(flags) / sizeof(flags[0]) * 80);
-
- for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
- struct tdb_data d;
- unsigned int num_oom_messages;
-
- /* TDB1 double logs here. */
- if (flags[i] & TDB_VERSION1) {
- num_oom_messages = 2;
- } else {
- num_oom_messages = 1;
- }
-
- /* Nonblocking open; expect no error message. */
- lock_err = EAGAIN;
- tdb = tdb_open("run-82-lockattr.tdb", flags[i],
- O_RDWR|O_CREAT|O_TRUNC, 0600, &lock_attr);
- ok(errno == lock_err, "Errno is %u", errno);
- ok1(!tdb);
- ok1(tap_log_messages == 0);
-
- lock_err = EINTR;
- tdb = tdb_open("run-82-lockattr.tdb", flags[i],
- O_RDWR|O_CREAT|O_TRUNC, 0600, &lock_attr);
- ok(errno == lock_err, "Errno is %u", errno);
- ok1(!tdb);
- ok1(tap_log_messages == 0);
-
- /* Forced fail open. */
- lock_err = ENOMEM;
- tdb = tdb_open("run-82-lockattr.tdb", flags[i],
- O_RDWR|O_CREAT|O_TRUNC, 0600, &lock_attr);
- ok1(errno == lock_err);
- ok1(!tdb);
- ok1(tap_log_messages == 1);
- tap_log_messages = 0;
-
- lock_err = 0;
- tdb = tdb_open("run-82-lockattr.tdb", flags[i],
- O_RDWR|O_CREAT|O_TRUNC, 0600, &lock_attr);
- if (!ok1(tdb))
- continue;
- ok1(tap_log_messages == 0);
-
- /* Nonblocking store. */
- lock_err = EAGAIN;
- ok1(tdb_store(tdb, key, data, TDB_REPLACE) == TDB_ERR_LOCK);
- ok1(tap_log_messages == 0);
- lock_err = EINTR;
- ok1(tdb_store(tdb, key, data, TDB_REPLACE) == TDB_ERR_LOCK);
- ok1(tap_log_messages == 0);
- lock_err = ENOMEM;
- ok1(tdb_store(tdb, key, data, TDB_REPLACE) == TDB_ERR_LOCK);
- ok1(tap_log_messages == num_oom_messages);
- tap_log_messages = 0;
-
- /* Nonblocking fetch. */
- lock_err = EAGAIN;
- ok1(!tdb_exists(tdb, key));
- ok1(tap_log_messages == 0);
- lock_err = EINTR;
- ok1(!tdb_exists(tdb, key));
- ok1(tap_log_messages == 0);
- lock_err = ENOMEM;
- ok1(!tdb_exists(tdb, key));
- ok1(tap_log_messages == num_oom_messages);
- tap_log_messages = 0;
-
- lock_err = EAGAIN;
- ok1(tdb_fetch(tdb, key, &d) == TDB_ERR_LOCK);
- ok1(tap_log_messages == 0);
- lock_err = EINTR;
- ok1(tdb_fetch(tdb, key, &d) == TDB_ERR_LOCK);
- ok1(tap_log_messages == 0);
- lock_err = ENOMEM;
- ok1(tdb_fetch(tdb, key, &d) == TDB_ERR_LOCK);
- ok1(tap_log_messages == num_oom_messages);
- tap_log_messages = 0;
-
- /* Nonblocking delete. */
- lock_err = EAGAIN;
- ok1(tdb_delete(tdb, key) == TDB_ERR_LOCK);
- ok1(tap_log_messages == 0);
- lock_err = EINTR;
- ok1(tdb_delete(tdb, key) == TDB_ERR_LOCK);
- ok1(tap_log_messages == 0);
- lock_err = ENOMEM;
- ok1(tdb_delete(tdb, key) == TDB_ERR_LOCK);
- ok1(tap_log_messages == num_oom_messages);
- tap_log_messages = 0;
-
- /* Nonblocking locks. */
- lock_err = EAGAIN;
- ok1(tdb_chainlock(tdb, key) == TDB_ERR_LOCK);
- ok1(tap_log_messages == 0);
- lock_err = EINTR;
- ok1(tdb_chainlock(tdb, key) == TDB_ERR_LOCK);
- ok1(tap_log_messages == 0);
- lock_err = ENOMEM;
- ok1(tdb_chainlock(tdb, key) == TDB_ERR_LOCK);
- ok1(tap_log_messages == num_oom_messages);
- tap_log_messages = 0;
-
- lock_err = EAGAIN;
- ok1(tdb_chainlock_read(tdb, key) == TDB_ERR_LOCK);
- ok1(tap_log_messages == 0);
- lock_err = EINTR;
- ok1(tdb_chainlock_read(tdb, key) == TDB_ERR_LOCK);
- ok1(tap_log_messages == 0);
- lock_err = ENOMEM;
- ok1(tdb_chainlock_read(tdb, key) == TDB_ERR_LOCK);
- ok1(tap_log_messages == num_oom_messages);
- tap_log_messages = 0;
-
- lock_err = EAGAIN;
- ok1(tdb_lockall(tdb) == TDB_ERR_LOCK);
- ok1(tap_log_messages == 0);
- lock_err = EINTR;
- ok1(tdb_lockall(tdb) == TDB_ERR_LOCK);
- ok1(tap_log_messages == 0);
- lock_err = ENOMEM;
- ok1(tdb_lockall(tdb) == TDB_ERR_LOCK);
- /* This actually does divide and conquer. */
- ok1(tap_log_messages > 0);
- tap_log_messages = 0;
-
- lock_err = EAGAIN;
- ok1(tdb_lockall_read(tdb) == TDB_ERR_LOCK);
- ok1(tap_log_messages == 0);
- lock_err = EINTR;
- ok1(tdb_lockall_read(tdb) == TDB_ERR_LOCK);
- ok1(tap_log_messages == 0);
- lock_err = ENOMEM;
- ok1(tdb_lockall_read(tdb) == TDB_ERR_LOCK);
- ok1(tap_log_messages > 0);
- tap_log_messages = 0;
-
- /* Nonblocking traverse; go nonblock partway through. */
- lock_err = 0;
- ok1(tdb_store(tdb, key, data, TDB_REPLACE) == 0);
- trav_err = EAGAIN;
- ok1(tdb_traverse(tdb, trav, &lock_err) == TDB_ERR_LOCK);
- ok1(tap_log_messages == 0);
- trav_err = EINTR;
- lock_err = 0;
- ok1(tdb_traverse(tdb, trav, &lock_err) == TDB_ERR_LOCK);
- ok1(tap_log_messages == 0);
- trav_err = ENOMEM;
- lock_err = 0;
- ok1(tdb_traverse(tdb, trav, &lock_err) == TDB_ERR_LOCK);
- ok1(tap_log_messages == num_oom_messages);
- tap_log_messages = 0;
-
- /* Nonblocking transactions. */
- lock_err = EAGAIN;
- ok1(tdb_transaction_start(tdb) == TDB_ERR_LOCK);
- ok1(tap_log_messages == 0);
- lock_err = EINTR;
- ok1(tdb_transaction_start(tdb) == TDB_ERR_LOCK);
- ok1(tap_log_messages == 0);
- lock_err = ENOMEM;
- ok1(tdb_transaction_start(tdb) == TDB_ERR_LOCK);
- ok1(tap_log_messages == 1);
- tap_log_messages = 0;
-
- /* Nonblocking transaction prepare. */
- lock_err = 0;
- ok1(tdb_transaction_start(tdb) == 0);
- ok1(tdb_delete(tdb, key) == 0);
-
- lock_err = EAGAIN;
- ok1(tdb_transaction_prepare_commit(tdb) == TDB_ERR_LOCK);
- ok1(tap_log_messages == 0);
-
- lock_err = 0;
- ok1(tdb_transaction_prepare_commit(tdb) == 0);
- ok1(tdb_transaction_commit(tdb) == 0);
-
- /* And the transaction was committed, right? */
- ok1(!tdb_exists(tdb, key));
- tdb_close(tdb);
- ok1(tap_log_messages == 0);
- }
- return exit_status();
-}
+++ /dev/null
-#include "tdb2-source.h"
-#include <ccan/tap/tap.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <stdarg.h>
-#include <err.h>
-#include "external-agent.h"
-#include "logging.h"
-
-static enum TDB_ERROR clear_if_first(int fd, void *arg)
-{
-/* We hold a lock offset 4 always, so we can tell if anyone is holding it.
- * (This is compatible with tdb1's TDB_CLEAR_IF_FIRST flag). */
- struct flock fl;
-
- if (arg != clear_if_first)
- return TDB_ERR_CORRUPT;
-
- fl.l_type = F_WRLCK;
- fl.l_whence = SEEK_SET;
- fl.l_start = 4;
- fl.l_len = 1;
-
- if (fcntl(fd, F_SETLK, &fl) == 0) {
- /* We must be first ones to open it! */
- diag("truncating file!");
- if (ftruncate(fd, 0) != 0) {
- return TDB_ERR_IO;
- }
- }
- fl.l_type = F_RDLCK;
- if (fcntl(fd, F_SETLKW, &fl) != 0) {
- return TDB_ERR_IO;
- }
- return TDB_SUCCESS;
-}
-
-int main(int argc, char *argv[])
-{
- unsigned int i;
- struct tdb_context *tdb;
- struct agent *agent;
- union tdb_attribute cif;
- struct tdb_data key = tdb_mkdata("key", 3);
- int flags[] = { TDB_DEFAULT, TDB_NOMMAP,
- TDB_CONVERT, TDB_NOMMAP|TDB_CONVERT,
- TDB_VERSION1, TDB_NOMMAP|TDB_VERSION1,
- TDB_CONVERT|TDB_VERSION1,
- TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
-
- cif.openhook.base.attr = TDB_ATTRIBUTE_OPENHOOK;
- cif.openhook.base.next = &tap_log_attr;
- cif.openhook.fn = clear_if_first;
- cif.openhook.data = clear_if_first;
-
- agent = prepare_external_agent();
- plan_tests(sizeof(flags) / sizeof(flags[0]) * 13);
- for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
- /* Create it */
- tdb = tdb_open("run-83-openhook.tdb", flags[i],
- O_RDWR|O_CREAT|O_TRUNC, 0600, NULL);
- ok1(tdb);
- ok1(tdb_store(tdb, key, key, TDB_REPLACE) == 0);
- tdb_close(tdb);
-
- /* Now, open with CIF, should clear it. */
- tdb = tdb_open("run-83-openhook.tdb", flags[i],
- O_RDWR, 0, &cif);
- ok1(tdb);
- ok1(!tdb_exists(tdb, key));
- ok1(tdb_store(tdb, key, key, TDB_REPLACE) == 0);
-
- /* Agent should not clear it, since it's still open. */
- ok1(external_agent_operation(agent, OPEN_WITH_HOOK,
- "run-83-openhook.tdb") == SUCCESS);
- ok1(external_agent_operation(agent, FETCH, "key") == SUCCESS);
- ok1(external_agent_operation(agent, CLOSE, "") == SUCCESS);
-
- /* Still exists for us too. */
- ok1(tdb_exists(tdb, key));
-
- /* Close it, now agent should clear it. */
- tdb_close(tdb);
-
- ok1(external_agent_operation(agent, OPEN_WITH_HOOK,
- "run-83-openhook.tdb") == SUCCESS);
- ok1(external_agent_operation(agent, FETCH, "key") == FAILED);
- ok1(external_agent_operation(agent, CLOSE, "") == SUCCESS);
-
- ok1(tap_log_messages == 0);
- }
-
- free_external_agent(agent);
- return exit_status();
-}
-
+++ /dev/null
-#include "tdb2-source.h"
-#include <ccan/tap/tap.h>
-#include "logging.h"
-
-int main(int argc, char *argv[])
-{
- unsigned int i;
- struct tdb_context *tdb;
- int flags[] = { TDB_DEFAULT, TDB_NOMMAP,
- TDB_CONVERT, TDB_NOMMAP|TDB_CONVERT,
- TDB_VERSION1, TDB_NOMMAP|TDB_VERSION1,
- TDB_CONVERT|TDB_VERSION1,
- TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
-
- plan_tests(sizeof(flags) / sizeof(flags[0]) * 11);
-
- for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
- union tdb_attribute *attr;
- struct tdb_data key = tdb_mkdata("key", 3);
-
- tdb = tdb_open("run-91-get-stats.tdb", flags[i],
- O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
- ok1(tdb);
- ok1(tdb_store(tdb, key, key, TDB_REPLACE) == 0);
-
- /* Use malloc so valgrind will catch overruns. */
- attr = malloc(sizeof *attr);
- attr->stats.base.attr = TDB_ATTRIBUTE_STATS;
- attr->stats.size = sizeof(*attr);
-
- ok1(tdb_get_attribute(tdb, attr) == 0);
- ok1(attr->stats.size == sizeof(*attr));
- ok1(attr->stats.allocs > 0);
- ok1(attr->stats.expands > 0);
- ok1(attr->stats.locks > 0);
- free(attr);
-
- /* Try short one. */
- attr = malloc(offsetof(struct tdb_attribute_stats, allocs)
- + sizeof(attr->stats.allocs));
- attr->stats.base.attr = TDB_ATTRIBUTE_STATS;
- attr->stats.size = offsetof(struct tdb_attribute_stats, allocs)
- + sizeof(attr->stats.allocs);
- ok1(tdb_get_attribute(tdb, attr) == 0);
- ok1(attr->stats.size == sizeof(*attr));
- ok1(attr->stats.allocs > 0);
- free(attr);
- ok1(tap_log_messages == 0);
-
- tdb_close(tdb);
-
- }
- return exit_status();
-}
+++ /dev/null
-#include "tdb2-source.h"
-#include <ccan/tap/tap.h>
-#include "logging.h"
-
-int main(int argc, char *argv[])
-{
- unsigned int i, extra_msgs;
- struct tdb_context *tdb;
- struct tdb_data key = tdb_mkdata("key", 3);
- struct tdb_data data = tdb_mkdata("data", 4);
- int flags[] = { TDB_DEFAULT, TDB_NOMMAP,
- TDB_CONVERT, TDB_NOMMAP|TDB_CONVERT,
- TDB_VERSION1, TDB_NOMMAP|TDB_VERSION1,
- TDB_CONVERT|TDB_VERSION1,
- TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
-
- plan_tests(sizeof(flags) / sizeof(flags[0]) * 48);
-
- for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
- /* RW -> R0 */
- tdb = tdb_open("run-92-get-set-readonly.tdb", flags[i],
- O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
- ok1(tdb);
- ok1(!(tdb_get_flags(tdb) & TDB_RDONLY));
-
- /* TDB1 complains multiple times. */
- if (flags[i] & TDB_VERSION1) {
- extra_msgs = 1;
- } else {
- extra_msgs = 0;
- }
-
- ok1(tdb_store(tdb, key, data, TDB_INSERT) == TDB_SUCCESS);
-
- tdb_add_flag(tdb, TDB_RDONLY);
- ok1(tdb_get_flags(tdb) & TDB_RDONLY);
-
- /* Can't store, append, delete. */
- ok1(tdb_store(tdb, key, data, TDB_MODIFY) == TDB_ERR_RDONLY);
- ok1(tap_log_messages == 1);
- ok1(tdb_append(tdb, key, data) == TDB_ERR_RDONLY);
- tap_log_messages -= extra_msgs;
- ok1(tap_log_messages == 2);
- ok1(tdb_delete(tdb, key) == TDB_ERR_RDONLY);
- tap_log_messages -= extra_msgs;
- ok1(tap_log_messages == 3);
-
- /* Can't start a transaction, or any write lock. */
- ok1(tdb_transaction_start(tdb) == TDB_ERR_RDONLY);
- ok1(tap_log_messages == 4);
- ok1(tdb_chainlock(tdb, key) == TDB_ERR_RDONLY);
- tap_log_messages -= extra_msgs;
- ok1(tap_log_messages == 5);
- ok1(tdb_lockall(tdb) == TDB_ERR_RDONLY);
- ok1(tap_log_messages == 6);
- ok1(tdb_wipe_all(tdb) == TDB_ERR_RDONLY);
- ok1(tap_log_messages == 7);
-
- /* Back to RW. */
- tdb_remove_flag(tdb, TDB_RDONLY);
- ok1(!(tdb_get_flags(tdb) & TDB_RDONLY));
-
- ok1(tdb_store(tdb, key, data, TDB_MODIFY) == TDB_SUCCESS);
- ok1(tdb_append(tdb, key, data) == TDB_SUCCESS);
- ok1(tdb_delete(tdb, key) == TDB_SUCCESS);
-
- ok1(tdb_transaction_start(tdb) == TDB_SUCCESS);
- ok1(tdb_store(tdb, key, data, TDB_INSERT) == TDB_SUCCESS);
- ok1(tdb_transaction_commit(tdb) == TDB_SUCCESS);
-
- ok1(tdb_chainlock(tdb, key) == TDB_SUCCESS);
- tdb_chainunlock(tdb, key);
- ok1(tdb_lockall(tdb) == TDB_SUCCESS);
- tdb_unlockall(tdb);
- ok1(tdb_wipe_all(tdb) == TDB_SUCCESS);
- ok1(tap_log_messages == 7);
-
- tdb_close(tdb);
-
- /* R0 -> RW */
- tdb = tdb_open("run-92-get-set-readonly.tdb", flags[i],
- O_RDONLY, 0600, &tap_log_attr);
- ok1(tdb);
- ok1(tdb_get_flags(tdb) & TDB_RDONLY);
-
- /* Can't store, append, delete. */
- ok1(tdb_store(tdb, key, data, TDB_INSERT) == TDB_ERR_RDONLY);
- ok1(tap_log_messages == 8);
- ok1(tdb_append(tdb, key, data) == TDB_ERR_RDONLY);
- tap_log_messages -= extra_msgs;
- ok1(tap_log_messages == 9);
- ok1(tdb_delete(tdb, key) == TDB_ERR_RDONLY);
- tap_log_messages -= extra_msgs;
- ok1(tap_log_messages == 10);
-
- /* Can't start a transaction, or any write lock. */
- ok1(tdb_transaction_start(tdb) == TDB_ERR_RDONLY);
- ok1(tap_log_messages == 11);
- ok1(tdb_chainlock(tdb, key) == TDB_ERR_RDONLY);
- tap_log_messages -= extra_msgs;
- ok1(tap_log_messages == 12);
- ok1(tdb_lockall(tdb) == TDB_ERR_RDONLY);
- ok1(tap_log_messages == 13);
- ok1(tdb_wipe_all(tdb) == TDB_ERR_RDONLY);
- ok1(tap_log_messages == 14);
-
- /* Can't remove TDB_RDONLY since we opened with O_RDONLY */
- tdb_remove_flag(tdb, TDB_RDONLY);
- ok1(tap_log_messages == 15);
- ok1(tdb_get_flags(tdb) & TDB_RDONLY);
- tdb_close(tdb);
-
- ok1(tap_log_messages == 15);
- tap_log_messages = 0;
- }
- return exit_status();
-}
+++ /dev/null
-#include "tdb2-source.h"
-#include <ccan/tap/tap.h>
-#include "logging.h"
-
-#define NUM_TESTS 50000
-
-static bool store_all(struct tdb_context *tdb)
-{
- unsigned int i;
- struct tdb_data key = { (unsigned char *)&i, sizeof(i) };
- struct tdb_data dbuf = { (unsigned char *)&i, sizeof(i) };
-
- for (i = 0; i < NUM_TESTS; i++) {
- if (tdb_store(tdb, key, dbuf, TDB_INSERT) != TDB_SUCCESS)
- return false;
- }
- return true;
-}
-
-static int mark_entry(struct tdb_context *tdb,
- TDB_DATA key, TDB_DATA data, bool found[])
-{
- unsigned int num;
-
- if (key.dsize != sizeof(num))
- return -1;
- memcpy(&num, key.dptr, key.dsize);
- if (num >= NUM_TESTS)
- return -1;
- if (found[num])
- return -1;
- found[num] = true;
- return 0;
-}
-
-static bool is_all_set(bool found[], unsigned int num)
-{
- unsigned int i;
-
- for (i = 0; i < num; i++)
- if (!found[i])
- return false;
- return true;
-}
-
-int main(int argc, char *argv[])
-{
- unsigned int i;
- bool found[NUM_TESTS];
- struct tdb_context *tdb;
- int flags[] = { TDB_DEFAULT, TDB_NOMMAP,
- TDB_CONVERT, TDB_NOMMAP|TDB_CONVERT,
- };
-
- plan_tests(sizeof(flags) / sizeof(flags[0]) * 6 + 1);
-
- for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
- tdb = tdb_open("run-93-repack.tdb", flags[i],
- O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
- ok1(tdb);
- if (!tdb)
- break;
-
- ok1(store_all(tdb));
-
- ok1(tdb_repack(tdb) == TDB_SUCCESS);
- memset(found, 0, sizeof(found));
- ok1(tdb_check(tdb, NULL, NULL) == TDB_SUCCESS);
- ok1(tdb_traverse(tdb, mark_entry, found) == NUM_TESTS);
- ok1(is_all_set(found, NUM_TESTS));
- tdb_close(tdb);
- }
-
- ok1(tap_log_messages == 0);
- return exit_status();
-}
+++ /dev/null
-#include "tdb2-source.h"
-#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_NOMMAP,
- TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
- TDB_NOMMAP|TDB_CONVERT,
- TDB_INTERNAL|TDB_VERSION1, TDB_VERSION1,
- TDB_NOMMAP|TDB_VERSION1,
- TDB_INTERNAL|TDB_CONVERT|TDB_VERSION1,
- TDB_CONVERT|TDB_VERSION1,
- TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
-
- plan_tests(173);
- for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
- tdb = tdb_open("run-add-remove-flags.tdb", flags[i],
- O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
- ok1(tdb);
- if (!tdb)
- continue;
-
- ok1(tdb_get_flags(tdb) == tdb->flags);
- tap_log_messages = 0;
- tdb_add_flag(tdb, TDB_NOLOCK);
- if (flags[i] & TDB_INTERNAL)
- ok1(tap_log_messages == 1);
- else {
- ok1(tap_log_messages == 0);
- ok1(tdb_get_flags(tdb) & TDB_NOLOCK);
- }
-
- tap_log_messages = 0;
- tdb_add_flag(tdb, TDB_NOMMAP);
- if (flags[i] & TDB_INTERNAL)
- ok1(tap_log_messages == 1);
- else {
- ok1(tap_log_messages == 0);
- ok1(tdb_get_flags(tdb) & TDB_NOMMAP);
- ok1(tdb->file->map_ptr == NULL);
- }
-
- tap_log_messages = 0;
- tdb_add_flag(tdb, TDB_NOSYNC);
- if (flags[i] & TDB_INTERNAL)
- ok1(tap_log_messages == 1);
- else {
- ok1(tap_log_messages == 0);
- ok1(tdb_get_flags(tdb) & TDB_NOSYNC);
- }
-
- ok1(tdb_get_flags(tdb) == tdb->flags);
-
- tap_log_messages = 0;
- tdb_remove_flag(tdb, TDB_NOLOCK);
- if (flags[i] & TDB_INTERNAL)
- ok1(tap_log_messages == 1);
- else {
- ok1(tap_log_messages == 0);
- ok1(!(tdb_get_flags(tdb) & TDB_NOLOCK));
- }
-
- tap_log_messages = 0;
- tdb_remove_flag(tdb, TDB_NOMMAP);
- if (flags[i] & TDB_INTERNAL)
- ok1(tap_log_messages == 1);
- else {
- ok1(tap_log_messages == 0);
- ok1(!(tdb_get_flags(tdb) & TDB_NOMMAP));
- ok1(tdb->file->map_ptr != NULL);
- }
-
- tap_log_messages = 0;
- tdb_remove_flag(tdb, TDB_NOSYNC);
- if (flags[i] & TDB_INTERNAL)
- ok1(tap_log_messages == 1);
- else {
- ok1(tap_log_messages == 0);
- ok1(!(tdb_get_flags(tdb) & TDB_NOSYNC));
- }
-
- tdb_close(tdb);
- }
-
- ok1(tap_log_messages == 0);
- return exit_status();
-}
+++ /dev/null
-#include "tdb2-source.h"
-#include <ccan/tap/tap.h>
-#include "logging.h"
-
-#define NUM_RECORDS 1000
-
-static bool store_records(struct tdb_context *tdb)
-{
- int i;
- struct tdb_data key = { (unsigned char *)&i, sizeof(i) };
- struct tdb_data data = { (unsigned char *)&i, sizeof(i) };
-
- for (i = 0; i < NUM_RECORDS; i++)
- if (tdb_store(tdb, key, data, TDB_REPLACE) != 0)
- return false;
- return true;
-}
-
-static enum TDB_ERROR check(struct tdb_data key,
- struct tdb_data data,
- bool *array)
-{
- int val;
-
- if (key.dsize != sizeof(val)) {
- diag("Wrong key size: %u\n", key.dsize);
- return TDB_ERR_CORRUPT;
- }
-
- if (key.dsize != data.dsize
- || memcmp(key.dptr, data.dptr, sizeof(val)) != 0) {
- diag("Key and data differ\n");
- return TDB_ERR_CORRUPT;
- }
-
- memcpy(&val, key.dptr, sizeof(val));
- if (val >= NUM_RECORDS || val < 0) {
- diag("check value %i\n", val);
- return TDB_ERR_CORRUPT;
- }
-
- if (array[val]) {
- diag("Value %i already seen\n", val);
- return TDB_ERR_CORRUPT;
- }
-
- array[val] = true;
- return TDB_SUCCESS;
-}
-
-int main(int argc, char *argv[])
-{
- unsigned int i, j;
- struct tdb_context *tdb;
- int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
- TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
- TDB_NOMMAP|TDB_CONVERT,
- TDB_INTERNAL|TDB_VERSION1, TDB_VERSION1,
- TDB_NOMMAP|TDB_VERSION1,
- TDB_INTERNAL|TDB_CONVERT|TDB_VERSION1,
- TDB_CONVERT|TDB_VERSION1,
- TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
-
- plan_tests(sizeof(flags) / sizeof(flags[0]) * 4 + 1);
- for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
- bool array[NUM_RECORDS];
-
- tdb = tdb_open("run-check-callback.tdb", flags[i],
- O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
- ok1(tdb);
- if (!tdb)
- continue;
-
- ok1(store_records(tdb));
- for (j = 0; j < NUM_RECORDS; j++)
- array[j] = false;
- ok1(tdb_check(tdb, check, array) == TDB_SUCCESS);
- for (j = 0; j < NUM_RECORDS; j++)
- if (!array[j])
- break;
- ok1(j == NUM_RECORDS);
- tdb_close(tdb);
- }
-
- ok1(tap_log_messages == 0);
- return exit_status();
-}
+++ /dev/null
-#include "tdb2-source.h"
-#include <ccan/tap/tap.h>
-#include "logging.h"
-
-#define NUM_RECORDS 1000
-
-static bool store_records(struct tdb_context *tdb)
-{
- int i;
- struct tdb_data key = { (unsigned char *)&i, sizeof(i) };
- struct tdb_data data = { (unsigned char *)&i, sizeof(i) };
-
- for (i = 0; i < NUM_RECORDS; i++)
- if (tdb_store(tdb, key, data, TDB_REPLACE) != 0)
- return false;
- return true;
-}
-
-struct trav_data {
- unsigned int records[NUM_RECORDS];
- unsigned int calls;
-};
-
-static int trav(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, void *p)
-{
- struct trav_data *td = p;
- int val;
-
- memcpy(&val, dbuf.dptr, dbuf.dsize);
- td->records[td->calls++] = val;
- return 0;
-}
-
-/* Since tdb_nextkey frees dptr, we need to clone it. */
-static TDB_DATA dup_key(TDB_DATA key)
-{
- void *p = malloc(key.dsize);
- memcpy(p, key.dptr, key.dsize);
- key.dptr = p;
- return key;
-}
-
-int main(int argc, char *argv[])
-{
- unsigned int i, j;
- int num;
- struct trav_data td;
- TDB_DATA k;
- struct tdb_context *tdb;
- union tdb_attribute seed_attr;
- enum TDB_ERROR ecode;
- int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
- TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
- TDB_NOMMAP|TDB_CONVERT,
- TDB_INTERNAL|TDB_VERSION1, TDB_VERSION1,
- TDB_NOMMAP|TDB_VERSION1,
- TDB_INTERNAL|TDB_CONVERT|TDB_VERSION1,
- TDB_CONVERT|TDB_VERSION1,
- TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
-
- seed_attr.base.attr = TDB_ATTRIBUTE_SEED;
- seed_attr.base.next = &tap_log_attr;
- seed_attr.seed.seed = 6334326220117065685ULL;
-
- plan_tests(sizeof(flags) / sizeof(flags[0])
- * (NUM_RECORDS*6 + (NUM_RECORDS-1)*3 + 22) + 1);
- for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
- tdb = tdb_open("run-traverse.tdb", flags[i],
- O_RDWR|O_CREAT|O_TRUNC, 0600,
- flags[i] & TDB_VERSION1 ? NULL : &seed_attr);
- ok1(tdb);
- if (!tdb)
- continue;
-
- ok1(tdb_firstkey(tdb, &k) == TDB_ERR_NOEXIST);
-
- /* One entry... */
- k.dptr = (unsigned char *)#
- k.dsize = sizeof(num);
- num = 0;
- ok1(tdb_store(tdb, k, k, TDB_INSERT) == 0);
- ok1(tdb_firstkey(tdb, &k) == TDB_SUCCESS);
- ok1(k.dsize == sizeof(num));
- ok1(memcmp(k.dptr, &num, sizeof(num)) == 0);
- ok1(tdb_nextkey(tdb, &k) == TDB_ERR_NOEXIST);
-
- /* Two entries. */
- k.dptr = (unsigned char *)#
- k.dsize = sizeof(num);
- num = 1;
- ok1(tdb_store(tdb, k, k, TDB_INSERT) == 0);
- ok1(tdb_firstkey(tdb, &k) == TDB_SUCCESS);
- ok1(k.dsize == sizeof(num));
- memcpy(&num, k.dptr, sizeof(num));
- ok1(num == 0 || num == 1);
- ok1(tdb_nextkey(tdb, &k) == TDB_SUCCESS);
- ok1(k.dsize == sizeof(j));
- memcpy(&j, k.dptr, sizeof(j));
- ok1(j == 0 || j == 1);
- ok1(j != num);
- ok1(tdb_nextkey(tdb, &k) == TDB_ERR_NOEXIST);
-
- /* Clean up. */
- k.dptr = (unsigned char *)#
- k.dsize = sizeof(num);
- num = 0;
- ok1(tdb_delete(tdb, k) == 0);
- num = 1;
- ok1(tdb_delete(tdb, k) == 0);
-
- /* Now lots of records. */
- ok1(store_records(tdb));
- td.calls = 0;
-
- num = tdb_traverse(tdb, trav, &td);
- ok1(num == NUM_RECORDS);
- ok1(td.calls == NUM_RECORDS);
-
- /* Simple loop should match tdb_traverse */
- for (j = 0, ecode = tdb_firstkey(tdb, &k); j < td.calls; j++) {
- int val;
-
- ok1(ecode == TDB_SUCCESS);
- ok1(k.dsize == sizeof(val));
- memcpy(&val, k.dptr, k.dsize);
- ok1(td.records[j] == val);
- ecode = tdb_nextkey(tdb, &k);
- }
-
- /* But arbitrary orderings should work too. */
- for (j = td.calls-1; j > 0; j--) {
- k.dptr = (unsigned char *)&td.records[j-1];
- k.dsize = sizeof(td.records[j-1]);
- k = dup_key(k);
- ok1(tdb_nextkey(tdb, &k) == TDB_SUCCESS);
- ok1(k.dsize == sizeof(td.records[j]));
- ok1(memcmp(k.dptr, &td.records[j], k.dsize) == 0);
- free(k.dptr);
- }
-
- /* Even delete should work. */
- for (j = 0, ecode = tdb_firstkey(tdb, &k);
- ecode != TDB_ERR_NOEXIST;
- j++) {
- ok1(ecode == TDB_SUCCESS);
- ok1(k.dsize == 4);
- ok1(tdb_delete(tdb, k) == 0);
- ecode = tdb_nextkey(tdb, &k);
- }
-
- diag("delete using first/nextkey gave %u of %u records",
- j, NUM_RECORDS);
- ok1(j == NUM_RECORDS);
- tdb_close(tdb);
- }
-
- ok1(tap_log_messages == 0);
- return exit_status();
-}
+++ /dev/null
-/* Test forking while holding lock.
- *
- * There are only five ways to do this currently:
- * (1) grab a tdb_chainlock, then fork.
- * (2) grab a tdb_lockall, then fork.
- * (3) grab a tdb_lockall_read, then fork.
- * (4) start a transaction, then fork.
- * (5) fork from inside a tdb_parse() callback.
- *
- * Note that we don't hold a lock across tdb_traverse callbacks, so
- * that doesn't matter.
- */
-#include "tdb2-source.h"
-#include <ccan/tap/tap.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include "logging.h"
-
-static enum TDB_ERROR fork_in_parse(TDB_DATA key, TDB_DATA data,
- struct tdb_context *tdb)
-{
- int status, extra_messages;
-
- if (tdb_get_flags(tdb) & TDB_VERSION1) {
- extra_messages = 1;
- } else {
- extra_messages = 0;
- }
-
- if (fork() == 0) {
- /* We expect this to fail. */
- if (tdb_store(tdb, key, data, TDB_REPLACE) != TDB_ERR_LOCK)
- exit(1);
- tap_log_messages -= extra_messages;
-
- if (tdb_fetch(tdb, key, &data) != TDB_ERR_LOCK)
- exit(1);
-
- tap_log_messages -= extra_messages;
- if (tap_log_messages != 2)
- exit(2);
-
- tdb_close(tdb);
- if (tap_log_messages != 2)
- exit(3);
- exit(0);
- }
- wait(&status);
- ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
- return TDB_SUCCESS;
-}
-
-int main(int argc, char *argv[])
-{
- unsigned int i;
- struct tdb_context *tdb;
- int flags[] = { TDB_DEFAULT, TDB_NOMMAP,
- TDB_CONVERT, TDB_NOMMAP|TDB_CONVERT,
- TDB_VERSION1, TDB_NOMMAP|TDB_VERSION1,
- TDB_CONVERT|TDB_VERSION1,
- TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
- struct tdb_data key = tdb_mkdata("key", 3);
- struct tdb_data data = tdb_mkdata("data", 4);
-
- plan_tests(sizeof(flags) / sizeof(flags[0]) * 14);
- for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
- int status, extra_messages;
-
- if (flags[i] & TDB_VERSION1) {
- extra_messages = 1;
- } else {
- extra_messages = 0;
- }
-
- tap_log_messages = 0;
-
- tdb = tdb_open("run-fork-test.tdb", flags[i],
- O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
- if (!ok1(tdb))
- continue;
-
- /* Put a record in here. */
- ok1(tdb_store(tdb, key, data, TDB_REPLACE) == TDB_SUCCESS);
-
- ok1(tdb_chainlock(tdb, key) == TDB_SUCCESS);
- if (fork() == 0) {
- /* We expect this to fail. */
- if (tdb_store(tdb, key, data, TDB_REPLACE) != TDB_ERR_LOCK)
- return 1;
- tap_log_messages -= extra_messages;
-
- if (tdb_fetch(tdb, key, &data) != TDB_ERR_LOCK)
- return 1;
- tap_log_messages -= extra_messages;
-
- if (tap_log_messages != 2)
- return 2;
-
- tdb_chainunlock(tdb, key);
- if (tap_log_messages != 3)
- return 3;
- tdb_close(tdb);
- if (tap_log_messages != 3)
- return 4;
- return 0;
- }
- wait(&status);
- ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
- tdb_chainunlock(tdb, key);
-
- ok1(tdb_lockall(tdb) == TDB_SUCCESS);
- if (fork() == 0) {
- /* We expect this to fail. */
- if (tdb_store(tdb, key, data, TDB_REPLACE) != TDB_ERR_LOCK)
- return 1;
- tap_log_messages -= extra_messages;
-
- if (tdb_fetch(tdb, key, &data) != TDB_ERR_LOCK)
- return 1;
- tap_log_messages -= extra_messages;
-
- if (tap_log_messages != 2)
- return 2;
-
- tdb_unlockall(tdb);
- if (tap_log_messages != 2)
- return 3;
- tdb_close(tdb);
- if (tap_log_messages != 2)
- return 4;
- return 0;
- }
- wait(&status);
- ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
- tdb_unlockall(tdb);
-
- ok1(tdb_lockall_read(tdb) == TDB_SUCCESS);
- if (fork() == 0) {
- /* We expect this to fail. */
- /* This would always fail anyway... */
- if (tdb_store(tdb, key, data, TDB_REPLACE) != TDB_ERR_LOCK)
- return 1;
- tap_log_messages -= extra_messages;
-
- if (tdb_fetch(tdb, key, &data) != TDB_ERR_LOCK)
- return 1;
- tap_log_messages -= extra_messages;
-
- if (tap_log_messages != 2)
- return 2;
-
- tdb_unlockall_read(tdb);
- if (tap_log_messages != 2)
- return 3;
- tdb_close(tdb);
- if (tap_log_messages != 2)
- return 4;
- return 0;
- }
- wait(&status);
- ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
- tdb_unlockall_read(tdb);
-
- ok1(tdb_transaction_start(tdb) == TDB_SUCCESS);
- /* If transactions is empty, noop "commit" succeeds. */
- ok1(tdb_delete(tdb, key) == TDB_SUCCESS);
- if (fork() == 0) {
- /* We expect this to fail. */
- if (tdb_store(tdb, key, data, TDB_REPLACE) != TDB_ERR_LOCK)
- return 1;
- tap_log_messages -= extra_messages;
-
- if (tdb_fetch(tdb, key, &data) != TDB_ERR_LOCK)
- return 1;
- tap_log_messages -= extra_messages;
-
- if (tap_log_messages != 2)
- return 2;
-
- if (tdb_transaction_commit(tdb) != TDB_ERR_LOCK)
- return 3;
- tap_log_messages -= extra_messages;
-
- tdb_close(tdb);
- if (tap_log_messages < 3)
- return 4;
- return 0;
- }
- wait(&status);
- ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
- tdb_transaction_cancel(tdb);
-
- ok1(tdb_parse_record(tdb, key, fork_in_parse, tdb)
- == TDB_SUCCESS);
- tdb_close(tdb);
- ok1(tap_log_messages == 0);
- }
- return exit_status();
-}
+++ /dev/null
-#include "tdb2-source.h"
-#include <ccan/tap/tap.h>
-#include "logging.h"
-#include "external-agent.h"
-
-#undef alarm
-#define alarm fast_alarm
-
-/* Speed things up by doing things in milliseconds. */
-static unsigned int fast_alarm(unsigned int milli_seconds)
-{
- struct itimerval it;
-
- it.it_interval.tv_sec = it.it_interval.tv_usec = 0;
- it.it_value.tv_sec = milli_seconds / 1000;
- it.it_value.tv_usec = milli_seconds * 1000;
- setitimer(ITIMER_REAL, &it, NULL);
- return 0;
-}
-
-#define CatchSignal(sig, handler) signal((sig), (handler))
-
-static void do_nothing(int signum)
-{
-}
-
-/* This example code is taken from SAMBA, so try not to change it. */
-static struct flock flock_struct;
-
-/* Return a value which is none of v1, v2 or v3. */
-static inline short int invalid_value(short int v1, short int v2, short int v3)
-{
- short int try = (v1+v2+v3)^((v1+v2+v3) << 16);
- while (try == v1 || try == v2 || try == v3)
- try++;
- return try;
-}
-
-/* We invalidate in as many ways as we can, so the OS rejects it */
-static void invalidate_flock_struct(int signum)
-{
- flock_struct.l_type = invalid_value(F_RDLCK, F_WRLCK, F_UNLCK);
- flock_struct.l_whence = invalid_value(SEEK_SET, SEEK_CUR, SEEK_END);
- flock_struct.l_start = -1;
- /* A large negative. */
- flock_struct.l_len = (((off_t)1 << (sizeof(off_t)*CHAR_BIT - 1)) + 1);
-}
-
-static int timeout_lock(int fd, int rw, off_t off, off_t len, bool waitflag,
- void *_timeout)
-{
- int ret, saved_errno = errno;
- unsigned int timeout = *(unsigned int *)_timeout;
-
- flock_struct.l_type = rw;
- flock_struct.l_whence = SEEK_SET;
- flock_struct.l_start = off;
- flock_struct.l_len = len;
-
- CatchSignal(SIGALRM, invalidate_flock_struct);
- alarm(timeout);
-
- for (;;) {
- if (waitflag)
- ret = fcntl(fd, F_SETLKW, &flock_struct);
- else
- ret = fcntl(fd, F_SETLK, &flock_struct);
-
- if (ret == 0)
- break;
-
- /* Not signalled? Something else went wrong. */
- if (flock_struct.l_len == len) {
- if (errno == EAGAIN || errno == EINTR)
- continue;
- saved_errno = errno;
- break;
- } else {
- saved_errno = EINTR;
- break;
- }
- }
-
- alarm(0);
- errno = saved_errno;
- return ret;
-}
-
-static int tdb_chainlock_with_timeout_internal(struct tdb_context *tdb,
- TDB_DATA key,
- unsigned int timeout,
- int rw_type)
-{
- union tdb_attribute locking;
- enum TDB_ERROR ecode;
-
- if (timeout) {
- locking.base.attr = TDB_ATTRIBUTE_FLOCK;
- ecode = tdb_get_attribute(tdb, &locking);
- if (ecode != TDB_SUCCESS)
- return ecode;
-
- /* Replace locking function with our own. */
- locking.flock.data = &timeout;
- locking.flock.lock = timeout_lock;
-
- ecode = tdb_set_attribute(tdb, &locking);
- if (ecode != TDB_SUCCESS)
- return ecode;
- }
- if (rw_type == F_RDLCK)
- ecode = tdb_chainlock_read(tdb, key);
- else
- ecode = tdb_chainlock(tdb, key);
-
- if (timeout) {
- tdb_unset_attribute(tdb, TDB_ATTRIBUTE_FLOCK);
- }
- return ecode;
-}
-
-int main(int argc, char *argv[])
-{
- unsigned int i;
- struct tdb_context *tdb;
- TDB_DATA key = tdb_mkdata("hello", 5);
- int flags[] = { TDB_DEFAULT, TDB_NOMMAP,
- TDB_CONVERT, TDB_NOMMAP|TDB_CONVERT,
- TDB_VERSION1, TDB_NOMMAP|TDB_VERSION1,
- TDB_CONVERT|TDB_VERSION1,
- TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
- struct agent *agent;
-
- plan_tests(sizeof(flags) / sizeof(flags[0]) * 15);
-
- agent = prepare_external_agent();
-
- for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
- enum TDB_ERROR ecode;
- tdb = tdb_open("run-locktimeout.tdb", flags[i],
- O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
- if (!ok1(tdb))
- break;
-
- /* Simple cases: should succeed. */
- ecode = tdb_chainlock_with_timeout_internal(tdb, key, 20,
- F_RDLCK);
- ok1(ecode == TDB_SUCCESS);
- ok1(tap_log_messages == 0);
-
- tdb_chainunlock_read(tdb, key);
- ok1(tap_log_messages == 0);
-
- ecode = tdb_chainlock_with_timeout_internal(tdb, key, 20,
- F_WRLCK);
- ok1(ecode == TDB_SUCCESS);
- ok1(tap_log_messages == 0);
-
- tdb_chainunlock(tdb, key);
- ok1(tap_log_messages == 0);
-
- /* OK, get agent to start transaction, then we should time out. */
- ok1(external_agent_operation(agent, OPEN, "run-locktimeout.tdb")
- == SUCCESS);
- ok1(external_agent_operation(agent, TRANSACTION_START, "")
- == SUCCESS);
- ecode = tdb_chainlock_with_timeout_internal(tdb, key, 20,
- F_WRLCK);
- ok1(ecode == TDB_ERR_LOCK);
- ok1(tap_log_messages == 0);
-
- /* Even if we get a different signal, should be fine. */
- CatchSignal(SIGUSR1, do_nothing);
- external_agent_operation(agent, SEND_SIGNAL, "");
- ecode = tdb_chainlock_with_timeout_internal(tdb, key, 20,
- F_WRLCK);
- ok1(ecode == TDB_ERR_LOCK);
- ok1(tap_log_messages == 0);
-
- ok1(external_agent_operation(agent, TRANSACTION_COMMIT, "")
- == SUCCESS);
- ok1(external_agent_operation(agent, CLOSE, "")
- == SUCCESS);
- tdb_close(tdb);
- }
- free_external_agent(agent);
- return exit_status();
-}
+++ /dev/null
-#include "tdb2-source.h"
-/* Another test revealed that we lost an entry. This reproduces it. */
-#include <ccan/tap/tap.h>
-#include "logging.h"
-
-#define NUM_RECORDS 1189
-
-/* We use the same seed which we saw this failure on. */
-static uint64_t failhash(const void *key, size_t len, uint64_t seed, void *p)
-{
- seed = 699537674708983027ULL;
- return hash64_stable((const unsigned char *)key, len, seed);
-}
-
-int main(int argc, char *argv[])
-{
- int i;
- struct tdb_context *tdb;
- struct tdb_data key = { (unsigned char *)&i, sizeof(i) };
- struct tdb_data data = { (unsigned char *)&i, sizeof(i) };
- union tdb_attribute hattr = { .hash = { .base = { TDB_ATTRIBUTE_HASH },
- .fn = failhash } };
-
- hattr.base.next = &tap_log_attr;
- plan_tests(1 + 2 * NUM_RECORDS + 1);
-
- tdb = tdb_open("run-missing-entries.tdb", TDB_INTERNAL,
- O_RDWR|O_CREAT|O_TRUNC, 0600, &hattr);
- ok1(tdb);
- if (tdb) {
- for (i = 0; i < NUM_RECORDS; i++) {
- ok1(tdb_store(tdb, key, data, TDB_REPLACE) == 0);
- ok1(tdb_check(tdb, NULL, NULL) == 0);
- }
- tdb_close(tdb);
- }
-
- ok1(tap_log_messages == 0);
- return exit_status();
-}
+++ /dev/null
-#include "tdb2-source.h"
-#include <ccan/tap/tap.h>
-#include "logging.h"
-
-int main(int argc, char *argv[])
-{
- unsigned int i, extra_messages;
- struct tdb_context *tdb, *tdb2;
- struct tdb_data key = { (unsigned char *)&i, sizeof(i) };
- struct tdb_data data = { (unsigned char *)&i, sizeof(i) };
- struct tdb_data d = { NULL, 0 }; /* Bogus GCC warning */
- int flags[] = { TDB_DEFAULT, TDB_NOMMAP,
- TDB_CONVERT, TDB_NOMMAP|TDB_CONVERT,
- TDB_VERSION1, TDB_NOMMAP|TDB_VERSION1,
- TDB_CONVERT|TDB_VERSION1,
- TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
-
- plan_tests(sizeof(flags) / sizeof(flags[0]) * 28);
- for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
- tdb = tdb_open("run-open-multiple-times.tdb", flags[i],
- O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
- ok1(tdb);
- if (!tdb)
- continue;
-
- if (flags[i] & TDB_VERSION1) {
- extra_messages = 1;
- } else {
- extra_messages = 0;
- }
- tdb2 = tdb_open("run-open-multiple-times.tdb", flags[i],
- O_RDWR|O_CREAT, 0600, &tap_log_attr);
- ok1(tdb_check(tdb, NULL, NULL) == 0);
- ok1(tdb_check(tdb2, NULL, NULL) == 0);
-
- /* Store in one, fetch in the other. */
- ok1(tdb_store(tdb, key, data, TDB_REPLACE) == 0);
- ok1(tdb_fetch(tdb2, key, &d) == TDB_SUCCESS);
- ok1(tdb_deq(d, data));
- free(d.dptr);
-
- /* Vice versa, with delete. */
- ok1(tdb_delete(tdb2, key) == 0);
- ok1(tdb_fetch(tdb, key, &d) == TDB_ERR_NOEXIST);
-
- /* OK, now close first one, check second still good. */
- ok1(tdb_close(tdb) == 0);
-
- ok1(tdb_store(tdb2, key, data, TDB_REPLACE) == 0);
- ok1(tdb_fetch(tdb2, key, &d) == TDB_SUCCESS);
- ok1(tdb_deq(d, data));
- free(d.dptr);
-
- /* Reopen */
- tdb = tdb_open("run-open-multiple-times.tdb", flags[i],
- O_RDWR|O_CREAT, 0600, &tap_log_attr);
- ok1(tdb);
-
- ok1(tdb_transaction_start(tdb2) == 0);
-
- /* Anything in the other one should fail. */
- ok1(tdb_fetch(tdb, key, &d) == TDB_ERR_LOCK);
- tap_log_messages -= extra_messages;
- ok1(tap_log_messages == 1);
- ok1(tdb_store(tdb, key, data, TDB_REPLACE) == TDB_ERR_LOCK);
- tap_log_messages -= extra_messages;
- ok1(tap_log_messages == 2);
- ok1(tdb_transaction_start(tdb) == TDB_ERR_LOCK);
- ok1(tap_log_messages == 3);
- ok1(tdb_chainlock(tdb, key) == TDB_ERR_LOCK);
- tap_log_messages -= extra_messages;
- ok1(tap_log_messages == 4);
-
- /* Transaciton should work as normal. */
- ok1(tdb_store(tdb2, key, data, TDB_REPLACE) == TDB_SUCCESS);
-
- /* Now... try closing with locks held. */
- ok1(tdb_close(tdb2) == 0);
-
- ok1(tdb_fetch(tdb, key, &d) == TDB_SUCCESS);
- ok1(tdb_deq(d, data));
- free(d.dptr);
- ok1(tdb_close(tdb) == 0);
- ok1(tap_log_messages == 4);
- tap_log_messages = 0;
- }
-
- return exit_status();
-}
+++ /dev/null
-#include "tdb2-source.h"
-#include <ccan/tap/tap.h>
-#include "logging.h"
-
-#define MAX_SIZE 10000
-#define SIZE_STEP 131
-
-int main(int argc, char *argv[])
-{
- unsigned int i;
- struct tdb_context *tdb;
- int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
- TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
- TDB_NOMMAP|TDB_CONVERT,
- TDB_INTERNAL|TDB_VERSION1, TDB_VERSION1,
- TDB_NOMMAP|TDB_VERSION1,
- TDB_INTERNAL|TDB_CONVERT|TDB_VERSION1,
- TDB_CONVERT|TDB_VERSION1,
- TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
- struct tdb_data key = tdb_mkdata("key", 3);
- struct tdb_data data;
-
- data.dptr = malloc(MAX_SIZE);
- memset(data.dptr, 0x24, MAX_SIZE);
-
- plan_tests(sizeof(flags) / sizeof(flags[0])
- * (3 + (1 + (MAX_SIZE/SIZE_STEP)) * 2) + 1);
- for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
- tdb = tdb_open("run-record-expand.tdb", flags[i],
- O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
- ok1(tdb);
- if (!tdb)
- continue;
-
- data.dsize = 0;
- ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
- ok1(tdb_check(tdb, NULL, NULL) == 0);
- for (data.dsize = 0;
- data.dsize < MAX_SIZE;
- data.dsize += SIZE_STEP) {
- memset(data.dptr, data.dsize, data.dsize);
- ok1(tdb_store(tdb, key, data, TDB_MODIFY) == 0);
- ok1(tdb_check(tdb, NULL, NULL) == 0);
- }
- tdb_close(tdb);
- }
- ok1(tap_log_messages == 0);
- free(data.dptr);
-
- return exit_status();
-}
+++ /dev/null
-#include "tdb2-source.h"
-#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_NOMMAP,
- TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
- TDB_NOMMAP|TDB_CONVERT,
- TDB_INTERNAL|TDB_VERSION1, TDB_VERSION1,
- TDB_NOMMAP|TDB_VERSION1,
- TDB_INTERNAL|TDB_CONVERT|TDB_VERSION1,
- TDB_CONVERT|TDB_VERSION1,
- TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
- struct tdb_data key = tdb_mkdata("key", 3);
- struct tdb_data data = tdb_mkdata("data", 4);
-
- plan_tests(sizeof(flags) / sizeof(flags[0]) * 7 + 1);
- for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
- tdb = tdb_open("run-simple-delete.tdb", flags[i],
- O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
- ok1(tdb);
- if (tdb) {
- /* Delete should fail. */
- ok1(tdb_delete(tdb, key) == 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 "tdb2-source.h"
-#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_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
- TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
- TDB_NOMMAP|TDB_CONVERT,
- TDB_INTERNAL|TDB_VERSION1, TDB_VERSION1,
- TDB_NOMMAP|TDB_VERSION1,
- TDB_INTERNAL|TDB_CONVERT|TDB_VERSION1,
- TDB_CONVERT|TDB_VERSION1,
- TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };
- struct tdb_data key = { (unsigned char *)&j, sizeof(j) };
- struct tdb_data data = { (unsigned char *)&j, sizeof(j) };
- char *summary;
-
- plan_tests(sizeof(flags) / sizeof(flags[0]) * (1 + 2 * 5) + 1);
- for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
- tdb = tdb_open("run-summary.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 < 500; j++) {
- /* Make sure padding varies to we get some graphs! */
- data.dsize = j % (sizeof(j) + 1);
- if (tdb_store(tdb, key, data, TDB_REPLACE) != 0)
- fail("Storing in tdb");
- }
-
- for (j = 0;
- j <= TDB_SUMMARY_HISTOGRAMS;
- j += TDB_SUMMARY_HISTOGRAMS) {
- ok1(tdb_summary(tdb, j, &summary) == TDB_SUCCESS);
- ok1(strstr(summary, "Number of records: 500\n"));
- ok1(strstr(summary, "Smallest/average/largest keys: 4/4/4\n"));
- ok1(strstr(summary, "Smallest/average/largest data: 0/2/4\n"));
- if (!(flags[i] & TDB_VERSION1)
- && j == TDB_SUMMARY_HISTOGRAMS) {
- ok1(strstr(summary, "|")
- && strstr(summary, "*"));
- } else {
- ok1(!strstr(summary, "|")
- && !strstr(summary, "*"));
- }
- free(summary);
- }
- tdb_close(tdb);
- }
-
- ok1(tap_log_messages == 0);
- return exit_status();
-}
-
-