Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-lmdb for openSUSE:Factory 
checked in at 2025-07-15 16:43:57
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-lmdb (Old)
 and      /work/SRC/openSUSE:Factory/.python-lmdb.new.7373 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-lmdb"

Tue Jul 15 16:43:57 2025 rev:16 rq:1293127 version:1.7.2

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-lmdb/python-lmdb.changes  2025-01-14 
18:41:15.322077047 +0100
+++ /work/SRC/openSUSE:Factory/.python-lmdb.new.7373/python-lmdb.changes        
2025-07-15 16:45:09.814915054 +0200
@@ -1,0 +2,9 @@
+Mon Jul 14 12:26:32 UTC 2025 - Dirk Müller <dmuel...@suse.com>
+
+- update to 1.7.2:
+  * CI-only fix
+  * Update bundled LMDB to 0.9.33, plus a patch to fix ITS#10346.
+  * Prevent some accidental use of LMDB objects by child
+    processes.
+
+-------------------------------------------------------------------

Old:
----
  lmdb-1.6.2.tar.gz

New:
----
  lmdb-1.7.2.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-lmdb.spec ++++++
--- /var/tmp/diff_new_pack.OUHGVF/_old  2025-07-15 16:45:10.718952802 +0200
+++ /var/tmp/diff_new_pack.OUHGVF/_new  2025-07-15 16:45:10.722952969 +0200
@@ -18,7 +18,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-lmdb
-Version:        1.6.2
+Version:        1.7.2
 Release:        0
 Summary:        Universal Python binding for the LMDB 'Lightning' Database
 License:        OLDAP-2.8

++++++ lmdb-1.6.2.tar.gz -> lmdb-1.7.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.6.2/ChangeLog new/lmdb-1.7.2/ChangeLog
--- old/lmdb-1.6.2/ChangeLog    2025-01-06 06:52:59.000000000 +0100
+++ new/lmdb-1.7.2/ChangeLog    2025-07-11 00:36:25.000000000 +0200
@@ -1,3 +1,17 @@
+2025-07-10 1.7.2
+* CI-only fix
+
+2025-07-09 1.7.1
+* CI-only fix
+
+2025-07-09 1.7.0
+* Rewrite CI to use cibuildwheel.
+
+* Update bundled LMDB to 0.9.33, plus a patch to fix ITS#10346.
+
+* Prevent some accidental use of LMDB objects by child processes.
+Contributed by Callum Walker.
+
 2025-01-05 1.6.2
 * CI-only fix.
 
@@ -31,7 +45,7 @@
 * Add Python 3.10 support.
 
 * Fix crash relating to caching of transactions.  The 'max_spare_txns'
-  parameter to Environment/open is currently ignored.
+  parameter to Environment/open is currently ignored in cpython.
 
 2021-04-19 v1.2.1
 * Resolve CI bug where non-Linux wheels were not being published to PyPI.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.6.2/PKG-INFO new/lmdb-1.7.2/PKG-INFO
--- old/lmdb-1.6.2/PKG-INFO     2025-01-06 06:53:10.220817300 +0100
+++ new/lmdb-1.7.2/PKG-INFO     2025-07-11 00:36:29.482029400 +0200
@@ -1,6 +1,6 @@
-Metadata-Version: 2.1
+Metadata-Version: 2.4
 Name: lmdb
-Version: 1.6.2
+Version: 1.7.2
 Summary: Universal Python binding for the LMDB 'Lightning' Database
 Home-page: http://github.com/jnwatson/py-lmdb/
 Author: David Wilson
@@ -23,5 +23,14 @@
 Classifier: Topic :: Database :: Database Engines/Servers
 Description-Content-Type: text/plain
 License-File: LICENSE
