diff --git a/libraries/liblmdb/lmdb.h b/libraries/liblmdb/lmdb.h
index 280b43795c4793c1526f42d926fb58d98c8ff835..954ffde1cb2715a3288617331066f3a86be47807 100644
--- a/libraries/liblmdb/lmdb.h
+++ b/libraries/liblmdb/lmdb.h
@@ -206,6 +206,9 @@ typedef struct MDB_cursor MDB_cursor;
  * #MDB_MAXKEYSIZE inclusive. This currently defaults to 511. The
  * same applies to data sizes in databases with the #MDB_DUPSORT flag.
  * Other data items can in theory be from 0 to 0xffffffff bytes long.
+ *
+ * Values returned from the database are valid only until a subsequent
+ * update operation, or the end of the transaction.
  */
 typedef struct MDB_val {
 	size_t		 mv_size;	/**< size of the data item */
@@ -691,8 +694,7 @@ int  mdb_env_set_maxdbs(MDB_env *env, MDB_dbi dbs);
 	 * @note A transaction and its cursors must only be used by a single
 	 * thread, and a thread may only have a single transaction at a time.
 	 * If #MDB_NOTLS is in use, this does not apply to read-only transactions.
-	 * @note Cursors may not span transactions; each cursor must be opened and closed
-	 * within a single transaction.
+	 * @note Cursors may not span transactions.
 	 * @param[in] env An environment handle returned by #mdb_env_create()
 	 * @param[in] parent If this parameter is non-NULL, the new transaction
 	 * will be a nested transaction, with the transaction indicated by \b parent
@@ -723,8 +725,10 @@ int  mdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB_txn **
 
 	/** @brief Commit all the operations of a transaction into the database.
 	 *
-	 * All cursors opened within the transaction will be closed by this call. The cursors
-	 * and transaction handle will be freed and must not be used again after this call.
+	 * The transaction handle is freed. It and its cursors must not be used
+	 * again after this call, except with #mdb_cursor_renew().
+	 * @note Earlier documentation incorrectly said all cursors would be freed.
+	 * Only write-transactions free cursors.
 	 * @param[in] txn A transaction handle returned by #mdb_txn_begin()
 	 * @return A non-zero error value on failure and 0 on success. Some possible
 	 * errors are:
@@ -739,8 +743,10 @@ int  mdb_txn_commit(MDB_txn *txn);
 
 	/** @brief Abandon all the operations of the transaction instead of saving them.
 	 *
-	 * All cursors opened within the transaction will be closed by this call. The cursors
-	 * and transaction handle will be freed and must not be used again after this call.
+	 * The transaction handle is freed. It and its cursors must not be used
+	 * again after this call, except with #mdb_cursor_renew().
+	 * @note Earlier documentation incorrectly said all cursors would be freed.
+	 * Only write-transactions free cursors.
 	 * @param[in] txn A transaction handle returned by #mdb_txn_begin()
 	 */
 void mdb_txn_abort(MDB_txn *txn);
@@ -754,8 +760,8 @@ void mdb_txn_abort(MDB_txn *txn);
 	 * lock is released, but the table slot stays tied to its thread or
 	 * #MDB_txn. Use mdb_txn_abort() to discard a reset handle, and to free
 	 * its lock table slot if MDB_NOTLS is in use.
-	 * All cursors opened within the transaction must be closed before the transaction
-	 * is reset.
+	 * Cursors opened within the transaction must not be used
+	 * again after this call, except with #mdb_cursor_renew().
 	 * Reader locks generally don't interfere with writers, but they keep old
 	 * versions of database pages allocated. Thus they prevent the old pages
 	 * from being reused when writers commit new data, and so under heavy load
@@ -787,6 +793,8 @@ int  mdb_txn_renew(MDB_txn *txn);
 
 	/** @brief Open a database in the environment.
 	 *
+	 * A database handle denotes the name and parameters of a database,
+	 * independently of whether such a database exists.
 	 * The database handle may be discarded by calling #mdb_dbi_close().
 	 * The old database handle is returned if the database was already open.
 	 * The handle must only be closed once.
@@ -978,6 +986,8 @@ int  mdb_set_relctx(MDB_txn *txn, MDB_dbi dbi, void *ctx);
 	 * database. The caller need not dispose of the memory, and may not
 	 * modify it in any way. For values returned in a read-only transaction
 	 * any modification attempts will cause a SIGSEGV.
+	 * @note Values returned from the database are valid only until a
+	 * subsequent update operation, or the end of the transaction.
 	 * @param[in] txn A transaction handle returned by #mdb_txn_begin()
 	 * @param[in] dbi A database handle returned by #mdb_dbi_open()
 	 * @param[in] key The key to search for in the database
@@ -1017,7 +1027,8 @@ int  mdb_get(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data);
 	 *		parameter will be set to point to the existing item.
 	 *	<li>#MDB_RESERVE - reserve space for data of the given size, but
 	 *		don't copy the given data. Instead, return a pointer to the
-	 *		reserved space, which the caller can fill in later. This saves
+	 *		reserved space, which the caller can fill in later - before
+	 *		the next update operation or the transaction ends. This saves
 	 *		an extra memcpy if the data is being generated later.
 	 *	<li>#MDB_APPEND - append the given key/data pair to the end of the
 	 *		database. No key comparisons are performed. This option allows
@@ -1065,7 +1076,16 @@ int  mdb_del(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data);
 	/** @brief Create a cursor handle.
 	 *
 	 * A cursor is associated with a specific transaction and database.
-	 * It must be closed before its transaction ends.
+	 * A cursor cannot be used when its database handle is closed.  Nor
+	 * when its transaction has ended, except with #mdb_cursor_renew().
+	 * It can be discarded with #mdb_cursor_close().
+	 * A cursor in a write-transaction can be closed before its transaction
+	 * ends, and will otherwise be closed when its transaction ends.
+	 * A cursor in a read-only transaction must be closed explicitly, before
+	 * or after its transaction ends. It can be reused with
+	 * #mdb_cursor_renew() before finally closing it.
+	 * @note Earlier documentation said that cursors in every transaction
+	 * were closed when the transaction committed or aborted.
 	 * @param[in] txn A transaction handle returned by #mdb_txn_begin()
 	 * @param[in] dbi A database handle returned by #mdb_dbi_open()
 	 * @param[out] cursor Address where the new #MDB_cursor handle will be stored
@@ -1080,6 +1100,7 @@ int  mdb_cursor_open(MDB_txn *txn, MDB_dbi dbi, MDB_cursor **cursor);
 	/** @brief Close a cursor handle.
 	 *
 	 * The cursor handle will be freed and must not be used again after this call.
+	 * Its transaction must still be live if it is a write-transaction.
 	 * @param[in] cursor A cursor handle returned by #mdb_cursor_open()
 	 */
 void mdb_cursor_close(MDB_cursor *cursor);
@@ -1087,11 +1108,11 @@ void mdb_cursor_close(MDB_cursor *cursor);
 	/** @brief Renew a cursor handle.
 	 *
 	 * A cursor is associated with a specific transaction and database.
-	 * It must be closed before its transaction ends.
 	 * Cursors that are only used in read-only
 	 * transactions may be re-used, to avoid unnecessary malloc/free overhead.
 	 * The cursor may be associated with a new read-only transaction, and
 	 * referencing the same database handle as it was created with.
+	 * This may be done whether the previous transaction is live or dead.
 	 * @param[in] txn A transaction handle returned by #mdb_txn_begin()
 	 * @param[in] cursor A cursor handle returned by #mdb_cursor_open()
 	 * @return A non-zero error value on failure and 0 on success. Some possible
@@ -1121,6 +1142,7 @@ MDB_dbi mdb_cursor_dbi(MDB_cursor *cursor);
 	 * case of the #MDB_SET option, in which the \b key object is unchanged), and
 	 * the address and length of the data are returned in the object to which \b data
 	 * refers.
+	 * See #mdb_get() for restrictions on using the output values.
 	 * @param[in] cursor A cursor handle returned by #mdb_cursor_open()
 	 * @param[in,out] key The key for a retrieved item
 	 * @param[in,out] data The data of a retrieved item
@@ -1230,7 +1252,7 @@ int  mdb_cmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b);
 	/** @brief Compare two data items according to a particular database.
 	 *
 	 * This returns a comparison as if the two items were data items of
-	 * a sorted duplicates #MDB_DUPSORT database.
+	 * the specified database. The database must have the #MDB_DUPSORT flag.
 	 * @param[in] txn A transaction handle returned by #mdb_txn_begin()
 	 * @param[in] dbi A database handle returned by #mdb_dbi_open()
 	 * @param[in] a The first item to compare
diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c
index 09fc3e29e8c9a85cb4850f5c172e800d14838904..80336831e14389c6bb596b0b1acc03e64871110d 100644
--- a/libraries/liblmdb/mdb.c
+++ b/libraries/liblmdb/mdb.c
@@ -900,6 +900,7 @@ struct MDB_cursor {
 #define C_SHADOW	0x08		/**< Cursor is a dup from a parent txn */
 #define C_ALLOCD	0x10		/**< Cursor was malloc'd */
 #define C_SPLITTING	0x20		/**< Cursor is in page_split */
+#define C_UNTRACK	0x40		/**< Un-track cursor when closing */
 /** @} */
 	unsigned int	mc_flags;	/**< @ref mdb_cursor */
 	MDB_page	*mc_pg[CURSOR_STACK];	/**< stack of pushed pages */
@@ -1013,6 +1014,9 @@ static int	mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata,
 static int  mdb_env_read_header(MDB_env *env, MDB_meta *meta);
 static int  mdb_env_pick_meta(const MDB_env *env);
 static int  mdb_env_write_meta(MDB_txn *txn);
+#if !(defined(_WIN32) || defined(MDB_USE_POSIX_SEM)) /* Drop unused excl arg */
+# define mdb_env_close0(env, excl) mdb_env_close1(env)
+#endif
 static void mdb_env_close0(MDB_env *env, int excl);
 
 static MDB_node *mdb_node_search(MDB_cursor *mc, MDB_val *key, int *exactp);
@@ -1135,7 +1139,7 @@ mdb_dkey(MDB_val *key, char *buf)
 }
 
 /** Display all the keys in the page. */
