}
return "**INVALID**";
}
+
+void free_external_agent(struct agent *agent)
+{
+ close(agent->cmdfd);
+ close(agent->responsefd);
+ free(agent);
+}
const char *agent_return_name(enum agent_return ret);
const char *operation_name(enum operation op);
+void free_external_agent(struct agent *agent);
#endif /* TDB2_TEST_EXTERNAL_AGENT_H */
return tdb;
}
+
+void tdb_layout_free(struct tdb_layout *layout)
+{
+ unsigned int i;
+
+ for (i = 0; i < layout->num_elems; i++) {
+ if (layout->elem[i].base.type == DATA) {
+ free(layout->elem[i].used.key.dptr);
+ free(layout->elem[i].used.data.dptr);
+ }
+ }
+ free(layout->elem);
+ free(layout);
+}
tdb_len_t extra);
#endif
struct tdb_context *tdb_layout_get(struct tdb_layout *layout);
+void tdb_layout_free(struct tdb_layout *layout);
enum layout_type {
FREETABLE, FREE, DATA, HASHTABLE,
ok1(free_record_length(tdb, layout->elem[1].base.off) == len);
ok1(tdb_check(tdb, NULL, NULL) == 0);
tdb_close(tdb);
+ tdb_layout_free(layout);
/* No coalescing can be done due to used record */
layout = new_tdb_layout(NULL);
ok1(free_record_length(tdb, layout->elem[1].base.off) == 1024);
ok1(tdb_check(tdb, NULL, NULL) == 0);
tdb_close(tdb);
+ tdb_layout_free(layout);
/* Coalescing can be done due to two free records, then EOF */
layout = new_tdb_layout(NULL);
== 1024 + sizeof(struct tdb_used_record) + 2048);
ok1(tdb_check(tdb, NULL, NULL) == 0);
tdb_close(tdb);
+ tdb_layout_free(layout);
/* Coalescing can be done due to two free records, then data */
layout = new_tdb_layout(NULL);
== 1024 + sizeof(struct tdb_used_record) + 512);
ok1(tdb_check(tdb, NULL, NULL) == 0);
tdb_close(tdb);
+ tdb_layout_free(layout);
/* Coalescing can be done due to three free records, then EOF */
layout = new_tdb_layout(NULL);
+ sizeof(struct tdb_used_record) + 256);
ok1(tdb_check(tdb, NULL, NULL) == 0);
tdb_close(tdb);
+ tdb_layout_free(layout);
ok1(tap_log_messages == 0);
return exit_status();
/* Fetch should now work. */
d = tdb_fetch(tdb, key);
ok1(data_equal(d, data));
+ free(d.dptr);
ok1(tdb_check(tdb, NULL, NULL) == 0);
tdb_close(tdb);
}
/* We seemed to lose some keys.
* Insert and check they're in there! */
for (j = 0; j < 500; j++) {
+ struct tdb_data d;
ok1(tdb_store(tdb, key, data, TDB_REPLACE) == 0);
- ok1(equal(tdb_fetch(tdb, key), data));
+ d = tdb_fetch(tdb, key);
+ ok1(equal(d, data));
+ free(d.dptr);
}
tdb_close(tdb);
}
{
int i;
struct tdb_data key = { (unsigned char *)&i, sizeof(i) };
- struct tdb_data data = { (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;
- if (tdb_fetch(tdb, key).dsize != data.dsize)
+ d = tdb_fetch(tdb, key);
+ if (d.dsize != data.dsize)
return false;
+ if (memcmp(d.dptr, data.dptr, d.dsize) != 0)
+ return false;
+ free(d.dptr);
}
return true;
}
{
uint64_t v;
struct tdb_data key = { (unsigned char *)&v, sizeof(v) };
- struct tdb_data data = { (unsigned char *)&v, sizeof(v) };
+ struct tdb_data d, data = { (unsigned char *)&v, sizeof(v) };
/* Insert an entry, then delete it. */
v = val;
ok1(tdb_check(tdb, NULL, NULL) == 0);
/* Can find both? */
- ok1(tdb_fetch(tdb, key).dsize == data.dsize);
+ d = tdb_fetch(tdb, key);
+ ok1(d.dsize == data.dsize);
+ free(d.dptr);
v = val;
- ok1(tdb_fetch(tdb, key).dsize == data.dsize);
+ d = tdb_fetch(tdb, key);
+ ok1(d.dsize == data.dsize);
+ free(d.dptr);
/* Delete second one. */
v = val + 1;
/* Can still find second? */
v = val + 1;
- ok1(tdb_fetch(tdb, key).dsize == data.dsize);
+ d = tdb_fetch(tdb, key);
+ 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);
/* We can still find them all, right? */
- ok1(tdb_fetch(tdb, key).dsize == data.dsize);
+ d = tdb_fetch(tdb, key);
+ ok1(d.dsize == data.dsize);
+ free(d.dptr);
v = val + 1;
- ok1(tdb_fetch(tdb, key).dsize == data.dsize);
+ d = tdb_fetch(tdb, key);
+ ok1(d.dsize == data.dsize);
+ free(d.dptr);
v = val + 2;
- ok1(tdb_fetch(tdb, key).dsize == data.dsize);
+ d = tdb_fetch(tdb, key);
+ 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_check(tdb, NULL, NULL) == 0);
v = val;
- ok1(tdb_fetch(tdb, key).dsize == data.dsize);
+ d = tdb_fetch(tdb, key);
+ ok1(d.dsize == data.dsize);
+ free(d.dptr);
v = val + 2;
- ok1(tdb_fetch(tdb, key).dsize == data.dsize);
+ d = tdb_fetch(tdb, key);
+ ok1(d.dsize == data.dsize);
+ free(d.dptr);
/* Delete those two, so we are empty. */
ok1(tdb_delete(tdb, key) == 0);
}
ok1(tap_log_messages == 0);
+ free(buffer);
return exit_status();
}
ok1(d.dsize == sizeof(j));
ok1(d.dptr != NULL);
ok1(d.dptr && memcmp(d.dptr, &j, d.dsize) == 0);
+ free(d.dptr);
}
/* Now add a *lot* more. */
ok1(d.dsize == sizeof(j));
ok1(d.dptr != NULL);
ok1(d.dptr && memcmp(d.dptr, &j, d.dsize) == 0);
+ free(d.dptr);
}
ok1(tdb_check(tdb, NULL, NULL) == 0);
ok1(d.dsize == sizeof(j));
ok1(d.dptr != NULL);
ok1(d.dptr && memcmp(d.dptr, &j, d.dsize) == 0);
+ free(d.dptr);
}
/* Traverse through them. */
ok1(off == 0);
tdb_close(tdb);
+ tdb_layout_free(layout);
ok1(tap_log_messages == 0);
return exit_status();
}
ok1(tap_log_messages == 0);
+ free(buffer);
return exit_status();
}
#define _XOPEN_SOURCE 500
#include <unistd.h>
#include "lock-tracking.h"
+#include <ccan/tap/tap.h>
+#include <stdlib.h>
+#include <assert.h>
static ssize_t pwrite_check(int fd, const void *buf, size_t count, off_t offset);
static ssize_t write_check(int fd, const void *buf, size_t count);
static int ftruncate_check(int fd, off_t length);
#define fcntl fcntl_with_lockcheck
#define ftruncate ftruncate_check
+/* There's a malloc inside transaction_setup_recovery, and valgrind complains
+ * when we longjmp and leak it. */
+#define MAX_ALLOCATIONS 200
+static void *allocated[MAX_ALLOCATIONS];
+
+static void *malloc_noleak(size_t len)
+{
+ unsigned int i;
+
+ for (i = 0; i < MAX_ALLOCATIONS; i++)
+ if (!allocated[i]) {
+ allocated[i] = malloc(len);
+ return allocated[i];
+ }
+ diag("Too many allocations!");
+ abort();
+}
+
+static void free_noleak(void *p)
+{
+ unsigned int i;
+
+ /* We don't catch realloc, so don't care if we miss one. */
+ for (i = 0; i < MAX_ALLOCATIONS; i++) {
+ if (allocated[i] == p) {
+ allocated[i] = NULL;
+ break;
+ }
+ }
+ free(p);
+}
+
+static void free_all(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < MAX_ALLOCATIONS; i++) {
+ free(allocated[i]);
+ allocated[i] = NULL;
+ }
+}
+
+#define malloc malloc_noleak
+#define free free_noleak
+
#include <ccan/tdb2/tdb.c>
#include <ccan/tdb2/free.c>
#include <ccan/tdb2/lock.c>
#include <ccan/tdb2/hash.c>
#include <ccan/tdb2/check.c>
#include <ccan/tdb2/transaction.c>
-#include <ccan/tap/tap.h>
-#include <stdlib.h>
+#undef malloc
+#undef free
+#undef write
+#undef pwrite
+#undef fcntl
+#undef ftruncate
+
#include <stdbool.h>
#include <stdarg.h>
#include <err.h>
#include "external-agent.h"
#include "logging.h"
-#undef write
-#undef pwrite
-#undef fcntl
-#undef ftruncate
-
static bool in_transaction;
static int target, current;
static jmp_buf jmpbuf;
suppress_lockcheck = false;
target++;
current = 0;
+ free_all();
goto reset;
}
ok1(test_death(ops[i], agent));
}
+ free_external_agent(agent);
return exit_status();
}
tdb_close(tdb);
}
ok1(tap_log_messages == 0);
+ free(data.dptr);
+
return exit_status();
}
/* Now store something! */
ok1(tdb_store(tdb, d, d, TDB_INSERT) == 0);
ok1(tap_log_messages == 0);
+ free_external_agent(agent);
return exit_status();
}