+Dynamic: author
+Dynamic: classifier
+Dynamic: description
+Dynamic: description-content-type
+Dynamic: home-page
+Dynamic: license
+Dynamic: license-file
+Dynamic: maintainer
+Dynamic: summary
 
 Universal Python binding for the LMDB 'Lightning' Database
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.6.2/README.md new/lmdb-1.7.2/README.md
--- old/lmdb-1.6.2/README.md    2025-01-06 06:52:59.000000000 +0100
+++ new/lmdb-1.7.2/README.md    2025-07-11 00:36:25.000000000 +0200
@@ -3,11 +3,12 @@
 See [the documentation](https://lmdb.readthedocs.io) for more information.
 
 ### CI State
-![Build, run, and test 
py-lmdb](https://github.com/jnwatson/py-lmdb/workflows/Build,%20run,%20and%20test%20py-lmdb/badge.svg)
+[![master](https://github.com/jnwatson/py-lmdb/workflows/Build,%20run,%20and%20test%20py-lmdb/badge.svg)](https://github.com/jnwatson/py-lmdb/actions/workflows/python-package.yml)
 
 # Python Version Support Statement
 
-This project has been around for a while.  Previously, it supported all the 
way back to before 2.5.  Currently, py-lmdb
-supports Python >= 3.5 and pypy.
+This project has been around for a while.  Previously, it supported all the 
+way back to before Python 2.5.  Currently, py-lmdb supports Python >= 3.5 
+and pypy.
 
 The last version of py-lmdb that supported Python 2.7 was 1.4.1.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.6.2/lib/lmdb.h new/lmdb-1.7.2/lib/lmdb.h
--- old/lmdb-1.6.2/lib/lmdb.h   2025-01-06 06:52:59.000000000 +0100
+++ new/lmdb-1.7.2/lib/lmdb.h   2025-07-11 00:36:25.000000000 +0200
@@ -200,7 +200,7 @@
 /** Library minor version */
 #define MDB_VERSION_MINOR      9
 /** Library patch version */
-#define MDB_VERSION_PATCH      31
+#define MDB_VERSION_PATCH      33
 
 /** Combine args a,b,c into a single integer for easy version comparisons */
 #define MDB_VERINT(a,b,c)      (((a) << 24) | ((b) << 16) | (c))
@@ -210,7 +210,7 @@
        MDB_VERINT(MDB_VERSION_MAJOR,MDB_VERSION_MINOR,MDB_VERSION_PATCH)
 
 /** The release date of this library version */
-#define MDB_VERSION_DATE       "July 10, 2023"
+#define MDB_VERSION_DATE       "May 21, 2024"
 
 /** A stringifier for the version info */
 #define MDB_VERSTR(a,b,c,d)    "LMDB " #a "." #b "." #c ": (" d ")"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.6.2/lib/mdb.c new/lmdb-1.7.2/lib/mdb.c
--- old/lmdb-1.6.2/lib/mdb.c    2025-01-06 06:52:59.000000000 +0100
+++ new/lmdb-1.7.2/lib/mdb.c    2025-07-11 00:36:25.000000000 +0200
@@ -481,18 +481,26 @@
 #define MDB_DEBUG 0
 #endif
 
+#define MDB_DBG_INFO   1
+#define MDB_DBG_TRACE  2
+
 #if MDB_DEBUG
-static int mdb_debug;
+static int mdb_debug = MDB_DBG_TRACE;
 static txnid_t mdb_debug_start;
 
        /**     Print a debug message with printf formatting.
         *      Requires double parenthesis around 2 or more args.
         */
-# define DPRINTF(args) ((void) ((mdb_debug) && DPRINTF0 args))
+# define DPRINTF(args) ((void) ((mdb_debug & MDB_DBG_INFO) && DPRINTF0 args))
 # define DPRINTF0(fmt, ...) \
        fprintf(stderr, "%s:%d " fmt "\n", mdb_func_, __LINE__, __VA_ARGS__)
+       /** Trace info for replaying */
+# define MDB_TRACE(args)       ((void) ((mdb_debug & MDB_DBG_TRACE) && 
DPRINTF1 args))
+# define DPRINTF1(fmt, ...) \
+       fprintf(stderr, ">%d:%s: " fmt "\n", getpid(), mdb_func_, __VA_ARGS__)
 #else
 # define DPRINTF(args) ((void) 0)
+# define MDB_TRACE(args)       ((void) 0)
 #endif
        /**     Print a debug string.
         *      The string is printed literally, with no format processing.
@@ -589,6 +597,11 @@
         *      This is used for printing a hex dump of a key's contents.
         */
 #define DKBUF  char kbuf[DKBUF_MAXKEYSIZE*2+1]
+       /**     A data value buffer.
+        *      @ingroup debug
+        *      This is used for printing a hex dump of a #MDB_DUPSORT value's 
contents.
+        */
+#define DDBUF  char dbuf[DKBUF_MAXKEYSIZE*2+1+2]
        /**     Display a key in hex.
         *      @ingroup debug
         *      Invoke a function to display a key in hex.
@@ -596,6 +609,7 @@
 #define        DKEY(x) mdb_dkey(x, kbuf)
 #else
 #define        DKBUF
+#define        DDBUF
 #define DKEY(x)        0
 #endif
 
@@ -1423,6 +1437,9 @@
 static void    mdb_cursor_pop(MDB_cursor *mc);
 static int     mdb_cursor_push(MDB_cursor *mc, MDB_page *mp);
 
+static int     _mdb_cursor_del(MDB_cursor *mc, unsigned int flags);
+static int     _mdb_cursor_put(MDB_cursor *mc, MDB_val *key, MDB_val *data, 
unsigned int flags);
+
 static int     mdb_cursor_del0(MDB_cursor *mc);
 static int     mdb_del0(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val 
*data, unsigned flags);
 static int     mdb_cursor_sibling(MDB_cursor *mc, int move_right);
@@ -1538,7 +1555,7 @@
        buf[0] = 0;
        FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
                FORMAT_MESSAGE_IGNORE_INSERTS,
-               NULL, err, 0, ptr, MSGSIZE, (va_list *)buf+MSGSIZE);
+               NULL, err, 0, ptr, MSGSIZE, NULL);
        return ptr;
 #else
        if (err < 0)
@@ -1614,6 +1631,18 @@
        return buf;
 }
 
+static char *
+mdb_dval(MDB_txn *txn, MDB_dbi dbi, MDB_val *data, char *buf)
+{
+       if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT) {
+               mdb_dkey(data, buf+1);
+               *buf = '[';
+               strcpy(buf + data->mv_size * 2 + 1, "]");
+       } else
+               *buf = '\0';
+       return buf;
+}
+
 static const char *
 mdb_leafnode_type(MDB_node *n)
 {
@@ -2767,9 +2796,14 @@
                        do /* LY: Retry on a race, ITS#7970. */
                                r->mr_txnid = ti->mti_txnid;
                        while(r->mr_txnid != ti->mti_txnid);
+                       if (!r->mr_txnid && (env->me_flags & MDB_RDONLY)) {
+                               meta = mdb_env_pick_meta(env);
+                               r->mr_txnid = meta->mm_txnid;
+                       } else {
+                               meta = env->me_metas[r->mr_txnid & 1];
+                       }
                        txn->mt_txnid = r->mr_txnid;
                        txn->mt_u.reader = r;
-                       meta = env->me_metas[txn->mt_txnid & 1];
                }
 
        } else {
@@ -2786,7 +2820,7 @@
                txn->mt_txnid++;
 #if MDB_DEBUG
                if (txn->mt_txnid == mdb_debug_start)
-                       mdb_debug = 1;
+                       mdb_debug = MDB_DBG_INFO;
 #endif
                txn->mt_child = NULL;
                txn->mt_loose_pgs = NULL;
@@ -2945,6 +2979,7 @@
                        txn->mt_txnid, (flags & MDB_RDONLY) ? 'r' : 'w',
                        (void *) txn, (void *) env, 
txn->mt_dbs[MAIN_DBI].md_root));
        }
+       MDB_TRACE(("%p, %p, %u = %p", env, parent, flags, txn));
 
        return rc;
 }
@@ -3080,18 +3115,25 @@
        mdb_txn_end(txn, MDB_END_RESET);
 }
 
-void
-mdb_txn_abort(MDB_txn *txn)
+static void
+_mdb_txn_abort(MDB_txn *txn)
 {
        if (txn == NULL)
                return;
 
        if (txn->mt_child)
-               mdb_txn_abort(txn->mt_child);
+               _mdb_txn_abort(txn->mt_child);
 
        mdb_txn_end(txn, MDB_END_ABORT|MDB_END_SLOT|MDB_END_FREE);
 }
 
