}
#endif
+#if MDB_DEBUG > 2
+/** Count all the pages in each DB and in the freelist
+ * and make sure it matches the actual number of pages
+ * being used.
+ */
+static void mdb_audit(MDB_txn *txn)
+{
+ MDB_cursor mc;
+ MDB_val key, data;
+ int rc, i;
+ ID freecount, count;
+
+ freecount = 0;
+ mdb_cursor_init(&mc, txn, FREE_DBI, NULL);
+ while ((rc = mdb_cursor_get(&mc, &key, &data, MDB_NEXT)) == 0)
+ freecount += *(ID *)data.mv_data;
+ freecount += txn->mt_dbs[0].md_branch_pages + txn->mt_dbs[0].md_leaf_pages +
+ txn->mt_dbs[0].md_overflow_pages;
+
+ count = 0;
+ for (i = 0; i<txn->mt_numdbs; i++) {
+ count += txn->mt_dbs[i].md_branch_pages +
+ txn->mt_dbs[i].md_leaf_pages +
+ txn->mt_dbs[i].md_overflow_pages;
+ if (txn->mt_dbs[i].md_flags & MDB_DUPSORT) {
+ MDB_xcursor mx;
+ mdb_cursor_init(&mc, txn, i, &mx);
+ mdb_page_search(&mc, NULL, 0);
+ do {
+ int j;
+ MDB_page *mp;
+ mp = mc.mc_pg[mc.mc_top];
+ for (j=0; j<NUMKEYS(mp); j++) {
+ MDB_node *leaf = NODEPTR(mp, j);
+ if (leaf->mn_flags & F_SUBDATA) {
+ MDB_db db;
+ memcpy(&db, NODEDATA(leaf), sizeof(db));
+ count += db.md_branch_pages + db.md_leaf_pages +
+ db.md_overflow_pages;
+ }
+ }
+ }
+ while (mdb_cursor_sibling(&mc, 1) == 0);
+ }
+ }
+ assert(freecount + count + 2 >= txn->mt_next_pgno - 1);
+}
+#endif
+
int
mdb_cmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b)
{
}
}
#endif
- if (mop->mo_txnid == 87869 && txn->mt_txnid == 87879) {
- int i=1;
- }
}
}
none:
off_t size;
MDB_page *dp;
MDB_env *env;
- pgno_t next;
+ pgno_t next, freecnt;
MDB_cursor mc;
assert(txn != NULL);
}
/* save to free list */
+ freecnt = txn->mt_free_pgs[0];
if (!MDB_IDL_IS_ZERO(txn->mt_free_pgs)) {
MDB_val key, data;
- pgno_t i;
/* make sure last page of freeDB is touched and on freelist */
key.mv_size = MAXKEYSIZE+1;
* and make sure the entire thing got written.
*/
do {
- i = txn->mt_free_pgs[0];
+ freecnt = txn->mt_free_pgs[0];
data.mv_size = MDB_IDL_SIZEOF(txn->mt_free_pgs);
rc = mdb_cursor_put(&mc, &key, &data, 0);
if (rc) {
mdb_txn_abort(txn);
return rc;
}
- } while (i != txn->mt_free_pgs[0]);
+ } while (freecnt != txn->mt_free_pgs[0]);
if (mdb_midl_shrink(&txn->mt_free_pgs))
env->me_free_pgs = txn->mt_free_pgs;
}
/* should only be one record now */
+again:
if (env->me_pghead) {
MDB_val key, data;
MDB_oldpages *mop;
pgno_t orig;
+ txnid_t id;
mop = env->me_pghead;
- key.mv_size = sizeof(pgno_t);
- key.mv_data = &mop->mo_txnid;
+ id = mop->mo_txnid;
+ key.mv_size = sizeof(id);
+ key.mv_data = &id;
data.mv_size = MDB_IDL_SIZEOF(mop->mo_pages);
data.mv_data = mop->mo_pages;
orig = mop->mo_pages[0];
mdb_cursor_put(&mc, &key, &data, 0);
- /* could have been used again here */
- if (mop->mo_pages[0] != orig) {
- data.mv_size = MDB_IDL_SIZEOF(mop->mo_pages);
- data.mv_data = mop->mo_pages;
- mdb_cursor_put(&mc, &key, &data, 0);
- env->me_pgfirst = 0;
- env->me_pglast = 0;
+ if (mop == env->me_pghead) {
+ /* could have been used again here */
+ if (mop->mo_pages[0] != orig) {
+ data.mv_size = MDB_IDL_SIZEOF(mop->mo_pages);
+ data.mv_data = mop->mo_pages;
+ id = mop->mo_txnid;
+ mdb_cursor_put(&mc, &key, &data, 0);
+ }
+ env->me_pghead = NULL;
+ free(mop);
+ } else {
+ /* was completely used up */
+ mdb_cursor_del(&mc, 0);
+ if (env->me_pghead)
+ goto again;
}
- env->me_pghead = NULL;
- free(mop);
+ env->me_pgfirst = 0;
+ env->me_pglast = 0;
}
/* Update DB root pointers. Their pages have already been
}
}
}
+#if MDB_DEBUG > 2
+ mdb_audit(txn);
+#endif
/* Commit up to MDB_COMMIT_PAGES dirty pages to disk until done.
*/
dp = txn->mt_u.dirty_list[i].mptr;
if (dp->mp_pgno != next) {
if (n) {
- DPRINTF("committing %u dirty pages", n);
rc = writev(env->me_fd, iov, n);
if (rc != size) {
n = ErrCode();
if (n == 0)
break;
- DPRINTF("committing %u dirty pages", n);
rc = writev(env->me_fd, iov, n);
if (rc != size) {
n = ErrCode();
MDB_xcursor *mx = NULL;
size_t size = sizeof(MDB_cursor);
- if (txn == NULL || ret == NULL || !dbi || dbi >= txn->mt_numdbs)
+ if (txn == NULL || ret == NULL || dbi >= txn->mt_numdbs)
+ return EINVAL;
+
+ /* Allow read access to the freelist */
+ if (!dbi && !F_ISSET(txn->mt_flags, MDB_TXN_RDONLY))
return EINVAL;
if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT)
IS_LEAF(mp) ? "leaf" : "branch", mp->mp_pgno,
DKEY(newkey), mc->mc_ki[mc->mc_top]);
+ /* Create a right sibling. */
+ if ((rp = mdb_page_new(mc, mp->mp_flags, 1)) == NULL)
+ return ENOMEM;
+ DPRINTF("new right sibling: page %zu", rp->mp_pgno);
+
if (mc->mc_snum < 2) {
if ((pp = mdb_page_new(mc, P_BRANCH, 1)) == NULL)
return ENOMEM;
DPRINTF("parent branch page is %zu", mc->mc_pg[ptop]->mp_pgno);
}
- /* Create a right sibling. */
- if ((rp = mdb_page_new(mc, mp->mp_flags, 1)) == NULL)
- return ENOMEM;
- DPRINTF("new right sibling: page %zu", rp->mp_pgno);
-
mdb_cursor_copy(mc, &mn);
mn.mc_pg[mn.mc_top] = rp;
mn.mc_ki[ptop] = mc->mc_ki[ptop]+1;