-static void
+void
 mdb_page_list(MDB_page *mp)
 {
 	MDB_node *node;
@@ -1202,9 +1206,8 @@ static void mdb_audit(MDB_txn *txn)
 
 	count = 0;
 	for (i = 0; i<txn->mt_numdbs; i++) {
-		MDB_xcursor mx, *mxp;
-		mxp = (txn->mt_dbs[i].md_flags & MDB_DUPSORT) ? &mx : NULL;
-		mdb_cursor_init(&mc, txn, i, mxp);
+		MDB_xcursor mx;
+		mdb_cursor_init(&mc, txn, i, &mx);
 		if (txn->mt_dbs[i].md_root == P_INVALID)
 			continue;
 		count += txn->mt_dbs[i].md_branch_pages +
@@ -1245,10 +1248,7 @@ mdb_cmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b)
 int
 mdb_dcmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b)
 {
-	if (txn->mt_dbxs[dbi].md_dcmp)
-		return txn->mt_dbxs[dbi].md_dcmp(a, b);
-	else
-		return EINVAL;	/* too bad you can't distinguish this from a valid result */
+	return txn->mt_dbxs[dbi].md_dcmp(a, b);
 }
 
 /** Allocate a single page.
@@ -1398,6 +1398,7 @@ none:
 
 				mdb_cursor_init(&m2, txn, FREE_DBI, NULL);
 				do {
+#ifdef MDB_PARANOID	/* Seems like we can ignore this now */
 					/* If on freelist, don't try to read more. If what we have
 					 * right now isn't enough just use new pages.
 					 * TODO: get all of this working. Many circular dependencies...
@@ -1406,6 +1407,7 @@ none:
 						retry = 0;
 						readit = 0;
 					}
+#endif
 					if (readit) {
 						MDB_val key, data;
 						pgno_t *idl, *mop2;
@@ -1704,7 +1706,7 @@ mdb_cursor_shadow(MDB_txn *src, MDB_txn *dst)
 				mc->mc_dbflag = &dst->mt_dbflags[i];
 				mc->mc_snum = m2->mc_snum;
 				mc->mc_top = m2->mc_top;
-				mc->mc_flags = m2->mc_flags | C_SHADOW;
+				mc->mc_flags = m2->mc_flags | (C_SHADOW|C_ALLOCD);
 				for (j=0; j<mc->mc_snum; j++) {
 					mc->mc_pg[j] = m2->mc_pg[j];
 					mc->mc_ki[j] = m2->mc_ki[j];
@@ -1740,30 +1742,34 @@ mdb_cursor_shadow(MDB_txn *src, MDB_txn *dst)
 	return MDB_SUCCESS;
 }
 
-/** Merge shadow cursors back into parent's */
+/** Close this write txn's cursors, after optionally merging its shadow
+ * cursors back into parent's.
+ * @param[in] txn the transaction handle.
+ * @param[in] merge 0 to not merge cursors, C_SHADOW to merge.
+ * @return 0 on success, non-zero on failure.
+ */
 static void