+void
+mdb_txn_abort(MDB_txn *txn)
+{
+       MDB_TRACE(("%p", txn));
+       _mdb_txn_abort(txn);
+}
+
 /** Save the freelist as of this transaction to the freeDB.
  * This changes the freelist. Keep trying until it stabilizes.
  */
@@ -3182,7 +3224,7 @@
                        pglast = head_id = *(txnid_t *)key.mv_data;
                        total_room = head_room = 0;
                        mdb_tassert(txn, pglast <= env->me_pglast);
-                       rc = mdb_cursor_del(&mc, 0);
+                       rc = _mdb_cursor_del(&mc, 0);
                        if (rc)
                                return rc;
                }
@@ -3202,7 +3244,7 @@
                        do {
                                freecnt = free_pgs[0];
                                data.mv_size = MDB_IDL_SIZEOF(free_pgs);
-                               rc = mdb_cursor_put(&mc, &key, &data, 
MDB_RESERVE);
+                               rc = _mdb_cursor_put(&mc, &key, &data, 
MDB_RESERVE);
                                if (rc)
                                        return rc;
                                /* Retry if mt_free_pgs[] grew during the Put() 
*/
@@ -3251,7 +3293,7 @@
                key.mv_size = sizeof(head_id);
                key.mv_data = &head_id;
                data.mv_size = (head_room + 1) * sizeof(pgno_t);
-               rc = mdb_cursor_put(&mc, &key, &data, MDB_RESERVE);
+               rc = _mdb_cursor_put(&mc, &key, &data, MDB_RESERVE);
                if (rc)
                        return rc;
                /* IDL is initially empty, zero out at least the length */
@@ -3306,7 +3348,7 @@
                        data.mv_data = mop -= len;
                        save = mop[0];
                        mop[0] = len;
-                       rc = mdb_cursor_put(&mc, &key, &data, MDB_CURRENT);
+                       rc = _mdb_cursor_put(&mc, &key, &data, MDB_CURRENT);
                        mop[0] = save;
                        if (rc || !(mop_len -= len))
                                break;
@@ -3467,8 +3509,8 @@
        return MDB_SUCCESS;
 }
 
-int
-mdb_txn_commit(MDB_txn *txn)
+static int
+_mdb_txn_commit(MDB_txn *txn)
 {
        int             rc;
        unsigned int i, end_mode;
@@ -3481,7 +3523,7 @@
        end_mode = 
MDB_END_EMPTY_COMMIT|MDB_END_UPDATE|MDB_END_SLOT|MDB_END_FREE;
 
        if (txn->mt_child) {
-               rc = mdb_txn_commit(txn->mt_child);
+               rc = _mdb_txn_commit(txn->mt_child);
                if (rc)
                        goto fail;
        }
@@ -3661,7 +3703,7 @@
                                        goto fail;
                                }
                                data.mv_data = &txn->mt_dbs[i];
-                               rc = mdb_cursor_put(&mc, 
&txn->mt_dbxs[i].md_name, &data,
+                               rc = _mdb_cursor_put(&mc, 
&txn->mt_dbxs[i].md_name, &data,
                                        F_SUBDATA);
                                if (rc)
                                        goto fail;
@@ -3692,10 +3734,17 @@
        return MDB_SUCCESS;
 
 fail:
-       mdb_txn_abort(txn);
+       _mdb_txn_abort(txn);
        return rc;
 }
 
+int
+mdb_txn_commit(MDB_txn *txn)
+{
+       MDB_TRACE(("%p", txn));
+       return _mdb_txn_commit(txn);
+}
+
 /** Read the environment parameters of a DB environment before
  * mapping it into memory.
  * @param[in] env the environment handle
@@ -3992,6 +4041,7 @@
        GET_PAGESIZE(e->me_os_psize);
        VGMEMP_CREATE(e,0,0);
        *env = e;
+       MDB_TRACE(("%p", e));
        return MDB_SUCCESS;
 }
 
@@ -4115,6 +4165,7 @@
        env->me_mapsize = size;
        if (env->me_psize)
                env->me_maxpg = env->me_mapsize / env->me_psize;
+       MDB_TRACE(("%p, %"Yu"", env, size));
        return MDB_SUCCESS;
 }
 
@@ -4124,6 +4175,7 @@
        if (env->me_map)
                return EINVAL;
        env->me_maxdbs = dbs + CORE_DBS;
+       MDB_TRACE(("%p, %u", env, dbs));
        return MDB_SUCCESS;
 }
 
@@ -4133,6 +4185,7 @@
        if (env->me_map || readers < 1)
                return EINVAL;
        env->me_maxreaders = readers;
+       MDB_TRACE(("%p, %u", env, readers));
        return MDB_SUCCESS;
 }
 
@@ -5076,6 +5129,7 @@
        }
 
 leave:
+       MDB_TRACE(("%p, %s, %u, %04o", env, path, flags & 
(CHANGEABLE|CHANGELESS), mode));
        if (rc) {
                mdb_env_close0(env, excl);
        }
@@ -5162,17 +5216,6 @@
                                sem_unlink(env->me_txns->mti_wmname);
                        }
                }
-#elif defined(MDB_ROBUST_SUPPORTED)
-               /* If we have the filelock:  If we are the
-                * only remaining user, clean up robust
-                * mutexes.
-                */
-               if (excl == 0)
-                       mdb_env_excl_lock(env, &excl);
-               if (excl > 0) {
-                       pthread_mutex_destroy(env->me_txns->mti_rmutex);
-                       pthread_mutex_destroy(env->me_txns->mti_wmutex);
-               }
 #endif
                munmap((void *)env->me_txns, 
(env->me_maxreaders-1)*sizeof(MDB_reader)+sizeof(MDB_txninfo));
        }
@@ -5199,6 +5242,7 @@
        if (env == NULL)
                return;
 
