* BerkeleyDB API, but much simplified.
*/
/*
- * Copyright 2011-2015 Howard Chu, Symas Corp.
+ * Copyright 2011-2016 Howard Chu, Symas Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#ifndef _GNU_SOURCE
#define _GNU_SOURCE 1
#endif
-#ifdef MDB_VL32
+#if defined(MDB_VL32) || defined(__WIN64__)
#define _FILE_OFFSET_BITS 64
#endif
#ifdef _WIN32
pgno_t md_branch_pages; /**< number of internal pages */
pgno_t md_leaf_pages; /**< number of leaf pages */
pgno_t md_overflow_pages; /**< number of overflow pages */
- pgno_t md_entries; /**< number of data items */
+ mdb_size_t md_entries; /**< number of data items */
pgno_t md_root; /**< the root page of this tree */
} MDB_db;
rc = MDB_MAP_FULL;
goto fail;
}
-#ifdef _WIN32
- if (env->me_flags & MDB_WRITEMAP) {
+#if defined(_WIN32) && !defined(MDB_VL32)
+ if (!(env->me_flags & MDB_RDONLY)) {
void *p;
p = (MDB_page *)(env->me_map + env->me_psize * pgno);
p = VirtualAlloc(p, env->me_psize * num, MEM_COMMIT,
size = meta->mm_mapsize;
{
/* Silently round up to minimum if the size is too small */
- size_t minsize = (meta->mm_last_pg + 1) * env->me_psize;
+ mdb_size_t minsize = (meta->mm_last_pg + 1) * env->me_psize;
if (size < minsize)
size = minsize;
}
free(env->me_dbflags);
free(env->me_path);
free(env->me_dirty_list);
- free(env->me_txn0);
#ifdef MDB_VL32
+ if (env->me_txn0 && env->me_txn0->mt_rpages)
+ free(env->me_txn0->mt_rpages);
{ unsigned int x;
for (x=1; x<=env->me_rpages[0].mid; x++)
munmap(env->me_rpages[x].mptr, env->me_rpages[x].mcnt * env->me_psize);
}
free(env->me_rpages);
#endif
+ free(env->me_txn0);
mdb_midl_free(env->me_free_pgs);
if (env->me_flags & MDB_ENV_TXKEY) {
pthread_mutex_lock(&env->me_rpmutex);
retry:
y = 0;
- for (i=1; i<tl[0].mid; i++) {
+ for (i=1; i<=tl[0].mid; i++) {
if (!tl[i].mref) {
if (!y) y = i;
/* tmp overflow pages don't go to env */
if (rc)
goto fail;
if (!el[x].mref) {
- munmap(el[x].mptr, el[x].mcnt);
+ munmap(el[x].mptr, env->me_psize * el[x].mcnt);
el[x].mptr = id3.mptr;
el[x].mcnt = id3.mcnt;
} else {
if (el[0].mid >= MDB_ERPAGE_MAX - env->me_rpcheck) {
/* purge unref'd pages */
unsigned i, y = 0;
- for (i=1; i<el[0].mid; i++) {
+ for (i=1; i<=el[0].mid; i++) {
if (!el[i].mref) {
if (!y) y = i;
munmap(el[i].mptr, env->me_psize * el[i].mcnt);
pthread_mutex_unlock(&env->me_rpmutex);
return rc;
}
- /* If this page is far enough from the end of the env, scan for
- * any overflow pages that would spill onto another block.
- * Note we must compare against mt_last_pgno, the last written
- * page in the environment. Not mt_next_pgno, which increases
- * for every newly allocated (but not yet written) page. If
- * we scanned beyond the last written page we'd get a bus error.
- */
- if (pgno + MDB_RPAGE_CHUNK <= txn->mt_last_pgno) {
- int i;
- char *cp = (char *)id3.mptr + rem * env->me_psize;
- for (i=rem; i<MDB_RPAGE_CHUNK;) {
- p = (MDB_page *)cp;
- if (IS_OVERFLOW(p)) {
- int nop = p->mp_pages;
- if (nop + i > MDB_RPAGE_CHUNK) {
- munmap(id3.mptr, len);
- id3.mcnt = nop + i;
- len = id3.mcnt * env->me_psize;
- MAP(rc, env, id3.mptr, len, off);
- if (rc)
- goto fail;
- break;
- }
- i += nop;
- cp += nop * env->me_psize;
- } else {
- i++;
- cp += env->me_psize;
- }
- }
+ /* check for overflow size */
+ p = (MDB_page *)((char *)id3.mptr + rem * env->me_psize);
+ if (IS_OVERFLOW(p) && p->mp_pages + rem > id3.mcnt) {
+ id3.mcnt = p->mp_pages + rem;
+ munmap(id3.mptr, len);
+ len = id3.mcnt * env->me_psize;
+ MAP(rc, env, id3.mptr, len, off);
+ if (rc)
+ goto fail;
}
mdb_mid3l_insert(el, &id3);
pthread_mutex_unlock(&env->me_rpmutex);
DPRINTF(("cursor_next: top page is %"Y"u in cursor %p",
mdb_dbg_pgno(mp), (void *) mc));
- if (mc->mc_flags & C_DEL)
+ if (mc->mc_flags & C_DEL) {
+ mc->mc_flags ^= C_DEL;
goto skip;
+ }
if (mc->mc_ki[mc->mc_top] + 1u >= NUMKEYS(mp)) {
DPUTS("=====> move to next sibling page");
DPRINTF(("cursor_prev: top page is %"Y"u in cursor %p",
mdb_dbg_pgno(mp), (void *) mc));
+ mc->mc_flags &= ~(C_EOF|C_DEL);
+
if (mc->mc_ki[mc->mc_top] == 0) {
DPUTS("=====> move to prev sibling page");
if ((rc = mdb_cursor_sibling(mc, 0)) != MDB_SUCCESS) {
}
}
break;
+ case MDB_PREV_MULTIPLE:
+ if (data == NULL) {
+ rc = EINVAL;
+ break;
+ }
+ if (!(mc->mc_db->md_flags & MDB_DUPFIXED)) {
+ rc = MDB_INCOMPATIBLE;
+ break;
+ }
+ if (!(mc->mc_flags & C_INITIALIZED))
+ rc = mdb_cursor_first(mc, key, data);
+ else {
+ MDB_cursor *mx = &mc->mc_xcursor->mx_cursor;
+ if (mx->mc_flags & C_INITIALIZED) {
+ rc = mdb_cursor_sibling(mx, 0);
+ if (rc == MDB_SUCCESS)
+ goto fetchm;
+ } else {
+ rc = MDB_NOTFOUND;
+ }
+ }
+ break;
case MDB_NEXT:
case MDB_NEXT_DUP:
case MDB_NEXT_NODUP:
*/
if (do_sub) {
int xflags, new_dupdata;
- size_t ecount;
+ mdb_size_t ecount;
put_sub:
xdata.mv_size = 0;
xdata.mv_data = "";
/* Return the count of duplicate data items for the current key */
int
-mdb_cursor_count(MDB_cursor *mc, size_t *countp)
+mdb_cursor_count(MDB_cursor *mc, mdb_size_t *countp)
{
MDB_node *leaf;
#ifdef _WIN32
rc = utf8_to_utf16(lpath, -1, &wpath, NULL);
if (rc)
- return rc;
+ goto leave;
newfd = CreateFileW(wpath, GENERIC_WRITE, 0, NULL, CREATE_NEW,
FILE_FLAG_NO_BUFFERING|FILE_FLAG_WRITE_THROUGH, NULL);
free(wpath);