Fixes for loose pages

mdb_txn_commit(child): Give loose pages to parent.
Use a pointer beyond the page header instead of mp_next, so
we will not need to save/restore mp_pgno. This avoids a crash
caused by references to mp_pgno.
robust
Hallvard Furuseth 11 years ago committed by Howard Chu
parent b3e8c71dc7
commit 6ed295b256
  1. 32
      libraries/liblmdb/mdb.c

@ -655,7 +655,7 @@ typedef struct MDB_page {
#define mp_next mp_p.p_next #define mp_next mp_p.p_next
union { union {
pgno_t p_pgno; /**< page number */ pgno_t p_pgno; /**< page number */
void * p_next; /**< for in-memory list of freed structs */ struct MDB_page *p_next; /**< for in-memory list of freed pages */
} mp_p; } mp_p;
uint16_t mp_pad; uint16_t mp_pad;
/** @defgroup mdb_page Page Flags /** @defgroup mdb_page Page Flags
@ -731,7 +731,7 @@ typedef struct MDB_page {
#define OVPAGES(size, psize) ((PAGEHDRSZ-1 + (size)) / (psize) + 1) #define OVPAGES(size, psize) ((PAGEHDRSZ-1 + (size)) / (psize) + 1)
/** Link in #MDB_txn.%mt_loose_pages list */ /** Link in #MDB_txn.%mt_loose_pages list */
#define NEXT_LOOSE_PAGE(p) (*(MDB_page **)METADATA(p)) #define NEXT_LOOSE_PAGE(p) (*(MDB_page **)((p) + 2))
/** Header for a single key/data pair within a page. /** Header for a single key/data pair within a page.
* Used in pages of type #P_BRANCH and #P_LEAF without #P_LEAF2. * Used in pages of type #P_BRANCH and #P_LEAF without #P_LEAF2.
@ -1601,6 +1601,8 @@ mdb_page_loose(MDB_cursor *mc, MDB_page *mp)
} }
} }
if (loose) { if (loose) {
DPRINTF(("loosen db %d page %"Z"u", DDBI(mc),
mp->mp_pgno));
NEXT_LOOSE_PAGE(mp) = mc->mc_txn->mt_loose_pgs; NEXT_LOOSE_PAGE(mp) = mc->mc_txn->mt_loose_pgs;
mc->mc_txn->mt_loose_pgs = mp; mc->mc_txn->mt_loose_pgs = mp;
mp->mp_flags |= P_LOOSE; mp->mp_flags |= P_LOOSE;
@ -1623,7 +1625,7 @@ mdb_page_loose(MDB_cursor *mc, MDB_page *mp)
static int static int
mdb_pages_xkeep(MDB_cursor *mc, unsigned pflags, int all) mdb_pages_xkeep(MDB_cursor *mc, unsigned pflags, int all)
{ {
enum { Mask = P_SUBP|P_DIRTY|P_KEEP }; enum { Mask = P_SUBP|P_DIRTY|P_LOOSE|P_KEEP };
MDB_txn *txn = mc->mc_txn; MDB_txn *txn = mc->mc_txn;
MDB_cursor *m3; MDB_cursor *m3;
MDB_xcursor *mx; MDB_xcursor *mx;
@ -1661,12 +1663,6 @@ mdb_pages_xkeep(MDB_cursor *mc, unsigned pflags, int all)
break; break;
} }
/* Loose pages shouldn't be spilled */
for (dp = txn->mt_loose_pgs; dp; dp = NEXT_LOOSE_PAGE(dp)) {
if ((dp->mp_flags & Mask) == pflags)
dp->mp_flags ^= P_KEEP;
}
if (all) { if (all) {
/* Mark dirty root pages */ /* Mark dirty root pages */
for (i=0; i<txn->mt_numdbs; i++) { for (i=0; i<txn->mt_numdbs; i++) {
@ -1780,7 +1776,7 @@ mdb_page_spill(MDB_cursor *m0, MDB_val *key, MDB_val *data)
for (i=dl[0].mid; i && need; i--) { for (i=dl[0].mid; i && need; i--) {
MDB_ID pn = dl[i].mid << 1; MDB_ID pn = dl[i].mid << 1;
dp = dl[i].mptr; dp = dl[i].mptr;
if (dp->mp_flags & P_KEEP) if (dp->mp_flags & (P_LOOSE|P_KEEP))
continue; continue;
/* Can't spill twice, make sure it's not already in a parent's /* Can't spill twice, make sure it's not already in a parent's
* spill list. * spill list.
@ -1898,6 +1894,8 @@ mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp)
if (num == 1 && txn->mt_loose_pgs) { if (num == 1 && txn->mt_loose_pgs) {
np = txn->mt_loose_pgs; np = txn->mt_loose_pgs;
txn->mt_loose_pgs = NEXT_LOOSE_PAGE(np); txn->mt_loose_pgs = NEXT_LOOSE_PAGE(np);
DPRINTF(("db %d use loose page %"Z"u", DDBI(mc),
np->mp_pgno));
*mp = np; *mp = np;
return MDB_SUCCESS; return MDB_SUCCESS;
} }
@ -2951,8 +2949,8 @@ mdb_page_flush(MDB_txn *txn, int keep)
while (++i <= pagecount) { while (++i <= pagecount) {
dp = dl[i].mptr; dp = dl[i].mptr;
/* Don't flush this page yet */ /* Don't flush this page yet */
if (dp->mp_flags & P_KEEP) { if (dp->mp_flags & (P_LOOSE|P_KEEP)) {
dp->mp_flags ^= P_KEEP; dp->mp_flags &= ~P_KEEP;
dl[++j] = dl[i]; dl[++j] = dl[i];
continue; continue;
} }
@ -2966,8 +2964,8 @@ mdb_page_flush(MDB_txn *txn, int keep)
if (++i <= pagecount) { if (++i <= pagecount) {
dp = dl[i].mptr; dp = dl[i].mptr;
/* Don't flush this page yet */ /* Don't flush this page yet */
if (dp->mp_flags & P_KEEP) { if (dp->mp_flags & (P_LOOSE|P_KEEP)) {
dp->mp_flags ^= P_KEEP; dp->mp_flags &= ~P_KEEP;
dl[i].mid = 0; dl[i].mid = 0;
continue; continue;
} }
@ -3096,6 +3094,7 @@ mdb_txn_commit(MDB_txn *txn)
if (txn->mt_parent) { if (txn->mt_parent) {
MDB_txn *parent = txn->mt_parent; MDB_txn *parent = txn->mt_parent;
MDB_page **lp;
MDB_ID2L dst, src; MDB_ID2L dst, src;
MDB_IDL pspill; MDB_IDL pspill;
unsigned x, y, len, ps_len; unsigned x, y, len, ps_len;
@ -3193,6 +3192,11 @@ mdb_txn_commit(MDB_txn *txn)
} }
} }
/* Append our loose page list to parent's */
for (lp = &parent->mt_loose_pgs; *lp; lp = &NEXT_LOOSE_PAGE(lp))
;
*lp = txn->mt_loose_pgs;
parent->mt_child = NULL; parent->mt_child = NULL;
mdb_midl_free(((MDB_ntxn *)txn)->mnt_pgstate.mf_pghead); mdb_midl_free(((MDB_ntxn *)txn)->mnt_pgstate.mf_pghead);
free(txn); free(txn);

Loading…
Cancel
Save