diff --git a/CHANGELOG.md b/CHANGELOG.md index f24328887..e9da25f67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ `ReadOnlyMultimapTable::range()`, whose `'static` iterators do not keep the transaction alive, are removed under the flag; use the `ReadableTable` and `ReadableMultimapTable` methods, or the `range_owned()` variants when the iterator must outlive the table. +* The inherent `ReadOnlyTable::get()` and `ReadOnlyMultimapTable::get()`, whose `'static` guards + and iterators likewise do not keep the transaction alive, are also removed under the + `experimental-api-5` flag; use the `ReadableTable` and `ReadableMultimapTable` methods, or the + `get_owned()` variants when the guard must outlive the table. ## 4.2.0 - 2026-XX-XX * Fix a panic when opening a database containing a corrupted persistent savepoint record; diff --git a/crates/redb-derive/tests/crate_attr_tests.rs b/crates/redb-derive/tests/crate_attr_tests.rs index 6ca87fc65..d11b28389 100644 --- a/crates/redb-derive/tests/crate_attr_tests.rs +++ b/crates/redb-derive/tests/crate_attr_tests.rs @@ -54,6 +54,8 @@ use new::NewValue; use old::OldValue; use old3::{Old3Inner, Old3Value}; use redb::ReadableDatabase; +#[allow(unused_imports)] +use redb::ReadableTable; use redb3_0::ReadableDatabase as _; fn create_tempfile() -> tempfile::NamedTempFile { diff --git a/crates/redb-derive/tests/derive_tests.rs b/crates/redb-derive/tests/derive_tests.rs index 2238b7968..44fe87764 100644 --- a/crates/redb-derive/tests/derive_tests.rs +++ b/crates/redb-derive/tests/derive_tests.rs @@ -1,3 +1,5 @@ +#[allow(unused_imports)] +use redb::ReadableTable; use redb::{Database, Key, ReadableDatabase, TableDefinition, TableError, TypeName, Value}; use redb_derive::{Key, Value}; use std::fmt::Debug; diff --git a/src/multimap_table.rs b/src/multimap_table.rs index 3668c9a8b..49e89cc13 100644 --- a/src/multimap_table.rs +++ b/src/multimap_table.rs @@ -1133,7 +1133,15 @@ impl ReadOnlyMultimapTable { /// This method is like [`ReadableMultimapTable::get()`], but the iterator is reference counted and keeps the transaction /// alive until it is dropped. + #[cfg(not(feature = "experimental-api-5"))] pub fn get<'a>(&self, key: impl Borrow>) -> Result> { + self.get_inner(key) + } + + fn get_inner<'a>( + &self, + key: impl Borrow>, + ) -> Result> { let iter = if let Some(collection) = self.tree.get(key.borrow())? { MultimapValue::from_collection( collection, @@ -1164,7 +1172,7 @@ impl ReadOnlyMultimapTable { key: impl Borrow>, ) -> Result> { Ok(OwnedMultimapValue::new( - self.get(key)?, + self.get_inner(key)?, self.transaction_guard.clone(), )) } diff --git a/src/table.rs b/src/table.rs index 31ed2b6d7..c2762ad4f 100644 --- a/src/table.rs +++ b/src/table.rs @@ -879,6 +879,7 @@ impl ReadOnlyTable { /// This method is like [`ReadableTable::get()`], but the [`AccessGuard`] is reference counted /// and keeps the transaction alive until it is dropped. + #[cfg(not(feature = "experimental-api-5"))] pub fn get<'a>( &self, key: impl Borrow>, @@ -893,7 +894,8 @@ impl ReadOnlyTable { key: impl Borrow>, ) -> Result>> { Ok(self - .get(key)? + .tree + .get(key.borrow())? .map(|x| OwnedAccessGuard::new(x, self.transaction_guard.clone()))) } diff --git a/src/transactions.rs b/src/transactions.rs index bf0a864fe..c714ae25c 100644 --- a/src/transactions.rs +++ b/src/transactions.rs @@ -2682,6 +2682,8 @@ impl Debug for ReadTransaction { #[cfg(test)] mod test { + #[cfg(feature = "experimental-api-5")] + use crate::ReadableTable; use crate::{Database, ReadableDatabase, StorageError, TableDefinition, TransactionError}; const X: TableDefinition<&str, &str> = TableDefinition::new("x"); diff --git a/src/tree_store/page_store/header.rs b/src/tree_store/page_store/header.rs index 48895903d..b6f734136 100644 --- a/src/tree_store/page_store/header.rs +++ b/src/tree_store/page_store/header.rs @@ -563,6 +563,8 @@ impl TransactionHeader { #[cfg(test)] mod test { + #[cfg(feature = "experimental-api-5")] + use crate::ReadableTable; use crate::backends::FileBackend; use crate::db::TableDefinition; use crate::tree_store::page_store::base::MAX_REGIONS; diff --git a/tests/backward_compatibility.rs b/tests/backward_compatibility.rs index 37f492afe..ebd5d1ecc 100644 --- a/tests/backward_compatibility.rs +++ b/tests/backward_compatibility.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "experimental-api-5")] +use redb::ReadableTable; use redb::{ReadableDatabase, ReadableTableMetadata}; const ELEMENTS: usize = 3; diff --git a/tests/check_integrity_nondurable.rs b/tests/check_integrity_nondurable.rs index 60d50c689..6f1af46ec 100644 --- a/tests/check_integrity_nondurable.rs +++ b/tests/check_integrity_nondurable.rs @@ -3,6 +3,8 @@ //! the live state from disk; it refuses to promote when the backing file was externally truncated //! or extended, falling back to repairing the durable state instead. +#[cfg(feature = "experimental-api-5")] +use redb::ReadableTable; use redb::{ Database, Durability, ReadableDatabase, ReadableTableMetadata, StorageBackend, TableDefinition, }; diff --git a/tests/crash_consistency.rs b/tests/crash_consistency.rs index e1d1f7db4..a828626db 100644 --- a/tests/crash_consistency.rs +++ b/tests/crash_consistency.rs @@ -6,6 +6,8 @@ //! `Corrupted("File truncated below stored layout")` -- permanent data loss -- even though the //! previous durable state was intact. The fix makes the file extension durable as the file grows. +#[cfg(feature = "experimental-api-5")] +use redb::ReadableTable; use redb::backends::InMemoryBackend; use redb::{Database, ReadableDatabase, StorageBackend, TableDefinition}; use std::io::ErrorKind; diff --git a/tests/multimap_tests.rs b/tests/multimap_tests.rs index fb9425bed..814ab06a7 100644 --- a/tests/multimap_tests.rs +++ b/tests/multimap_tests.rs @@ -237,7 +237,13 @@ fn get_arc_lifetime() { let read_txn = db.begin_read().unwrap(); let table = read_txn.open_multimap_table(definition).unwrap(); let start = "hello".to_string(); - table.get(start.as_str()).unwrap() + // The 'static get() does not keep the transaction alive, so experimental-api-5 drops it + // in favour of get_owned() + #[cfg(feature = "experimental-api-5")] + let iter = table.get_owned(start.as_str()).unwrap(); + #[cfg(not(feature = "experimental-api-5"))] + let iter = table.get(start.as_str()).unwrap(); + iter }; assert_eq!(iter.next().unwrap().unwrap().value(), "world"); assert!(iter.next().is_none());