From 7e3c53282323aa83ebd332798bdd4350c9b71e18 Mon Sep 17 00:00:00 2001
From: Howard Chu <hyc@openldap.org>
Date: Wed, 7 Oct 2015 06:30:58 +0100
Subject: [PATCH] ITS#8263 fix cursor tracking in cursor_put

---
 libraries/liblmdb/mdb.c | 77 +++++++++++++++++++++++++++++++++--------
 1 file changed, 63 insertions(+), 14 deletions(-)

diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c
index 47ba402f3c..e0884e5a6c 100644
--- a/libraries/liblmdb/mdb.c
+++ b/libraries/liblmdb/mdb.c
@@ -1242,6 +1242,7 @@ static int	mdb_cursor_last(MDB_cursor *mc, MDB_val *key, MDB_val *data);
 static void	mdb_cursor_init(MDB_cursor *mc, MDB_txn *txn, MDB_dbi dbi, MDB_xcursor *mx);
 static void	mdb_xcursor_init0(MDB_cursor *mc);
 static void	mdb_xcursor_init1(MDB_cursor *mc, MDB_node *node);
+static void	mdb_xcursor_init2(MDB_cursor *mc, MDB_node *node);
 
 static int	mdb_drop0(MDB_cursor *mc, int subs);
 static void mdb_default_cmp(MDB_txn *txn, MDB_dbi dbi);
@@ -6554,23 +6555,23 @@ put_sub:
 				rc = mdb_cursor_put(&mc->mc_xcursor->mx_cursor, &dkey, &xdata, xflags);
 				if (rc)
 					goto bad_sub;
-				{
-					/* Adjust other cursors pointing to mp */
-					MDB_cursor *m2;
-					unsigned i = mc->mc_top;
-					MDB_page *mp = mc->mc_pg[i];
-
-					for (m2 = mc->mc_txn->mt_cursors[mc->mc_dbi]; m2; m2=m2->mc_next) {
-						if (m2 == mc || m2->mc_snum < mc->mc_snum) continue;
-						if (!(m2->mc_flags & C_INITIALIZED)) continue;
-						if (m2->mc_pg[i] == mp && m2->mc_ki[i] == mc->mc_ki[i]) {
-							mdb_xcursor_init1(m2, leaf);
-						}
-					}
-				}
 				/* we've done our job */
 				dkey.mv_size = 0;
 			}
+			{
+				/* Adjust other cursors pointing to mp */
+				MDB_cursor *m2;
+				unsigned i = mc->mc_top;
+				MDB_page *mp = mc->mc_pg[i];
+
+				for (m2 = mc->mc_txn->mt_cursors[mc->mc_dbi]; m2; m2=m2->mc_next) {
+					if (m2 == mc || m2->mc_snum < mc->mc_snum) continue;
+					if (!(m2->mc_flags & C_INITIALIZED)) continue;
+					if (m2->mc_pg[i] == mp && m2->mc_ki[i] == mc->mc_ki[i]) {
+						mdb_xcursor_init2(m2, leaf);
+					}
+				}
+			}
 			ecount = mc->mc_xcursor->mx_db.md_entries;
 			if (flags & MDB_APPENDDUP)
 				xflags |= MDB_APPEND;
@@ -7122,6 +7123,54 @@ mdb_xcursor_init1(MDB_cursor *mc, MDB_node *node)
 #endif
 }
 
+
+/** Fixup a sorted-dups cursor due to underlying update.
+ *	Sets up some fields that depend on the data from the main cursor.
+ *	Almost the same as init1, but skips initialization steps if the
+ *	xcursor had already been used.
+ * @param[in] mc The main cursor whose sorted-dups cursor is to be fixed up.
+ * @param[in] node The data containing the #MDB_db record for the
+ * sorted-dup database.
+ */
+static void
+mdb_xcursor_init2(MDB_cursor *mc, MDB_node *node)
+{
+	MDB_xcursor *mx = mc->mc_xcursor;
+
+	if (node->mn_flags & F_SUBDATA) {
+		memcpy(&mx->mx_db, NODEDATA(node), sizeof(MDB_db));
+		mdb_page_get(mc->mc_txn,mx->mx_db.md_root,&mx->mx_cursor.mc_pg[0],NULL);
+	} else {
+		MDB_page *fp = NODEDATA(node);
+		mx->mx_db.md_entries = NUMKEYS(fp);
+		COPY_PGNO(mx->mx_db.md_root, fp->mp_pgno);
+		mx->mx_cursor.mc_pg[0] = fp;
+	}
+	if (!(mx->mx_cursor.mc_flags & C_INITIALIZED)) {
+		mx->mx_cursor.mc_snum = 1;
+		mx->mx_cursor.mc_top = 0;
+		mx->mx_cursor.mc_flags |= C_INITIALIZED;
+		mx->mx_cursor.mc_ki[0] = 0;
+		if (!(node->mn_flags & F_SUBDATA)) {
+			mx->mx_db.md_pad = 0;
+			mx->mx_db.md_flags = 0;
+			mx->mx_db.md_depth = 1;
+			mx->mx_db.md_branch_pages = 0;
+			mx->mx_db.md_leaf_pages = 1;
+			mx->mx_db.md_overflow_pages = 0;
+			if (mc->mc_db->md_flags & MDB_DUPFIXED) {
+				mx->mx_db.md_flags = MDB_DUPFIXED;
+				mx->mx_db.md_pad = mx->mx_cursor.mc_pg[0]->mp_pad;
+				if (mc->mc_db->md_flags & MDB_INTEGERDUP)
+					mx->mx_db.md_flags |= MDB_INTEGERKEY;
+			}
+		}
+	}
+	DPRINTF(("Sub-db -%u root page %"Z"u", mx->mx_cursor.mc_dbi,
+		mx->mx_db.md_root));
+	mx->mx_dbflag = DB_VALID|DB_USRVALID|DB_DIRTY; /* DB_DIRTY guides mdb_cursor_touch */
+}
+
 /** Initialize a cursor for a given transaction and database. */
 static void
 mdb_cursor_init(MDB_cursor *mc, MDB_txn *txn, MDB_dbi dbi, MDB_xcursor *mx)
-- 
GitLab