More for mdb_page_loose

Require that the page is dirty in the current txn,
not a parent txn.
incre
Howard Chu 11 years ago
parent 7fe85f5c82
commit a3e5539505
  1. 81
      libraries/liblmdb/mdb.c

@ -899,6 +899,10 @@ struct MDB_txn {
/** The list of pages that became unused during this transaction. /** The list of pages that became unused during this transaction.
*/ */
MDB_IDL mt_free_pgs; MDB_IDL mt_free_pgs;
/** The list of loose pages that became unused and may be reused
* in this transaction.
*/
MDB_page *mt_loose_pgs;
/** The sorted list of dirty pages we temporarily wrote to disk /** The sorted list of dirty pages we temporarily wrote to disk
* because the dirty list was full. page numbers in here are * because the dirty list was full. page numbers in here are
* shifted left by 1, deleted slots have the LSB set. * shifted left by 1, deleted slots have the LSB set.
@ -1022,7 +1026,6 @@ typedef struct MDB_xcursor {
typedef struct MDB_pgstate { typedef struct MDB_pgstate {
pgno_t *mf_pghead; /**< Reclaimed freeDB pages, or NULL before use */ pgno_t *mf_pghead; /**< Reclaimed freeDB pages, or NULL before use */
txnid_t mf_pglast; /**< ID of last used record, or 0 if !mf_pghead */ txnid_t mf_pglast; /**< ID of last used record, or 0 if !mf_pghead */
MDB_page *mf_pgloose; /**< Dirty pages that can be reused */
} MDB_pgstate; } MDB_pgstate;
/** The database environment. */ /** The database environment. */
@ -1059,7 +1062,6 @@ struct MDB_env {
MDB_pgstate me_pgstate; /**< state of old pages from freeDB */ MDB_pgstate me_pgstate; /**< state of old pages from freeDB */
# define me_pglast me_pgstate.mf_pglast # define me_pglast me_pgstate.mf_pglast
# define me_pghead me_pgstate.mf_pghead # define me_pghead me_pgstate.mf_pghead
# define me_pgloose me_pgstate.mf_pgloose
MDB_page *me_dpages; /**< list of malloc'd blocks for re-use */ MDB_page *me_dpages; /**< list of malloc'd blocks for re-use */
/** IDL of pages that became unused in a write txn */ /** IDL of pages that became unused in a write txn */
MDB_IDL me_free_pgs; MDB_IDL me_free_pgs;
@ -1527,21 +1529,58 @@ mdb_dlist_free(MDB_txn *txn)
dl[0].mid = 0; dl[0].mid = 0;
} }
/** Loosen a single page. /** Loosen or free a single page.
* Saves single pages to a list for future reuse * Saves single pages to a list for future reuse
* in this same txn. It has been pulled from the freeDB * in this same txn. It has been pulled from the freeDB
* and already resides on the dirty list, but has been * and already resides on the dirty list, but has been
* deleted. Use these pages first before pulling again * deleted. Use these pages first before pulling again
* from the freeDB. * from the freeDB.
*
* If the page wasn't dirtied in this txn, just add it
* to this txn's free list.
*/ */
static void static int
mdb_page_loose(MDB_env *env, MDB_page *mp) mdb_page_loose(MDB_cursor *mc, MDB_page *mp)
{ {
int loose = 0;
pgno_t pgno = mp->mp_pgno;
if ((mp->mp_flags & P_DIRTY) && mc->mc_dbi != FREE_DBI) {
if (mc->mc_txn->mt_parent) {
MDB_ID2 *dl = mc->mc_txn->mt_u.dirty_list;
/* If txn has a parent, make sure the page is in our
* dirty list.
*/
if (dl[0].mid) {
unsigned x = mdb_mid2l_search(dl, pgno);
if (x <= dl[0].mid && dl[x].mid == pgno) {
if (mp != dl[x].mptr) { /* bad cursor? */
mc->mc_flags &= ~(C_INITIALIZED|C_EOF);
mc->mc_txn->mt_flags |= MDB_TXN_ERROR;
return MDB_CORRUPTED;
}
/* ok, it's ours */
loose = 1;
}
}
} else {
/* no parent txn, so it's just ours */
loose = 1;
}
}
if (loose) {
pgno_t *pp = (pgno_t *)mp->mp_ptrs; pgno_t *pp = (pgno_t *)mp->mp_ptrs;
*pp = mp->mp_pgno; *pp = pgno;
mp->mp_next = env->me_pgloose; mp->mp_next = mc->mc_txn->mt_loose_pgs;
env->me_pgloose = mp; mc->mc_txn->mt_loose_pgs = mp;
mp->mp_flags |= P_LOOSE; mp->mp_flags |= P_LOOSE;
} else {
int rc = mdb_midl_append(&mc->mc_txn->mt_free_pgs, pgno);
if (rc)
return rc;
}
return MDB_SUCCESS;
} }
/** Set or clear P_KEEP in dirty, non-overflow, non-sub pages watched by txn. /** Set or clear P_KEEP in dirty, non-overflow, non-sub pages watched by txn.
@ -1593,7 +1632,7 @@ mdb_pages_xkeep(MDB_cursor *mc, unsigned pflags, int all)
} }
/* Loose pages shouldn't be spilled */ /* Loose pages shouldn't be spilled */
for (dp = txn->mt_env->me_pgloose; dp; dp=dp->mp_next) { for (dp = txn->mt_loose_pgs; dp; dp=dp->mp_next) {
if ((dp->mp_flags & Mask) == pflags) if ((dp->mp_flags & Mask) == pflags)
dp->mp_flags ^= P_KEEP; dp->mp_flags ^= P_KEEP;
} }
@ -1826,10 +1865,10 @@ mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp)
MDB_cursor m2; MDB_cursor m2;
/* If there are any loose pages, just use them */ /* If there are any loose pages, just use them */
if (num == 1 && env->me_pgloose) { if (num == 1 && txn->mt_loose_pgs) {
pgno_t *pp; pgno_t *pp;
np = env->me_pgloose; np = txn->mt_loose_pgs;
env->me_pgloose = np->mp_next; txn->mt_loose_pgs = np->mp_next;
pp = (pgno_t *)np->mp_ptrs; pp = (pgno_t *)np->mp_ptrs;
np->mp_pgno = *pp; np->mp_pgno = *pp;
*mp = np; *mp = np;
@ -2700,8 +2739,8 @@ mdb_freelist_save(MDB_txn *txn)
/* Dispose of loose pages. Usually they will have all /* Dispose of loose pages. Usually they will have all
* been used up by the time we get here. * been used up by the time we get here.
*/ */
if (env->me_pgloose) { if (txn->mt_loose_pgs) {
MDB_page *mp = env->me_pgloose; MDB_page *mp = txn->mt_loose_pgs;
pgno_t *pp; pgno_t *pp;
/* Just return them to freeDB */ /* Just return them to freeDB */
if (env->me_pghead) { if (env->me_pghead) {
@ -2726,7 +2765,7 @@ mdb_freelist_save(MDB_txn *txn)
mp = mp->mp_next; mp = mp->mp_next;
} }
} }
env->me_pgloose = NULL; txn->mt_loose_pgs = NULL;
} }
/* MDB_RESERVE cancels meminit in ovpage malloc (when no WRITEMAP) */ /* MDB_RESERVE cancels meminit in ovpage malloc (when no WRITEMAP) */
@ -7343,15 +7382,11 @@ mdb_page_merge(MDB_cursor *csrc, MDB_cursor *cdst)
psrc = csrc->mc_pg[csrc->mc_top]; psrc = csrc->mc_pg[csrc->mc_top];
/* If not operating on FreeDB, allow this page to be reused /* If not operating on FreeDB, allow this page to be reused
* in this txn. * in this txn. Otherwise just add to free list.
*/ */
if ((psrc->mp_flags & P_DIRTY) && csrc->mc_dbi != FREE_DBI) { rc = mdb_page_loose(csrc, psrc);
mdb_page_loose(csrc->mc_txn->mt_env, psrc); if (rc)
} else { return rc;
rc = mdb_midl_append(&csrc->mc_txn->mt_free_pgs, psrc->mp_pgno);
if (rc)
return rc;
}
if (IS_LEAF(psrc)) if (IS_LEAF(psrc))
csrc->mc_db->md_leaf_pages--; csrc->mc_db->md_leaf_pages--;
else else

Loading…
Cancel
Save