From fe482a9416cb76b8903afdb838793bc98b397dac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20D=E2=80=99Aquino?= Date: Thu, 7 May 2026 13:07:12 -0700 Subject: [PATCH] ndb: Check and clear stale LMDB readers on init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changelog-Changed: Clear stale LMDB readers on NostrDB init to prevent reader slot leakage and runaway storage usage Signed-off-by: Daniel D’Aquino --- nostrdb/src/nostrdb.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/nostrdb/src/nostrdb.c b/nostrdb/src/nostrdb.c index a06e5821..4217d540 100644 --- a/nostrdb/src/nostrdb.c +++ b/nostrdb/src/nostrdb.c @@ -165,6 +165,32 @@ struct ndb_lmdb { MDB_dbi dbs[NDB_DBS]; }; +/** + * Clears stale LMDB reader slots after opening the environment. + * + * This protects startup on platforms where reader slots are not reclaimed + * automatically after process termination. + * + * @param[in] env The LMDB environment to inspect. + * @return 1 when the check succeeds, 0 when LMDB reports an error. + */ +static int ndb_lmdb_reader_check(MDB_env *env) +{ + int rc; + int dead = 0; + + rc = mdb_reader_check(env, &dead); + if (rc != MDB_SUCCESS) { + fprintf(stderr, "mdb_reader_check failed: %s\n", mdb_strerror(rc)); + return 0; + } + + if (dead > 0) + fprintf(stderr, "mdb_reader_check cleared %d stale reader(s)\n", dead); + + return 1; +} + struct ndb_writer { struct ndb_lmdb *lmdb; struct ndb_monitor *monitor; @@ -5849,6 +5875,12 @@ static int ndb_init_lmdb(const char *filename, struct ndb_lmdb *lmdb, size_t map return 0; } + if (!ndb_lmdb_reader_check(lmdb->env)) { + mdb_env_close(lmdb->env); + lmdb->env = NULL; + return 0; + } + // Initialize DBs if ((rc = mdb_txn_begin(lmdb->env, NULL, 0, &txn))) { fprintf(stderr, "mdb_txn_begin failed, error %d\n", rc);