Skip to content

Commit 0fec53a

Browse files
committed
PYCBC-1798: Fix dealloc_transactions leak and GIL-held close
* Delete the heap-allocated transactions wrapper on capsule destroy; it was previously never freed, leaking the whole C++ transactions runtime on every teardown * Release the GIL around the txns->close() and delete txns calls, so a pending IO-thread callback can't deadlock waiting to reacquire it * Free the same wrapper when PyCapsule_New fails in create_transactions; with no capsule the destructor is never registered, so the core cleanup threads it owns would otherwise run for the life of the process Change-Id: I87d4014122bf5b745ce157b0c73b359bbfa8e44d Reviewed-on: https://review.couchbase.org/c/couchbase-python-client/+/249285 Reviewed-by: Sergey Avseyev <sergey.avseyev@gmail.com> Tested-by: Build Bot <build@couchbase.com>
1 parent 971195b commit 0fec53a

1 file changed

Lines changed: 11 additions & 3 deletions

File tree

src/transactions/transactions.cxx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ void
3636
pycbc::txns::dealloc_transactions(PyObject* obj)
3737
{
3838
auto txns = reinterpret_cast<pycbc::txns::transactions*>(PyCapsule_GetPointer(obj, "txns_"));
39-
txns->txns->close();
40-
txns->txns.reset();
41-
CB_LOG_DEBUG("dealloc transactions");
39+
Py_BEGIN_ALLOW_THREADS txns->txns->close();
40+
delete txns;
41+
Py_END_ALLOW_THREADS CB_LOG_DEBUG("dealloc transactions");
4242
}
4343

4444
void
@@ -627,6 +627,14 @@ pycbc::txns::create_transactions([[maybe_unused]] PyObject* self, PyObject* args
627627

628628
pycbc::txns::transactions* txns = new pycbc::txns::transactions(res.second);
629629
PyObject* pyObj_txns = PyCapsule_New(txns, "txns_", dealloc_transactions);
630+
if (pyObj_txns == nullptr) {
631+
// No capsule means dealloc_transactions() never runs, so release the wrapper (and the core
632+
// cleanup threads it owns) here. GIL released b/c close() blocks joining those threads.
633+
Py_BEGIN_ALLOW_THREADS txns->txns->close();
634+
delete txns;
635+
res.second.reset();
636+
Py_END_ALLOW_THREADS return nullptr;
637+
}
630638
return pyObj_txns;
631639
}
632640

0 commit comments

Comments
 (0)