* 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
#define ESECT
#endif
-#ifdef _MSC_VER
+#ifdef _WIN32
#define CALL_CONV WINAPI
#else
#define CALL_CONV
# define MDB_USE_ROBUST 0
# else
# define MDB_USE_ROBUST 1
-/* glibc < 2.10 only provided _np API */
-# if defined(__GLIBC__) && GLIBC_VER < 0x02000a
+/* glibc < 2.12 only provided _np API */
+# if defined(__GLIBC__) && GLIBC_VER < 0x02000c
# define PTHREAD_MUTEX_ROBUST PTHREAD_MUTEX_ROBUST_NP
# define pthread_mutexattr_setrobust(attr, flag) pthread_mutexattr_setrobust_np(attr, flag)
# define pthread_mutex_consistent(mutex) pthread_mutex_consistent_np(mutex)
#endif
/** max bytes to write in one call */
-#define MAX_WRITE (0x80000000U >> (sizeof(ssize_t) == 4))
+#define MAX_WRITE (0x40000000U >> (sizeof(ssize_t) == 4))
/** Check \b txn and \b dbi arguments to a function */
#define TXN_DBI_EXIST(txn, dbi, validity) \
* This works as long as no function between the call to mdb_strerror
* and the actual use of the message uses more than 4K of stack.
*/
- char pad[4096];
- char buf[1024], *ptr = buf;
+#define MSGSIZE 1024
+#define PADSIZE 4096
+ char buf[MSGSIZE+PADSIZE], *ptr = buf;
#endif
int i;
if (!err)
buf[0] = 0;
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, err, 0, ptr, sizeof(buf), (va_list *)pad);
+ NULL, err, 0, ptr, MSGSIZE, (va_list *)buf+MSGSIZE);
return ptr;
#else
return strerror(err);
}
if (mc->mc_ki[i] >= NUMKEYS(mc->mc_pg[i]))
printf("ack!\n");
+ if (mc->mc_xcursor && (mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED)) {
+ node = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]);
+ if (((node->mn_flags & (F_DUPDATA|F_SUBDATA)) == F_DUPDATA) &&
+ mc->mc_xcursor->mx_cursor.mc_pg[0] != NODEDATA(node)) {
+ printf("blah!\n");
+ }
+ }
}
#endif
} else {
for (; m2; m2=m2->mc_next) {
if (m2->mc_snum < mc->mc_snum) continue;
+ if (m2 == mc) continue;
if (m2->mc_pg[mc->mc_top] == mp) {
m2->mc_pg[mc->mc_top] = np;
if ((mc->mc_db->md_flags & MDB_DUPSORT) &&
IS_LEAF(np) &&
- m2->mc_ki[mc->mc_top] == mc->mc_ki[mc->mc_top])
+ (m2->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED))
{
- MDB_node *leaf = NODEPTR(np, mc->mc_ki[mc->mc_top]);
- if (!(leaf->mn_flags & F_SUBDATA))
+ MDB_node *leaf = NODEPTR(np, m2->mc_ki[mc->mc_top]);
+ if ((leaf->mn_flags & (F_DUPDATA|F_SUBDATA)) == F_DUPDATA)
m2->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(leaf);
}
}
pspill[0] = y;
}
+ /* Remove anything in our spill list from parent's dirty list */
+ if (txn->mt_spill_pgs && txn->mt_spill_pgs[0]) {
+ for (i=1; i<=txn->mt_spill_pgs[0]; i++) {
+ MDB_ID pn = txn->mt_spill_pgs[i];
+ if (pn & 1)
+ continue; /* deleted spillpg */
+ pn >>= 1;
+ y = mdb_mid2l_search(dst, pn);
+ if (y <= dst[0].mid && dst[y].mid == pn) {
+ free(dst[y].mptr);
+ while (y < dst[0].mid) {
+ dst[y] = dst[y+1];
+ y++;
+ }
+ dst[0].mid--;
+ }
+ }
+ }
+
/* Find len = length of merging our dirty list with parent's */
x = dst[0].mid;
dst[0].mid = 0; /* simplify loops */
#ifdef _WIN32
wchar_t *wlpath;
- utf8_to_utf16(lpath, -1, &wlpath, NULL);
+ rc = utf8_to_utf16(lpath, -1, &wlpath, NULL);
+ if (rc)
+ return rc;
env->me_lfd = CreateFileW(wlpath, GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
len = OPEN_ALWAYS;
}
mode = FILE_ATTRIBUTE_NORMAL;
- utf8_to_utf16(dpath, -1, &wpath, NULL);
+ rc = utf8_to_utf16(dpath, -1, &wpath, NULL);
+ if (rc)
+ goto leave;
env->me_fd = CreateFileW(wpath, oflags, FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL, len, mode, NULL);
free(wpath);
*/
#ifdef _WIN32
len = OPEN_EXISTING;
- utf8_to_utf16(dpath, -1, &wpath, NULL);
+ rc = utf8_to_utf16(dpath, -1, &wpath, NULL);
+ if (rc)
+ goto leave;
env->me_mfd = CreateFileW(wpath, oflags,
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, len,
mode | FILE_FLAG_WRITE_THROUGH, NULL);
mc->mc_pg[mc->mc_top]->mp_pgno, DDBI(mc), (void *) mc));
mc->mc_snum--;
- if (mc->mc_snum)
+ if (mc->mc_snum) {
mc->mc_top--;
+ } else {
+ mc->mc_flags &= ~C_INITIALIZED;
+ }
}
}
indx_t i;
DPRINTF(("branch page %"Z"u has %u keys", mp->mp_pgno, NUMKEYS(mp)));
- mdb_cassert(mc, NUMKEYS(mp) > 1);
+ /* Don't assert on branch pages in the FreeDB. We can get here
+ * while in the process of rebalancing a FreeDB branch page; we must
+ * let that proceed. ITS#8336
+ */
+ mdb_cassert(mc, !mc->mc_dbi || NUMKEYS(mp) > 1);
DPRINTF(("found index 0 to page %"Z"u", NODEPGNO(NODEPTR(mp, 0))));
if (flags & (MDB_PS_FIRST|MDB_PS_LAST)) {
DPRINTF(("cursor_next: top page is %"Z"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 %"Z"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) {
} else
mc->mc_ki[mc->mc_top]--;
- mc->mc_flags &= ~C_EOF;
-
DPRINTF(("==> cursor points to page %"Z"u with %u keys, key index %u",
mdb_dbg_pgno(mp), NUMKEYS(mp), mc->mc_ki[mc->mc_top]));
} else
return MDB_NOTFOUND;
}
+ } else {
+ mc->mc_pg[0] = 0;
}
rc = mdb_page_search(mc, key, 0);
if (op == MDB_GET_BOTH || rc > 0)
return MDB_NOTFOUND;
rc = 0;
- *data = olddata;
}
+ *data = olddata;
} else {
if (mc->mc_xcursor)
MDB_GET_KEY(leaf, key);
if (data) {
if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
- if (mc->mc_flags & C_DEL)
- mdb_xcursor_init1(mc, leaf);
rc = mdb_cursor_get(&mc->mc_xcursor->mx_cursor, data, NULL, MDB_GET_CURRENT);
} else {
rc = mdb_node_read(mc->mc_txn, leaf, data);
#endif
/* does data match? */
if (!dcmp(data, &olddata)) {
- if (flags & MDB_NODUPDATA)
+ if (flags & (MDB_NODUPDATA|MDB_APPENDDUP))
return MDB_KEYEXIST;
/* overwrite it */
goto current;
} else {
/* There is room already in this leaf page. */
rc = mdb_node_add(mc, mc->mc_ki[mc->mc_top], key, rdata, 0, nflags);
- if (rc == 0 && insert_key) {
+ if (rc == 0) {
/* Adjust other cursors pointing to mp */
MDB_cursor *m2, *m3;
MDB_dbi dbi = mc->mc_dbi;
m3 = &m2->mc_xcursor->mx_cursor;
else
m3 = m2;
- if (m3 == mc || m3->mc_snum < mc->mc_snum) continue;
- if (m3->mc_pg[i] == mp && m3->mc_ki[i] >= mc->mc_ki[i]) {
+ if (m3 == mc || m3->mc_snum < mc->mc_snum || m3->mc_pg[i] != mp) continue;
+ if (m3->mc_ki[i] >= mc->mc_ki[i] && insert_key) {
m3->mc_ki[i]++;
}
+ if (m3->mc_xcursor && (m3->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED)) {
+ MDB_node *n2 = NODEPTR(mp, m3->mc_ki[i]);
+ if ((n2->mn_flags & (F_SUBDATA|F_DUPDATA)) == F_DUPDATA)
+ m3->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(n2);
+ }
}
}
}
if (flags & MDB_NODUPDATA) {
/* mdb_cursor_del0() will subtract the final entry */
mc->mc_db->md_entries -= mc->mc_xcursor->mx_db.md_entries - 1;
+ mc->mc_xcursor->mx_cursor.mc_flags &= ~C_INITIALIZED;
} else {
if (!F_ISSET(leaf->mn_flags, F_SUBDATA)) {
mc->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(leaf);
}
}
mc->mc_db->md_entries--;
- mc->mc_flags |= C_DEL;
return rc;
+ } else {
+ mc->mc_xcursor->mx_cursor.mc_flags &= ~C_INITIALIZED;
}
/* otherwise fall thru and delete the sub-DB */
}
static void
mdb_cursor_copy(const MDB_cursor *csrc, MDB_cursor *cdst);
-/** Track a temporary cursor */
-#define CURSOR_TMP_TRACK(mc, mn, dummy, tracked) \
- if (mc->mc_flags & C_SUB) { \
+/** Perform \b act while tracking temporary cursor \b mn */
+#define WITH_CURSOR_TRACKING(mn, act) do { \
+ MDB_cursor dummy, *tracked, **tp = &(mn).mc_txn->mt_cursors[mn.mc_dbi]; \
+ if ((mn).mc_flags & C_SUB) { \
dummy.mc_flags = C_INITIALIZED; \
- dummy.mc_xcursor = (MDB_xcursor *)&mn; \
+ dummy.mc_xcursor = (MDB_xcursor *)&(mn); \
tracked = &dummy; \
} else { \
- tracked = &mn; \
+ tracked = &(mn); \
} \
- tracked->mc_next = mc->mc_txn->mt_cursors[mc->mc_dbi]; \
- mc->mc_txn->mt_cursors[mc->mc_dbi] = tracked
-
-/** Stop tracking a temporary cursor */
-#define CURSOR_TMP_UNTRACK(mc, tracked) \
- mc->mc_txn->mt_cursors[mc->mc_dbi] = tracked->mc_next
+ tracked->mc_next = *tp; \
+ *tp = tracked; \
+ { act; } \
+ *tp = tracked->mc_next; \
+} while (0)
/** Move a node from csrc to cdst.
*/
data.mv_size = NODEDSZ(srcnode);
data.mv_data = NODEDATA(srcnode);
}
+ mn.mc_xcursor = NULL;
if (IS_BRANCH(cdst->mc_pg[cdst->mc_top]) && cdst->mc_ki[cdst->mc_top] == 0) {
unsigned int snum = cdst->mc_snum;
MDB_node *s2;
m3->mc_ki[csrc->mc_top] = cdst->mc_ki[cdst->mc_top];
m3->mc_ki[csrc->mc_top-1]++;
}
+ if (m3->mc_xcursor && (m3->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) &&
+ IS_LEAF(mps)) {
+ MDB_node *node = NODEPTR(m3->mc_pg[csrc->mc_top], m3->mc_ki[csrc->mc_top]);
+ if ((node->mn_flags & (F_DUPDATA|F_SUBDATA)) == F_DUPDATA)
+ m3->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(node);
+ }
}
} else
/* Adding on the right, bump others down */
} else {
m3->mc_ki[csrc->mc_top]--;
}
+ if (m3->mc_xcursor && (m3->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) &&
+ IS_LEAF(mps)) {
+ MDB_node *node = NODEPTR(m3->mc_pg[csrc->mc_top], m3->mc_ki[csrc->mc_top]);
+ if ((node->mn_flags & (F_DUPDATA|F_SUBDATA)) == F_DUPDATA)
+ m3->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(node);
+ }
}
}
}
*/
if (csrc->mc_ki[csrc->mc_top] == 0) {
if (csrc->mc_ki[csrc->mc_top-1] != 0) {
- MDB_cursor dummy, *tracked;
if (IS_LEAF2(csrc->mc_pg[csrc->mc_top])) {
key.mv_data = LEAF2KEY(csrc->mc_pg[csrc->mc_top], 0, key.mv_size);
} else {
mn.mc_snum--;
mn.mc_top--;
/* We want mdb_rebalance to find mn when doing fixups */
- CURSOR_TMP_TRACK(csrc, mn, dummy, tracked);
- rc = mdb_update_key(&mn, &key);
- CURSOR_TMP_UNTRACK(csrc, tracked);
+ WITH_CURSOR_TRACKING(mn,
+ rc = mdb_update_key(&mn, &key));
if (rc)
return rc;
}
if (cdst->mc_ki[cdst->mc_top] == 0) {
if (cdst->mc_ki[cdst->mc_top-1] != 0) {
- MDB_cursor dummy, *tracked;
if (IS_LEAF2(csrc->mc_pg[csrc->mc_top])) {
key.mv_data = LEAF2KEY(cdst->mc_pg[cdst->mc_top], 0, key.mv_size);
} else {
mn.mc_snum--;
mn.mc_top--;
/* We want mdb_rebalance to find mn when doing fixups */
- CURSOR_TMP_TRACK(cdst, mn, dummy, tracked);
- rc = mdb_update_key(&mn, &key);
- CURSOR_TMP_UNTRACK(cdst, tracked);
+ WITH_CURSOR_TRACKING(mn,
+ rc = mdb_update_key(&mn, &key));
if (rc)
return rc;
}
MDB_cursor mn;
MDB_node *s2;
mdb_cursor_copy(csrc, &mn);
+ mn.mc_xcursor = NULL;
/* must find the lowest key below src */
rc = mdb_page_search_lowest(&mn);
if (rc)
m3->mc_ki[top-1] > csrc->mc_ki[top-1]) {
m3->mc_ki[top-1]--;
}
+ if (m3->mc_xcursor && (m3->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) &&
+ IS_LEAF(psrc)) {
+ MDB_node *node = NODEPTR(m3->mc_pg[top], m3->mc_ki[top]);
+ if ((node->mn_flags & (F_DUPDATA|F_SUBDATA)) == F_DUPDATA)
+ m3->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(node);
+ }
}
}
{
if (!fromleft) {
rc = mdb_page_merge(&mn, mc);
} else {
- MDB_cursor dummy, *tracked;
oldki += NUMKEYS(mn.mc_pg[mn.mc_top]);
mn.mc_ki[mn.mc_top] += mc->mc_ki[mn.mc_top] + 1;
/* We want mdb_rebalance to find mn when doing fixups */
- CURSOR_TMP_TRACK(mc, mn, dummy, tracked);
- rc = mdb_page_merge(mc, &mn);
- CURSOR_TMP_UNTRACK(mc, tracked);
+ WITH_CURSOR_TRACKING(mn,
+ rc = mdb_page_merge(mc, &mn));
mdb_cursor_copy(&mn, mc);
}
mc->mc_flags &= ~C_EOF;
if (m3 == mc || m3->mc_snum < mc->mc_snum)
continue;
if (m3->mc_pg[mc->mc_top] == mp) {
- if (m3->mc_ki[mc->mc_top] >= ki) {
+ if (m3->mc_ki[mc->mc_top] == ki) {
m3->mc_flags |= C_DEL;
- if (m3->mc_ki[mc->mc_top] > ki)
- m3->mc_ki[mc->mc_top]--;
- else if (mc->mc_db->md_flags & MDB_DUPSORT)
+ if (mc->mc_db->md_flags & MDB_DUPSORT)
m3->mc_xcursor->mx_cursor.mc_flags &= ~C_INITIALIZED;
+ } else if (m3->mc_ki[mc->mc_top] > ki) {
+ m3->mc_ki[mc->mc_top]--;
+ }
+ if (m3->mc_xcursor && (m3->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED)) {
+ MDB_node *node = NODEPTR(m3->mc_pg[mc->mc_top], m3->mc_ki[mc->mc_top]);
+ if ((node->mn_flags & (F_DUPDATA|F_SUBDATA)) == F_DUPDATA)
+ m3->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(node);
}
}
}
}
mdb_cursor_copy(mc, &mn);
+ mn.mc_xcursor = NULL;
mn.mc_pg[mn.mc_top] = rp;
mn.mc_ki[ptop] = mc->mc_ki[ptop]+1;
*/
if (SIZELEFT(mn.mc_pg[ptop]) < mdb_branch_size(env, &sepkey)) {
int snum = mc->mc_snum;
- MDB_cursor dummy, *tracked;
mn.mc_snum--;
mn.mc_top--;
did_split = 1;
/* We want other splits to find mn when doing fixups */
- CURSOR_TMP_TRACK(mc, mn, dummy, tracked);
- rc = mdb_page_split(&mn, &sepkey, NULL, rp->mp_pgno, 0);
- CURSOR_TMP_UNTRACK(mc, tracked);
+ WITH_CURSOR_TRACKING(mn,
+ rc = mdb_page_split(&mn, &sepkey, NULL, rp->mp_pgno, 0));
if (rc)
goto done;
m3->mc_ki[k+1] = m3->mc_ki[k];
m3->mc_pg[k+1] = m3->mc_pg[k];
}
- if (m3->mc_ki[0] > nkeys) {
+ if (m3->mc_ki[0] >= nkeys) {
m3->mc_ki[0] = 1;
} else {
m3->mc_ki[0] = 0;
m3->mc_ki[ptop] >= mc->mc_ki[ptop]) {
m3->mc_ki[ptop]++;
}
+ if (m3->mc_xcursor && (m3->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) &&
+ IS_LEAF(mp)) {
+ MDB_node *node = NODEPTR(m3->mc_pg[mc->mc_top], m3->mc_ki[mc->mc_top]);
+ if ((node->mn_flags & (F_DUPDATA|F_SUBDATA)) == F_DUPDATA)
+ m3->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(node);
+ }
}
}
DPRINTF(("mp left: %d, rp left: %d", SIZELEFT(mp), SIZELEFT(rp)));
{
MDB_cursor mc;
MDB_xcursor mx;
+ int rc;
if (!key || !data || !TXN_DBI_EXIST(txn, dbi, DB_USRVALID))
return EINVAL;
return (txn->mt_flags & MDB_TXN_RDONLY) ? EACCES : MDB_BAD_TXN;
mdb_cursor_init(&mc, txn, dbi, &mx);
- return mdb_cursor_put(&mc, key, data, flags);
+ mc.mc_next = txn->mt_cursors[dbi];
+ txn->mt_cursors[dbi] = &mc;
+ rc = mdb_cursor_put(&mc, key, data, flags);
+ txn->mt_cursors[dbi] = mc.mc_next;
+ return rc;
}
#ifndef MDB_WBUF
MDB_txn *txn = NULL;
mdb_mutexref_t wmutex = NULL;
int rc;
- size_t wsize;
+ size_t wsize, w3;
char *ptr;
#ifdef _WIN32
DWORD len, w2;
if (rc)
goto leave;
- w2 = txn->mt_next_pgno * env->me_psize;
+ w3 = txn->mt_next_pgno * env->me_psize;
{
size_t fsize = 0;
if ((rc = mdb_fsize(env->me_fd, &fsize)))
goto leave;
- if (w2 > fsize)
- w2 = fsize;
+ if (w3 > fsize)
+ w3 = fsize;
}
- wsize = w2 - wsize;
+ wsize = w3 - wsize;
while (wsize > 0) {
if (wsize > MAX_WRITE)
w2 = MAX_WRITE;
* already in the OS cache.
*/
#ifdef _WIN32
- utf8_to_utf16(lpath, -1, &wpath, NULL);
+ rc = utf8_to_utf16(lpath, -1, &wpath, NULL);
+ if (rc)
+ goto leave;
newfd = CreateFileW(wpath, GENERIC_WRITE, 0, NULL, CREATE_NEW,
FILE_FLAG_NO_BUFFERING|FILE_FLAG_WRITE_THROUGH, NULL);
free(wpath);
MDB_db dummy;
int rc, dbflag, exact;
unsigned int unused = 0, seq;
+ char *namedup;
size_t len;
if (flags & ~VALID_FLAGS)
MDB_node *node = NODEPTR(mc.mc_pg[mc.mc_top], mc.mc_ki[mc.mc_top]);
if ((node->mn_flags & (F_DUPDATA|F_SUBDATA)) != F_SUBDATA)
return MDB_INCOMPATIBLE;
- } else if (rc == MDB_NOTFOUND && (flags & MDB_CREATE)) {
- /* Create if requested */
+ } else if (! (rc == MDB_NOTFOUND && (flags & MDB_CREATE))) {
+ return rc;
+ }
+
+ /* Done here so we cannot fail after creating a new DB */
+ if ((namedup = strdup(name)) == NULL)
+ return ENOMEM;
+
+ if (rc) {
+ /* MDB_NOTFOUND and MDB_CREATE: Create new DB */
data.mv_size = sizeof(MDB_db);
data.mv_data = &dummy;
memset(&dummy, 0, sizeof(dummy));
dbflag |= DB_DIRTY;
}
- /* OK, got info, add to table */
- if (rc == MDB_SUCCESS) {
+ if (rc) {
+ free(namedup);
+ } else {
+ /* Got info, register DBI in this txn */
unsigned int slot = unused ? unused : txn->mt_numdbs;
- txn->mt_dbxs[slot].md_name.mv_data = strdup(name);
+ txn->mt_dbxs[slot].md_name.mv_data = namedup;
txn->mt_dbxs[slot].md_name.mv_size = len;
txn->mt_dbxs[slot].md_rel = NULL;
txn->mt_dbflags[slot] = dbflag;
/* DUPSORT sub-DBs have no ovpages/DBs. Omit scanning leaves.
* This also avoids any P_LEAF2 pages, which have no nodes.
+ * Also if the DB doesn't have sub-DBs and has no overflow
+ * pages, omit scanning leaves.
*/
- if (mc->mc_flags & C_SUB)
+ if ((mc->mc_flags & C_SUB) ||
+ (!subs && !mc->mc_db->md_overflow_pages))
mdb_cursor_pop(mc);
mdb_cursor_copy(mc, &mx);
pg, omp->mp_pages);
if (rc)
goto done;
+ mc->mc_db->md_overflow_pages -= omp->mp_pages;
+ if (!mc->mc_db->md_overflow_pages && !subs)
+ break;
} else if (subs && (ni->mn_flags & F_SUBDATA)) {
mdb_xcursor_init1(mc, ni);
rc = mdb_drop0(&mc->mc_xcursor->mx_cursor, 0);
goto done;
}
}
+ if (!subs && !mc->mc_db->md_overflow_pages)
+ goto pop;
} else {
if ((rc = mdb_midl_need(&txn->mt_free_pgs, n)) != 0)
goto done;
/* no more siblings, go back to beginning
* of previous level.
*/
+pop:
mdb_cursor_pop(mc);
mc->mc_ki[0] = 0;
for (i=1; i<mc->mc_snum; i++) {
} else if (rc == MDB_NOTFOUND) {
rc = MDB_SUCCESS;
}
+ mc->mc_flags &= ~C_INITIALIZED;
return rc;
}
if (need == 0)
return EINVAL;
result = malloc(sizeof(wchar_t) * need);
+ if (!result)
+ return ENOMEM;
MultiByteToWideChar(CP_UTF8, 0, src, srcsize, result, need);
if (dstsize)
*dstsize = need;