]> git.sur5r.net Git - openldap/commitdiff
ITS#7515 Fix MDB parent/child txn interaction.
authorHallvard Furuseth <hallvard@openldap.org>
Sat, 16 Feb 2013 18:11:20 +0000 (19:11 +0100)
committerHallvard Furuseth <hallvard@openldap.org>
Sat, 16 Feb 2013 18:11:20 +0000 (19:11 +0100)
mdb_txn_commit(child): Copy more state. Copy all of mt_dbs:
Include mainDB, and even freeDB since mdb_drop() can update
it. Don't skip DBs with unchanged root, this could break
when the new was newly opened and the old unused junk.

mdb_page_get(): Search parents' dirty lists.

libraries/liblmdb/mdb.c

index 083b25bb8d679fe2385b99003505470181049fe0..40d0207f20c173dae7a454ca40349c4c106c903a 100644 (file)
@@ -2063,22 +2063,19 @@ mdb_txn_commit(MDB_txn *txn)
        }
 
        if (txn->mt_parent) {
-               MDB_db *ip, *jp;
-               MDB_dbi i;
+               MDB_txn *parent = txn->mt_parent;
                unsigned x, y;
                MDB_ID2L dst, src;
 
+               parent->mt_next_pgno = txn->mt_next_pgno;
+               parent->mt_flags = txn->mt_flags;
+
                /* Merge (and close) our cursors with parent's */
                mdb_cursor_merge(txn);
 
-               /* Update parent's DB table */
-               ip = &txn->mt_parent->mt_dbs[2];
-               jp = &txn->mt_dbs[2];
-               for (i = 2; i < txn->mt_numdbs; i++) {
-                       if (ip->md_root != jp->md_root)
-                               *ip = *jp;
-                       ip++; jp++;
-               }
+               /* Update parent's DB table. */
+               memcpy(parent->mt_dbs, txn->mt_dbs, txn->mt_numdbs * sizeof(MDB_db));
+               memcpy(parent->mt_dbflags, txn->mt_dbflags, txn->mt_numdbs);
                txn->mt_parent->mt_numdbs = txn->mt_numdbs;
 
                /* Append our free list to parent's */
@@ -3910,28 +3907,31 @@ mdb_page_get(MDB_txn *txn, pgno_t pgno, MDB_page **ret)
 {
        MDB_page *p = NULL;
 
-       if (txn->mt_env->me_flags & MDB_WRITEMAP) {
-               if (pgno < txn->mt_next_pgno)
-                       p = (MDB_page *)(txn->mt_env->me_map + txn->mt_env->me_psize * pgno);
-               goto done;
-       }
-       if (!F_ISSET(txn->mt_flags, MDB_TXN_RDONLY) && txn->mt_u.dirty_list[0].mid) {
-               unsigned x;
-               x = mdb_mid2l_search(txn->mt_u.dirty_list, pgno);
-               if (x <= txn->mt_u.dirty_list[0].mid && txn->mt_u.dirty_list[x].mid == pgno) {
-                       p = txn->mt_u.dirty_list[x].mptr;
-               }
-       }
-       if (!p) {
-               if (pgno < txn->mt_next_pgno)
-                       p = (MDB_page *)(txn->mt_env->me_map + txn->mt_env->me_psize * pgno);
+       if (!((txn->mt_flags & MDB_TXN_RDONLY) |
+                 (txn->mt_env->me_flags & MDB_WRITEMAP)))
+       {
+               MDB_txn *tx2 = txn;
+               do {
+                       MDB_ID2L dl = tx2->mt_u.dirty_list;
+                       if (dl[0].mid) {
+                               unsigned x = mdb_mid2l_search(dl, pgno);
+                               if (x <= dl[0].mid && dl[x].mid == pgno) {
+                                       p = dl[x].mptr;
+                                       goto done;
+                               }
+                       }
+               } while ((tx2 = tx2->mt_parent) != NULL);
        }
-done:
-       *ret = p;
-       if (!p) {
+
+       if (pgno < txn->mt_next_pgno) {
+               p = (MDB_page *)(txn->mt_env->me_map + txn->mt_env->me_psize * pgno);
+       } else {
                DPRINTF("page %zu not found", pgno);
                assert(p != NULL);
        }
+
+done:
+       *ret = p;
        return (p != NULL) ? MDB_SUCCESS : MDB_PAGE_NOTFOUND;
 }