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 - +[](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):