#include "private.h"
#include <ccan/likely/likely.h>
-void ntdb_munmap(struct ntdb_file *file)
+static void free_old_mmaps(struct ntdb_context *ntdb)
{
- if (file->fd == -1)
- return;
+ struct ntdb_old_mmap *i;
- if (file->map_ptr) {
- munmap(file->map_ptr, file->map_size);
- file->map_ptr = NULL;
+ assert(ntdb->file->direct_count == 0);
+
+ while ((i = ntdb->file->old_mmaps) != NULL) {
+ ntdb->file->old_mmaps = i->next;
+ munmap(i->map_ptr, i->map_size);
+ ntdb->free_fn(i, ntdb->alloc_data);
}
}
+enum NTDB_ERROR ntdb_munmap(struct ntdb_context *ntdb)
+{
+ if (ntdb->file->fd == -1) {
+ return NTDB_SUCCESS;
+ }
+
+ if (!ntdb->file->map_ptr) {
+ return NTDB_SUCCESS;
+ }
+
+ /* We can't unmap now if there are accessors. */
+ if (ntdb->file->direct_count) {
+ struct ntdb_old_mmap *old
+ = ntdb->alloc_fn(ntdb, sizeof(*old), ntdb->alloc_data);
+ if (!old) {
+ return ntdb_logerr(ntdb, NTDB_ERR_OOM, NTDB_LOG_ERROR,
+ "ntdb_munmap alloc failed");
+ }
+ old->next = ntdb->file->old_mmaps;
+ old->map_ptr = ntdb->file->map_ptr;
+ old->map_size = ntdb->file->map_size;
+ ntdb->file->old_mmaps = old;
+ } else {
+ munmap(ntdb->file->map_ptr, ntdb->file->map_size);
+ ntdb->file->map_ptr = NULL;
+ }
+ return NTDB_SUCCESS;
+}
+
enum NTDB_ERROR ntdb_mmap(struct ntdb_context *ntdb)
{
int mmap_flags;
struct stat st;
enum NTDB_ERROR ecode;
- /* We can't hold pointers during this: we could unmap! */
- assert(!ntdb->direct_access
- || (ntdb->flags & NTDB_NOLOCK)
- || ntdb_has_expansion_lock(ntdb));
-
if (len + off < len) {
if (probe)
return NTDB_SUCCESS;
}
/* Unmap, update size, remap */
- ntdb_munmap(ntdb->file);
+ ecode = ntdb_munmap(ntdb);
+ if (ecode) {
+ return ecode;
+ }
ntdb->file->map_size = st.st_size;
return ntdb_mmap(ntdb);
} else {
/* Unmap before trying to write; old NTDB claimed OpenBSD had
* problem with this otherwise. */
- ntdb_munmap(ntdb->file);
+ ecode = ntdb_munmap(ntdb);
+ if (ecode) {
+ return ecode;
+ }
/* If this fails, we try to fill anyway. */
if (ftruncate(ntdb->file->fd, ntdb->file->map_size + addition))
if (convert) {
ntdb_convert(ntdb, (void *)ret, len);
}
- } else
- ntdb->direct_access++;
+ } else {
+ ntdb->file->direct_count++;
+ }
return ret;
}
ret = hdr + 1;
if (convert)
ntdb_convert(ntdb, (void *)ret, len);
- } else
- ntdb->direct_access++;
-
+ } else {
+ ntdb->file->direct_count++;
+ }
return ret;
}
hdr = *hp;
*hp = hdr->next;
ntdb->free_fn(hdr, ntdb->alloc_data);
- } else
- ntdb->direct_access--;
+ } else {
+ if (--ntdb->file->direct_count == 0) {
+ free_old_mmaps(ntdb);
+ }
+ }
}
enum NTDB_ERROR ntdb_access_commit(struct ntdb_context *ntdb, void *p)
*hp = hdr->next;
ntdb->free_fn(hdr, ntdb->alloc_data);
} else {
- ntdb->direct_access--;
+ if (--ntdb->file->direct_count == 0) {
+ free_old_mmaps(ntdb);
+ }
ecode = NTDB_SUCCESS;
}
}
_PUBLIC_ enum NTDB_ERROR ntdb_fetch(struct ntdb_context *ntdb, NTDB_DATA key,
- NTDB_DATA *data)
+ NTDB_DATA *data)
{
ntdb_off_t off;
struct ntdb_used_record rec;
ntdb->flags |= NTDB_NOLOCK;
break;
case NTDB_NOMMAP:
+ if (ntdb->file->direct_count) {
+ ntdb_logerr(ntdb, NTDB_ERR_EINVAL, NTDB_LOG_USE_ERROR,
+ "ntdb_add_flag: Can't get NTDB_NOMMAP from"
+ " ntdb_parse_record!");
+ return;
+ }
ntdb->flags |= NTDB_NOMMAP;
#ifndef HAVE_INCOHERENT_MMAP
- ntdb_munmap(ntdb->file);
+ ntdb_munmap(ntdb);
#endif
break;
case NTDB_NOSYNC:
{
/* Initialize the NTDB fields here */
ntdb_io_init(ntdb);
- ntdb->direct_access = 0;
ntdb->transaction = NULL;
ntdb->access = NULL;
}
ntdb->file->allrecord_lock.count = 0;
ntdb->file->refcnt = 1;
ntdb->file->map_ptr = NULL;
+ ntdb->file->direct_count = 0;
+ ntdb->file->old_mmaps = NULL;
return NTDB_SUCCESS;
}
ntdb->free_fn(ntdb->file->map_ptr,
ntdb->alloc_data);
} else
- ntdb_munmap(ntdb->file);
+ ntdb_munmap(ntdb);
}
if (ntdb->file->fd != -1 && close(ntdb->file->fd) != 0)
ntdb_logerr(ntdb, NTDB_ERR_IO, NTDB_LOG_ERROR,
ntdb->free_fn(ntdb->file->map_ptr,
ntdb->alloc_data);
} else {
- ntdb_munmap(ntdb->file);
+ ntdb_munmap(ntdb);
}
}
ret = close(ntdb->file->fd);
bool convert;
};
+/* mmaps we are keeping around because they are still direct accessed */
+struct ntdb_old_mmap {
+ struct ntdb_old_mmap *next;
+
+ void *map_ptr;
+ ntdb_len_t map_size;
+};
+
struct ntdb_file {
/* How many are sharing us? */
unsigned int refcnt;
/* The file descriptor (-1 for NTDB_INTERNAL). */
int fd;
+ /* How many are accessing directly? */
+ unsigned int direct_count;
+
+ /* Old maps, still direct accessed. */
+ struct ntdb_old_mmap *old_mmaps;
+
/* Lock information */
pid_t locker;
struct ntdb_lock allrecord_lock;
void *ntdb_convert(const struct ntdb_context *ntdb, void *buf, ntdb_len_t size);
/* Unmap and try to map the ntdb. */
-void ntdb_munmap(struct ntdb_file *file);
+enum NTDB_ERROR ntdb_munmap(struct ntdb_context *ntdb);
enum NTDB_ERROR ntdb_mmap(struct ntdb_context *ntdb);
/* Either alloc a copy, or give direct access. Release frees or noop. */
enum NTDB_ERROR (*openhook)(int fd, void *data);
void *openhook_data;
- /* Are we accessing directly? (debugging check). */
- int direct_access;
-
/* Set if we are in a transaction. */
struct ntdb_transaction *transaction;