+       MDB_TRACE(("%p", env));
        VGMEMP_DESTROY(env);
        while ((dp = env->me_dpages) != NULL) {
                VGMEMP_DEFINED(&dp->mp_next, sizeof(dp->mp_next));
@@ -5662,7 +5706,7 @@
                                        MDB_node *leaf = mdb_node_search(&mc2,
                                                &mc->mc_dbx->md_name, &exact);
                                        if (!exact)
-                                               return MDB_NOTFOUND;
+                                               return MDB_BAD_DBI;
                                        if ((leaf->mn_flags & 
(F_DUPDATA|F_SUBDATA)) != F_SUBDATA)
                                                return MDB_INCOMPATIBLE; /* not 
a named DB */
                                        rc = mdb_node_read(&mc2, leaf, &data);
@@ -6570,8 +6614,8 @@
 /** Do not spill pages to disk if txn is getting full, may fail instead */
 #define MDB_NOSPILL    0x8000
 
-int
-mdb_cursor_put(MDB_cursor *mc, MDB_val *key, MDB_val *data,
+static int
+_mdb_cursor_put(MDB_cursor *mc, MDB_val *key, MDB_val *data,
     unsigned int flags)
 {
        MDB_env         *env;
@@ -7034,7 +7078,7 @@
                        new_dupdata = (int)dkey.mv_size;
                        /* converted, write the original data first */
                        if (dkey.mv_size) {
-                               rc = mdb_cursor_put(&mc->mc_xcursor->mx_cursor, 
&dkey, &xdata, xflags);
+                               rc = 
_mdb_cursor_put(&mc->mc_xcursor->mx_cursor, &dkey, &xdata, xflags);
                                if (rc)
                                        goto bad_sub;
                                /* we've done our job */
@@ -7062,7 +7106,7 @@
                        ecount = mc->mc_xcursor->mx_db.md_entries;
                        if (flags & MDB_APPENDDUP)
                                xflags |= MDB_APPEND;
-                       rc = mdb_cursor_put(&mc->mc_xcursor->mx_cursor, data, 
&xdata, xflags);
+                       rc = _mdb_cursor_put(&mc->mc_xcursor->mx_cursor, data, 
&xdata, xflags);
                        if (flags & F_SUBDATA) {
                                void *db = NODEDATA(leaf);
                                memcpy(db, &mc->mc_xcursor->mx_db, 
sizeof(MDB_db));
@@ -7103,7 +7147,20 @@
 }
 
 int
-mdb_cursor_del(MDB_cursor *mc, unsigned int flags)
+mdb_cursor_put(MDB_cursor *mc, MDB_val *key, MDB_val *data,
+    unsigned int flags)
+{
+       DKBUF;
+       DDBUF;
+       int rc = _mdb_cursor_put(mc, key, data, flags);
+       MDB_TRACE(("%p, %"Z"u[%s], %"Z"u%s, %u",
+               mc, key ? key->mv_size:0, DKEY(key), data ? data->mv_size:0,
+                       data ? mdb_dval(mc->mc_txn, mc->mc_dbi, data, dbuf):"", 
flags));
+       return rc;
+}
+
+static int
+_mdb_cursor_del(MDB_cursor *mc, unsigned int flags)
 {
        MDB_node        *leaf;
        MDB_page        *mp;
@@ -7141,7 +7198,7 @@
                        if (!F_ISSET(leaf->mn_flags, F_SUBDATA)) {
                                mc->mc_xcursor->mx_cursor.mc_pg[0] = 
NODEDATA(leaf);
                        }
-                       rc = mdb_cursor_del(&mc->mc_xcursor->mx_cursor, 
MDB_NOSPILL);
+                       rc = _mdb_cursor_del(&mc->mc_xcursor->mx_cursor, 
MDB_NOSPILL);
                        if (rc)
                                return rc;
                        /* If sub-DB still has entries, we're done */
@@ -7205,6 +7262,14 @@
        return rc;
 }
 
+int
+mdb_cursor_del(MDB_cursor *mc, unsigned int flags)
+{
+       MDB_TRACE(("%p, %u",
+               mc, flags));
+       return _mdb_cursor_del(mc, flags);
+}
+
 /** Allocate and initialize new pages for a database.
  * Set #MDB_TXN_ERROR on failure.
  * @param[in] mc a cursor on the database being added to.
@@ -7698,6 +7763,7 @@
                return ENOMEM;
        }
 
+       MDB_TRACE(("%p, %u = %p", txn, dbi, mc));
        *ret = mc;
 
        return MDB_SUCCESS;
@@ -7761,6 +7827,7 @@
 void
 mdb_cursor_close(MDB_cursor *mc)
 {
+       MDB_TRACE(("%p", mc));
        if (mc && !mc->mc_backup) {
                /* remove from txn, if tracked */
                if ((mc->mc_flags & C_UNTRACK) && mc->mc_txn->mt_cursors) {
@@ -8570,6 +8637,8 @@
 mdb_del(MDB_txn *txn, MDB_dbi dbi,
     MDB_val *key, MDB_val *data)
 {
+       DKBUF;
+       DDBUF;
        if (!key || !TXN_DBI_EXIST(txn, dbi, DB_USRVALID))
                return EINVAL;
 
@@ -8581,6 +8650,9 @@
                data = NULL;
        }
 
+       MDB_TRACE(("%p, %u, %"Z"u[%s], %"Z"u%s",
+               txn, dbi, key ? key->mv_size:0, DKEY(key), data ? 
data->mv_size:0,
+               data ? mdb_dval(txn, dbi, data, dbuf):""));
        return mdb_del0(txn, dbi, key, data, 0);
 }
 
@@ -8621,7 +8693,7 @@
                mc.mc_flags |= C_UNTRACK;
                mc.mc_next = txn->mt_cursors[dbi];
                txn->mt_cursors[dbi] = &mc;
-               rc = mdb_cursor_del(&mc, flags);
+               rc = _mdb_cursor_del(&mc, flags);
                txn->mt_cursors[dbi] = mc.mc_next;
        }
        return rc;
@@ -9063,6 +9135,8 @@
        MDB_cursor mc;
        MDB_xcursor mx;
        int rc;
+       DKBUF;
+       DDBUF;
 
        if (!key || !data || !TXN_DBI_EXIST(txn, dbi, DB_USRVALID))
                return EINVAL;
@@ -9073,10 +9147,12 @@
        if (txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_BLOCKED))
                return (txn->mt_flags & MDB_TXN_RDONLY) ? EACCES : MDB_BAD_TXN;
 
+       MDB_TRACE(("%p, %u, %"Z"u[%s], %"Z"u%s, %u",
+               txn, dbi, key ? key->mv_size:0, DKEY(key), data->mv_size, 
mdb_dval(txn, dbi, data, dbuf), flags));
        mdb_cursor_init(&mc, txn, dbi, &mx);
        mc.mc_next = txn->mt_cursors[dbi];
        txn->mt_cursors[dbi] = &mc;
-       rc = mdb_cursor_put(&mc, key, data, flags);
+       rc = _mdb_cursor_put(&mc, key, data, flags);
        txn->mt_cursors[dbi] = mc.mc_next;
        return rc;
 }
@@ -9479,7 +9555,7 @@
                my.mc_error = rc;
        mdb_env_cthr_toggle(&my, 1 | MDB_EOF);
        rc = THREAD_FINISH(thr);
-       mdb_txn_abort(txn);
+       _mdb_txn_abort(txn);
 
 done:
 #ifdef _WIN32
@@ -9591,7 +9667,7 @@
        }
 
 leave:
