]> git.sur5r.net Git - openldap/commitdiff
Fixes for loose pages
authorHallvard Furuseth <hallvard@openldap.org>
Tue, 8 Jul 2014 18:52:53 +0000 (11:52 -0700)
committerHoward Chu <hyc@symas.com>
Tue, 8 Jul 2014 21:39:57 +0000 (14:39 -0700)
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.

libraries/liblmdb/mdb.c

index ac1850733f50c38328da8402dca8dbd7dc10a80f..3d539ffa8fa8b189dc0719271e7ed45c2ffda3c6 100644 (file)
@@ -655,7 +655,7 @@ typedef struct MDB_page {
 #define        mp_next mp_p.p_next
        union {
                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;
        uint16_t        mp_pad;
 /**    @defgroup mdb_page      Page Flags
@@ -731,7 +731,7 @@ typedef struct MDB_page {
 #define OVPAGES(size, psize)   ((PAGEHDRSZ-1 + (size)) / (psize) + 1)
 
        /** 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.
         * 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) {
+               DPRINTF(("loosen db %d page %"Z"u", DDBI(mc),
+                       mp->mp_pgno));
                NEXT_LOOSE_PAGE(mp) = mc->mc_txn->mt_loose_pgs;
                mc->mc_txn->mt_loose_pgs = mp;
                mp->mp_flags |= P_LOOSE;
@@ -1623,7 +1625,7 @@ mdb_page_loose(MDB_cursor *mc, MDB_page *mp)
 static int
 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_cursor *m3;
        MDB_xcursor *mx;
@@ -1661,12 +1663,6 @@ mdb_pages_xkeep(MDB_cursor *mc, unsigned pflags, int all)
                        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) {
                /* Mark dirty root pages */
                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--) {
                MDB_ID pn = dl[i].mid << 1;
                dp = dl[i].mptr;
-               if (dp->mp_flags & P_KEEP)
+               if (dp->mp_flags & (P_LOOSE|P_KEEP))
                        continue;
                /* Can't spill twice, make sure it's not already in a parent's
                 * spill list.
@@ -1898,6 +1894,8 @@ mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp)
        if (num == 1 && txn->mt_loose_pgs) {
                np = txn->mt_loose_pgs;
                txn->mt_loose_pgs = NEXT_LOOSE_PAGE(np);
+               DPRINTF(("db %d use loose page %"Z"u", DDBI(mc),
+                               np->mp_pgno));
                *mp = np;
                return MDB_SUCCESS;
        }
@@ -2951,8 +2949,8 @@ mdb_page_flush(MDB_txn *txn, int keep)
                while (++i <= pagecount) {
                        dp = dl[i].mptr;
                        /* Don't flush this page yet */
-                       if (dp->mp_flags & P_KEEP) {
-                               dp->mp_flags ^= P_KEEP;
+                       if (dp->mp_flags & (P_LOOSE|P_KEEP)) {
+                               dp->mp_flags &= ~P_KEEP;
                                dl[++j] = dl[i];
                                continue;
                        }
@@ -2966,8 +2964,8 @@ mdb_page_flush(MDB_txn *txn, int keep)
                if (++i <= pagecount) {
                        dp = dl[i].mptr;
                        /* Don't flush this page yet */
-                       if (dp->mp_flags & P_KEEP) {
-                               dp->mp_flags ^= P_KEEP;
+                       if (dp->mp_flags & (P_LOOSE|P_KEEP)) {
+                               dp->mp_flags &= ~P_KEEP;
                                dl[i].mid = 0;
                                continue;
                        }
@@ -3096,6 +3094,7 @@ mdb_txn_commit(MDB_txn *txn)
 
        if (txn->mt_parent) {
                MDB_txn *parent = txn->mt_parent;
+               MDB_page **lp;
                MDB_ID2L dst, src;
                MDB_IDL pspill;
                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;
                mdb_midl_free(((MDB_ntxn *)txn)->mnt_pgstate.mf_pghead);
                free(txn);