#define DB_STALE 0x02 /**< Named-DB record is older than txnID */
#define DB_NEW 0x04 /**< Named-DB handle opened in this txn */
#define DB_VALID 0x08 /**< DB handle is valid, see also #MDB_VALID */
+#define DB_USRVALID 0x10 /**< As #DB_VALID, but not set for #FREE_DBI */
/** @} */
/** In write txns, array of cursors for each DB */
MDB_cursor **mt_cursors;
#define MAX_WRITE (0x80000000U >> (sizeof(ssize_t) == 4))
/** Check \b txn and \b dbi arguments to a function */
-#define TXN_DBI_EXIST(txn, dbi) \
- ((txn) && (dbi) < (txn)->mt_numdbs && ((txn)->mt_dbflags[dbi] & DB_VALID))
+#define TXN_DBI_EXIST(txn, dbi, validity) \
+ ((txn) && (dbi)<(txn)->mt_numdbs && ((txn)->mt_dbflags[dbi] & (validity)))
/** Check for misused \b dbi handles */
#define TXN_DBI_CHANGED(txn, dbi) \
for (i=2; i<txn->mt_numdbs; i++) {
x = env->me_dbflags[i];
txn->mt_dbs[i].md_flags = x & PERSISTENT_FLAGS;
- txn->mt_dbflags[i] = (x & MDB_VALID) ? DB_VALID|DB_STALE : 0;
+ txn->mt_dbflags[i] = (x & MDB_VALID) ? DB_VALID|DB_USRVALID|DB_STALE : 0;
}
- txn->mt_dbflags[0] = txn->mt_dbflags[1] = DB_VALID;
+ txn->mt_dbflags[MAIN_DBI] = DB_VALID|DB_USRVALID;
+ txn->mt_dbflags[FREE_DBI] = DB_VALID;
if (env->me_maxpg < txn->mt_next_pgno) {
mdb_txn_reset0(txn, "renew0-mapfail");
unsigned int i;
MDB_env *env;
- if (txn == NULL || txn->mt_env == NULL)
+ if (txn == NULL)
return EINVAL;
if (txn->mt_child) {
rc = mdb_txn_commit(txn->mt_child);
- txn->mt_child = NULL;
if (rc)
goto fail;
}
mdb_cursor_pop(MDB_cursor *mc)
{
if (mc->mc_snum) {
-#if MDB_DEBUG
- MDB_page *top = mc->mc_pg[mc->mc_top];
-#endif
+ DPRINTF(("popping page %"Z"u off db %d cursor %p",
+ mc->mc_pg[mc->mc_top]->mp_pgno, DDBI(mc), (void *) mc));
+
mc->mc_snum--;
if (mc->mc_snum)
mc->mc_top--;
-
- DPRINTF(("popped page %"Z"u off db %d cursor %p", top->mp_pgno,
- DDBI(mc), (void *) mc));
}
}
DPRINTF(("===> get db %u key [%s]", dbi, DKEY(key)));
- if (!key || !data || dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi))
+ if (!key || !data || !TXN_DBI_EXIST(txn, dbi, DB_USRVALID))
return EINVAL;
if (txn->mt_flags & MDB_TXN_ERROR)
MDB_node *node;
MDB_page *sp, *xp;
char *base;
- int nsize, delta;
- indx_t i, numkeys, ptr;
+ indx_t delta, nsize, len, ptr;
+ int i;
node = NODEPTR(mp, indx);
sp = (MDB_page *)NODEDATA(node);
delta = SIZELEFT(sp);
- xp = (MDB_page *)((char *)sp + delta);
+ nsize = NODEDSZ(node) - delta;
- /* shift subpage upward */
+ /* Prepare to shift upward, set len = length(subpage part to shift) */
if (IS_LEAF2(sp)) {
- nsize = NUMKEYS(sp) * sp->mp_pad;
+ len = nsize;
if (nsize & 1)
return; /* do not make the node uneven-sized */
- memmove(METADATA(xp), METADATA(sp), nsize);
} else {
- int i;
- numkeys = NUMKEYS(sp);
- for (i=numkeys-1; i>=0; i--)
+ xp = (MDB_page *)((char *)sp + delta); /* destination subpage */
+ for (i = NUMKEYS(sp); --i >= 0; )
xp->mp_ptrs[i] = sp->mp_ptrs[i] - delta;
+ len = PAGEHDRSZ;
}
- xp->mp_upper = sp->mp_lower;
- xp->mp_lower = sp->mp_lower;
- xp->mp_flags = sp->mp_flags;
- xp->mp_pad = sp->mp_pad;
- COPY_PGNO(xp->mp_pgno, mp->mp_pgno);
-
- nsize = NODEDSZ(node) - delta;
+ sp->mp_upper = sp->mp_lower;
+ COPY_PGNO(sp->mp_pgno, mp->mp_pgno);
SETDSZ(node, nsize);
- /* shift lower nodes upward */
+ /* Shift <lower nodes...initial part of subpage> upward */
+ base = (char *)mp + mp->mp_upper + PAGEBASE;
+ memmove(base + delta, base, (char *)sp + len - base);
+
ptr = mp->mp_ptrs[indx];
- numkeys = NUMKEYS(mp);
- for (i = 0; i < numkeys; i++) {
+ for (i = NUMKEYS(mp); --i >= 0; ) {
if (mp->mp_ptrs[i] <= ptr)
mp->mp_ptrs[i] += delta;
}
-
- base = (char *)mp + mp->mp_upper + PAGEBASE;
- memmove(base + delta, base, ptr - mp->mp_upper + NODESIZE + NODEKSZ(node));
mp->mp_upper += delta;
}
}
DPRINTF(("Sub-db -%u root page %"Z"u", mx->mx_cursor.mc_dbi,
mx->mx_db.md_root));
- mx->mx_dbflag = DB_VALID|DB_DIRTY; /* DB_DIRTY guides mdb_cursor_touch */
+ mx->mx_dbflag = DB_VALID|DB_USRVALID|DB_DIRTY; /* DB_DIRTY guides mdb_cursor_touch */
#if UINT_MAX < SIZE_MAX
if (mx->mx_dbx.md_cmp == mdb_cmp_int && mx->mx_db.md_pad == sizeof(size_t))
mx->mx_dbx.md_cmp = mdb_cmp_clong;
MDB_cursor *mc;
size_t size = sizeof(MDB_cursor);
- if (!ret || !TXN_DBI_EXIST(txn, dbi))
+ if (!ret || !TXN_DBI_EXIST(txn, dbi, DB_VALID))
return EINVAL;
if (txn->mt_flags & MDB_TXN_ERROR)
int
mdb_cursor_renew(MDB_txn *txn, MDB_cursor *mc)
{
- if (!mc || !TXN_DBI_EXIST(txn, mc->mc_dbi))
+ if (!mc || !TXN_DBI_EXIST(txn, mc->mc_dbi, DB_VALID))
return EINVAL;
if ((mc->mc_flags & C_UNTRACK) || txn->mt_cursors)
mdb_del(MDB_txn *txn, MDB_dbi dbi,
MDB_val *key, MDB_val *data)
{
- if (!key || dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi))
+ if (!key || !TXN_DBI_EXIST(txn, dbi, DB_USRVALID))
return EINVAL;
if (txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_ERROR))
MDB_cursor mc;
MDB_xcursor mx;
- if (!key || !data || dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi))
+ if (!key || !data || !TXN_DBI_EXIST(txn, dbi, DB_USRVALID))
return EINVAL;
- if ((flags & (MDB_NOOVERWRITE|MDB_NODUPDATA|MDB_RESERVE|MDB_APPEND|MDB_APPENDDUP)) != flags)
+ if (flags & ~(MDB_NOOVERWRITE|MDB_NODUPDATA|MDB_RESERVE|MDB_APPEND|MDB_APPENDDUP))
return EINVAL;
mdb_cursor_init(&mc, txn, dbi, &mx);
int ESECT
mdb_env_set_flags(MDB_env *env, unsigned int flag, int onoff)
{
- if ((flag & CHANGEABLE) != flag)
+ if (flag & ~CHANGEABLE)
return EINVAL;
if (onoff)
env->me_flags |= flag;
unsigned int unused = 0, seq;
size_t len;
- if ((flags & VALID_FLAGS) != flags)
+ if (flags & ~VALID_FLAGS)
return EINVAL;
if (txn->mt_flags & MDB_TXN_ERROR)
return MDB_BAD_TXN;
return (flags & MDB_CREATE) ? MDB_INCOMPATIBLE : MDB_NOTFOUND;
/* Find the DB info */
- dbflag = DB_NEW|DB_VALID;
+ dbflag = DB_NEW|DB_VALID|DB_USRVALID;
exact = 0;
key.mv_size = len;
key.mv_data = (void *)name;
int mdb_stat(MDB_txn *txn, MDB_dbi dbi, MDB_stat *arg)
{
- if (!arg || !TXN_DBI_EXIST(txn, dbi))
+ if (!arg || !TXN_DBI_EXIST(txn, dbi, DB_VALID))
return EINVAL;
if (txn->mt_flags & MDB_TXN_ERROR)
int mdb_dbi_flags(MDB_txn *txn, MDB_dbi dbi, unsigned int *flags)
{
/* We could return the flags for the FREE_DBI too but what's the point? */
- if (dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi))
+ if (!TXN_DBI_EXIST(txn, dbi, DB_USRVALID))
return EINVAL;
*flags = txn->mt_dbs[dbi].md_flags & PERSISTENT_FLAGS;
return MDB_SUCCESS;
MDB_cursor *mc, *m2;
int rc;
- if ((unsigned)del > 1 || dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi))
+ if ((unsigned)del > 1 || !TXN_DBI_EXIST(txn, dbi, DB_USRVALID))
return EINVAL;
if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY))
return EACCES;
- if (dbi > MAIN_DBI && TXN_DBI_CHANGED(txn, dbi))
+ if (TXN_DBI_CHANGED(txn, dbi))
return MDB_BAD_DBI;
rc = mdb_cursor_open(txn, dbi, &mc);
int mdb_set_compare(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp)
{
- if (dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi))
+ if (!TXN_DBI_EXIST(txn, dbi, DB_USRVALID))
return EINVAL;
txn->mt_dbxs[dbi].md_cmp = cmp;
int mdb_set_dupsort(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp)
{
- if (dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi))
+ if (!TXN_DBI_EXIST(txn, dbi, DB_USRVALID))
return EINVAL;
txn->mt_dbxs[dbi].md_dcmp = cmp;
int mdb_set_relfunc(MDB_txn *txn, MDB_dbi dbi, MDB_rel_func *rel)
{
- if (dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi))
+ if (!TXN_DBI_EXIST(txn, dbi, DB_USRVALID))
return EINVAL;
txn->mt_dbxs[dbi].md_rel = rel;
int mdb_set_relctx(MDB_txn *txn, MDB_dbi dbi, void *ctx)
{
- if (dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi))
+ if (!TXN_DBI_EXIST(txn, dbi, DB_USRVALID))
return EINVAL;
txn->mt_dbxs[dbi].md_relctx = ctx;