-       mdb_txn_abort(txn);
+       _mdb_txn_abort(txn);
        return rc;
 }
 
@@ -9806,6 +9882,7 @@
                        }
                }
                mdb_default_cmp(txn, MAIN_DBI);
+               MDB_TRACE(("%p, (null), %u = %u", txn, flags, MAIN_DBI));
                return MDB_SUCCESS;
        }
 
@@ -9867,7 +9944,7 @@
                dummy.md_root = P_INVALID;
                dummy.md_flags = flags & PERSISTENT_FLAGS;
                WITH_CURSOR_TRACKING(mc,
-                       rc = mdb_cursor_put(&mc, &key, &data, F_SUBDATA));
+                       rc = _mdb_cursor_put(&mc, &key, &data, F_SUBDATA));
                dbflag |= DB_DIRTY;
        }
 
@@ -9892,6 +9969,7 @@
                if (!unused) {
                        txn->mt_numdbs++;
                }
+               MDB_TRACE(("%p, %s, %u = %u", txn, name, flags, slot));
        }
 
        return rc;
@@ -9923,6 +10001,7 @@
        ptr = env->me_dbxs[dbi].md_name.mv_data;
        /* If there was no name, this was already closed */
        if (ptr) {
+               MDB_TRACE(("%p, %u", env, dbi));
                env->me_dbxs[dbi].md_name.mv_data = NULL;
                env->me_dbxs[dbi].md_name.mv_size = 0;
                env->me_dbflags[dbi] = 0;
@@ -10057,6 +10136,7 @@
        if (rc)
                return rc;
 
+       MDB_TRACE(("%u, %d", dbi, del));
        rc = mdb_drop0(mc, mc->mc_db->md_flags & MDB_DUPSORT);
        /* Invalidate the dropped DB's cursors */
        for (m2 = txn->mt_cursors[dbi]; m2; m2 = m2->mc_next)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.6.2/lib/midl.h new/lmdb-1.7.2/lib/midl.h
--- old/lmdb-1.6.2/lib/midl.h   2025-01-06 06:52:59.000000000 +0100
+++ new/lmdb-1.7.2/lib/midl.h   2025-07-11 00:36:25.000000000 +0200
@@ -56,7 +56,9 @@
 /* IDL sizes - likely should be even bigger
  *   limiting factors: sizeof(ID), thread stack size
  */
+#ifndef MDB_IDL_LOGN
 #define        MDB_IDL_LOGN    16      /* DB_SIZE is 2^16, UM_SIZE is 2^17 */
+#endif
 #define MDB_IDL_DB_SIZE                (1<<MDB_IDL_LOGN)
 #define MDB_IDL_UM_SIZE                (1<<(MDB_IDL_LOGN+1))
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.6.2/lib/py-lmdb/env-copy-txn.patch 
new/lmdb-1.7.2/lib/py-lmdb/env-copy-txn.patch
--- old/lmdb-1.6.2/lib/py-lmdb/env-copy-txn.patch       2025-01-06 
06:52:59.000000000 +0100
+++ new/lmdb-1.7.2/lib/py-lmdb/env-copy-txn.patch       2025-07-11 
00:36:25.000000000 +0200
@@ -1,5 +1,5 @@
 diff --git a/libraries/liblmdb/lmdb.h b/libraries/liblmdb/lmdb.h
-index ff03c22..3d6f4cc 100644
+index 199382a..dd8374e 100644
 --- a/libraries/liblmdb/lmdb.h
 +++ b/libraries/liblmdb/lmdb.h
 @@ -682,9 +682,14 @@ int  mdb_env_copyfd(MDB_env *env, mdb_filehandle_t fd);
@@ -32,10 +32,10 @@
        /** @brief Return statistics about the LMDB environment.
         *
 diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c
-index deb6779..b5d152c 100644
+index 668f966..380e931 100644
 --- a/libraries/liblmdb/mdb.c
 +++ b/libraries/liblmdb/mdb.c
-@@ -9366,12 +9366,12 @@ done:
+@@ -9442,12 +9442,12 @@ done:
  
        /** Copy environment with compaction. */
  static int ESECT
@@ -50,7 +50,7 @@
        pthread_t thr;
        pgno_t root, new_root;
        int rc = MDB_SUCCESS;
-@@ -9417,9 +9417,11 @@ mdb_env_copyfd1(MDB_env *env, HANDLE fd)
+@@ -9493,9 +9493,11 @@ mdb_env_copyfd1(MDB_env *env, HANDLE fd)
        if (rc)
                goto done;
  
@@ -65,17 +65,17 @@
  
        mp = (MDB_page *)my.mc_wbuf[0];
        memset(mp, 0, NUM_METAS * env->me_psize);
-@@ -9479,7 +9481,8 @@ finish:
+@@ -9555,7 +9557,8 @@ finish:
                my.mc_error = rc;
        mdb_env_cthr_toggle(&my, 1 | MDB_EOF);
        rc = THREAD_FINISH(thr);
--      mdb_txn_abort(txn);
+-      _mdb_txn_abort(txn);
 +      if (!orig_txn)
-+              mdb_txn_abort(txn);
++              _mdb_txn_abort(txn);
  
  done:
  #ifdef _WIN32
-@@ -9596,12 +9599,22 @@ leave:
+@@ -9672,12 +9675,22 @@ leave:
  }
  
  int ESECT