-mdb_cursor_merge(MDB_txn *txn)
+mdb_cursors_close(MDB_txn *txn, unsigned merge)
 {
-	MDB_dbi i;
-	for (i=0; i<txn->mt_numdbs; i++) {
-		if (txn->mt_cursors[i]) {
-			MDB_cursor *mc;
-			while ((mc = txn->mt_cursors[i])) {
-				txn->mt_cursors[i] = mc->mc_next;
-				if (mc->mc_flags & C_SHADOW) {
+	MDB_cursor **cursors = txn->mt_cursors, *mc, *next;
+	int i, j;
+
+	for (i = txn->mt_numdbs; --i >= 0; ) {
+		for (mc = cursors[i]; mc; mc = next) {
+				next = mc->mc_next;
+				if (mc->mc_flags & merge) {
 					MDB_cursor *m2 = mc->mc_orig;
-					unsigned int j;
 					m2->mc_snum = mc->mc_snum;
 					m2->mc_top = mc->mc_top;
-					for (j=0; j<mc->mc_snum; j++) {
+					for (j = mc->mc_snum; --j >= 0; ) {
 						m2->mc_pg[j] = mc->mc_pg[j];
 						m2->mc_ki[j] = mc->mc_ki[j];
 					}
 				}
 				if (mc->mc_flags & C_ALLOCD)
 					free(mc);
-			}
 		}
+		cursors[i] = NULL;
 	}
 }
 
@@ -1780,7 +1786,7 @@ mdb_txn_renew0(MDB_txn *txn)
 	MDB_env *env = txn->mt_env;
 	unsigned int i;
 	uint16_t x;
-	int rc;
+	int rc, new_notls = 0;
 
 	/* Setup db info */
 	txn->mt_numdbs = env->me_numdbs;
@@ -1817,9 +1823,9 @@ mdb_txn_renew0(MDB_txn *txn)
 				env->me_numreaders = env->me_txns->mti_numreaders;
 				UNLOCK_MUTEX_R(env);
 				r = &env->me_txns->mti_readers[i];
-				if (!(env->me_flags & MDB_NOTLS) &&
-					(rc = pthread_setspecific(env->me_txkey, r)) != 0) {
-					env->me_txns->mti_readers[i].mr_pid = 0;
+				new_notls = (env->me_flags & MDB_NOTLS);
+				if (!new_notls && (rc=pthread_setspecific(env->me_txkey, r))) {
+					r->mr_pid = 0;
 					return rc;
 				}
 			}
@@ -1858,6 +1864,10 @@ mdb_txn_renew0(MDB_txn *txn)
 
 	if (env->me_maxpg < txn->mt_next_pgno) {
 		mdb_txn_reset0(txn);
+		if (new_notls) {
+			txn->mt_u.reader->mr_pid = 0;
+			txn->mt_u.reader = NULL;
+		}
 		return MDB_MAP_RESIZED;
 	}
 
@@ -1869,7 +1879,7 @@ mdb_txn_renew(MDB_txn *txn)
 {
 	int rc;
 
-	if (!txn || txn->mt_numdbs || !(txn->mt_flags & MDB_TXN_RDONLY))
+	if (!txn || txn->mt_dbxs)	/* A reset txn has mt_dbxs==NULL */
 		return EINVAL;
 
 	if (txn->mt_env->me_flags & MDB_FATAL_ERROR) {
@@ -1929,14 +1939,11 @@ mdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB_txn **ret)
 
 	if (parent) {
 		unsigned int i;
-		txn->mt_free_pgs = mdb_midl_alloc();
-		if (!txn->mt_free_pgs) {
-			free(txn);
-			return ENOMEM;
-		}
 		txn->mt_u.dirty_list = malloc(sizeof(MDB_ID2)*MDB_IDL_UM_SIZE);
-		if (!txn->mt_u.dirty_list) {
-			free(txn->mt_free_pgs);
+		if (!txn->mt_u.dirty_list ||
+			!(txn->mt_free_pgs = mdb_midl_alloc(MDB_IDL_UM_MAX)))
+		{
+			free(txn->mt_u.dirty_list);
 			free(txn);
 			return ENOMEM;
 		}
@@ -1985,6 +1992,32 @@ mdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB_txn **ret)
 	return rc;
 }
 
+/** Export or close DBI handles opened in this txn. */
+static void
+mdb_dbis_update(MDB_txn *txn, int keep)
+{
+	int i;
+	MDB_dbi n = txn->mt_numdbs;
+	MDB_env *env = txn->mt_env;
+	unsigned char *tdbflags = txn->mt_dbflags;
+
+	for (i = n; --i >= 2;) {
+		if (tdbflags[i] & DB_NEW) {
+			if (keep) {
+				env->me_dbflags[i] = txn->mt_dbs[i].md_flags | MDB_VALID;
+			} else {
+				char *ptr = env->me_dbxs[i].md_name.mv_data;
+				env->me_dbxs[i].md_name.mv_data = NULL;
+				env->me_dbxs[i].md_name.mv_size = 0;
+				env->me_dbflags[i] = 0;
+				free(ptr);
+			}
+		}
+	}
+	if (keep && env->me_numdbs < n)
+		env->me_numdbs = n;
+}
+
 /** Common code for #mdb_txn_reset() and #mdb_txn_abort().
  * May be called twice for readonly txns: First reset it, then abort.
  * @param[in] txn the transaction handle to reset
@@ -1996,14 +2029,7 @@ mdb_txn_reset0(MDB_txn *txn)
 	unsigned int i;
 
 	/* Close any DBI handles opened in this txn */
-	for (i=2; i<txn->mt_numdbs; i++) {
-		if (txn->mt_dbflags[i] & DB_NEW) {
-			char *ptr = env->me_dbxs[i].md_name.mv_data;
-			env->me_dbxs[i].md_name.mv_data = NULL;
-			env->me_dbxs[i].md_name.mv_size = 0;
-			free(ptr);
-		}
-	}
+	mdb_dbis_update(txn, 0);
 
 	if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY)) {
 		if (txn->mt_u.reader) {
@@ -2011,21 +2037,12 @@ mdb_txn_reset0(MDB_txn *txn)
 			if (!(env->me_flags & MDB_NOTLS))
 				txn->mt_u.reader = NULL; /* txn does not own reader */
 		}
-		txn->mt_numdbs = 0;	/* mark txn as reset, do not close DBs again */
+		txn->mt_numdbs = 0;		/* close nothing if called again */
+		txn->mt_dbxs = NULL;	/* mark txn as reset */
 	} else {
 		MDB_page *dp;
 
-		/* close(free) all cursors */
-		for (i=0; i<txn->mt_numdbs; i++) {
-			if (txn->mt_cursors[i]) {
-				MDB_cursor *mc;
-				while ((mc = txn->mt_cursors[i])) {
-					txn->mt_cursors[i] = mc->mc_next;
-					if (mc->mc_flags & C_ALLOCD)
-						free(mc);
-				}
-			}
-		}
+		mdb_cursors_close(txn, 0);
 
 		if (!(env->me_flags & MDB_WRITEMAP)) {
 			/* return all dirty pages to dpage list */
@@ -2118,20 +2135,18 @@ mdb_txn_commit(MDB_txn *txn)
 	assert(txn->mt_env != NULL);
 
 	if (txn->mt_child) {
-		mdb_txn_commit(txn->mt_child);
+		rc = mdb_txn_commit(txn->mt_child);
 		txn->mt_child = NULL;
+		if (rc) {
+			mdb_txn_abort(txn);
+			return rc;
+		}
 	}
 
 	env = txn->mt_env;
 
 	if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY)) {
-		/* update the DB flags */
-		for (i = 2; i<txn->mt_numdbs; i++) {
-			if (txn->mt_dbflags[i] & DB_NEW)
-				env->me_dbflags[i] = txn->mt_dbs[i].md_flags | MDB_VALID;
-		}
-		if (txn->mt_numdbs > env->me_numdbs)
-			env->me_numdbs = txn->mt_numdbs;
+		mdb_dbis_update(txn, 1);
 		txn->mt_numdbs = 2; /* so txn_abort() doesn't close any new handles */
 		mdb_txn_abort(txn);
 		return MDB_SUCCESS;
@@ -2160,8 +2175,8 @@ mdb_txn_commit(MDB_txn *txn)
 		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);
+		/* Merge our cursors into parent's and close them */
+		mdb_cursors_close(txn, C_SHADOW);
 
 		/* Update parent's DB table. */
 		memcpy(parent->mt_dbs, txn->mt_dbs, txn->mt_numdbs * sizeof(MDB_db));
@@ -2220,6 +2235,8 @@ mdb_txn_commit(MDB_txn *txn)
 		return EINVAL;
 	}
 
+	mdb_cursors_close(txn, 0);
+
 	if (!txn->mt_u.dirty_list[0].mid && !(txn->mt_flags & MDB_TXN_DIRTY))
 		goto done;
 
@@ -2515,13 +2532,7 @@ sync:
 done:
 	env->me_pglast = 0;
 	env->me_txn = NULL;
-	/* update the DB flags */
-	for (i = 2; i<txn->mt_numdbs; i++) {
-		if (txn->mt_dbflags[i] & DB_NEW)
-			env->me_dbflags[i] = txn->mt_dbs[i].md_flags | MDB_VALID;
-	}
-	if (txn->mt_numdbs > env->me_numdbs)
-		env->me_numdbs = txn->mt_numdbs;
+	mdb_dbis_update(txn, 1);
 
 	UNLOCK_MUTEX_W(env);
 	free(txn);
@@ -3461,7 +3472,7 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode
 		/* silently ignore WRITEMAP when we're only getting read access */
 		flags &= ~MDB_WRITEMAP;
 	} else {
-		if (!((env->me_free_pgs = mdb_midl_alloc()) &&
+		if (!((env->me_free_pgs = mdb_midl_alloc(MDB_IDL_UM_MAX)) &&
 			  (env->me_dirty_list = calloc(MDB_IDL_UM_SIZE, sizeof(MDB_ID2)))))
 			rc = ENOMEM;
 	}
@@ -3538,7 +3549,7 @@ leave:
 	return rc;
 }
 
-/** Destroy resources from mdb_env_open() and clear our readers */
+/** Destroy resources from mdb_env_open(), clear our readers & DBIs */
 static void
 mdb_env_close0(MDB_env *env, int excl)
 {
@@ -3547,6 +3558,10 @@ mdb_env_close0(MDB_env *env, int excl)
 	if (!(env->me_flags & MDB_ENV_ACTIVE))
 		return;
 
+	/* Doing this here since me_dbxs may not exist during mdb_env_close */
+	for (i = env->me_maxdbs; --i > MAIN_DBI; )
+		free(env->me_dbxs[i].md_name.mv_data);
+
 	free(env->me_dbflags);
 	free(env->me_dbxs);
 	free(env->me_path);
@@ -3741,9 +3756,9 @@ mdb_env_copy(MDB_env *env, const char *path)
 		ptr += wres;
 	}
 #endif
-	mdb_txn_abort(txn);
 
 leave:
+	mdb_txn_abort(txn);
 	if (newfd != INVALID_HANDLE_VALUE)
 		close(newfd);
 
@@ -3754,14 +3769,10 @@ void
 mdb_env_close(MDB_env *env)
 {
 	MDB_page *dp;
-	int i;
 
 	if (env == NULL)
 		return;
 
-	for (i = env->me_numdbs; --i > MAIN_DBI; )
-		free(env->me_dbxs[i].md_name.mv_data);
-
 	VGMEMP_DESTROY(env);
 	while ((dp = env->me_dpages) != NULL) {
 		VGMEMP_DEFINED(&dp->mp_next, sizeof(dp->mp_next));
@@ -4922,8 +4933,7 @@ mdb_cursor_touch(MDB_cursor *mc)
 	if (mc->mc_dbi > MAIN_DBI && !(*mc->mc_dbflag & DB_DIRTY)) {
 		MDB_cursor mc2;
 		MDB_xcursor mcx;
-		mdb_cursor_init(&mc2, mc->mc_txn, MAIN_DBI,
-			mc->mc_txn->mt_dbs[MAIN_DBI].md_flags & MDB_DUPSORT ? &mcx : NULL);
+		mdb_cursor_init(&mc2, mc->mc_txn, MAIN_DBI, &mcx);
 		rc = mdb_page_search(&mc2, &mc->mc_dbx->md_name, MDB_PS_MODIFY);
 		if (rc)
 			 return rc;
@@ -5827,7 +5837,6 @@ int
 mdb_cursor_open(MDB_txn *txn, MDB_dbi dbi, MDB_cursor **ret)
 {
 	MDB_cursor	*mc;
-	MDB_xcursor	*mx = NULL;
 	size_t size = sizeof(MDB_cursor);
 
 	if (txn == NULL || ret == NULL || dbi >= txn->mt_numdbs || !(txn->mt_dbflags[dbi] & DB_VALID))
@@ -5841,13 +5850,11 @@ mdb_cursor_open(MDB_txn *txn, MDB_dbi dbi, MDB_cursor **ret)
 		size += sizeof(MDB_xcursor);
 
 	if ((mc = malloc(size)) != NULL) {
-		if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT) {
-			mx = (MDB_xcursor *)(mc + 1);
-		}
-		mdb_cursor_init(mc, txn, dbi, mx);
+		mdb_cursor_init(mc, txn, dbi, (MDB_xcursor *)(mc + 1));
 		if (txn->mt_cursors) {
 			mc->mc_next = txn->mt_cursors[dbi];
 			txn->mt_cursors[dbi] = mc;
+			mc->mc_flags |= C_UNTRACK;
 		}
 		mc->mc_flags |= C_ALLOCD;
 	} else {
@@ -5867,7 +5874,7 @@ mdb_cursor_renew(MDB_txn *txn, MDB_cursor *mc)
 	if (txn == NULL || mc == NULL || mc->mc_dbi >= txn->mt_numdbs)
 		return EINVAL;
 
-	if (txn->mt_cursors)
+	if ((mc->mc_flags & C_UNTRACK) || txn->mt_cursors)
 		return EINVAL;
 
 	flags = mc->mc_flags;
@@ -5907,7 +5914,7 @@ mdb_cursor_close(MDB_cursor *mc)
 {
 	if (mc != NULL) {
 		/* remove from txn, if tracked */
-		if (mc->mc_txn->mt_cursors) {
+		if ((mc->mc_flags & C_UNTRACK) && mc->mc_txn->mt_cursors) {
 			MDB_cursor **prev = &mc->mc_txn->mt_cursors[mc->mc_dbi];
 			while (*prev && *prev != mc) prev = &(*prev)->mc_next;
 			if (*prev == mc)
@@ -7224,6 +7231,7 @@ void mdb_dbi_close(MDB_env *env, MDB_dbi dbi)
 	ptr = env->me_dbxs[dbi].md_name.mv_data;
 	env->me_dbxs[dbi].md_name.mv_data = NULL;
 	env->me_dbxs[dbi].md_name.mv_size = 0;
+	env->me_dbflags[dbi] = 0;
 	free(ptr);
 }
 
diff --git a/libraries/liblmdb/midl.c b/libraries/liblmdb/midl.c
index 8020edc0ae91639980142f1683bf1582874953d8..57f1e049a27f6d86c1fe71b2fceea600818096bc 100644
--- a/libraries/liblmdb/midl.c
+++ b/libraries/liblmdb/midl.c
@@ -18,6 +18,7 @@
 #include <limits.h>
 #include <string.h>
 #include <stdlib.h>
+#include <errno.h>
 #include <sys/types.h>
 #include <assert.h>
 #include "midl.h"
@@ -117,16 +118,18 @@ int mdb_midl_insert( MDB_IDL ids, MDB_ID id )
 }
 #endif
 
-MDB_IDL mdb_midl_alloc(void)
+MDB_IDL mdb_midl_alloc(int num)
 {
-	MDB_IDL ids = malloc((MDB_IDL_UM_MAX+1) * sizeof(MDB_ID));
-	*ids++ = MDB_IDL_UM_MAX;
+	MDB_IDL ids = malloc((num+2) * sizeof(MDB_ID));
+	if (ids)
+		*ids++ = num;
 	return ids;
 }
 
 void mdb_midl_free(MDB_IDL ids)
 {
-	free(ids-1);
+	if (ids)
+		free(ids-1);
 }
 
 int mdb_midl_shrink( MDB_IDL *idp )
@@ -141,19 +144,26 @@ int mdb_midl_shrink( MDB_IDL *idp )
 	return 0;
 }
 
+int mdb_midl_grow( MDB_IDL *idp, int num )
+{
+	MDB_IDL idn = *idp-1;
+	/* grow it */
+	idn = realloc(idn, (*idn + num + 2) * sizeof(MDB_ID));
+	if (!idn)
+		return ENOMEM;
+	*idn++ += num;
+	*idp = idn;
+	return 0;
+}
+
 int mdb_midl_append( MDB_IDL *idp, MDB_ID id )
 {
 	MDB_IDL ids = *idp;
 	/* Too big? */
 	if (ids[0] >= ids[-1]) {
-		MDB_IDL idn = ids-1;
-		/* grow it */
-		idn = realloc(idn, (*idn + MDB_IDL_UM_MAX + 1) * sizeof(MDB_ID));
-		if (!idn)
-			return -1;
-		*idn++ += MDB_IDL_UM_MAX;
-		ids = idn;
-		*idp = ids;
+		if (mdb_midl_grow(idp, MDB_IDL_UM_MAX))
+			return ENOMEM;
+		ids = *idp;
 	}
 	ids[0]++;
 	ids[ids[0]] = id;
@@ -165,14 +175,9 @@ int mdb_midl_append_list( MDB_IDL *idp, MDB_IDL app )
 	MDB_IDL ids = *idp;
 	/* Too big? */
 	if (ids[0] + app[0] >= ids[-1]) {
-		MDB_IDL idn = ids-1;
-		/* grow it */
-		idn = realloc(idn, (*idn + app[-1]) * sizeof(MDB_ID));
-		if (!idn)
-			return -1;
-		*idn++ += app[-1];
-		ids = idn;
-		*idp = ids;
+		if (mdb_midl_grow(idp, app[0]))
+			return ENOMEM;
+		ids = *idp;
 	}
 	memcpy(&ids[ids[0]+1], &app[1], app[0] * sizeof(MDB_ID));
 	ids[0] += app[0];
diff --git a/libraries/liblmdb/midl.h b/libraries/liblmdb/midl.h
index a284223ab3a2c12e560159561d95b6fc481dc302..9319fb590bf32fef302b700172b2fdedda696d66 100644
--- a/libraries/liblmdb/midl.h
+++ b/libraries/liblmdb/midl.h
@@ -115,10 +115,10 @@ int mdb_midl_insert( MDB_IDL ids, MDB_ID id );
 #endif
 
 	/** Allocate an IDL.
-	 * Allocates memory for an IDL of a default size.
+	 * Allocates memory for an IDL of the given size.
 	 * @return	IDL on success, NULL on failure.
 	 */
-MDB_IDL mdb_midl_alloc(void);
+MDB_IDL mdb_midl_alloc(int num);
 
 	/** Free an IDL.
 	 * @param[in] ids	The IDL to free.
@@ -132,6 +132,14 @@ void mdb_midl_free(MDB_IDL ids);
 	 */
 int mdb_midl_shrink(MDB_IDL *idp);
 
+	/** Grow an IDL.
+	 * Add room for num additional elements.
+	 * @param[in,out] idp	Address of the IDL to grow.
+	 * @param[i] num	Number of elements to add.
+	 * @return	0 on success, -1 on failure.
+	 */
+int mdb_midl_grow(MDB_IDL *idp, int num);
+
 	/** Append an ID onto an IDL.
 	 * @param[in,out] idp	Address of the IDL to append to.
 	 * @param[in] id	The ID to append.