lib ldb: lmdb clear stale readers on write txn start
authorGary Lockyer <gary@catalyst.net.nz>
Sun, 29 Mar 2020 23:08:30 +0000 (12:08 +1300)
committerAndrew Bartlett <abartlet@samba.org>
Tue, 31 Mar 2020 01:26:07 +0000 (01:26 +0000)
In use process failures and Bind9 shut downs leave stale entries in the
lmdb reader table.  This can result in lmdb filling it's database file, as
the free list can not be reclaimed due to the stale reader.

In this fix we call mdb_reader_check at the start of each transaction,
to free any stale readers.  As the default maximum number of readers is
127, this should not impact on performance to any great extent.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14330

Signed-off-by: Gary Lockyer <gary@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Autobuild-User(master): Andrew Bartlett <abartlet@samba.org>
Autobuild-Date(master): Tue Mar 31 01:26:07 UTC 2020 on sn-devel-184

lib/ldb/ldb_mdb/ldb_mdb.c
lib/ldb/tests/ldb_lmdb_free_list_test.c

index 6c679c214b876d0eb9353d075d8e323cbe17d700..1187aba578ada145497b03444004a61b421adf89 100644 (file)
@@ -641,6 +641,23 @@ static int lmdb_transaction_start(struct ldb_kv_private *ldb_kv)
                return LDB_ERR_PROTOCOL_ERROR;
        }
 
+       /*
+        * Clear out any stale readers
+        */
+       {
+               int stale;
+               mdb_reader_check(lmdb->env, &stale);
+               if (stale > 0) {
+                       ldb_debug(
+                               lmdb->ldb,
+                               LDB_DEBUG_ERROR,
+                               "LMDB Stale readers, deleted (%d)",
+                               stale);
+               }
+       }
+
+
+
        ltx_head = lmdb_private_trans_head(lmdb);
 
        tx_parent = lmdb_trans_get_tx(ltx_head);
index fe78e3ab7020f824a5337a6f00059f821a146a27..9b2954607309f8c4a70240654d8e3365e4f28e86 100644 (file)
@@ -617,7 +617,12 @@ static void test_free_list_stale_reader(void **state)
                ret = ldb_kv->kv_ops->finish_write(ldb_kv);
                assert_int_equal(ret, LDB_SUCCESS);
        }
-       assert_int_equal(ret, LDB_ERR_BUSY);
+       /*
+        * We now do an explicit clear of stale readers at the start of a
+        * write transaction so should not get LDB_ERR_BUSY any more
+        * assert_int_equal(ret, LDB_ERR_BUSY);
+        */
+       assert_int_equal(ret, LDB_SUCCESS);
        assert_int_not_equal(i, 0);
 
        /*