@@ -100,7 +100,7 @@
  }
  
  int ESECT
-@@ -9612,6 +9625,12 @@ mdb_env_copyfd(MDB_env *env, HANDLE fd)
+@@ -9688,6 +9701,12 @@ mdb_env_copyfd(MDB_env *env, HANDLE fd)
  
  int ESECT
  mdb_env_copy2(MDB_env *env, const char *path, unsigned int flags)
@@ -113,7 +113,7 @@
  {
        int rc;
        MDB_name fname;
-@@ -9623,7 +9642,7 @@ mdb_env_copy2(MDB_env *env, const char *path, unsigned 
int flags)
+@@ -9699,7 +9718,7 @@ mdb_env_copy2(MDB_env *env, const char *path, unsigned 
int flags)
                mdb_fname_destroy(fname);
        }
        if (rc == MDB_SUCCESS) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.6.2/lib/py-lmdb/its-10346.patch 
new/lmdb-1.7.2/lib/py-lmdb/its-10346.patch
--- old/lmdb-1.6.2/lib/py-lmdb/its-10346.patch  1970-01-01 01:00:00.000000000 
+0100
+++ new/lmdb-1.7.2/lib/py-lmdb/its-10346.patch  2025-07-11 00:36:25.000000000 
+0200
@@ -0,0 +1,25 @@
+diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c
+index 668f966..0fe2328 100644
+--- a/libraries/liblmdb/mdb.c
++++ b/libraries/liblmdb/mdb.c
+@@ -9170,8 +9170,8 @@ typedef struct mdb_copy {
+       pthread_cond_t mc_cond; /**< Condition variable for #mc_new */
+       char *mc_wbuf[2];
+       char *mc_over[2];
+-      int mc_wlen[2];
+-      int mc_olen[2];
++      size_t mc_wlen[2];
++      size_t mc_olen[2];
+       pgno_t mc_next_pgno;
+       HANDLE mc_fd;
+       int mc_toggle;                  /**< Buffer number in provider */
+@@ -9188,7 +9188,8 @@ mdb_env_copythr(void *arg)
+ {
+       mdb_copy *my = arg;
+       char *ptr;
+-      int toggle = 0, wsize, rc;
++      int toggle = 0, rc;
++      size_t wsize;
+ #ifdef _WIN32
+       DWORD len;
+ #define DO_WRITE(rc, fd, ptr, w2, len)        rc = WriteFile(fd, ptr, w2, 
&len, NULL)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.6.2/lmdb/__init__.py 
new/lmdb-1.7.2/lmdb/__init__.py
--- old/lmdb-1.6.2/lmdb/__init__.py     2025-01-06 06:52:59.000000000 +0100
+++ new/lmdb-1.7.2/lmdb/__init__.py     2025-07-11 00:36:25.000000000 +0200
@@ -1,4 +1,4 @@
-# Copyright 2013-2021 The py-lmdb authors, all rights reserved.
+# Copyright 2013-2025 The py-lmdb authors, all rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted only as authorized by the OpenLDAP
@@ -50,4 +50,4 @@
     from lmdb.cffi import __all__
     from lmdb.cffi import __doc__
 
-__version__ = '1.6.2'
+__version__ = '1.7.2'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.6.2/lmdb/_config.py 
new/lmdb-1.7.2/lmdb/_config.py
--- old/lmdb-1.6.2/lmdb/_config.py      2025-01-06 06:53:06.000000000 +0100
+++ new/lmdb-1.7.2/lmdb/_config.py      2025-07-11 00:36:29.000000000 +0200
@@ -1,2 +1,2 @@
-CONFIG = dict((('extra_compile_args', ['-DHAVE_PATCHED_LMDB=1', '-UNDEBUG', 
'-w']), ('extra_sources', ['build/lib/mdb.c', 'build/lib/midl.c']), 
('extra_library_dirs', []), ('extra_include_dirs', ['lib/py-lmdb', 
'build/lib']), ('libraries', [])))
+CONFIG = dict((('extra_compile_args', ['-DHAVE_PATCHED_LMDB=1', '-UNDEBUG', 
'-w']), ('extra_sources', ['/home/runner/work/py-lmdb/py-lmdb/build/lib/mdb.c', 
'/home/runner/work/py-lmdb/py-lmdb/build/lib/midl.c']), ('extra_library_dirs', 
[]), ('extra_include_dirs', ['lib/py-lmdb', 
'/home/runner/work/py-lmdb/py-lmdb/build/lib', 
'/home/runner/work/py-lmdb/py-lmdb/lib/py-lmdb']), ('libraries', [])))
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.6.2/lmdb/cpython.c 
new/lmdb-1.7.2/lmdb/cpython.c
--- old/lmdb-1.6.2/lmdb/cpython.c       2025-01-06 06:52:59.000000000 +0100
+++ new/lmdb-1.7.2/lmdb/cpython.c       2025-07-11 00:36:25.000000000 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 2013-2024 The py-lmdb authors, all rights reserved.
+ * Copyright 2013-2025 The py-lmdb authors, all rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted only as authorized by the OpenLDAP
@@ -166,8 +166,13 @@
     DbObject *main_db;
     /**  1 if env opened read-only; transactions must always be read-only. */
     int readonly;
-    /** Spare read-only transaction . */
+    /** Spare read-only transaction. */
     struct MDB_txn *spare_txn;
+    /** Maximum number of spare transactions.  In cpython only 0 and 1 are 
supported.
+     *  If process will be forked, this must be set to 0. */
+    int max_spare_txns;
+    /** Process ID of the process this Environment was opened in. */
+    pid_t pid;
 };
 
 /** TransObject.flags bitfield values. */
@@ -1162,7 +1167,7 @@
         int max_dbs;
         int max_spare_txns;
         int lock;
