* 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
#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);
#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);
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]));
if (op == MDB_GET_BOTH || rc > 0)
return MDB_NOTFOUND;
rc = 0;
- *data = olddata;
}
+ *data = olddata;
} else {
if (mc->mc_xcursor)
#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;
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);
/* 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++) {
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;