if (!mop) {
if (!(env->me_pghead = mop = mdb_midl_alloc(i)))
return ENOMEM;
- } else if (mop_len+i > mop[-1]) {
- if ((rc = mdb_midl_grow(&env->me_pghead, i)) != 0)
+ } else {
+ if ((rc = mdb_midl_need(&env->me_pghead, i)) != 0)
return rc;
mop = env->me_pghead;
}
int rc;
if (!F_ISSET(mp->mp_flags, P_DIRTY)) {
- if ((rc = mdb_page_alloc(mc, 1, &np)))
+ if ((rc = mdb_midl_need(&txn->mt_free_pgs, 1)) ||
+ (rc = mdb_page_alloc(mc, 1, &np)))
return rc;
pgno = np->mp_pgno;
DPRINTF("touched db %u page %zu -> %zu", mc->mc_dbi,mp->mp_pgno,pgno);
assert(mp->mp_pgno != pgno);
- mdb_midl_append(&txn->mt_free_pgs, mp->mp_pgno);
+ mdb_midl_xappend(txn->mt_free_pgs, mp->mp_pgno);
/* Update the parent page, if any, to point to the new page */
if (mc->mc_top) {
MDB_page *parent = mc->mc_pg[mc->mc_top-1];
*/
if ((mp->mp_flags & P_DIRTY) && !txn->mt_parent && txn->mt_env->me_pghead) {
unsigned j, x;
- pgno_t *mop = txn->mt_env->me_pghead;
+ pgno_t *mop;
MDB_ID2 *dl, ix, iy;
- /* Prepare to insert pg */
- j = mop[0] + ovpages;
- if (j > mop[-1]) {
- rc = mdb_midl_grow(&mop, ovpages);
- if (rc)
- return rc;
- txn->mt_env->me_pghead = mop;
- }
+ rc = mdb_midl_need(&txn->mt_env->me_pghead, ovpages);
+ if (rc)
+ return rc;
/* Remove from dirty list */
dl = txn->mt_u.dirty_list;
x = dl[0].mid--;
}
}
/* Insert in me_pghead */
+ mop = txn->mt_env->me_pghead;
+ j = mop[0] + ovpages;
for (i = mop[0]; i && mop[i] < pg; i--)
mop[j--] = mop[i];
while (j>i)
mop[j--] = pg++;
mop[0] += ovpages;
} else {
- for (i=0; i<ovpages; i++) {
- mdb_midl_append(&txn->mt_free_pgs, pg);
- pg++;
- }
+ rc = mdb_midl_append_range(&txn->mt_free_pgs, pg, ovpages);
+ if (rc)
+ return rc;
}
mc->mc_db->md_overflow_pages -= ovpages;
return 0;
memcpy(METADATA(omp), data->mv_data, data->mv_size);
goto done;
} else {
- mdb_ovpage_free(mc, omp);
+ if ((rc2 = mdb_ovpage_free(mc, omp)) != MDB_SUCCESS)
+ return rc2;
}
} else if (NODEDSZ(leaf) == data->mv_size) {
/* same size, just replace it. Note that we could
return rc;
}
- mdb_midl_append(&csrc->mc_txn->mt_free_pgs, csrc->mc_pg[csrc->mc_top]->mp_pgno);
+ rc = mdb_midl_append(&csrc->mc_txn->mt_free_pgs,
+ csrc->mc_pg[csrc->mc_top]->mp_pgno);
+ if (rc)
+ return rc;
if (IS_LEAF(csrc->mc_pg[csrc->mc_top]))
csrc->mc_db->md_leaf_pages--;
else
mc->mc_db->md_root = P_INVALID;
mc->mc_db->md_depth = 0;
mc->mc_db->md_leaf_pages = 0;
- mdb_midl_append(&mc->mc_txn->mt_free_pgs, mp->mp_pgno);
+ rc = mdb_midl_append(&mc->mc_txn->mt_free_pgs, mp->mp_pgno);
+ if (rc)
+ return rc;
/* Adjust cursors pointing to mp */
mc->mc_snum = 0;
mc->mc_top = 0;
}
} else if (IS_BRANCH(mp) && NUMKEYS(mp) == 1) {
DPUTS("collapsing root page!");
- mdb_midl_append(&mc->mc_txn->mt_free_pgs, mp->mp_pgno);
+ rc = mdb_midl_append(&mc->mc_txn->mt_free_pgs, mp->mp_pgno);
+ if (rc)
+ return rc;
mc->mc_db->md_root = NODEPGNO(NODEPTR(mp, 0));
rc = mdb_page_get(mc->mc_txn,mc->mc_db->md_root,&mc->mc_pg[0],NULL);
if (rc)
pgno_t pg;
memcpy(&pg, NODEDATA(leaf), sizeof(pg));
- if ((rc = mdb_page_get(mc->mc_txn, pg, &omp, NULL)) != 0)
+ if ((rc = mdb_page_get(mc->mc_txn, pg, &omp, NULL)) ||
+ (rc = mdb_ovpage_free(mc, omp)))
return rc;
- assert(IS_OVERFLOW(omp));
- mdb_ovpage_free(mc, omp);
}
mdb_node_del(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top], mc->mc_db->md_pad);
mc->mc_db->md_entries--;
for (i=0; i<n; i++) {
ni = NODEPTR(mp, i);
if (ni->mn_flags & F_BIGDATA) {
- int j, ovpages;
MDB_page *omp;
pgno_t pg;
memcpy(&pg, NODEDATA(ni), sizeof(pg));
if (rc != 0)
return rc;
assert(IS_OVERFLOW(omp));
- ovpages = omp->mp_pages;
- for (j=0; j<ovpages; j++) {
- mdb_midl_append(&txn->mt_free_pgs, pg);
- pg++;
- }
+ rc = mdb_midl_append_range(&txn->mt_free_pgs,
+ pg, omp->mp_pages);
+ if (rc)
+ return rc;
} else if (subs && (ni->mn_flags & F_SUBDATA)) {
mdb_xcursor_init1(mc, ni);
rc = mdb_drop0(&mc->mc_xcursor->mx_cursor, 0);
}
}
} else {
+ if ((rc = mdb_midl_need(&txn->mt_free_pgs, n)) != 0)
+ return rc;
for (i=0; i<n; i++) {
pgno_t pg;
ni = NODEPTR(mp, i);
pg = NODEPGNO(ni);
/* free it */
- mdb_midl_append(&txn->mt_free_pgs, pg);
+ mdb_midl_xappend(txn->mt_free_pgs, pg);
}
}
if (!mc->mc_top)
}
}
/* free it */
- mdb_midl_append(&txn->mt_free_pgs, mc->mc_db->md_root);
+ rc = mdb_midl_append(&txn->mt_free_pgs, mc->mc_db->md_root);
+ } else if (rc == MDB_NOTFOUND) {
+ rc = MDB_SUCCESS;
}
- return 0;
+ return rc;
}
int mdb_drop(MDB_txn *txn, MDB_dbi dbi, int del)
int mdb_midl_shrink( MDB_IDL *idp )
{
MDB_IDL ids = *idp;
- if (*(--ids) > MDB_IDL_UM_MAX) {
- ids = realloc(ids, (MDB_IDL_UM_MAX+1) * sizeof(MDB_ID));
+ if (*(--ids) > MDB_IDL_UM_MAX &&
+ (ids = realloc(ids, (MDB_IDL_UM_MAX+1) * sizeof(MDB_ID))))
+ {
*ids++ = MDB_IDL_UM_MAX;
*idp = ids;
return 1;
return 0;
}
-int mdb_midl_grow( MDB_IDL *idp, int num )
+static int mdb_midl_grow( MDB_IDL *idp, int num )
{
MDB_IDL idn = *idp-1;
/* grow it */
return 0;
}
+int mdb_midl_need( MDB_IDL *idp, unsigned num )
+{
+ MDB_IDL ids = *idp;
+ num += ids[0];
+ if (num > ids[-1]) {
+ num = (num + num/4 + (256 + 2)) & -256;
+ if (!(ids = realloc(ids-1, num * sizeof(MDB_ID))))
+ return ENOMEM;
+ *ids++ += num -= 2;
+ *idp = ids;
+ }
+ return 0;
+}
+
int mdb_midl_append( MDB_IDL *idp, MDB_ID id )
{
MDB_IDL ids = *idp;
return 0;
}
+int mdb_midl_append_range( MDB_IDL *idp, MDB_ID id, unsigned n )
+{
+ MDB_ID *ids = *idp, len = ids[0];
+ /* Too big? */
+ if (len + n > ids[-1]) {
+ if (mdb_midl_grow(idp, n | MDB_IDL_UM_MAX))
+ return ENOMEM;
+ ids = *idp;
+ }
+ ids[0] = len + n;
+ ids += len;
+ while (n)
+ ids[n--] = id++;
+ return 0;
+}
+
/* Quicksort + Insertion sort for small arrays */
#define SMALL 8
#define MDB_IDL_FIRST( ids ) ( (ids)[1] )
#define MDB_IDL_LAST( ids ) ( (ids)[(ids)[0]] )
+ /** Append ID to IDL. The IDL must be big enough. */
+#define mdb_midl_xappend(idl, id) do { \
+ MDB_ID *xidl = (idl), xlen = ++(xidl[0]); \
+ xidl[xlen] = (id); \
+ } while (0)
+
#if 0 /* superseded by append/sort */
/** Insert an ID into an IDL.
* @param[in,out] ids The IDL to insert into.
*/
int mdb_midl_shrink(MDB_IDL *idp);
- /** Grow an IDL.
- * Add room for num additional elements.
- * @param[in,out] idp Address of the IDL to grow.
- * @param[in] num Number of elements to add.
- * @return 0 on success, -1 on failure.
+ /** Make room for num additional elements in an IDL.
+ * @param[in,out] idp Address of the IDL.
+ * @param[in] num Number of elements to make room for.
+ * @return 0 on success, ENOMEM on failure.
*/
-int mdb_midl_grow(MDB_IDL *idp, int num);
+int mdb_midl_need(MDB_IDL *idp, unsigned num);
/** Append an ID onto an IDL.
* @param[in,out] idp Address of the IDL to append to.
* @param[in] id The ID to append.
- * @return 0 on success, -1 if the IDL is too large.
+ * @return 0 on success, ENOMEM if the IDL is too large.
*/
int mdb_midl_append( MDB_IDL *idp, MDB_ID id );
/** Append an IDL onto an IDL.
* @param[in,out] idp Address of the IDL to append to.
* @param[in] app The IDL to append.
- * @return 0 on success, -1 if the IDL is too large.
+ * @return 0 on success, ENOMEM if the IDL is too large.
*/
int mdb_midl_append_list( MDB_IDL *idp, MDB_IDL app );
+ /** Append an ID range onto an IDL.
+ * @param[in,out] idp Address of the IDL to append to.
+ * @param[in] id The lowest ID to append.
+ * @param[in] n Number of IDs to append.
+ * @return 0 on success, ENOMEM if the IDL is too large.
+ */
+int mdb_midl_append_range( MDB_IDL *idp, MDB_ID id, unsigned n );
+
/** Sort an IDL.
* @param[in,out] ids The IDL to sort.
*/