-    } arg = {NULL, 10485760, 1, 0, 1, 1, 0, 0755, 1, 1, 0, 1, 126, 0, 1, 1};
+    } arg = {NULL, 10485760, 1, 0, 1, 1, 0, 0755, 1, 1, 0, 1, 126, 0, 0, 1};
 
     static const struct argspec argspec[] = {
         {"path", ARG_OBJ, OFFSET(env_new, path)},
@@ -1180,7 +1185,7 @@
         {"max_readers", ARG_INT, OFFSET(env_new, max_readers)},
         {"max_dbs", ARG_INT, OFFSET(env_new, max_dbs)},
         {"max_spare_txns", ARG_INT, OFFSET(env_new, max_spare_txns)},
-        {"lock", ARG_BOOL, OFFSET(env_new, lock)}
+        {"lock", ARG_BOOL, OFFSET(env_new, lock)},
     };
 
     PyObject *fspath_obj = NULL;
@@ -1208,6 +1213,8 @@
     self->main_db = NULL;
     self->env = NULL;
     self->spare_txn = NULL;
+    self->max_spare_txns = arg.max_spare_txns;
+    self->pid = getpid();
 
     if((rc = mdb_env_create(&self->env))) {
         err_set("mdb_env_create", rc);
@@ -3213,16 +3220,21 @@
         PyObject_ClearWeakRefs((PyObject *) self);
     }
 
