From 28b1cfe02f82b1445ef6341258f76f90b8172167 Mon Sep 17 00:00:00 2001 From: Tamo Date: Mon, 6 May 2024 18:29:25 +0200 Subject: [PATCH] enable self referential static rtxn --- heed/src/env.rs | 30 ++++++++++++++++++++++++++++++ heed/src/txn.rs | 24 ++++++++++++++++++++---- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/heed/src/env.rs b/heed/src/env.rs index 3bc09c84..21fbcf68 100644 --- a/heed/src/env.rs +++ b/heed/src/env.rs @@ -748,6 +748,7 @@ impl Env { /// /// You can make this transaction `Send`able between threads by /// using the `read-txn-no-tls` crate feature. + /// See [`Self::static_read_txn`] if you want the txn to own the environment. /// /// ## LMDB Limitations /// @@ -771,6 +772,35 @@ impl Env { RoTxn::new(self) } + /// Create a transaction with read-only access for use with the environment. + /// Contrary to [`Self::read_txn`], this version **owns** the environment, which + /// means you won't be able to close the environment while this transaction is alive. + /// + /// You can make this transaction `Send`able between threads by + /// using the `read-txn-no-tls` crate feature. + /// + /// ## LMDB Limitations + /// + /// It's possible to have multiple read transactions in the same environment + /// while there is a write transaction ongoing. + /// + /// But read transactions prevent reuse of pages freed by newer write transactions, + /// thus the database can grow quickly. Write transactions prevent other write transactions, + /// since writes are serialized. + /// + /// So avoid long-lived read transactions. + /// + /// ## Errors + /// + /// * [`crate::MdbError::Panic`]: A fatal error occurred earlier, and the environment must be shut down + /// * [`crate::MdbError::MapResized`]: Another process wrote data beyond this [`Env`] mapsize and this env + /// map must be resized + /// * [`crate::MdbError::ReadersFull`]: a read-only transaction was requested, and the reader lock table is + /// full + pub fn static_read_txn(self) -> Result> { + RoTxn::static_read_txn(self) + } + /// Copy an LMDB environment to the specified path, with options. /// /// This function may be used to make a backup of an existing environment. diff --git a/heed/src/txn.rs b/heed/src/txn.rs index 611a9a65..b8c18ae9 100644 --- a/heed/src/txn.rs +++ b/heed/src/txn.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::ops::Deref; use std::ptr; @@ -26,7 +27,7 @@ use crate::{Env, Result}; /// You may increase the limit by editing it **at your own risk**: `/Library/LaunchDaemons/sysctl.plist` pub struct RoTxn<'e> { pub(crate) txn: *mut ffi::MDB_txn, - env: &'e Env, + env: Cow<'e, Env>, } impl<'e> RoTxn<'e> { @@ -42,7 +43,22 @@ impl<'e> RoTxn<'e> { ))? }; - Ok(RoTxn { txn, env }) + Ok(RoTxn { txn, env: Cow::Borrowed(env) }) + } + + pub(crate) fn static_read_txn(env: Env) -> Result> { + let mut txn: *mut ffi::MDB_txn = ptr::null_mut(); + + unsafe { + mdb_result(ffi::mdb_txn_begin( + env.env_mut_ptr(), + ptr::null_mut(), + ffi::MDB_RDONLY, + &mut txn, + ))? + }; + + Ok(RoTxn { txn, env: Cow::Owned(env) }) } pub(crate) fn env_mut_ptr(&self) -> *mut ffi::MDB_env { @@ -110,7 +126,7 @@ impl<'p> RwTxn<'p> { unsafe { mdb_result(ffi::mdb_txn_begin(env.env_mut_ptr(), ptr::null_mut(), 0, &mut txn))? }; - Ok(RwTxn { txn: RoTxn { txn, env } }) + Ok(RwTxn { txn: RoTxn { txn, env: Cow::Borrowed(env) } }) } pub(crate) fn nested(env: &'p Env, parent: &'p mut RwTxn) -> Result> { @@ -119,7 +135,7 @@ impl<'p> RwTxn<'p> { unsafe { mdb_result(ffi::mdb_txn_begin(env.env_mut_ptr(), parent_ptr, 0, &mut txn))? }; - Ok(RwTxn { txn: RoTxn { txn, env } }) + Ok(RwTxn { txn: RoTxn { txn, env: Cow::Borrowed(env) } }) } pub(crate) fn env_mut_ptr(&self) -> *mut ffi::MDB_env {