#include <ccan/asearch/asearch.h>
/* We keep an ordered array of offsets. */
-static bool append(ntdb_off_t **arr, size_t *num, ntdb_off_t off)
+static bool append(struct ntdb_context *ntdb,
+ ntdb_off_t **arr, size_t *num, ntdb_off_t off)
{
- ntdb_off_t *new = realloc(*arr, (*num + 1) * sizeof(ntdb_off_t));
+ ntdb_off_t *new;
+
+ if (*num == 0) {
+ new = ntdb->alloc_fn(ntdb, sizeof(ntdb_off_t), ntdb->alloc_data);
+ } else {
+ new = ntdb->expand_fn(*arr, (*num + 1) * sizeof(ntdb_off_t),
+ ntdb->alloc_data);
+ }
if (!new)
return false;
new[(*num)++] = off;
}
/* This record should be in free lists. */
if (frec_ftable(&rec.f) != NTDB_FTABLE_NONE
- && !append(fr, num_free, off)) {
+ && !append(ntdb, fr, num_free, off)) {
return ntdb_logerr(ntdb, NTDB_ERR_OOM,
NTDB_LOG_ERROR,
"ntdb_check: tracking %zu'th"
uint64_t klen, dlen, extra;
/* This record is used! */
- if (!append(used, num_used, off)) {
+ if (!append(ntdb, used, num_used, off)) {
return ntdb_logerr(ntdb, NTDB_ERR_OOM,
NTDB_LOG_ERROR,
"ntdb_check: tracking %zu'th"
out:
ntdb_allrecord_unlock(ntdb, F_RDLCK);
ntdb_unlock_expand(ntdb, F_RDLCK);
- free(fr);
- free(used);
+ ntdb->free_fn(fr, ntdb->alloc_data);
+ ntdb->free_fn(used, ntdb->alloc_data);
return ecode;
}
ntdb_logerr(ntdb, NTDB_ERR_IO, NTDB_LOG_ERROR,
"ntdb_oob len %lld beyond internal"
- " malloc size %lld",
+ " alloc size %lld",
(long long)(off + len),
(long long)ntdb->file->map_size);
return NTDB_ERR_IO;
enum NTDB_ERROR ecode;
if (unlikely((ntdb->flags & NTDB_CONVERT))) {
- void *conv = malloc(len);
+ void *conv = ntdb->alloc_fn(ntdb, len, ntdb->alloc_data);
if (!conv) {
return ntdb_logerr(ntdb, NTDB_ERR_OOM, NTDB_LOG_ERROR,
"ntdb_write: no memory converting"
}
memcpy(conv, rec, len);
ecode = ntdb->io->twrite(ntdb, off,
- ntdb_convert(ntdb, conv, len), len);
- free(conv);
+ ntdb_convert(ntdb, conv, len), len);
+ ntdb->free_fn(conv, ntdb->alloc_data);
} else {
ecode = ntdb->io->twrite(ntdb, off, rec, len);
}
enum NTDB_ERROR ecode;
/* some systems don't like zero length malloc */
- buf = malloc(prefix + len ? prefix + len : 1);
+ buf = ntdb->alloc_fn(ntdb, prefix + len ? prefix + len : 1,
+ ntdb->alloc_data);
if (!buf) {
ntdb_logerr(ntdb, NTDB_ERR_OOM, NTDB_LOG_USE_ERROR,
- "ntdb_alloc_read malloc failed len=%zu",
+ "ntdb_alloc_read alloc failed len=%zu",
(size_t)(prefix + len));
return NTDB_ERR_PTR(NTDB_ERR_OOM);
} else {
ecode = ntdb->io->tread(ntdb, offset, buf+prefix, len);
if (unlikely(ecode != NTDB_SUCCESS)) {
- free(buf);
+ ntdb->free_fn(buf, ntdb->alloc_data);
return NTDB_ERR_PTR(ecode);
}
}
}
if (ntdb->flags & NTDB_INTERNAL) {
- char *new = realloc(ntdb->file->map_ptr,
- ntdb->file->map_size + addition);
+ char *new = ntdb->expand_fn(ntdb->file->map_ptr,
+ ntdb->file->map_size + addition,
+ ntdb->alloc_data);
if (!new) {
return ntdb_logerr(ntdb, NTDB_ERR_OOM, NTDB_LOG_ERROR,
"No memory to expand database");
if (hp) {
hdr = *hp;
*hp = hdr->next;
- free(hdr);
+ ntdb->free_fn(hdr, ntdb->alloc_data);
} else
ntdb->direct_access--;
}
else
ecode = ntdb_write(ntdb, hdr->off, p, hdr->len);
*hp = hdr->next;
- free(hdr);
+ ntdb->free_fn(hdr, ntdb->alloc_data);
} else {
ntdb->direct_access--;
ecode = NTDB_SUCCESS;
"ntdb_nest_lock: already have a hash lock?");
}
#endif
-
- new_lck = (struct ntdb_lock *)realloc(
- ntdb->file->lockrecs,
- sizeof(*ntdb->file->lockrecs) * (ntdb->file->num_lockrecs+1));
+ if (ntdb->file->lockrecs == NULL) {
+ new_lck = ntdb->alloc_fn(ntdb->file, sizeof(*ntdb->file->lockrecs),
+ ntdb->alloc_data);
+ } else {
+ new_lck = (struct ntdb_lock *)ntdb->expand_fn(
+ ntdb->file->lockrecs,
+ sizeof(*ntdb->file->lockrecs)
+ * (ntdb->file->num_lockrecs+1),
+ ntdb->alloc_data);
+ }
if (new_lck == NULL) {
return ntdb_logerr(ntdb, NTDB_ERR_OOM, NTDB_LOG_ERROR,
"ntdb_nest_lock:"
}
/* Slow path. */
- newdata = malloc(key.dsize + old_dlen + dbuf.dsize);
+ newdata = ntdb->alloc_fn(ntdb, key.dsize + old_dlen + dbuf.dsize,
+ ntdb->alloc_data);
if (!newdata) {
ecode = ntdb_logerr(ntdb, NTDB_ERR_OOM, NTDB_LOG_ERROR,
"ntdb_append:"
ecode = replace_data(ntdb, &h, key, new_dbuf, off, old_room, true);
out_free_newdata:
- free(newdata);
+ ntdb->free_fn(newdata, ntdb->alloc_data);
out:
ntdb_unlock_hashes(ntdb, h.hlock_start, h.hlock_range, F_WRLCK);
return ecode;
return ecode;
va_start(ap, fmt);
- len = vasprintf(&message, fmt, ap);
+ len = vsnprintf(NULL, 0, fmt, ap);
va_end(ap);
- if (len < 0) {
+ message = ntdb->alloc_fn(ntdb, len + 1, ntdb->alloc_data);
+ if (!message) {
ntdb->log_fn(ntdb, NTDB_LOG_ERROR, NTDB_ERR_OOM,
"out of memory formatting message:", ntdb->log_data);
ntdb->log_fn(ntdb, level, ecode, fmt, ntdb->log_data);
} else {
+ va_start(ap, fmt);
+ vsnprintf(message, len+1, fmt, ap);
+ va_end(ap);
ntdb->log_fn(ntdb, level, ecode, message, ntdb->log_data);
- free(message);
+ ntdb->free_fn(message, ntdb->alloc_data);
}
errno = saved_errno;
return ecode;
NTDB_ATTRIBUTE_STATS = 3,
NTDB_ATTRIBUTE_OPENHOOK = 4,
NTDB_ATTRIBUTE_FLOCK = 5,
+ NTDB_ATTRIBUTE_ALLOCATOR = 6
};
/**
void *data;
};
+/**
+ * struct ntdb_attribute_allocator - allocator for ntdb to use.
+ *
+ * You can replace malloc/free with your own allocation functions.
+ * The allocator takes an "owner" pointer, which is either NULL (for
+ * the initial struct ntdb_context and struct ntdb_file), or a
+ * previously allocated pointer. This is useful for relationship
+ * tracking, such as the talloc library.
+ *
+ * The expand function is realloc, but only ever used to expand an
+ * existing allocation.
+ *
+ * Be careful mixing allocators: two ntdb_contexts which have the same file
+ * open will share the same struct ntdb_file. This may be allocated by one
+ * ntdb's allocator, and freed by the other.
+ */
+struct ntdb_attribute_allocator {
+ struct ntdb_attribute_base base; /* .attr = NTDB_ATTRIBUTE_ALLOCATOR */
+ void *(*alloc)(const void *owner, size_t len, void *priv_data);
+ void *(*expand)(void *old, size_t newlen, void *priv_data);
+ void (*free)(void *old, void *priv_data);
+ void *priv_data;
+};
+
/**
* union ntdb_attribute - ntdb attributes.
*
* See also:
* struct ntdb_attribute_log, struct ntdb_attribute_hash,
* struct ntdb_attribute_seed, struct ntdb_attribute_stats,
- * struct ntdb_attribute_openhook, struct ntdb_attribute_flock.
+ * struct ntdb_attribute_openhook, struct ntdb_attribute_flock,
+ * struct ntdb_attribute_allocator alloc.
*/
union ntdb_attribute {
struct ntdb_attribute_base base;
struct ntdb_attribute_stats stats;
struct ntdb_attribute_openhook openhook;
struct ntdb_attribute_flock flock;
+ struct ntdb_attribute_allocator alloc;
};
#ifdef __cplusplus
/* Always make db a multiple of NTDB_PGSIZE */
dbsize = (sizeof(*newdb) + NTDB_PGSIZE-1) & ~(NTDB_PGSIZE-1);
remaindersize = dbsize - sizeof(*newdb);
- newdb = malloc(dbsize);
+ newdb = ntdb->alloc_fn(ntdb, dbsize, ntdb->alloc_data);
if (!newdb) {
return ntdb_logerr(ntdb, NTDB_ERR_OOM, NTDB_LOG_ERROR,
"ntdb_new_database: failed to allocate");
}
out:
- free(newdb);
+ ntdb->free_fn(newdb, ntdb->alloc_data);
return ecode;
}
static enum NTDB_ERROR ntdb_new_file(struct ntdb_context *ntdb)
{
- ntdb->file = malloc(sizeof(*ntdb->file));
+ ntdb->file = ntdb->alloc_fn(NULL, sizeof(*ntdb->file), ntdb->alloc_data);
if (!ntdb->file)
return ntdb_logerr(ntdb, NTDB_ERR_OOM, NTDB_LOG_ERROR,
"ntdb_open: cannot alloc ntdb_file structure");
ntdb->unlock_fn = attr->flock.unlock;
ntdb->lock_data = attr->flock.data;
break;
+ case NTDB_ATTRIBUTE_ALLOCATOR:
+ ntdb->alloc_fn = attr->alloc.alloc;
+ ntdb->expand_fn = attr->alloc.expand;
+ ntdb->free_fn = attr->alloc.free;
+ ntdb->alloc_data = attr->alloc.priv_data;
+ break;
default:
return ntdb_logerr(ntdb, NTDB_ERR_EINVAL,
NTDB_LOG_USE_ERROR,
attr->flock.unlock = ntdb->unlock_fn;
attr->flock.data = ntdb->lock_data;
break;
+ case NTDB_ATTRIBUTE_ALLOCATOR:
+ attr->alloc.alloc = ntdb->alloc_fn;
+ attr->alloc.expand = ntdb->expand_fn;
+ attr->alloc.free = ntdb->free_fn;
+ attr->alloc.priv_data = ntdb->alloc_data;
+ break;
default:
return ntdb_logerr(ntdb, NTDB_ERR_EINVAL,
NTDB_LOG_USE_ERROR,
return ecode;
}
+static void *default_alloc(const void *owner, size_t len, void *priv_data)
+{
+ return malloc(len);
+}
+
+static void *default_expand(void *ptr, size_t len, void *priv_data)
+{
+ return realloc(ptr, len);
+}
+
+static void default_free(void *ptr, void *priv_data)
+{
+ free(ptr);
+}
+
+/* First allocation needs manual search of attributes. */
+static struct ntdb_context *alloc_ntdb(const union ntdb_attribute *attr,
+ const char *name)
+{
+ size_t len = sizeof(struct ntdb_context) + strlen(name) + 1;
+
+ while (attr) {
+ if (attr->base.attr == NTDB_ATTRIBUTE_ALLOCATOR) {
+ return attr->alloc.alloc(NULL, len,
+ attr->alloc.priv_data);
+ }
+ attr = attr->base.next;
+ }
+ return default_alloc(NULL, len, NULL);
+}
+
_PUBLIC_ struct ntdb_context *ntdb_open(const char *name, int ntdb_flags,
- int open_flags, mode_t mode,
- union ntdb_attribute *attr)
+ int open_flags, mode_t mode,
+ union ntdb_attribute *attr)
{
struct ntdb_context *ntdb;
struct stat st;
enum NTDB_ERROR ecode;
int openlock;
- ntdb = malloc(sizeof(*ntdb) + strlen(name) + 1);
+ ntdb = alloc_ntdb(attr, name);
if (!ntdb) {
/* Can't log this */
errno = ENOMEM;
memset(&ntdb->stats, 0, sizeof(ntdb->stats));
ntdb->stats.base.attr = NTDB_ATTRIBUTE_STATS;
ntdb->stats.size = sizeof(ntdb->stats);
+ ntdb->alloc_fn = default_alloc;
+ ntdb->expand_fn = default_expand;
+ ntdb->free_fn = default_free;
while (attr) {
switch (attr->base.attr) {
assert(ntdb->file->num_lockrecs == 0);
if (ntdb->file->map_ptr) {
if (ntdb->flags & NTDB_INTERNAL) {
- free(ntdb->file->map_ptr);
+ ntdb->free_fn(ntdb->file->map_ptr,
+ ntdb->alloc_data);
} else
ntdb_munmap(ntdb->file);
}
ntdb_logerr(ntdb, NTDB_ERR_IO, NTDB_LOG_ERROR,
"ntdb_open: failed to close ntdb fd"
" on error: %s", strerror(errno));
- free(ntdb->file->lockrecs);
- free(ntdb->file);
+ ntdb->free_fn(ntdb->file->lockrecs, ntdb->alloc_data);
+ ntdb->free_fn(ntdb->file, ntdb->alloc_data);
}
}
- free(ntdb);
+ ntdb->free_fn(ntdb, ntdb->alloc_data);
errno = saved_errno;
return NULL;
}
if (ntdb->file->map_ptr) {
if (ntdb->flags & NTDB_INTERNAL)
- free(ntdb->file->map_ptr);
+ ntdb->free_fn(ntdb->file->map_ptr, ntdb->alloc_data);
else
ntdb_munmap(ntdb->file);
}
ntdb_lock_cleanup(ntdb);
if (--ntdb->file->refcnt == 0) {
ret = close(ntdb->file->fd);
- free(ntdb->file->lockrecs);
- free(ntdb->file);
+ ntdb->free_fn(ntdb->file->lockrecs, ntdb->alloc_data);
+ ntdb->free_fn(ntdb->file, ntdb->alloc_data);
}
}
#ifdef NTDB_TRACE
close(ntdb->tracefd);
#endif
- free(ntdb);
+ ntdb->free_fn(ntdb, ntdb->alloc_data);
return ret;
}
void *hash_data;
uint64_t hash_seed;
+ /* Allocate and free functions. */
+ void *(*alloc_fn)(const void *owner, size_t len, void *priv_data);
+ void *(*expand_fn)(void *old, size_t newlen, void *priv_data);
+ void (*free_fn)(void *old, void *priv_data);
+ void *alloc_data;
+
/* Our open hook, if any. */
enum NTDB_ERROR (*openhook)(int fd, void *data);
void *openhook_data;
+ num_caps * (strlen(CAPABILITY_FORMAT) + 20
+ strlen(" (uncheckable,read-only)"));
- *summary = malloc(len);
+ *summary = ntdb->alloc_fn(ntdb, len, ntdb->alloc_data);
if (!*summary) {
ecode = ntdb_logerr(ntdb, NTDB_ERR_OOM, NTDB_LOG_ERROR,
"ntdb_summary: failed to allocate string");
add_capabilities(ntdb, *summary);
unlock:
- free(hashesg);
- free(freeg);
- free(keysg);
- free(datag);
- free(extrag);
- free(uncoalg);
- free(hashes);
- free(freet);
- free(keys);
- free(data);
- free(extra);
- free(uncoal);
- free(ftables);
- free(chains);
+ ntdb->free_fn(hashesg, ntdb->alloc_data);
+ ntdb->free_fn(freeg, ntdb->alloc_data);
+ ntdb->free_fn(keysg, ntdb->alloc_data);
+ ntdb->free_fn(datag, ntdb->alloc_data);
+ ntdb->free_fn(extrag, ntdb->alloc_data);
+ ntdb->free_fn(uncoalg, ntdb->alloc_data);
+ ntdb->free_fn(hashes, ntdb->alloc_data);
+ ntdb->free_fn(freet, ntdb->alloc_data);
+ ntdb->free_fn(keys, ntdb->alloc_data);
+ ntdb->free_fn(data, ntdb->alloc_data);
+ ntdb->free_fn(extra, ntdb->alloc_data);
+ ntdb->free_fn(uncoal, ntdb->alloc_data);
+ ntdb->free_fn(ftables, ntdb->alloc_data);
+ ntdb->free_fn(chains, ntdb->alloc_data);
ntdb_allrecord_unlock(ntdb, F_RDLCK);
ntdb_unlock_expand(ntdb, F_RDLCK);
--- /dev/null
+#include "config.h"
+#include "ntdb.h"
+#include "tap-interface.h"
+#include <ccan/hash/hash.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#include "logging.h"
+
+static const struct ntdb_context *curr_ntdb;
+static const struct ntdb_file *curr_file;
+
+static int owner_null_count,
+ owner_weird_count, alloc_count, free_count, expand_count;
+
+static void *test_alloc(const void *owner, size_t len, void *priv_data)
+{
+ void *ret;
+
+ if (!owner) {
+ owner_null_count++;
+ } else if (owner != curr_ntdb && owner != curr_file) {
+ owner_weird_count++;
+ }
+
+ alloc_count++;
+ ret = malloc(len);
+
+ /* The first time, this is the current ntdb, next is
+ * for the file struct. */
+ if (!owner) {
+ if (!curr_ntdb) {
+ curr_ntdb = ret;
+ } else if (!curr_file) {
+ curr_file = ret;
+ }
+ }
+ assert(priv_data == &owner_weird_count);
+ return ret;
+}
+
+static void *test_expand(void *old, size_t newlen, void *priv_data)
+{
+ expand_count++;
+
+ assert(priv_data == &owner_weird_count);
+ return realloc(old, newlen);
+}
+
+static void test_free(void *old, void *priv_data)
+{
+ assert(priv_data == &owner_weird_count);
+ if (old) {
+ free_count++;
+ }
+ free(old);
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned int i, j;
+ union ntdb_attribute alloc_attr;
+ struct ntdb_context *ntdb;
+ int flags[] = { NTDB_INTERNAL, NTDB_DEFAULT, NTDB_NOMMAP,
+ NTDB_INTERNAL|NTDB_CONVERT, NTDB_CONVERT,
+ NTDB_NOMMAP|NTDB_CONVERT };
+ NTDB_DATA key = { (unsigned char *)&j, sizeof(j) };
+ NTDB_DATA data = { (unsigned char *)&j, sizeof(j) };
+
+ alloc_attr.base.next = &tap_log_attr;
+ alloc_attr.base.attr = NTDB_ATTRIBUTE_ALLOCATOR;
+
+ alloc_attr.alloc.alloc = test_alloc;
+ alloc_attr.alloc.expand = test_expand;
+ alloc_attr.alloc.free = test_free;
+ alloc_attr.alloc.priv_data = &owner_weird_count;
+
+ plan_tests(sizeof(flags) / sizeof(flags[0]) * (1 + 500 * 3 + 4) + 1);
+
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+ curr_ntdb = NULL;
+ curr_file = NULL;
+ ntdb = ntdb_open("run-12-store.ntdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, &alloc_attr);
+ ok1(ntdb);
+ if (!ntdb)
+ continue;
+
+ for (j = 0; j < 500; j++) {
+ NTDB_DATA d = { NULL, 0 }; /* Bogus GCC warning */
+ ok1(ntdb_store(ntdb, key, data, NTDB_REPLACE) == 0);
+ ok1(ntdb_fetch(ntdb, key, &d) == NTDB_SUCCESS);
+ ok1(ntdb_deq(d, data));
+ test_free(d.dptr, &owner_weird_count);
+ }
+ ntdb_close(ntdb);
+
+ ok1(owner_null_count == 2+i*2);
+ ok1(owner_weird_count == 0);
+ ok1(alloc_count == free_count);
+ ok1(expand_count != 0);
+ }
+
+ ok1(tap_log_messages == 0);
+ return exit_status();
+}
bool exit_check_log(struct tlist_calls *history)
{
const struct failtest_call *i;
+ unsigned int malloc_count = 0;
tlist_for_each(history, i, list) {
if (!i->fail)
continue;
/* Initial allocation of ntdb doesn't log. */
- if (failmatch(i, INITIAL_NTDB_MALLOC))
- continue;
+ if (i->type == FAILTEST_MALLOC) {
+ if (malloc_count++ == 0) {
+ continue;
+ }
+ }
/* We don't block "failures" on non-blocking locks. */
if (is_nonblocking_lock(i))
if (failtest_suppress)
return FAIL_DONT_FAIL;
- if (failmatch(last, INITIAL_NTDB_MALLOC)
- || failmatch(last, URANDOM_OPEN)
+ if (failmatch(last, URANDOM_OPEN)
|| failmatch(last, URANDOM_READ)) {
return FAIL_PROBE;
}
#include <stdbool.h>
/* FIXME: Check these! */
-#define INITIAL_NTDB_MALLOC "open.c", 425, FAILTEST_MALLOC
#define URANDOM_OPEN "open.c", 62, FAILTEST_OPEN
#define URANDOM_READ "open.c", 42, FAILTEST_READ
}
#define malloc malloc_noleak
-#define free free_noleak
+#define free(x) free_noleak(x)
#define realloc realloc_noleak
#include "ntdb-source.h"
#include "private.h"
#include <assert.h>
-#define SAFE_FREE(x) do { if ((x) != NULL) {free((void *)x); (x)=NULL;} } while(0)
+#define SAFE_FREE(ntdb, x) do { if ((x) != NULL) {ntdb->free_fn((void *)x, ntdb->alloc_data); (x)=NULL;} } while(0)
/*
transaction design:
uint8_t **new_blocks;
/* expand the blocks array */
if (ntdb->transaction->blocks == NULL) {
- new_blocks = (uint8_t **)malloc(
- (blk+1)*sizeof(uint8_t *));
+ new_blocks = (uint8_t **)ntdb->alloc_fn(ntdb,
+ (blk+1)*sizeof(uint8_t *), ntdb->alloc_data);
} else {
- new_blocks = (uint8_t **)realloc(
+ new_blocks = (uint8_t **)ntdb->expand_fn(
ntdb->transaction->blocks,
- (blk+1)*sizeof(uint8_t *));
+ (blk+1)*sizeof(uint8_t *), ntdb->alloc_data);
}
if (new_blocks == NULL) {
ecode = ntdb_logerr(ntdb, NTDB_ERR_OOM, NTDB_LOG_ERROR,
/* allocate and fill a block? */
if (ntdb->transaction->blocks[blk] == NULL) {
- ntdb->transaction->blocks[blk] = (uint8_t *)calloc(NTDB_PGSIZE, 1);
+ ntdb->transaction->blocks[blk] = (uint8_t *)
+ ntdb->alloc_fn(ntdb->transaction->blocks, NTDB_PGSIZE,
+ ntdb->alloc_data);
if (ntdb->transaction->blocks[blk] == NULL) {
ecode = ntdb_logerr(ntdb, NTDB_ERR_OOM, NTDB_LOG_ERROR,
"transaction_write:"
" failed to allocate");
goto fail;
}
+ memset(ntdb->transaction->blocks[blk], 0, NTDB_PGSIZE);
if (ntdb->transaction->old_map_size > blk * NTDB_PGSIZE) {
ntdb_len_t len2 = NTDB_PGSIZE;
if (len2 + (blk * NTDB_PGSIZE) > ntdb->transaction->old_map_size) {
" failed to"
" read old block: %s",
strerror(errno));
- SAFE_FREE(ntdb->transaction->blocks[blk]);
+ SAFE_FREE(ntdb, ntdb->transaction->blocks[blk]);
goto fail;
}
}
/* free all the transaction blocks */
for (i=0;i<ntdb->transaction->num_blocks;i++) {
if (ntdb->transaction->blocks[i] != NULL) {
- free(ntdb->transaction->blocks[i]);
+ ntdb->free_fn(ntdb->transaction->blocks[i],
+ ntdb->alloc_data);
}
}
- SAFE_FREE(ntdb->transaction->blocks);
+ SAFE_FREE(ntdb, ntdb->transaction->blocks);
if (ntdb->transaction->magic_offset) {
const struct ntdb_methods *methods = ntdb->transaction->io_methods;
if (ntdb_has_open_lock(ntdb))
ntdb_unlock_open(ntdb, F_WRLCK);
- SAFE_FREE(ntdb->transaction);
+ SAFE_FREE(ntdb, ntdb->transaction);
}
/*
}
ntdb->transaction = (struct ntdb_transaction *)
- calloc(sizeof(struct ntdb_transaction), 1);
+ ntdb->alloc_fn(ntdb, sizeof(struct ntdb_transaction),
+ ntdb->alloc_data);
if (ntdb->transaction == NULL) {
return ntdb_logerr(ntdb, NTDB_ERR_OOM, NTDB_LOG_ERROR,
"ntdb_transaction_start:"
" cannot allocate");
}
+ memset(ntdb->transaction, 0, sizeof(*ntdb->transaction));
/* get the transaction write lock. This is a blocking lock. As
discussed with Volker, there are a number of ways we could
make this async, which we will probably do in the future */
ecode = ntdb_transaction_lock(ntdb, F_WRLCK);
if (ecode != NTDB_SUCCESS) {
- SAFE_FREE(ntdb->transaction->blocks);
- SAFE_FREE(ntdb->transaction);
+ SAFE_FREE(ntdb, ntdb->transaction->blocks);
+ SAFE_FREE(ntdb, ntdb->transaction);
return ecode;
}
fail_allrecord_lock:
ntdb_transaction_unlock(ntdb, F_WRLCK);
- SAFE_FREE(ntdb->transaction->blocks);
- SAFE_FREE(ntdb->transaction);
+ SAFE_FREE(ntdb, ntdb->transaction->blocks);
+ SAFE_FREE(ntdb, ntdb->transaction);
return ecode;
}
unsigned char *p;
const struct ntdb_methods *old_methods = ntdb->io;
- rec = malloc(sizeof(*rec) + ntdb_recovery_size(ntdb));
+ rec = ntdb->alloc_fn(ntdb, sizeof(*rec) + ntdb_recovery_size(ntdb),
+ ntdb->alloc_data);
if (!rec) {
ntdb_logerr(ntdb, NTDB_ERR_OOM, NTDB_LOG_ERROR,
"transaction_setup_recovery:"
return rec;
fail:
- free(rec);
+ ntdb->free_fn(rec, ntdb->alloc_data);
ntdb->io = old_methods;
return NTDB_ERR_PTR(ecode);
}
ecode = ntdb_recovery_area(ntdb, methods, &recovery_off, recovery);
if (ecode) {
- free(recovery);
+ ntdb->free_fn(recovery, ntdb->alloc_data);
return ecode;
}
sizeof(*recovery)
+ recovery->max_len,
NTDB_LOCK_WAIT, true);
- free(recovery);
+ ntdb->free_fn(recovery, ntdb->alloc_data);
if (ecode != NTDB_SUCCESS) {
return ntdb_logerr(ntdb, ecode, NTDB_LOG_ERROR,
"ntdb_recovery_allocate:"
recovery_off = create_recovery_area(ntdb, recovery_size,
recovery);
if (NTDB_OFF_IS_ERR(recovery_off)) {
- free(recovery);
+ ntdb->free_fn(recovery, ntdb->alloc_data);
return NTDB_OFF_TO_ERR(recovery_off);
}
}
ecode = methods->twrite(ntdb, recovery_off, recovery,
sizeof(*recovery) + recovery_size);
if (ecode != NTDB_SUCCESS) {
- free(recovery);
+ ntdb->free_fn(recovery, ntdb->alloc_data);
return ntdb_logerr(ntdb, ecode, NTDB_LOG_ERROR,
"ntdb_transaction_setup_recovery:"
" failed to write recovery data");
}
transaction_write_existing(ntdb, recovery_off, recovery, recovery_size);
- free(recovery);
+ ntdb->free_fn(recovery, ntdb->alloc_data);
/* as we don't have ordered writes, we have to sync the recovery
data before we update the magic to indicate that the recovery
return ecode;
}
- SAFE_FREE(ntdb->transaction->blocks[i]);
+ SAFE_FREE(ntdb, ntdb->transaction->blocks[i]);
}
- SAFE_FREE(ntdb->transaction->blocks);
+ SAFE_FREE(ntdb, ntdb->transaction->blocks);
ntdb->transaction->num_blocks = 0;
/* ensure the new data is on disk */
recovery_eof = rec.eof;
- data = (unsigned char *)malloc(rec.len);
+ data = (unsigned char *)ntdb->alloc_fn(ntdb, rec.len, ntdb->alloc_data);
if (data == NULL) {
return ntdb_logerr(ntdb, NTDB_ERR_OOM, NTDB_LOG_ERROR,
"ntdb_transaction_recover:"
ecode = ntdb->io->twrite(ntdb, ofs, p, len);
if (ecode != NTDB_SUCCESS) {
- free(data);
+ ntdb->free_fn(data, ntdb->alloc_data);
return ntdb_logerr(ntdb, ecode, NTDB_LOG_ERROR,
"ntdb_transaction_recover:"
" failed to recover %zu bytes"
p += len;
}
- free(data);
+ ntdb->free_fn(data, ntdb->alloc_data);
ecode = transaction_sync(ntdb, 0, ntdb->file->map_size);
if (ecode != NTDB_SUCCESS) {
count++;
if (fn && fn(ntdb, k, d, p)) {
- free(k.dptr);
+ ntdb->free_fn(k.dptr, ntdb->alloc_data);
return count;
}
- free(k.dptr);
+ ntdb->free_fn(k.dptr, ntdb->alloc_data);
}
if (ecode != NTDB_ERR_NOEXIST) {
struct ntdb_used_record rec;
tinfo.prev = find_and_lock(ntdb, *key, F_RDLCK, &h, &rec, &tinfo);
- free(key->dptr);
+ ntdb->free_fn(key->dptr, ntdb->alloc_data);
if (NTDB_OFF_IS_ERR(tinfo.prev)) {
return NTDB_OFF_TO_ERR(tinfo.prev);
}
'test/api-13-delete.c',
'test/api-14-exists.c',
'test/api-16-wipe_all.c',
+ 'test/api-20-alloc-attr.c',
'test/api-21-parse_record.c',
'test/api-55-transaction.c',
'test/api-80-tdb_fd.c',