From 7abf49995f18fa293b52e001a5c526e02c99c29f Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Wed, 11 Sep 2024 14:16:05 +0100 Subject: [PATCH] fix(libmdbx): renew tx on timeout when dropping cursor (#10840) --- crates/storage/libmdbx-rs/src/cursor.rs | 7 +++++-- crates/storage/libmdbx-rs/src/transaction.rs | 22 +++++++++++++++++++- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/crates/storage/libmdbx-rs/src/cursor.rs b/crates/storage/libmdbx-rs/src/cursor.rs index 99fe5256ea..d007cc03e4 100644 --- a/crates/storage/libmdbx-rs/src/cursor.rs +++ b/crates/storage/libmdbx-rs/src/cursor.rs @@ -486,8 +486,11 @@ where K: TransactionKind, { fn drop(&mut self) { - // Ignore the error, because we're dropping the cursor anyway. - let _ = self.txn.txn_execute(|_| unsafe { ffi::mdbx_cursor_close(self.cursor) }); + // To be able to close a cursor of a timed out transaction, we need to renew it first. + // Hence the usage of `txn_execute_renew_on_timeout` here. + let _ = self + .txn + .txn_execute_renew_on_timeout(|_| unsafe { ffi::mdbx_cursor_close(self.cursor) }); } } diff --git a/crates/storage/libmdbx-rs/src/transaction.rs b/crates/storage/libmdbx-rs/src/transaction.rs index 37af501c18..88236ebe99 100644 --- a/crates/storage/libmdbx-rs/src/transaction.rs +++ b/crates/storage/libmdbx-rs/src/transaction.rs @@ -112,6 +112,18 @@ where self.inner.txn_execute(f) } + /// Executes the given closure once the lock on the transaction is acquired. If the transaction + /// is timed out, it will be renewed first. + /// + /// Returns the result of the closure or an error if the transaction renewal fails. + #[inline] + pub(crate) fn txn_execute_renew_on_timeout(&self, f: F) -> Result + where + F: FnOnce(*mut ffi::MDBX_txn) -> T, + { + self.inner.txn_execute_renew_on_timeout(f) + } + /// Returns a copy of the raw pointer to the underlying MDBX transaction. #[doc(hidden)] #[cfg(test)] @@ -321,6 +333,14 @@ where { self.txn.txn_execute_fail_on_timeout(f) } + + #[inline] + fn txn_execute_renew_on_timeout(&self, f: F) -> Result + where + F: FnOnce(*mut ffi::MDBX_txn) -> T, + { + self.txn.txn_execute_renew_on_timeout(f) + } } impl Drop for TransactionInner @@ -596,7 +616,7 @@ impl TransactionPtr { /// /// Returns the result of the closure or an error if the transaction renewal fails. #[inline] - fn txn_execute_renew_on_timeout(&self, f: F) -> Result + pub(crate) fn txn_execute_renew_on_timeout(&self, f: F) -> Result where F: FnOnce(*mut ffi::MDBX_txn) -> T, {