-    if(txn && self->env && !self->env->spare_txn &&
-      (self->flags & TRANS_RDONLY)) {
-        MDEBUG("caching trans")
-        mdb_txn_reset(txn);
-        self->env->spare_txn = txn;
-        self->txn = NULL;
+    if(self->env && self->env->pid == getpid()) {
+        if(txn && self->env && !self->env->spare_txn && 
+                self->env->max_spare_txns && (self->flags & TRANS_RDONLY)) {
+            MDEBUG("caching trans")
+            mdb_txn_reset(txn);
+            self->env->spare_txn = txn;
+            self->txn = NULL;
+        }
+        MDEBUG("deleting trans")
+        trans_clear(self);
+    }
+    else {
+       MDEBUG("In forked process, not deleting trans");
     }
 
-    MDEBUG("deleting trans")
-    trans_clear(self);
     PyObject_Del(self);
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.6.2/lmdb.egg-info/PKG-INFO 
new/lmdb-1.7.2/lmdb.egg-info/PKG-INFO
--- old/lmdb-1.6.2/lmdb.egg-info/PKG-INFO       2025-01-06 06:53:06.000000000 
+0100
+++ new/lmdb-1.7.2/lmdb.egg-info/PKG-INFO       2025-07-11 00:36:29.000000000 
+0200
@@ -1,6 +1,6 @@
-Metadata-Version: 2.1
+Metadata-Version: 2.4
 Name: lmdb
-Version: 1.6.2
+Version: 1.7.2
 Summary: Universal Python binding for the LMDB 'Lightning' Database
 Home-page: http://github.com/jnwatson/py-lmdb/
 Author: David Wilson
@@ -23,5 +23,14 @@
 Classifier: Topic :: Database :: Database Engines/Servers
 Description-Content-Type: text/plain
 License-File: LICENSE
+Dynamic: author
+Dynamic: classifier
+Dynamic: description
+Dynamic: description-content-type
+Dynamic: home-page
+Dynamic: license
+Dynamic: license-file
+Dynamic: maintainer
+Dynamic: summary
 
 Universal Python binding for the LMDB 'Lightning' Database
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.6.2/lmdb.egg-info/SOURCES.txt 
new/lmdb-1.7.2/lmdb.egg-info/SOURCES.txt
--- old/lmdb-1.6.2/lmdb.egg-info/SOURCES.txt    2025-01-06 06:53:06.000000000 
+0100
+++ new/lmdb-1.7.2/lmdb.egg-info/SOURCES.txt    2025-07-11 00:36:29.000000000 
+0200
@@ -2,7 +2,10 @@
 LICENSE
 MANIFEST.in
 README.md
+pyproject.toml
 setup.py
+/home/runner/work/py-lmdb/py-lmdb/build/lib/mdb.c
+/home/runner/work/py-lmdb/py-lmdb/build/lib/midl.c
 docs/Makefile
 docs/conf.py
 docs/index.rst
@@ -30,6 +33,7 @@
 lib/midl.c
 lib/midl.h
 lib/py-lmdb/env-copy-txn.patch
+lib/py-lmdb/its-10346.patch
 lib/py-lmdb/preload.h
 lib/win32/inttypes.h
 lib/win32/unistd.h
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.6.2/pyproject.toml 
new/lmdb-1.7.2/pyproject.toml
--- old/lmdb-1.6.2/pyproject.toml       1970-01-01 01:00:00.000000000 +0100
+++ new/lmdb-1.7.2/pyproject.toml       2025-07-11 00:36:25.000000000 +0200
@@ -0,0 +1,19 @@
+[build-system]
+requires = ["setuptools", "wheel", "cffi>=0.8", "patch-ng"]
+build-backend = "setuptools.build_meta"
+
+[tool.cibuildwheel]
+build-verbosity = 1
+skip = "*-musllinux_*"
+
+# Before building, install patch-ng, which is needed for applying patches.
+before-build = "pip install cffi patch-ng"
+
+[tool.cibuildwheel.linux]
+archs = ["x86_64", "aarch64"]
+
+[tool.cibuildwheel.macos]
+archs = ["x86_64", "arm64"]
+
+[tool.cibuildwheel.windows]
+archs = ["AMD64", "ARM64"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.6.2/setup.py new/lmdb-1.7.2/setup.py
--- old/lmdb-1.6.2/setup.py     2025-01-06 06:52:59.000000000 +0100
+++ new/lmdb-1.7.2/setup.py     2025-07-11 00:36:25.000000000 +0200
@@ -66,25 +66,27 @@
 extra_include_dirs += ['lib/py-lmdb']
 extra_compile_args = []
 
-patch_lmdb_source = False
-
+patch_lmdb_source = True
 if os.getenv('LMDB_FORCE_SYSTEM') is not None:
     print('py-lmdb: Using system version of liblmdb.')
     extra_sources = []
     extra_include_dirs += []
     libraries = ['lmdb']
+    patch_lmdb_source = False
 elif os.getenv('LMDB_PURE') is not None:
     print('py-lmdb: Using bundled unmodified liblmdb; override with 
LMDB_FORCE_SYSTEM=1.')
     extra_sources = ['lib/mdb.c', 'lib/midl.c']
     extra_include_dirs += ['lib']
     libraries = []
+    patch_lmdb_source = False
 else:
     print('py-lmdb: Using bundled liblmdb with py-lmdb patches; override with 
LMDB_FORCE_SYSTEM=1 or LMDB_PURE=1.')
-    extra_sources = ['build/lib/mdb.c', 'build/lib/midl.c']
-    extra_include_dirs += ['build/lib']
+    extra_sources = [os.path.abspath(s) for s in ['build/lib/mdb.c', 
'build/lib/midl.c']]
+    extra_include_dirs += [os.path.abspath('build/lib'), 
os.path.abspath('lib/py-lmdb')]
     extra_compile_args += ['-DHAVE_PATCHED_LMDB=1']
     libraries = []
-    patch_lmdb_source = True
+
+
 
 if patch_lmdb_source:
     if sys.platform.startswith('win'):
@@ -108,13 +110,15 @@
 
     # Copy away the lmdb source then patch it
     if sys.platform.startswith('win'):
-        patchfile = 'lib' + os.sep + 'py-lmdb' + os.sep + 'env-copy-txn.patch'
-        patchset = patch.fromfile(patchfile)
-        rv = patchset.apply(2, root=dest)
-        if not rv:
-            raise Exception('Applying patch failed')
+
+        for patchfile in ['lib\\py-lmdb\\env-copy-txn.patch', 
'lib\\py-lmdb\\its-10346.patch']:
+            patchset = patch.fromfile(patchfile)
+            rv = patchset.apply(2, root=dest)
+            if not rv:
+                raise Exception('Applying patch failed')
     else:
         rv = os.system('patch -N -p3 -d build/lib < 
lib/py-lmdb/env-copy-txn.patch')
+        rv = os.system('patch -N -p3 -d build/lib < 
lib/py-lmdb/its-10346.patch')
         if rv:
             raise Exception('Applying patch failed')
 
@@ -176,12 +180,17 @@
 else:
     print('Using cffi extension.')
     install_requires = ['cffi>=0.8']
-    try:
-        import lmdb.cffi
-        ext_modules = [lmdb.cffi._ffi.verifier.get_extension()]
-    except ImportError:
-        sys.stderr.write('Could not import lmdb; ensure cffi is installed!\n')
+    if platform.python_implementation() == 'PyPy':
+        print('Using cffi with PyPy, no extension module to build.')
         ext_modules = []
+    else:
+        print('Using cffi with CPython, building extension module.')
+        try:
+            import lmdb.cffi
+            ext_modules = [lmdb.cffi._ffi.verifier.get_extension()]
+        except ImportError:
+            sys.stderr.write('Could not import lmdb; ensure cffi is 
installed!\n')
+            ext_modules = []
 
 def grep_version():
     path = os.path.join(os.path.dirname(__file__), 'lmdb/__init__.py')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.6.2/tests/env_test.py 
new/lmdb-1.7.2/tests/env_test.py
--- old/lmdb-1.6.2/tests/env_test.py    2025-01-06 06:52:59.000000000 +0100
+++ new/lmdb-1.7.2/tests/env_test.py    2025-07-11 00:36:25.000000000 +0200
@@ -826,7 +826,6 @@
     def tearDown(self):
         testlib.cleanup()
 
-    @unittest.skip('Temporarily removed this functionality')
     def test_none(self):
         _, env = testlib.temp_env(max_spare_txns=0)
         assert 0 == reader_count(env)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lmdb-1.6.2/tests/txn_test.py 
new/lmdb-1.7.2/tests/txn_test.py
--- old/lmdb-1.6.2/tests/txn_test.py    2025-01-06 06:52:59.000000000 +0100
+++ new/lmdb-1.7.2/tests/txn_test.py    2025-07-11 00:36:25.000000000 +0200
@@ -1,5 +1,5 @@
 #
-# Copyright 2013 The py-lmdb authors, all rights reserved.
+# Copyright 2013-2025 The py-lmdb authors, all rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted only as authorized by the OpenLDAP
@@ -20,8 +20,8 @@
 # <http://www.openldap.org/>.
 #
 
-from __future__ import absolute_import
-from __future__ import with_statement
+import os
+import sys
 import struct
 import unittest
 import weakref
@@ -40,7 +40,7 @@
 ULONG_0002 = struct.pack('L', 2)  # L != size_t
 
 
-class InitTest(unittest.TestCase):
+class InitTest(testlib.LmdbTest):
     def tearDown(self):
         testlib.cleanup()
 
@@ -140,6 +140,39 @@
         assert isinstance(b, type(B('')))
         txn.abort()
 
+    @unittest.skipIf(sys.platform.startswith('win'), "No fork on Windows")
+    def test_cached_txn_across_fork(self):
+        _, env = testlib.temp_env()
+        txn = env.begin(write=False)
+        del txn
+
+        if os.fork() != 0:
+            # I am the parent
+            os.wait()  # Wait for child to finish
+            txn = env.begin(write=False)  # Used to raise MDB_BAD_RSLOT (#346)
+
+    @unittest.skipIf(sys.platform.startswith('win'), "No fork on Windows")
+    def test_child_deleting_transaction(self):
+        _, env = testlib.temp_env()
+        with env.begin(write=True) as txn:
+            txn.put(b'a', b'foo')
+        txn = env.begin()
+
+        r = env.readers()
+        assert r != '(no active readers)\n'
+
+        pid = os.fork()
+        if pid == 0:
+            del txn   # I am the child
+            os._exit(0)
+
+        os.waitpid(pid, 0)
+        # Make sure my child didn't mess with my environment
+        r2 = env.readers()
+        assert r2 == r, '%r != %r' % (r2, r)
+        assert txn.get(b'a') == b'foo'
+        del txn
+
 
 class ContextManagerTest(unittest.TestCase):
     def tearDown(self):

Reply via email to