@@ -879,8 +879,8 @@ struct MDB_xcursor;
879879struct MDB_cursor {
880880/** Next cursor on this DB in this txn */
881881MDB_cursor * mc_next ;
882- /** Original cursor if this is a shadow */
883- MDB_cursor * mc_orig ;
882+ /** Backup of the original cursor if this cursor is a shadow */
883+ MDB_cursor * mc_backup ;
884884/** Context used for databases with #MDB_DUPSORT, otherwise NULL */
885885struct MDB_xcursor * mc_xcursor ;
886886/** The transaction that owns this cursor */
@@ -1633,57 +1633,35 @@ mdb_env_sync(MDB_env *env, int force)
16331633return rc ;
16341634}
16351635
1636- /** Make shadow copies of all of parent txn's cursors */
1636+ /** Back up parent txn's cursors, then grab the originals for tracking */
16371637static int
16381638mdb_cursor_shadow (MDB_txn * src , MDB_txn * dst )
16391639{
1640- MDB_cursor * mc , * m2 ;
1641- unsigned int i , j , size ;
1640+ MDB_cursor * mc , * bk ;
1641+ MDB_xcursor * mx ;
1642+ size_t size ;
1643+ int i ;
16421644
1643- for (i = 0 ; i < src -> mt_numdbs ; i ++ ) {
1644- if (src -> mt_cursors [i ]) {
1645+ for (i = src -> mt_numdbs ; -- i >= 0 ; ) {
1646+ if (( mc = src -> mt_cursors [i ]) != NULL ) {
16451647size = sizeof (MDB_cursor );
1646- if (src -> mt_cursors [ i ] -> mc_xcursor )
1648+ if (mc -> mc_xcursor )
16471649size += sizeof (MDB_xcursor );
1648- for (m2 = src -> mt_cursors [ i ]; m2 ; m2 = m2 -> mc_next ) {
1649- mc = malloc (size );
1650- if (!mc )
1650+ for (; mc ; mc = bk -> mc_next ) {
1651+ bk = malloc (size );
1652+ if (!bk )
16511653return ENOMEM ;
1652- mc -> mc_orig = m2 ;
1653- mc -> mc_txn = dst ;
1654- mc -> mc_dbi = i ;
1654+ * bk = * mc ;
1655+ mc -> mc_backup = bk ;
16551656mc -> mc_db = & dst -> mt_dbs [i ];
1656- mc -> mc_dbx = m2 -> mc_dbx ;
1657- mc -> mc_dbflag = & dst -> mt_dbflags [i ];
1658- mc -> mc_snum = m2 -> mc_snum ;
1659- mc -> mc_top = m2 -> mc_top ;
1660- mc -> mc_flags = m2 -> mc_flags ;
1661- for (j = 0 ; j < mc -> mc_snum ; j ++ ) {
1662- mc -> mc_pg [j ] = m2 -> mc_pg [j ];
1663- mc -> mc_ki [j ] = m2 -> mc_ki [j ];
1664- }
1665- if (m2 -> mc_xcursor ) {
1666- MDB_xcursor * mx , * mx2 ;
1667- mx = (MDB_xcursor * )(mc + 1 );
1668- mc -> mc_xcursor = mx ;
1669- mx2 = m2 -> mc_xcursor ;
1670- mx -> mx_db = mx2 -> mx_db ;
1671- mx -> mx_dbx = mx2 -> mx_dbx ;
1672- mx -> mx_dbflag = mx2 -> mx_dbflag ;
1673- mx -> mx_cursor .mc_txn = dst ;
1674- mx -> mx_cursor .mc_dbi = mx2 -> mx_cursor .mc_dbi ;
1675- mx -> mx_cursor .mc_db = & mx -> mx_db ;
1676- mx -> mx_cursor .mc_dbx = & mx -> mx_dbx ;
1677- mx -> mx_cursor .mc_dbflag = & mx -> mx_dbflag ;
1678- mx -> mx_cursor .mc_snum = mx2 -> mx_cursor .mc_snum ;
1679- mx -> mx_cursor .mc_top = mx2 -> mx_cursor .mc_top ;
1680- mx -> mx_cursor .mc_flags = mx2 -> mx_cursor .mc_flags ;
1681- for (j = 0 ; j < mx2 -> mx_cursor .mc_snum ; j ++ ) {
1682- mx -> mx_cursor .mc_pg [j ] = mx2 -> mx_cursor .mc_pg [j ];
1683- mx -> mx_cursor .mc_ki [j ] = mx2 -> mx_cursor .mc_ki [j ];
1684- }
1685- } else {
1686- mc -> mc_xcursor = NULL ;
1657+ /* Kill pointers into src - and dst to reduce abuse: The
1658+ * user may not use mc until dst ends. Otherwise we'd...
1659+ */
1660+ mc -> mc_txn = NULL ;/* ...set this to dst */
1661+ mc -> mc_dbflag = NULL ;/* ...and &dst->mt_dbflags[i] */
1662+ if ((mx = mc -> mc_xcursor ) != NULL ) {
1663+ * (MDB_xcursor * )(bk + 1 ) = * mx ;
1664+ mx -> mx_cursor .mc_txn = NULL ; /* ...and dst. */
16871665}
16881666mc -> mc_next = dst -> mt_cursors [i ];
16891667dst -> mt_cursors [i ] = mc ;
@@ -1693,32 +1671,40 @@ mdb_cursor_shadow(MDB_txn *src, MDB_txn *dst)
16931671return MDB_SUCCESS ;
16941672}
16951673
1696- /** Close this write txn's cursors, after optionally merging its shadow
1697- * cursors back into parent's.
1674+ /** Close this write txn's cursors, give parent txn's cursors back to parent.
16981675 * @param[in] txn the transaction handle.
1699- * @param[in] merge zero to not merge cursors, non-zero to merge .
1676+ * @param[in] merge true to keep changes to parent cursors, false to revert .
17001677 * @return 0 on success, non-zero on failure.
17011678 */
17021679static void
17031680mdb_cursors_close (MDB_txn * txn , unsigned merge )
17041681{
1705- MDB_cursor * * cursors = txn -> mt_cursors , * mc , * next ;
1706- int i , j ;
1682+ MDB_cursor * * cursors = txn -> mt_cursors , * mc , * next , * bk ;
1683+ MDB_xcursor * mx ;
1684+ int i ;
17071685
17081686for (i = txn -> mt_numdbs ; -- i >= 0 ; ) {
17091687for (mc = cursors [i ]; mc ; mc = next ) {
1710- next = mc -> mc_next ;
1711- if (merge && mc -> mc_orig ) {
1712- MDB_cursor * m2 = mc -> mc_orig ;
1713- m2 -> mc_snum = mc -> mc_snum ;
1714- m2 -> mc_top = mc -> mc_top ;
1715- for (j = mc -> mc_snum ; -- j >= 0 ; ) {
1716- m2 -> mc_pg [j ] = mc -> mc_pg [j ];
1717- m2 -> mc_ki [j ] = mc -> mc_ki [j ];
1718- }
1688+ next = mc -> mc_next ;
1689+ if ((bk = mc -> mc_backup ) != NULL ) {
1690+ if (merge ) {
1691+ /* Commit changes to parent txn */
1692+ mc -> mc_next = bk -> mc_next ;
1693+ mc -> mc_backup = bk -> mc_backup ;
1694+ mc -> mc_txn = bk -> mc_txn ;
1695+ mc -> mc_db = bk -> mc_db ;
1696+ mc -> mc_dbflag = bk -> mc_dbflag ;
1697+ if ((mx = mc -> mc_xcursor ) != NULL )
1698+ mx -> mx_cursor .mc_txn = bk -> mc_txn ;
1699+ } else {
1700+ /* Abort nested txn */
1701+ * mc = * bk ;
1702+ if ((mx = mc -> mc_xcursor ) != NULL )
1703+ * mx = * (MDB_xcursor * )(bk + 1 );
17191704}
1720- /* Only malloced cursors are permanently tracked. */
1721- free (mc );
1705+ mc = bk ;
1706+ }
1707+ free (mc );
17221708}
17231709cursors [i ] = NULL ;
17241710}
@@ -5867,7 +5853,7 @@ mdb_xcursor_init1(MDB_cursor *mc, MDB_node *node)
58675853static void
58685854mdb_cursor_init (MDB_cursor * mc , MDB_txn * txn , MDB_dbi dbi , MDB_xcursor * mx )
58695855{
5870- mc -> mc_orig = NULL ;
5856+ mc -> mc_backup = NULL ;
58715857mc -> mc_dbi = dbi ;
58725858mc -> mc_txn = txn ;
58735859mc -> mc_db = & txn -> mt_dbs [dbi ];
@@ -5961,7 +5947,7 @@ mdb_cursor_count(MDB_cursor *mc, size_t *countp)
59615947void
59625948mdb_cursor_close (MDB_cursor * mc )
59635949{
5964- if (mc != NULL ) {
5950+ if (mc && ! mc -> mc_backup ) {
59655951/* remove from txn, if tracked */
59665952if ((mc -> mc_flags & C_UNTRACK ) && mc -> mc_txn -> mt_cursors ) {
59675953MDB_cursor * * prev = & mc -> mc_txn -> mt_cursors [mc -> mc_dbi ];
0 commit comments