Repository: cberner/redb
Pull request #463 (2022-12-19 22:12:17)

Make all APIs consistent in returning AccessGuard instead of SelfType


Patch:
diff --git a/benches/common.rs b/benches/common.rs
index 9555166..6c3e771 100644
--- a/benches/common.rs
+++ b/benches/common.rs
@@ -1,5 +1,5 @@
-use redb::ReadableTable;
 use redb::TableDefinition;
+use redb::{AccessGuard, ReadableTable};
 use rocksdb::{Direction, IteratorMode, TransactionDB, TransactionOptions, WriteOptions};
 use sanakirja::btree::page_unsized;
 use sanakirja::{Commit, RootDb};
@@ -121,11 +121,11 @@ pub struct RedbBenchReader<'txn> {
 }
 
 impl<'txn> BenchReader for RedbBenchReader<'txn> {
-    type Output<'out> = &'out [u8] where Self: 'out;
+    type Output<'out> = RedbAccessGuard<'out> where Self: 'out;
     type Iterator<'out> = RedbBenchIterator<'out> where Self: 'out;
 
-    fn get(&self, key: &[u8]) -> Option<&[u8]> {
-        self.table.get(key).unwrap()
+    fn get<'a>(&'a self, key: &[u8]) -> Option<Self::Output<'a>> {
+        self.table.get(key).unwrap().map(RedbAccessGuard::new)
     }
 
     fn range_from<'a>(&'a self, key: &'a [u8]) -> Self::Iterator<'a> {
@@ -139,10 +139,28 @@ pub struct RedbBenchIterator<'a> {
 }
 
 impl BenchIterator for RedbBenchIterator<'_> {
-    type Output<'a> = &'a [u8] where Self: 'a;
+    type Output<'a> = RedbAccessGuard<'a> where Self: 'a;
 
     fn next(&mut self) -> Option<(Self::Output<'_>, Self::Output<'_>)> {
-        self.iter.next()
+        self.iter
+            .next()
+            .map(|(k, v)| (RedbAccessGuard::new(k), RedbAccessGuard::new(v)))
+    }
+}
+
+pub struct RedbAccessGuard<'a> {
+    inner: AccessGuard<'a, &'a [u8]>,
+}
+
+impl<'a> RedbAccessGuard<'a> {
+    fn new(inner: AccessGuard<'a, &'a [u8]>) -> Self {
+        Self { inner }
+    }
+}
+
+impl<'a> AsRef<[u8]> for RedbAccessGuard<'a> {
+    fn as_ref(&self) -> &[u8] {
+        self.inner.value()
     }
 }
 
diff --git a/examples/int_keys.rs b/examples/int_keys.rs
index b451e5a..ee7691f 100644
--- a/examples/int_keys.rs
+++ b/examples/int_keys.rs
@@ -13,7 +13,7 @@ fn main() -> Result<(), Error> {
 
     let read_txn = db.begin_read()?;
     let table = read_txn.open_table(TABLE)?;
-    assert_eq!(table.get(&0)?.unwrap(), 0);
+    assert_eq!(table.get(&0)?.unwrap().value(), 0);
 
     Ok(())
 }
diff --git a/fuzz/fuzz_targets/fuzz_redb.rs b/fuzz/fuzz_targets/fuzz_redb.rs
index c64b115..0498726 100644
--- a/fuzz/fuzz_targets/fuzz_redb.rs
+++ b/fuzz/fuzz_targets/fuzz_redb.rs
@@ -1,10 +1,7 @@
 #![no_main]
 
 use libfuzzer_sys::fuzz_target;
-use redb::{
-    Database, Durability, Error, MultimapTableDefinition, MultimapValueIter, ReadableMultimapTable,
-    ReadableTable, TableDefinition, WriteStrategy,
-};
+use redb::{AccessGuard, Database, Durability, Error, MultimapTableDefinition, MultimapValueIter, ReadableMultimapTable, ReadableTable, TableDefinition, WriteStrategy};
 use std::collections::{BTreeMap, BTreeSet};
 use std::sync::{Arc, Mutex};
 use std::thread;
@@ -67,7 +64,7 @@ fn exec_table_inner(db: Arc<Database>, transactions: &[FuzzTransaction], referen
                         match local_reference.get(&key) {
                             Some(reference_len) => {
                                 let value = table.get(&key).unwrap().unwrap();
-                                assert_eq!(value.len(), *reference_len);
+                                assert_eq!(value.value().len(), *reference_len);
                             }
                             None => {
                                 assert!(table.get(&key).unwrap().is_none());
@@ -93,7 +90,7 @@ fn exec_table_inner(db: Arc<Database>, transactions: &[FuzzTransaction], referen
                         match local_reference.remove(&key) {
                             Some(reference_len) => {
                                 let value = table.remove(&key)?;
-                                assert_eq!(value.unwrap().to_value().len(), reference_len);
+                                assert_eq!(value.unwrap().value().len(), reference_len);
                             }
                             None => {
                                 assert!(table.remove(&key).unwrap().is_none());
@@ -116,15 +113,15 @@ fn exec_table_inner(db: Arc<Database>, transactions: &[FuzzTransaction], referen
                             } else {
                                 Box::new(local_reference.range(start..end))
                             };
-                        let mut iter: Box<dyn Iterator<Item = (u64, &[u8])>> = if *reversed {
+                        let mut iter: Box<dyn Iterator<Item = (AccessGuard<u64>, AccessGuard<&[u8]>)>> = if *reversed {
                             Box::new(table.range(start..end).unwrap().rev())
                         } else {
                             Box::new(table.range(start..end).unwrap())
                         };
                         while let Some((ref_key, ref_value_len)) = reference_iter.next() {
                             let (key, value) = iter.next().unwrap();
-                            assert_eq!(*ref_key, key);
-                            assert_eq!(*ref_value_len, value.len());
+                            assert_eq!(*ref_key, key.value());
+                            assert_eq!(*ref_value_len, value.value().len());
                         }
                         assert!(iter.next().is_none());
                     }
@@ -149,7 +146,7 @@ fn assert_multimap_value_eq(
 ) {
     if let Some(values) = reference {
         for value in values.iter() {
-            assert_eq!(iter.next().unwrap().len(), *value);
+            assert_eq!(iter.next().unwrap().value().len(), *value);
         }
     }
     assert!(iter.next().is_none());
@@ -253,14 +250,14 @@ fn exec_multimap_table_inner(db: Arc<Database>, transactions: &[FuzzTransaction]
                             } else {
                                 Box::new(local_reference.range(start..end))
                             };
-                        let mut iter: Box<dyn Iterator<Item = (u64, MultimapValueIter<&[u8]>)>> = if *reversed {
+                        let mut iter: Box<dyn Iterator<Item = (AccessGuard<u64>, MultimapValueIter<&[u8]>)>> = if *reversed {
                             Box::new(table.range(&start..&end).unwrap().rev())
                         } else {
                             Box::new(table.range(&start..&end).unwrap())
                         };
                         while let Some((ref_key, ref_values)) = reference_iter.next() {
                             let (key, value_iter) = iter.next().unwrap();
-                            assert_eq!(*ref_key, key);
+                            assert_eq!(*ref_key, key.value());
                             assert_multimap_value_eq(value_iter, Some(ref_values));
                         }
                         assert!(iter.next().is_none());
diff --git a/src/multimap_table.rs b/src/multimap_table.rs
index 25b0260..6cb0ba7 100644
--- a/src/multimap_table.rs
+++ b/src/multimap_table.rs
@@ -1,10 +1,10 @@
 use crate::multimap_table::DynamicCollectionType::{Inline, Subtree};
 use crate::tree_store::{
-    AllPageNumbersBtreeIter, Btree, BtreeMut, BtreeRangeIter, Checksum, LeafAccessor, LeafKeyIter,
-    Page, PageNumber, RawLeafBuilder, TransactionalMemory, BRANCH, LEAF,
+    AllPageNumbersBtreeIter, Btree, BtreeMut, BtreeRangeIter, Checksum, LeafAccessor, Page,
+    PageNumber, RawLeafBuilder, TransactionalMemory, BRANCH, LEAF,
 };
 use crate::types::{RedbKey, RedbValue};
-use crate::{Result, WriteTransaction};
+use crate::{AccessGuard, Result, WriteTransaction};
 use std::borrow::Borrow;
 use std::cell::RefCell;
 use std::convert::TryInto;
@@ -40,6 +40,63 @@ pub(crate) fn parse_subtree_roots<T: Page>(
     }
 }
 
+pub(crate) struct LeafKeyIter<'a> {
+    inline_collection: AccessGuard<'a, DynamicCollection>,
+    fixed_key_size: Option<usize>,
+    fixed_value_size: Option<usize>,
+    start_entry: isize, // inclusive
+    end_entry: isize,   // inclusive
+}
+
+impl<'a> LeafKeyIter<'a> {
+    fn new(
+        data: AccessGuard<'a, DynamicCollection>,
+        fixed_key_size: Option<usize>,
+        fixed_value_size: Option<usize>,
+    ) -> Self {
+        let accessor =
+            LeafAccessor::new(data.value().as_inline(), fixed_key_size, fixed_value_size);
+        let end_entry = isize::try_from(accessor.num_pairs()).unwrap() - 1;
+        Self {
+            inline_collection: data,
+            fixed_key_size,
+            fixed_value_size,
+            start_entry: 0,
+            end_entry,
+        }
+    }
+
+    fn next_key(&mut self) -> Option<&[u8]> {
+        if self.end_entry < self.start_entry {
+            return None;
+        }
+        let accessor = LeafAccessor::new(
+            self.inline_collection.value().as_inline(),
+            self.fixed_key_size,
+            self.fixed_value_size,
+        );
+        self.start_entry += 1;
+        accessor
+            .entry((self.start_entry - 1).try_into().unwrap())
+            .map(|e| e.key())
+    }
+
+    fn next_key_back(&mut self) -> Option<&[u8]> {
+        if self.end_entry < self.start_entry {
+            return None;
+        }
+        let accessor = LeafAccessor::new(
+            self.inline_collection.value().as_inline(),
+            self.fixed_key_size,
+            self.fixed_value_size,
+        );
+        self.end_entry -= 1;
+        accessor
+            .entry((self.end_entry + 1).try_into().unwrap())
+            .map(|e| e.key())
+    }
+}
+
 enum DynamicCollectionType {
     Inline,
     Subtree,
@@ -146,20 +203,20 @@ impl DynamicCollection {
     }
 
     fn iter<'a, V: RedbKey + ?Sized>(
-        &'a self,
+        collection: AccessGuard<'a, DynamicCollection>,
         mem: &'a TransactionalMemory,
     ) -> MultimapValueIter<'a, V> {
-        match self.collection_type() {
+        match collection.value().collection_type() {
             Inline => {
                 let leaf_iter = LeafKeyIter::new(
-                    self.as_inline(),
+                    collection,
                     V::fixed_width(),
                     <() as RedbValue>::fixed_width(),
                 );
                 MultimapValueIter::new_inline(leaf_iter)
             }
             Subtree => {
-                let root = self.as_subtree().0;
+                let root = collection.value().as_subtree().0;
                 MultimapValueIter::new_subtree(
                     BtreeRangeIter::new::<RangeFull, &V::RefBaseType<'_>>(.., Some(root), mem),
                 )
@@ -168,22 +225,22 @@ impl DynamicCollection {
     }
 
     fn iter_free_on_drop<'a, V: RedbKey + ?Sized>(
-        &'a self,
+        collection: AccessGuard<'a, DynamicCollection>,
         pages: Vec<PageNumber>,
         freed_pages: Rc<RefCell<Vec<PageNumber>>>,
         mem: &'a TransactionalMemory,
     ) -> MultimapValueIter<'a, V> {
-        match self.collection_type() {
+        match collection.value().collection_type() {
             Inline => {
                 let leaf_iter = LeafKeyIter::new(
-                    self.as_inline(),
+                    collection,
                     V::fixed_width(),
                     <() as RedbValue>::fixed_width(),
                 );
                 MultimapValueIter::new_inline(leaf_iter)
             }
             Subtree => {
-                let root = self.as_subtree().0;
+                let root = collection.value().as_subtree().0;
                 let inner =
                     BtreeRangeIter::new::<RangeFull, &V::RefBaseType<'_>>(.., Some(root), mem);
                 MultimapValueIter::new_subtree_free_on_drop(inner, freed_pages, pages, mem)
@@ -213,7 +270,7 @@ enum ValueIterState<'a, V: RedbKey + ?Sized + 'a> {
 }
 
 pub struct MultimapValueIter<'a, V: RedbKey + ?Sized + 'a> {
-    inner: ValueIterState<'a, V>,
+    inner: Option<ValueIterState<'a, V>>,
     freed_pages: Option<Rc<RefCell<Vec<PageNumber>>>>,
     free_on_drop: Vec<PageNumber>,
     mem: Option<&'a TransactionalMemory>,
@@ -223,7 +280,7 @@ pub struct MultimapValueIter<'a, V: RedbKey + ?Sized + 'a> {
 impl<'a, V: RedbKey + ?Sized + 'a> MultimapValueIter<'a, V> {
     fn new_subtree(inner: BtreeRangeIter<'a, V, ()>) -> Self {
         Self {
-            inner: ValueIterState::Subtree(inner),
+            inner: Some(ValueIterState::Subtree(inner)),
             freed_pages: None,
             free_on_drop: vec![],
             mem: None,
@@ -238,7 +295,7 @@ impl<'a, V: RedbKey + ?Sized + 'a> MultimapValueIter<'a, V> {
         mem: &'a TransactionalMemory,
     ) -> Self {
         Self {
-            inner: ValueIterState::Subtree(inner),
+            inner: Some(ValueIterState::Subtree(inner)),
             freed_pages: Some(freed_pages),
             free_on_drop: pages,
             mem: Some(mem),
@@ -248,7 +305,7 @@ impl<'a, V: RedbKey + ?Sized + 'a> MultimapValueIter<'a, V> {
 
     fn new_inline(inner: LeafKeyIter<'a>) -> Self {
         Self {
-            inner: ValueIterState::InlineLeaf(inner),
+            inner: Some(ValueIterState::InlineLeaf(inner)),
             freed_pages: None,
             free_on_drop: vec![],
             mem: None,
@@ -258,41 +315,33 @@ impl<'a, V: RedbKey + ?Sized + 'a> MultimapValueIter<'a, V> {
 }
 
 impl<'a, V: RedbKey + ?Sized> Iterator for MultimapValueIter<'a, V> {
-    type Item = V::SelfType<'a>;
+    type Item = AccessGuard<'a, V>;
 
     fn next(&mut self) -> Option<Self::Item> {
-        match self.inner {
-            ValueIterState::Subtree(ref mut iter) => iter.next().map(|e| V::from_bytes(e.key())),
-            ValueIterState::InlineLeaf(ref mut iter) => {
-                iter.next_key().map(|key| V::from_bytes(key))
-            }
-        }
+        // TODO: optimize out this copy
+        let bytes = match self.inner.as_mut().unwrap() {
+            ValueIterState::Subtree(ref mut iter) => iter.next().map(|e| e.key().to_vec())?,
+            ValueIterState::InlineLeaf(ref mut iter) => iter.next_key()?.to_vec(),
+        };
+        Some(AccessGuard::with_owned_value(bytes))
     }
 }
 
 impl<'a, V: RedbKey + ?Sized> DoubleEndedIterator for MultimapValueIter<'a, V> {
     fn next_back(&mut self) -> Option<Self::Item> {
-        match self.inner {
-            ValueIterState::Subtree(ref mut iter) => {
-                iter.next_back().map(|e| V::from_bytes(e.key()))
-            }
-            ValueIterState::InlineLeaf(ref mut iter) => {
-                iter.next_key_back().map(|key| V::from_bytes(key))
-            }
-        }
+        // TODO: optimize out this copy
+        let bytes = match self.inner.as_mut().unwrap() {
+            ValueIterState::Subtree(ref mut iter) => iter.next_back().map(|e| e.key().to_vec())?,
+            ValueIterState::InlineLeaf(ref mut iter) => iter.next_key_back()?.to_vec(),
+        };
+        Some(AccessGuard::with_owned_value(bytes))
     }
 }
 
 impl<'a, V: RedbKey + ?Sized> Drop for MultimapValueIter<'a, V> {
     fn drop(&mut self) {
         // Drop our references to the pages that are about to be freed
-        let mut dummy_state = ValueIterState::InlineLeaf(LeafKeyIter::new(
-            b"\x01\x00\x00\x00".as_slice(),
-            None,
-            None,
-        ));
-        mem::swap(&mut self.inner, &mut dummy_state);
-        drop(dummy_state);
+        drop(mem::take(&mut self.inner));
         for page in self.free_on_drop.iter() {
             // TODO: make free_if_uncommitted not return a Result by moving the dirtying of the allocator state into the open method of the TransactionMemory
             unsafe {
@@ -329,13 +378,14 @@ impl<'a, K: RedbKey + ?Sized + 'a, V: RedbKey + ?Sized + 'a> MultimapRangeIter<'
 impl<'a, K: RedbKey + ?Sized + 'a, V: RedbKey + ?Sized + 'a> Iterator
     for MultimapRangeIter<'a, K, V>
 {
-    type Item = (K::SelfType<'a>, MultimapValueIter<'a, V>);
+    type Item = (AccessGuard<'a, K>, MultimapValueIter<'a, V>);
 
     fn next(&mut self) -> Option<Self::Item> {
         let entry = self.inner.next()?;
-        let key = K::from_bytes(entry.key());
-        let collection = DynamicCollection::from_bytes(entry.value());
-        let iter = collection.iter(self.mem);
+        let key = AccessGuard::with_owned_value(entry.key().to_vec());
+        let (page, _, value_range) = entry.into_raw();
+        let collection = AccessGuard::with_page(page, value_range);
+        let iter = DynamicCollection::iter(collection, self.mem);
 
         Some((key, iter))
     }
@@ -346,9 +396,10 @@ impl<'a, K: RedbKey + ?Sized + 'a, V: RedbKey + ?Sized + 'a> DoubleEndedIterator
 {
     fn next_back(&mut self) -> Option<Self::Item> {
         let entry = self.inner.next_back()?;
-        let key = K::from_bytes(entry.key());
-        let collection = DynamicCollection::from_bytes(entry.value());
-        let iter = collection.iter(self.mem);
+        let key = AccessGuard::with_owned_value(entry.key().to_vec());
+        let (page, _, value_range) = entry.into_raw();
+        let collection = AccessGuard::with_page(page, value_range);
+        let iter = DynamicCollection::iter(collection, self.mem);
 
         Some((key, iter))
     }
@@ -405,10 +456,14 @@ impl<'db, 'txn, K: RedbKey + ?Sized + 'txn, V: RedbKey + ?Sized + 'txn>
     {
         let value_bytes = V::as_bytes(value.borrow());
         let value_bytes_ref = value_bytes.as_ref();
-        let existed = if let Some(v) = self.tree.get(key.borrow())? {
-            match v.collection_type() {
+        let get_result = self.tree.get(key.borrow())?;
+        let existed = if get_result.is_some() {
+            #[allow(clippy::unnecessary_unwrap)]
+            let guard = get_result.unwrap();
+            let collection_type = guard.value().collection_type();
+            match collection_type {
                 Inline => {
-                    let leaf_data = v.as_inline();
+                    let leaf_data = guard.value().as_inline();
                     let accessor = LeafAccessor::new(
                         leaf_data,
                         V::fixed_width(),
@@ -451,6 +506,7 @@ impl<'db, 'txn, K: RedbKey + ?Sized + 'txn, V: RedbKey + ?Sized + 'txn>
                                 .append(value_bytes_ref, <() as RedbValue>::as_bytes(&()).as_ref());
                         }
                         drop(builder);
+                        drop(guard);
                         let inline_data = DynamicCollection::make_inline_data(&data);
                         unsafe {
                             self.tree
@@ -462,6 +518,7 @@ impl<'db, 'txn, K: RedbKey + ?Sized + 'txn, V: RedbKey + ?Sized + 'txn>
                         page.memory_mut()[..leaf_data.len()].copy_from_slice(leaf_data);
                         let page_number = page.get_page_number();
                         drop(page);
+                        drop(guard);
 
                         // Don't bother computing the checksum, since we're about to modify the tree
                         let mut subtree: BtreeMut<'_, V, ()> = BtreeMut::new(
@@ -486,8 +543,12 @@ impl<'db, 'txn, K: RedbKey + ?Sized + 'txn, V: RedbKey + ?Sized + 'txn>
                     found
                 }
                 Subtree => {
-                    let mut subtree: BtreeMut<'_, V, ()> =
-                        BtreeMut::new(Some(v.as_subtree()), self.mem, self.freed_pages.clone());
+                    let mut subtree: BtreeMut<'_, V, ()> = BtreeMut::new(
+                        Some(guard.value().as_subtree()),
+                        self.mem,
+                        self.freed_pages.clone(),
+                    );
+                    drop(guard);
                     // Safety: No other references to this table can exist.
                     // Tables can only be opened mutably in one location (see Error::TableAlreadyOpen),
                     // and we borrow &mut self.
@@ -503,6 +564,7 @@ impl<'db, 'txn, K: RedbKey + ?Sized + 'txn, V: RedbKey + ?Sized + 'txn>
                 }
             }
         } else {
+            drop(get_result);
             let required_inline_bytes = RawLeafBuilder::required_bytes(1, value_bytes_ref.len());
             if required_inline_bytes < self.mem.get_page_size() / 2 {
                 let mut data = vec![0; required_inline_bytes];
@@ -545,118 +607,120 @@ impl<'db, 'txn, K: RedbKey + ?Sized + 'txn, V: RedbKey + ?Sized + 'txn>
     /// Returns `true` if the key-value pair was present
     // TODO: should take a Borrow instead of a &
     pub fn remove(&mut self, key: &K::RefBaseType<'_>, value: &V::RefBaseType<'_>) -> Result<bool> {
-        let existed = if let Some(v) = self.tree.get(key)? {
-            match v.collection_type() {
-                Inline => {
-                    let leaf_data = v.as_inline();
-                    let accessor = LeafAccessor::new(
-                        leaf_data,
-                        V::fixed_width(),
-                        <() as RedbValue>::fixed_width(),
-                    );
-                    if let Some(position) = accessor.find_key::<V>(V::as_bytes(value).as_ref()) {
-                        let old_num_pairs = accessor.num_pairs();
-                        if old_num_pairs == 1 {
-                            unsafe { self.tree.remove(key)? };
-                        } else {
-                            let old_pairs_len = accessor.length_of_pairs(0, old_num_pairs);
-                            let removed_value_len = accessor.entry(position).unwrap().key().len();
-                            let required = RawLeafBuilder::required_bytes(
-                                old_num_pairs - 1,
-                                old_pairs_len - removed_value_len,
-                            );
-                            let mut new_data = vec![0; required];
-                            let new_key_len =
-                                accessor.length_of_keys(0, old_num_pairs) - removed_value_len;
-                            let mut builder = RawLeafBuilder::new(
-                                &mut new_data,
-                                old_num_pairs - 1,
-                                V::fixed_width(),
-                                <() as RedbValue>::fixed_width(),
-                                new_key_len,
-                            );
-                            for i in 0..old_num_pairs {
-                                if i != position {
-                                    let entry = accessor.entry(i).unwrap();
-                                    builder.append(entry.key(), entry.value());
-                                }
+        let get_result = self.tree.get(key)?;
+        if get_result.is_none() {
+            return Ok(false);
+        }
+        let guard = get_result.unwrap();
+        let v = guard.value();
+        let existed = match v.collection_type() {
+            Inline => {
+                let leaf_data = v.as_inline();
+                let accessor = LeafAccessor::new(
+                    leaf_data,
+                    V::fixed_width(),
+                    <() as RedbValue>::fixed_width(),
+                );
+                if let Some(position) = accessor.find_key::<V>(V::as_bytes(value).as_ref()) {
+                    let old_num_pairs = accessor.num_pairs();
+                    if old_num_pairs == 1 {
+                        drop(guard);
+                        unsafe { self.tree.remove(key)? };
+                    } else {
+                        let old_pairs_len = accessor.length_of_pairs(0, old_num_pairs);
+                        let removed_value_len = accessor.entry(position).unwrap().key().len();
+                        let required = RawLeafBuilder::required_bytes(
+                            old_num_pairs - 1,
+                            old_pairs_len - removed_value_len,
+                        );
+                        let mut new_data = vec![0; required];
+                        let new_key_len =
+                            accessor.length_of_keys(0, old_num_pairs) - removed_value_len;
+                        let mut builder = RawLeafBuilder::new(
+                            &mut new_data,
+                            old_num_pairs - 1,
+                            V::fixed_width(),
+                            <() as RedbValue>::fixed_width(),
+                            new_key_len,
+                        );
+                        for i in 0..old_num_pairs {
+                            if i != position {
+                                let entry = accessor.entry(i).unwrap();
+                                builder.append(entry.key(), entry.value());
                             }
-                            drop(builder);
-
-                            let inline_data = DynamicCollection::make_inline_data(&new_data);
-                            unsafe {
-                                self.tree
-                                    .insert(key, &DynamicCollection::new(&inline_data))?
-                            };
                         }
-                        true
-                    } else {
-                        false
+                        drop(builder);
+                        drop(guard);
+
+                        let inline_data = DynamicCollection::make_inline_data(&new_data);
+                        unsafe {
+                            self.tree
+                                .insert(key, &DynamicCollection::new(&inline_data))?
+                        };
                     }
+                    true
+                } else {
+                    drop(guard);
+                    false
                 }
-                Subtree => {
-                    let mut subtree: BtreeMut<V, ()> =
-                        BtreeMut::new(Some(v.as_subtree()), self.mem, self.freed_pages.clone());
-                    // Safety: No other references to this table can exist.
-                    // Tables can only be opened mutably in one location (see Error::TableAlreadyOpen),
-                    // and we borrow &mut self.
-                    let existed = unsafe { subtree.remove(value)?.is_some() };
-
-                    if let Some((new_root, new_checksum)) = subtree.get_root() {
-                        let page = self.mem.get_page(new_root);
-                        match page.memory()[0] {
-                            LEAF => {
-                                let accessor = LeafAccessor::new(
-                                    page.memory(),
-                                    V::fixed_width(),
-                                    <() as RedbValue>::fixed_width(),
-                                );
-                                let len = accessor.total_length();
-                                if len < self.mem.get_page_size() / 2 {
-                                    let inline_data =
-                                        DynamicCollection::make_inline_data(&page.memory()[..len]);
-                                    unsafe {
-                                        self.tree
-                                            .insert(key, &DynamicCollection::new(&inline_data))?
-                                    };
-                                    drop(page);
-                                    unsafe {
-                                        if !self.mem.free_if_uncommitted(new_root)? {
-                                            (*self.freed_pages).borrow_mut().push(new_root);
-                                        }
+            }
+            Subtree => {
+                let mut subtree: BtreeMut<V, ()> =
+                    BtreeMut::new(Some(v.as_subtree()), self.mem, self.freed_pages.clone());
+                drop(guard);
+                // Safety: No other references to this table can exist.
+                // Tables can only be opened mutably in one location (see Error::TableAlreadyOpen),
+                // and we borrow &mut self.
+                let existed = unsafe { subtree.remove(value)?.is_some() };
+
+                if let Some((new_root, new_checksum)) = subtree.get_root() {
+                    let page = self.mem.get_page(new_root);
+                    match page.memory()[0] {
+                        LEAF => {
+                            let accessor = LeafAccessor::new(
+                                page.memory(),
+                                V::fixed_width(),
+                                <() as RedbValue>::fixed_width(),
+                            );
+                            let len = accessor.total_length();
+                            if len < self.mem.get_page_size() / 2 {
+                                let inline_data =
+                                    DynamicCollection::make_inline_data(&page.memory()[..len]);
+                                unsafe {
+                                    self.tree
+                                        .insert(key, &DynamicCollection::new(&inline_data))?
+                                };
+                                drop(page);
+                                unsafe {
+                                    if !self.mem.free_if_uncommitted(new_root)? {
+                                        (*self.freed_pages).borrow_mut().push(new_root);
                                     }
-                                } else {
-                                    let subtree_data = DynamicCollection::make_subtree_data(
-                                        new_root,
-                                        new_checksum,
-                                    );
-                                    unsafe {
-                                        self.tree
-                                            .insert(key, &DynamicCollection::new(&subtree_data))?
-                                    };
                                 }
-                            }
-                            BRANCH => {
+                            } else {
+                                let subtree_data =
+                                    DynamicCollection::make_subtree_data(new_root, new_checksum);
                                 unsafe {
-                                    let subtree_data = DynamicCollection::make_subtree_data(
-                                        new_root,
-                                        new_checksum,
-                                    );
                                     self.tree
                                         .insert(key, &DynamicCollection::new(&subtree_data))?
                                 };
                             }
-                            _ => unreachable!(),
                         }
-                    } else {
-                        unsafe { self.tree.remove(key)? };
+                        BRANCH => {
+                            unsafe {
+                                let subtree_data =
+                                    DynamicCollection::make_subtree_data(new_root, new_checksum);
+                                self.tree
+                                    .insert(key, &DynamicCollection::new(&subtree_data))?
+                            };
+                        }
+                        _ => unreachable!(),
                     }
-
-                    existed
+                } else {
+                    unsafe { self.tree.remove(key)? };
                 }
+
+                existed
             }
-        } else {
-            false
         };
 
         Ok(existed)
@@ -674,7 +738,7 @@ impl<'db, 'txn, K: RedbKey + ?Sized + 'txn, V: RedbKey + ?Sized + 'txn>
             if let Some(collection) = unsafe { self.tree.remove(key)? } {
                 // TODO: optimize out this copy. The .remove() above should be replaced with
                 // .remove_retain_uncommitted, which should return the PageNumber so we can free it ourselves
-                let value = collection.to_value();
+                let value = collection.value();
                 let collection_bytes = DynamicCollection::as_bytes(&value);
                 let len = collection_bytes.as_ref().len();
                 let mut tmp_page = self.mem.allocate(len)?;
@@ -683,10 +747,14 @@ impl<'db, 'txn, K: RedbKey + ?Sized + 'txn, V: RedbKey + ?Sized + 'txn>
                 let mut pages = vec![tmp_page_number];
                 drop(tmp_page);
                 let tmp_page = self.mem.get_page(tmp_page_number);
-                let collection = DynamicCollection::new(&tmp_page.memory_full_lifetime()[..len]);
-
-                if matches!(collection.collection_type(), DynamicCollectionType::Subtree) {
-                    let root = collection.as_subtree().0;
+                let collection: AccessGuard<DynamicCollection> =
+                    AccessGuard::with_page(tmp_page, 0..len);
+
+                if matches!(
+                    collection.value().collection_type(),
+                    DynamicCollectionType::Subtree
+                ) {
+                    let root = collection.value().as_subtree().0;
                     let all_pages = AllPageNumbersBtreeIter::new(
                         root,
                         V::fixed_width(),
@@ -697,7 +765,12 @@ impl<'db, 'txn, K: RedbKey + ?Sized + 'txn, V: RedbKey + ?Sized + 'txn>
                         pages.push(page);
                     }
                 }
-                collection.iter_free_on_drop(pages, self.freed_pages.clone(), self.mem)
+                DynamicCollection::iter_free_on_drop(
+                    collection,
+                    pages,
+                    self.freed_pages.clone(),
+                    self.mem,
+                )
             } else {
                 MultimapValueIter::new_subtree(
                     BtreeRangeIter::new::<RangeFull, &V::RefBaseType<'_>>(.., None, self.mem),
@@ -715,7 +788,7 @@ impl<'db, 'txn, K: RedbKey + ?Sized, V: RedbKey + ?Sized> ReadableMultimapTable<
     fn get<'a>(&'a self, key: impl Borrow<K::RefBaseType<'a>>) -> Result<MultimapValueIter<'a, V>> {
         let iter =
             if let Some(collection) = self.tree.get(key.borrow())? {
-                collection.iter(self.mem)
+                DynamicCollection::iter(collection, self.mem)
             } else {
                 MultimapValueIter::new_subtree(
                     BtreeRangeIter::new::<RangeFull, &V::RefBaseType<'_>>(.., None, self.mem),
@@ -807,7 +880,7 @@ impl<'txn, K: RedbKey + ?Sized, V: RedbKey + ?Sized> ReadableMultimapTable<K, V>
     fn get<'a>(&'a self, key: impl Borrow<K::RefBaseType<'a>>) -> Result<MultimapValueIter<'a, V>> {
         let iter =
             if let Some(collection) = self.tree.get(key.borrow())? {
-                collection.iter(self.mem)
+                DynamicCollection::iter(collection, self.mem)
             } else {
                 MultimapValueIter::new_subtree(
                     BtreeRangeIter::new::<RangeFull, &V::RefBaseType<'_>>(.., None, self.mem),
diff --git a/src/table.rs b/src/table.rs
index 8f5e1bd..0feddfc 100644
--- a/src/table.rs
+++ b/src/table.rs
@@ -92,7 +92,7 @@ impl<'db, 'txn, K: RedbKey + ?Sized + 'txn, V: RedbValue + ?Sized + 'txn> Table<
 impl<'db, 'txn, K: RedbKey + ?Sized, V: RedbValue + ?Sized> ReadableTable<K, V>
     for Table<'db, 'txn, K, V>
 {
-    fn get<'a, 'b: 'a, AK>(&self, key: &'a AK) -> Result<Option<V::SelfType<'_>>>
+    fn get<'a, 'b: 'a, AK>(&self, key: &'a AK) -> Result<Option<AccessGuard<V>>>
     where
         K: 'b,
         AK: Borrow<K::RefBaseType<'b>> + ?Sized,
@@ -125,7 +125,7 @@ impl<'db, 'txn, K: RedbKey + ?Sized, V: RedbValue + ?Sized> Drop for Table<'db,
 
 pub trait ReadableTable<K: RedbKey + ?Sized, V: RedbValue + ?Sized> {
     /// Returns the value corresponding to the given key
-    fn get<'a, 'b: 'a, AK>(&self, key: &'a AK) -> Result<Option<V::SelfType<'_>>>
+    fn get<'a, 'b: 'a, AK>(&self, key: &'a AK) -> Result<Option<AccessGuard<V>>>
     where
         K: 'b,
         AK: Borrow<K::RefBaseType<'b>> + ?Sized;
@@ -156,7 +156,9 @@ pub trait ReadableTable<K: RedbKey + ?Sized, V: RedbValue + ?Sized> {
     /// let read_txn = db.begin_read()?;
     /// let table = read_txn.open_table(TABLE)?;
     /// let mut iter = table.range("a".."c")?;
-    /// assert_eq!(Some(("a", 0)), iter.next());
+    /// let (key, value) = iter.next().unwrap();
+    /// assert_eq!("a", key.value());
+    /// assert_eq!(0, value.value());
     /// # Ok(())
     /// # }
     /// ```
@@ -196,7 +198,7 @@ impl<'txn, K: RedbKey + ?Sized, V: RedbValue + ?Sized> ReadOnlyTable<'txn, K, V>
 impl<'txn, K: RedbKey + ?Sized, V: RedbValue + ?Sized> ReadableTable<K, V>
     for ReadOnlyTable<'txn, K, V>
 {
-    fn get<'a, 'b: 'a, AK>(&self, key: &'a AK) -> Result<Option<V::SelfType<'_>>>
+    fn get<'a, 'b: 'a, AK>(&self, key: &'a AK) -> Result<Option<AccessGuard<V>>>
     where
         K: 'b,
         AK: Borrow<K::RefBaseType<'b>> + ?Sized,
@@ -232,12 +234,13 @@ impl<'a, K: RedbKey + ?Sized + 'a, V: RedbValue + ?Sized + 'a> RangeIter<'a, K,
 }
 
 impl<'a, K: RedbKey + ?Sized + 'a, V: RedbValue + ?Sized + 'a> Iterator for RangeIter<'a, K, V> {
-    type Item = (K::SelfType<'a>, V::SelfType<'a>);
+    type Item = (AccessGuard<'a, K>, AccessGuard<'a, V>);
 
     fn next(&mut self) -> Option<Self::Item> {
         if let Some(entry) = self.inner.next() {
-            let key = K::from_bytes(entry.key());
-            let value = V::from_bytes(entry.value());
+            let (page, key_range, value_range) = entry.into_raw();
+            let key = AccessGuard::with_page(page.clone(), key_range);
+            let value = AccessGuard::with_page(page, value_range);
             Some((key, value))
         } else {
             None
@@ -250,8 +253,9 @@ impl<'a, K: RedbKey + ?Sized + 'a, V: RedbValue + ?Sized + 'a> DoubleEndedIterat
 {
     fn next_back(&mut self) -> Option<Self::Item> {
         if let Some(entry) = self.inner.next_back() {
-            let key = K::from_bytes(entry.key());
-            let value = V::from_bytes(entry.value());
+            let (page, key_range, value_range) = entry.into_raw();
+            let key = AccessGuard::with_page(page.clone(), key_range);
+            let value = AccessGuard::with_page(page, value_range);
             Some((key, value))
         } else {
             None
@@ -333,8 +337,8 @@ mod test {
         let mut iter = table.range(start..=end).unwrap();
         for i in (3..=7u8).rev() {
             let (key, value) = iter.next().unwrap();
-            assert_eq!(&[i], key.0.as_slice());
-            assert_eq!(b"value", value);
+            assert_eq!(&[i], key.value().0.as_slice());
+            assert_eq!(b"value", value.value());
         }
         assert!(iter.next().is_none());
     }
diff --git a/src/tree_store/btree.rs b/src/tree_store/btree.rs
index eccc208..2aa08c8 100644
--- a/src/tree_store/btree.rs
+++ b/src/tree_store/btree.rs
@@ -155,11 +155,11 @@ impl<'a, K: RedbKey + ?Sized + 'a, V: RedbValue + ?Sized + 'a> BtreeMut<'a, K, V
         )
     }
 
-    fn read_tree(&self) -> Btree<K, V> {
+    fn read_tree(&self) -> Btree<'a, K, V> {
         Btree::new(self.get_root(), self.mem)
     }
 
-    pub(crate) fn get(&self, key: &K::RefBaseType<'_>) -> Result<Option<V::SelfType<'_>>> {
+    pub(crate) fn get(&self, key: &K::RefBaseType<'_>) -> Result<Option<AccessGuard<'_, V>>> {
         self.read_tree().get(key)
     }
 
@@ -261,7 +261,7 @@ impl<'a, K: RedbKey + ?Sized, V: RedbValue + ?Sized> Btree<'a, K, V> {
         }
     }
 
-    pub(crate) fn get(&self, key: &K::RefBaseType<'_>) -> Result<Option<V::SelfType<'a>>> {
+    pub(crate) fn get(&self, key: &K::RefBaseType<'_>) -> Result<Option<AccessGuard<'a, V>>> {
         if let Some((p, _)) = self.root {
             let root_page = self.mem.get_page(p);
             return Ok(self.get_helper(root_page, K::as_bytes(key).as_ref()));
@@ -271,14 +271,16 @@ impl<'a, K: RedbKey + ?Sized, V: RedbValue + ?Sized> Btree<'a, K, V> {
     }
 
     // Returns the value for the queried key, if present
-    fn get_helper(&self, page: PageImpl<'a>, query: &[u8]) -> Option<V::SelfType<'a>> {
+    fn get_helper(&self, page: PageImpl<'a>, query: &[u8]) -> Option<AccessGuard<'a, V>> {
         let node_mem = page.memory();
         match node_mem[0] {
             LEAF => {
                 let accessor = LeafAccessor::new(page.memory(), K::fixed_width(), V::fixed_width());
                 let entry_index = accessor.find_key::<K>(query)?;
                 let (start, end) = accessor.value_range(entry_index).unwrap();
-                Some(V::from_bytes(&page.into_memory()[start..end]))
+                // Safety: free_on_drop is false
+                let guard = unsafe { AccessGuard::new(page, start, end - start, false, self.mem) };
+                Some(guard)
             }
             BRANCH => {
                 let accessor = BranchAccessor::new(&page, K::fixed_width());
diff --git a/src/tree_store/btree_base.rs b/src/tree_store/btree_base.rs
index f324001..82171e9 100644
--- a/src/tree_store/btree_base.rs
+++ b/src/tree_store/btree_base.rs
@@ -6,6 +6,7 @@ use std::cell::RefCell;
 use std::cmp::Ordering;
 use std::marker::PhantomData;
 use std::mem::size_of;
+use std::ops::Range;
 use std::rc::Rc;
 use std::{mem, thread};
 
@@ -113,7 +114,7 @@ pub struct AccessGuard<'a, V: RedbValue + ?Sized> {
     offset: usize,
     len: usize,
     on_drop: OnDrop,
-    mem: &'a TransactionalMemory,
+    mem: Option<&'a TransactionalMemory>,
     _value_type: PhantomData<V>,
 }
 
@@ -137,19 +138,30 @@ impl<'a, V: RedbValue + ?Sized> AccessGuard<'a, V> {
             } else {
                 OnDrop::None
             },
-            mem,
+            mem: Some(mem),
+            _value_type: Default::default(),
+        }
+    }
+
+    pub(crate) fn with_page(page: PageImpl<'a>, range: Range<usize>) -> Self {
+        Self {
+            page: EitherPage::Immutable(page),
+            offset: range.start,
+            len: range.len(),
+            on_drop: OnDrop::None,
+            mem: None,
             _value_type: Default::default(),
         }
     }
 
-    pub(super) fn with_owned_value(value: Vec<u8>, mem: &'a TransactionalMemory) -> Self {
+    pub(crate) fn with_owned_value(value: Vec<u8>) -> Self {
         let len = value.len();
         Self {
             page: EitherPage::OwnedMemory(value),
             offset: 0,
             len,
             on_drop: OnDrop::None,
-            mem,
+            mem: None,
             _value_type: Default::default(),
         }
     }
@@ -172,13 +184,13 @@ impl<'a, V: RedbValue + ?Sized> AccessGuard<'a, V> {
                 position,
                 fixed_key_size,
             },
-            mem,
+            mem: Some(mem),
             _value_type: Default::default(),
         }
     }
 
     // TODO: implement Deref instead of this to_value() method, when GAT is stable
-    pub fn to_value(&self) -> V::SelfType<'_> {
+    pub fn value(&self) -> V::SelfType<'_> {
         V::from_bytes(&self.page.memory()[self.offset..(self.offset + self.len)])
     }
 }
@@ -194,7 +206,7 @@ impl<'a, V: RedbValue + ?Sized> Drop for AccessGuard<'a, V> {
                 drop(dummy);
                 // Safety: caller to new() guaranteed that no other references to this page exist
                 unsafe {
-                    self.mem.free(page_number).unwrap();
+                    self.mem.unwrap().free(page_number).unwrap();
                 }
             }
             OnDrop::RemoveEntry {
@@ -523,56 +535,14 @@ impl<'a> LeafAccessor<'a> {
         Some(EntryAccessor::new(key, value))
     }
 
-    pub(super) fn last_entry(&self) -> EntryAccessor<'a> {
-        self.entry(self.num_pairs() - 1).unwrap()
-    }
-}
-
-pub(crate) struct LeafKeyIter<'a> {
-    data: &'a [u8],
-    fixed_key_size: Option<usize>,
-    fixed_value_size: Option<usize>,
-    start_entry: isize, // inclusive
-    end_entry: isize,   // inclusive
-}
-
-impl<'a> LeafKeyIter<'a> {
-    pub(crate) fn new(
-        data: &'a [u8],
-        fixed_key_size: Option<usize>,
-        fixed_value_size: Option<usize>,
-    ) -> Self {
-        let accessor = LeafAccessor::new(data, fixed_key_size, fixed_value_size);
-        let end_entry = isize::try_from(accessor.num_pairs()).unwrap() - 1;
-        Self {
-            data,
-            fixed_key_size,
-            fixed_value_size,
-            start_entry: 0,
-            end_entry,
-        }
-    }
-
-    pub(crate) fn next_key(&mut self) -> Option<&'a [u8]> {
-        if self.end_entry < self.start_entry {
-            return None;
-        }
-        let accessor = LeafAccessor::new(self.data, self.fixed_key_size, self.fixed_value_size);
-        self.start_entry += 1;
-        accessor
-            .entry((self.start_entry - 1).try_into().unwrap())
-            .map(|e| e.key())
+    pub(crate) fn entry_ranges(&self, n: usize) -> Option<(Range<usize>, Range<usize>)> {
+        let key = self.key_start(n)?..self.key_end(n)?;
+        let value = self.value_start(n)?..self.value_end(n)?;
+        Some((key, value))
     }
 
-    pub(crate) fn next_key_back(&mut self) -> Option<&'a [u8]> {
-        if self.end_entry < self.start_entry {
-            return None;
-        }
-        let accessor = LeafAccessor::new(self.data, self.fixed_key_size, self.fixed_value_size);
-        self.end_entry -= 1;
-        accessor
-            .entry((self.end_entry + 1).try_into().unwrap())
-            .map(|e| e.key())
+    pub(super) fn last_entry(&self) -> EntryAccessor<'a> {
+        self.entry(self.num_pairs() - 1).unwrap()
     }
 }
 
diff --git a/src/tree_store/btree_iters.rs b/src/tree_store/btree_iters.rs
index 31ababc..e50d091 100644
--- a/src/tree_store/btree_iters.rs
+++ b/src/tree_store/btree_iters.rs
@@ -1,4 +1,4 @@
-use crate::tree_store::btree_base::{BranchAccessor, EntryAccessor, LeafAccessor};
+use crate::tree_store::btree_base::{BranchAccessor, LeafAccessor};
 use crate::tree_store::btree_base::{BRANCH, LEAF};
 use crate::tree_store::btree_iters::RangeIterState::{Internal, Leaf};
 use crate::tree_store::page_store::{Page, PageImpl, TransactionalMemory};
@@ -7,7 +7,7 @@ use crate::types::{RedbKey, RedbValue};
 use std::borrow::Borrow;
 use std::collections::Bound;
 use std::marker::PhantomData;
-use std::ops::RangeBounds;
+use std::ops::{Range, RangeBounds};
 
 #[derive(Debug)]
 pub enum RangeIterState<'a> {
@@ -121,7 +121,7 @@ impl<'a> RangeIterState<'a> {
         }
     }
 
-    fn get_entry(&self) -> Option<EntryAccessor<'a>> {
+    fn get_entry(&self) -> Option<EntryGuard<'a>> {
         match self {
             Leaf {
                 page,
@@ -129,17 +129,45 @@ impl<'a> RangeIterState<'a> {
                 fixed_value_size,
                 entry,
                 ..
-            } => LeafAccessor::new(
-                page.memory_full_lifetime(),
-                *fixed_key_size,
-                *fixed_value_size,
-            )
-            .entry(*entry),
+            } => {
+                let (key, value) =
+                    LeafAccessor::new(page.memory(), *fixed_key_size, *fixed_value_size)
+                        .entry_ranges(*entry)?;
+                Some(EntryGuard::new(page.clone(), key, value))
+            }
             _ => None,
         }
     }
 }
 
+pub(crate) struct EntryGuard<'a> {
+    page: PageImpl<'a>,
+    key_range: Range<usize>,
+    value_range: Range<usize>,
+}
+
+impl<'a> EntryGuard<'a> {
+    fn new(page: PageImpl<'a>, key_range: Range<usize>, value_range: Range<usize>) -> Self {
+        Self {
+            page,
+            key_range,
+            value_range,
+        }
+    }
+
+    pub(crate) fn key(&self) -> &[u8] {
+        &self.page.memory()[self.key_range.clone()]
+    }
+
+    pub(crate) fn value(&self) -> &[u8] {
+        &self.page.memory()[self.value_range.clone()]
+    }
+
+    pub(crate) fn into_raw(self) -> (PageImpl<'a>, Range<usize>, Range<usize>) {
+        (self.page, self.key_range, self.value_range)
+    }
+}
+
 pub(crate) struct AllPageNumbersBtreeIter<'a> {
     next: Option<RangeIterState<'a>>,
     manager: &'a TransactionalMemory,
@@ -198,7 +226,7 @@ impl<'a> Iterator for AllPageNumbersBtreeIter<'a> {
     }
 }
 
-pub struct BtreeRangeIter<'a, K: RedbKey + ?Sized + 'a, V: RedbValue + ?Sized + 'a> {
+pub(crate) struct BtreeRangeIter<'a, K: RedbKey + ?Sized + 'a, V: RedbValue + ?Sized + 'a> {
     left: Option<RangeIterState<'a>>, // Exclusive. The previous element returned
     right: Option<RangeIterState<'a>>, // Exclusive. The previous element returned
     include_left: bool,               // left is inclusive, instead of exclusive
@@ -290,7 +318,7 @@ impl<'a, K: RedbKey + ?Sized + 'a, V: RedbValue + ?Sized + 'a> BtreeRangeIter<'a
 impl<'a, K: RedbKey + ?Sized + 'a, V: RedbValue + ?Sized + 'a> Iterator
     for BtreeRangeIter<'a, K, V>
 {
-    type Item = EntryAccessor<'a>;
+    type Item = EntryGuard<'a>;
 
     fn next(&mut self) -> Option<Self::Item> {
         if let (
diff --git a/src/tree_store/btree_mutator.rs b/src/tree_store/btree_mutator.rs
index 84af836..0d21678 100644
--- a/src/tree_store/btree_mutator.rs
+++ b/src/tree_store/btree_mutator.rs
@@ -232,7 +232,7 @@ impl<'a, 'b, K: RedbKey + ?Sized, V: RedbValue + ?Sized> MutateHelper<'a, 'b, K,
                     let page_number = page.get_page_number();
                     let existing_value = if found {
                         let copied_value = accessor.entry(position).unwrap().value().to_vec();
-                        Some(AccessGuard::with_owned_value(copied_value, self.mem))
+                        Some(AccessGuard::with_owned_value(copied_value))
                     } else {
                         None
                     };
diff --git a/src/tree_store/mod.rs b/src/tree_store/mod.rs
index 4486395..f2fa239 100644
--- a/src/tree_store/mod.rs
+++ b/src/tree_store/mod.rs
@@ -9,7 +9,7 @@ pub(crate) use btree::{Btree, BtreeMut, RawBtree};
 pub use btree_base::AccessGuard;
 pub(crate) use btree_base::AccessGuardMut;
 pub(crate) use btree_base::Checksum;
-pub(crate) use btree_base::{LeafAccessor, LeafKeyIter, RawLeafBuilder, BRANCH, LEAF};
+pub(crate) use btree_base::{LeafAccessor, RawLeafBuilder, BRANCH, LEAF};
 pub(crate) use btree_iters::{AllPageNumbersBtreeIter, BtreeRangeIter};
 pub use page_store::Savepoint;
 pub(crate) use page_store::{Page, PageNumber, TransactionalMemory};
diff --git a/src/tree_store/page_store/base.rs b/src/tree_store/page_store/base.rs
index 12e456e..b229a7a 100644
--- a/src/tree_store/page_store/base.rs
+++ b/src/tree_store/page_store/base.rs
@@ -123,17 +123,6 @@ impl<'a> Drop for PageImpl<'a> {
     }
 }
 
-impl<'a> PageImpl<'a> {
-    pub(crate) fn into_memory(self) -> &'a [u8] {
-        self.mem
-    }
-
-    // Kind of hacky, but Page::memory() can't return the 'a lifetime, because then PageMut can't implement it
-    pub(crate) fn memory_full_lifetime(&self) -> &'a [u8] {
-        self.mem
-    }
-}
-
 impl<'a> Page for PageImpl<'a> {
     fn memory(&self) -> &[u8] {
         self.mem
@@ -144,6 +133,26 @@ impl<'a> Page for PageImpl<'a> {
     }
 }
 
+impl<'a> Clone for PageImpl<'a> {
+    fn clone(&self) -> Self {
+        #[cfg(debug_assertions)]
+        {
+            *self
+                .open_pages
+                .lock()
+                .unwrap()
+                .get_mut(&self.page_number)
+                .unwrap() += 1;
+        }
+        Self {
+            mem: self.mem,
+            page_number: self.page_number,
+            #[cfg(debug_assertions)]
+            open_pages: self.open_pages,
+        }
+    }
+}
+
 pub(crate) struct PageMut<'a> {
     pub(super) mem: &'a mut [u8],
     pub(super) page_number: PageNumber,
diff --git a/src/tree_store/page_store/header.rs b/src/tree_store/page_store/header.rs
index 165475b..f21211f 100644
--- a/src/tree_store/page_store/header.rs
+++ b/src/tree_store/page_store/header.rs
@@ -496,7 +496,7 @@ mod test {
         let write_txn = db2.begin_write().unwrap();
         {
             let mut table = write_txn.open_table(X).unwrap();
-            assert_eq!(table.get(b"hello").unwrap().unwrap(), b"world");
+            assert_eq!(table.get(b"hello").unwrap().unwrap().value(), b"world");
             table.insert(b"hello2", b"world2").unwrap();
         }
         write_txn.commit().unwrap();
diff --git a/src/tree_store/table_tree.rs b/src/tree_store/table_tree.rs
index a136d1c..36d67ec 100644
--- a/src/tree_store/table_tree.rs
+++ b/src/tree_store/table_tree.rs
@@ -320,7 +320,7 @@ impl<'txn> TableTree<'txn> {
         for (name, table_root) in self.pending_table_updates.drain() {
             // Bypass .get_table() since the table types are dynamic
             // TODO: optimize away this get()
-            let mut definition = self.tree.get(name.as_str()).unwrap().unwrap();
+            let mut definition = self.tree.get(name.as_str()).unwrap().unwrap().value();
             // No-op if the root has not changed
             if definition.table_root == table_root {
                 continue;
@@ -350,7 +350,8 @@ impl<'txn> TableTree<'txn> {
         name: &str,
         table_type: TableType,
     ) -> Result<Option<InternalTableDefinition>> {
-        if let Some(mut definition) = self.tree.get(name)? {
+        if let Some(guard) = self.tree.get(name)? {
+            let mut definition = guard.value();
             if definition.get_type() != table_type {
                 return Err(Error::TableTypeMismatch(format!(
                     "{:?} is not of type {:?}",


Test patch:
diff --git a/tests/basic_tests.rs b/tests/basic_tests.rs
index 93a0cc9..4e63509 100644
--- a/tests/basic_tests.rs
+++ b/tests/basic_tests.rs
@@ -57,7 +57,7 @@ fn create_open() {
 
     let read_txn = db2.begin_read().unwrap();
     let table = read_txn.open_table(U64_TABLE).unwrap();
-    assert_eq!(1, table.get(&0).unwrap().unwrap());
+    assert_eq!(1, table.get(&0).unwrap().unwrap().value());
 }
 
 #[test]
@@ -81,9 +81,9 @@ fn multiple_tables() {
     let table = read_txn.open_table(definition1).unwrap();
     let table2 = read_txn.open_table(definition2).unwrap();
     assert_eq!(table.len().unwrap(), 1);
-    assert_eq!(b"world", table.get(b"hello").unwrap().unwrap());
+    assert_eq!(b"world", table.get(b"hello").unwrap().unwrap().value());
     assert_eq!(table2.len().unwrap(), 1);
-    assert_eq!(b"world2", table2.get(b"hello").unwrap().unwrap());
+    assert_eq!(b"world2", table2.get(b"hello").unwrap().unwrap().value());
 }
 
 #[test]
@@ -153,7 +153,7 @@ fn tuple_type_lifetime() {
 
     let read_txn = db.begin_read().unwrap();
     let table = read_txn.open_table(table_def).unwrap();
-    assert_eq!(table.get(&("hello", 5)).unwrap().unwrap(), (0, 123));
+    assert_eq!(table.get(&("hello", 5)).unwrap().unwrap().value(), (0, 123));
 }
 
 #[test]
@@ -172,7 +172,7 @@ fn tuple2_type() {
 
     let read_txn = db.begin_read().unwrap();
     let table = read_txn.open_table(table_def).unwrap();
-    assert_eq!(table.get(&("hello", 5)).unwrap().unwrap(), (0, 123));
+    assert_eq!(table.get(&("hello", 5)).unwrap().unwrap().value(), (0, 123));
 }
 
 #[test]
@@ -191,7 +191,10 @@ fn tuple3_type() {
 
     let read_txn = db.begin_read().unwrap();
     let table = read_txn.open_table(table_def).unwrap();
-    assert_eq!(table.get(&("hello", 5, 6)).unwrap().unwrap(), (0, 123));
+    assert_eq!(
+        table.get(&("hello", 5, 6)).unwrap().unwrap().value(),
+        (0, 123)
+    );
 }
 
 #[test]
@@ -211,7 +214,10 @@ fn tuple4_type() {
 
     let read_txn = db.begin_read().unwrap();
     let table = read_txn.open_table(table_def).unwrap();
-    assert_eq!(table.get(&("hello", 5, 6, 7)).unwrap().unwrap(), (0, 123));
+    assert_eq!(
+        table.get(&("hello", 5, 6, 7)).unwrap().unwrap().value(),
+        (0, 123)
+    );
 }
 
 #[test]
@@ -233,7 +239,7 @@ fn tuple5_type() {
     let read_txn = db.begin_read().unwrap();
     let table = read_txn.open_table(table_def).unwrap();
     assert_eq!(
-        table.get(&("hello", 5, 6, 7, 8)).unwrap().unwrap(),
+        table.get(&("hello", 5, 6, 7, 8)).unwrap().unwrap().value(),
         (0, 123)
     );
 }
@@ -257,7 +263,11 @@ fn tuple6_type() {
     let read_txn = db.begin_read().unwrap();
     let table = read_txn.open_table(table_def).unwrap();
     assert_eq!(
-        table.get(&("hello", 5, 6, 7, 8, 9)).unwrap().unwrap(),
+        table
+            .get(&("hello", 5, 6, 7, 8, 9))
+            .unwrap()
+            .unwrap()
+            .value(),
         (0, 123)
     );
 }
@@ -283,7 +293,11 @@ fn tuple7_type() {
     let read_txn = db.begin_read().unwrap();
     let table = read_txn.open_table(table_def).unwrap();
     assert_eq!(
-        table.get(&("hello", 5, 6, 7, 8, 9, -1)).unwrap().unwrap(),
+        table
+            .get(&("hello", 5, 6, 7, 8, 9, -1))
+            .unwrap()
+            .unwrap()
+            .value(),
         (0, 123)
     );
 }
@@ -312,7 +326,8 @@ fn tuple8_type() {
         table
             .get(&("hello", 5, 6, 7, 8, 9, -1, -2))
             .unwrap()
-            .unwrap(),
+            .unwrap()
+            .value(),
         (0, 123)
     );
 }
@@ -341,7 +356,8 @@ fn tuple9_type() {
         table
             .get(&("hello", 5, 6, 7, 8, 9, -1, -2, -3))
             .unwrap()
-            .unwrap(),
+            .unwrap()
+            .value(),
         (0, 123)
     );
 }
@@ -370,7 +386,8 @@ fn tuple10_type() {
         table
             .get(&("hello", 5, 6, 7, 8, 9, -1, -2, -3, -4))
             .unwrap()
-            .unwrap(),
+            .unwrap()
+            .value(),
         (0, 123)
     );
 }
@@ -401,7 +418,8 @@ fn tuple11_type() {
         table
             .get(&("hello", 5, 6, 7, 8, 9, -1, -2, -3, -4, -5))
             .unwrap()
-            .unwrap(),
+            .unwrap()
+            .value(),
         (0, 123)
     );
 }
@@ -435,7 +453,8 @@ fn tuple12_type() {
         table
             .get(&("hello", 5, 6, 7, 8, 9, -1, -2, -3, -4, -5, "end"))
             .unwrap()
-            .unwrap(),
+            .unwrap()
+            .value(),
         (0, 123)
     );
 }
@@ -466,7 +485,7 @@ fn abort() {
     {
         let mut table = write_txn.open_table(SLICE_TABLE).unwrap();
         table.insert(b"hello", b"aborted").unwrap();
-        assert_eq!(b"aborted", table.get(b"hello").unwrap().unwrap());
+        assert_eq!(b"aborted", table.get(b"hello").unwrap().unwrap().value());
     }
     write_txn.abort().unwrap();
 
@@ -483,7 +502,7 @@ fn abort() {
 
     let read_txn = db.begin_read().unwrap();
     let table = read_txn.open_table(SLICE_TABLE).unwrap();
-    assert_eq!(b"world", table.get(b"hello").unwrap().unwrap());
+    assert_eq!(b"world", table.get(b"hello").unwrap().unwrap().value());
     assert_eq!(table.len().unwrap(), 1);
 }
 
@@ -500,19 +519,19 @@ fn insert_overwrite() {
 
     let read_txn = db.begin_read().unwrap();
     let table = read_txn.open_table(SLICE_TABLE).unwrap();
-    assert_eq!(b"world", table.get(b"hello").unwrap().unwrap());
+    assert_eq!(b"world", table.get(b"hello").unwrap().unwrap().value());
 
     let write_txn = db.begin_write().unwrap();
     {
         let mut table = write_txn.open_table(SLICE_TABLE).unwrap();
         let old_value = table.insert(b"hello", b"replaced").unwrap();
-        assert_eq!(old_value.unwrap().to_value(), b"world");
+        assert_eq!(old_value.unwrap().value(), b"world");
     }
     write_txn.commit().unwrap();
 
     let read_txn = db.begin_read().unwrap();
     let table = read_txn.open_table(SLICE_TABLE).unwrap();
-    assert_eq!(b"replaced", table.get(b"hello").unwrap().unwrap());
+    assert_eq!(b"replaced", table.get(b"hello").unwrap().unwrap().value());
 }
 
 #[test]
@@ -530,7 +549,7 @@ fn insert_reserve() {
 
     let read_txn = db.begin_read().unwrap();
     let table = read_txn.open_table(SLICE_TABLE).unwrap();
-    assert_eq!(value, table.get(b"hello").unwrap().unwrap());
+    assert_eq!(value, table.get(b"hello").unwrap().unwrap().value());
 }
 
 #[test]
@@ -547,16 +566,13 @@ fn delete() {
 
     let read_txn = db.begin_read().unwrap();
     let table = read_txn.open_table(SLICE_TABLE).unwrap();
-    assert_eq!(b"world", table.get(b"hello").unwrap().unwrap());
+    assert_eq!(b"world", table.get(b"hello").unwrap().unwrap().value());
     assert_eq!(table.len().unwrap(), 2);
 
     let write_txn = db.begin_write().unwrap();
     {
         let mut table = write_txn.open_table(SLICE_TABLE).unwrap();
-        assert_eq!(
-            b"world",
-            table.remove(b"hello").unwrap().unwrap().to_value()
-        );
+        assert_eq!(b"world", table.remove(b"hello").unwrap().unwrap().value());
         assert!(table.remove(b"hello").unwrap().is_none());
     }
     write_txn.commit().unwrap();
@@ -584,7 +600,7 @@ fn no_dirty_reads() {
 
     let read_txn = db.begin_read().unwrap();
     let table = read_txn.open_table(SLICE_TABLE).unwrap();
-    assert_eq!(b"world", table.get(b"hello").unwrap().unwrap());
+    assert_eq!(b"world", table.get(b"hello").unwrap().unwrap().value());
 }
 
 #[test]
@@ -600,7 +616,7 @@ fn read_isolation() {
 
     let read_txn = db.begin_read().unwrap();
     let table = read_txn.open_table(SLICE_TABLE).unwrap();
-    assert_eq!(b"world", table.get(b"hello").unwrap().unwrap());
+    assert_eq!(b"world", table.get(b"hello").unwrap().unwrap().value());
 
     let write_txn = db.begin_write().unwrap();
     {
@@ -614,11 +630,11 @@ fn read_isolation() {
     let read_txn2 = db.begin_read().unwrap();
     let table2 = read_txn2.open_table(SLICE_TABLE).unwrap();
     assert!(table2.get(b"hello").unwrap().is_none());
-    assert_eq!(b"world2", table2.get(b"hello2").unwrap().unwrap());
-    assert_eq!(b"world3", table2.get(b"hello3").unwrap().unwrap());
+    assert_eq!(b"world2", table2.get(b"hello2").unwrap().unwrap().value());
+    assert_eq!(b"world3", table2.get(b"hello3").unwrap().unwrap().value());
     assert_eq!(table2.len().unwrap(), 2);
 
-    assert_eq!(b"world", table.get(b"hello").unwrap().unwrap());
+    assert_eq!(b"world", table.get(b"hello").unwrap().unwrap().value());
     assert!(table.get(b"hello2").unwrap().is_none());
     assert!(table.get(b"hello3").unwrap().is_none());
     assert_eq!(table.len().unwrap(), 1);
@@ -638,7 +654,7 @@ fn read_isolation2() {
     let write_txn = db.begin_write().unwrap();
     let read_txn = db.begin_read().unwrap();
     let table = read_txn.open_table(SLICE_TABLE).unwrap();
-    assert_eq!(b"world", table.get(b"hello").unwrap().unwrap());
+    assert_eq!(b"world", table.get(b"hello").unwrap().unwrap().value());
     {
         let mut write_table = write_txn.open_table(SLICE_TABLE).unwrap();
         write_table.remove(b"hello").unwrap();
@@ -650,11 +666,11 @@ fn read_isolation2() {
     let read_txn2 = db.begin_read().unwrap();
     let table2 = read_txn2.open_table(SLICE_TABLE).unwrap();
     assert!(table2.get(b"hello").unwrap().is_none());
-    assert_eq!(b"world2", table2.get(b"hello2").unwrap().unwrap());
-    assert_eq!(b"world3", table2.get(b"hello3").unwrap().unwrap());
+    assert_eq!(b"world2", table2.get(b"hello2").unwrap().unwrap().value());
+    assert_eq!(b"world3", table2.get(b"hello3").unwrap().unwrap().value());
     assert_eq!(table2.len().unwrap(), 2);
 
-    assert_eq!(b"world", table.get(b"hello").unwrap().unwrap());
+    assert_eq!(b"world", table.get(b"hello").unwrap().unwrap().value());
     assert!(table.get(b"hello2").unwrap().is_none());
     assert!(table.get(b"hello3").unwrap().is_none());
     assert_eq!(table.len().unwrap(), 1);
@@ -690,8 +706,11 @@ fn u64_type() {
 
     let read_txn = db.begin_read().unwrap();
     let table = read_txn.open_table(U64_TABLE).unwrap();
-    assert_eq!(2u64, table.range(0..2).unwrap().map(|(_, x)| x).sum());
-    assert_eq!(1, table.get(&0).unwrap().unwrap());
+    assert_eq!(
+        2u64,
+        table.range(0..2).unwrap().map(|(_, x)| x.value()).sum()
+    );
+    assert_eq!(1, table.get(&0).unwrap().unwrap().value());
 }
 
 #[test]
@@ -712,10 +731,10 @@ fn i128_type() {
 
     let read_txn = db.begin_read().unwrap();
     let table = read_txn.open_table(definition).unwrap();
-    assert_eq!(-2, table.get(&-1).unwrap().unwrap());
+    assert_eq!(-2, table.get(&-1).unwrap().unwrap().value());
     let mut iter: RangeIter<i128, i128> = table.range::<i128>(..).unwrap();
     for i in -11..10 {
-        assert_eq!(iter.next().unwrap().1, i);
+        assert_eq!(iter.next().unwrap().1.value(), i);
     }
     assert!(iter.next().is_none());
 }
@@ -736,7 +755,7 @@ fn f32_type() {
 
     let read_txn = db.begin_read().unwrap();
     let table = read_txn.open_table(definition).unwrap();
-    assert_eq!(0.3, table.get(&0).unwrap().unwrap());
+    assert_eq!(0.3, table.get(&0).unwrap().unwrap().value());
 }
 
 #[test]
@@ -755,14 +774,14 @@ fn str_type() {
 
     let read_txn = db.begin_read().unwrap();
     let table = read_txn.open_table(definition).unwrap();
-    assert_eq!("world", table.get("hello").unwrap().unwrap());
+    assert_eq!("world", table.get("hello").unwrap().unwrap().value());
 
     let mut iter = table.iter().unwrap();
-    assert_eq!(iter.next().unwrap().1, "world");
+    assert_eq!(iter.next().unwrap().1.value(), "world");
     assert!(iter.next().is_none());
 
     let mut iter: RangeIter<&str, &str> = table.range("a".."z").unwrap();
-    assert_eq!(iter.next().unwrap().1, "world");
+    assert_eq!(iter.next().unwrap().1.value(), "world");
     assert!(iter.next().is_none());
 }
 
@@ -802,10 +821,10 @@ fn array_type() {
     let read_txn = db.begin_read().unwrap();
     let table = read_txn.open_table(definition).unwrap();
     let hello = b"hello";
-    assert_eq!(b"world_123", table.get(hello).unwrap().unwrap());
+    assert_eq!(b"world_123", table.get(hello).unwrap().unwrap().value());
 
     let mut iter: RangeIter<&[u8; 5], &[u8; 9]> = table.range::<&[u8; 5]>(..).unwrap();
-    assert_eq!(iter.next().unwrap().1, b"world_123");
+    assert_eq!(iter.next().unwrap().1.value(), b"world_123");
     assert!(iter.next().is_none());
 }
 
@@ -828,21 +847,21 @@ fn owned_get_signatures() {
     let read_txn = db.begin_read().unwrap();
     let table = read_txn.open_table(definition).unwrap();
 
-    assert_eq!(2, table.get(&1).unwrap().unwrap());
+    assert_eq!(2, table.get(&1).unwrap().unwrap().value());
 
     let mut iter: RangeIter<u32, u32> = table.range::<u32>(..).unwrap();
     for i in 0..10 {
-        assert_eq!(iter.next().unwrap().1, i + 1);
+        assert_eq!(iter.next().unwrap().1.value(), i + 1);
     }
     assert!(iter.next().is_none());
     let mut iter: RangeIter<u32, u32> = table.range(0..10).unwrap();
     for i in 0..10 {
-        assert_eq!(iter.next().unwrap().1, i + 1);
+        assert_eq!(iter.next().unwrap().1.value(), i + 1);
     }
     assert!(iter.next().is_none());
     let mut iter = table.range::<&u32>(&0..&10).unwrap();
     for i in 0..10 {
-        assert_eq!(iter.next().unwrap().1, i + 1);
+        assert_eq!(iter.next().unwrap().1.value(), i + 1);
     }
     assert!(iter.next().is_none());
 }
@@ -864,34 +883,34 @@ fn ref_get_signatures() {
     let table = read_txn.open_table(SLICE_TABLE).unwrap();
 
     let zero = vec![0u8];
-    assert_eq!(&[1], table.get(&[0]).unwrap().unwrap());
-    assert_eq!(&[1], table.get(b"\0").unwrap().unwrap());
-    assert_eq!(&[1], table.get(&zero).unwrap().unwrap());
+    assert_eq!(&[1], table.get(&[0]).unwrap().unwrap().value());
+    assert_eq!(&[1], table.get(b"\0").unwrap().unwrap().value());
+    assert_eq!(&[1], table.get(&zero).unwrap().unwrap().value());
 
     let start = vec![0u8];
     let end = vec![10u8];
     let mut iter = table.range::<&[u8]>(..).unwrap();
     for i in 0..10 {
-        assert_eq!(iter.next().unwrap().1, &[i + 1]);
+        assert_eq!(iter.next().unwrap().1.value(), &[i + 1]);
     }
     assert!(iter.next().is_none());
 
     let mut iter = table.range(start.as_slice()..&end).unwrap();
     for i in 0..10 {
-        assert_eq!(iter.next().unwrap().1, &[i + 1]);
+        assert_eq!(iter.next().unwrap().1.value(), &[i + 1]);
     }
     assert!(iter.next().is_none());
     drop(iter);
 
     let mut iter = table.range(start..end).unwrap();
     for i in 0..10 {
-        assert_eq!(iter.next().unwrap().1, &[i + 1]);
+        assert_eq!(iter.next().unwrap().1.value(), &[i + 1]);
     }
     assert!(iter.next().is_none());
 
     let mut iter = table.range([0u8]..[10u8]).unwrap();
     for i in 0..10 {
-        assert_eq!(iter.next().unwrap().1, &[i + 1]);
+        assert_eq!(iter.next().unwrap().1.value(), &[i + 1]);
     }
     assert!(iter.next().is_none());
 }
@@ -935,7 +954,7 @@ fn iter() {
     let mut iter = table.iter().unwrap();
     for i in 0..10 {
         let (k, v) = iter.next().unwrap();
-        assert_eq!(i, k);
-        assert_eq!(i, v);
+        assert_eq!(i, k.value());
+        assert_eq!(i, v.value());
     }
 }
diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs
index 0d05efb..144ba22 100644
--- a/tests/integration_tests.rs
+++ b/tests/integration_tests.rs
@@ -75,8 +75,7 @@ fn non_durable_commit_persistence() {
     {
         for i in &key_order {
             let (key, value) = &pairs[*i % pairs.len()];
-            let result = table.get(key).unwrap().unwrap();
-            assert_eq!(result, value);
+            assert_eq!(table.get(key).unwrap().unwrap().value(), value);
         }
     }
 }
@@ -108,8 +107,7 @@ fn test_persistence(durability: Durability) {
     {
         for i in &key_order {
             let (key, value) = &pairs[*i % pairs.len()];
-            let result = &table.get(key).unwrap().unwrap();
-            assert_eq!(result, value);
+            assert_eq!(table.get(key).unwrap().unwrap().value(), value);
         }
     }
 }
@@ -307,7 +305,7 @@ fn multi_page_kv() {
     for i in 0..elements {
         key[0] = i;
         value[0] = i;
-        assert_eq!(&value, table.get(&key).unwrap().unwrap());
+        assert_eq!(&value, table.get(&key).unwrap().unwrap().value());
     }
 
     let txn = db.begin_write().unwrap();
@@ -378,7 +376,7 @@ fn regression() {
 
     let txn = db.begin_read().unwrap();
     let table = txn.open_table(U64_TABLE).unwrap();
-    let v = table.get(&6).unwrap().unwrap();
+    let v = table.get(&6).unwrap().unwrap().value();
     assert_eq!(v, 9);
 }
 
@@ -461,8 +459,8 @@ fn regression7() {
         t.remove(&145227).unwrap();
 
         let mut iter = t.range(138763..(138763 + 232359)).unwrap().rev();
-        assert_eq!(iter.next().unwrap().0, 153701);
-        assert_eq!(iter.next().unwrap().0, 146255);
+        assert_eq!(iter.next().unwrap().0.value(), 153701);
+        assert_eq!(iter.next().unwrap().0.value(), 146255);
         assert!(iter.next().is_none());
     }
     tx.commit().unwrap();
@@ -510,8 +508,8 @@ fn regression8() {
     {
         let t = tx.open_table(table_def).unwrap();
         let mut iter = t.range(118749..142650).unwrap();
-        assert_eq!(iter.next().unwrap().0, 118749);
-        assert_eq!(iter.next().unwrap().0, 130571);
+        assert_eq!(iter.next().unwrap().0.value(), 118749);
+        assert_eq!(iter.next().unwrap().0.value(), 130571);
         assert!(iter.next().is_none());
     }
     tx.commit().unwrap();
@@ -616,11 +614,11 @@ fn regression12() {
     {
         let mut t = tx.open_table(table_def).unwrap();
         t.insert(&0, &0).unwrap();
-        assert_eq!(t.get(&0).unwrap().unwrap(), 0);
+        assert_eq!(t.get(&0).unwrap().unwrap().value(), 0);
         drop(t);
 
         let t2 = tx.open_table(table_def).unwrap();
-        assert_eq!(t2.get(&0).unwrap().unwrap(), 0);
+        assert_eq!(t2.get(&0).unwrap().unwrap().value(), 0);
     }
     tx.commit().unwrap();
 }
@@ -672,13 +670,13 @@ fn regression14() {
         let mut iter = t.range(&514043..&(514043 + 514043)).unwrap().rev();
         {
             let (key, mut value_iter) = iter.next().unwrap();
-            assert_eq!(key, 776971);
-            assert_eq!(value_iter.next().unwrap(), &[0; 2230]);
+            assert_eq!(key.value(), 776971);
+            assert_eq!(value_iter.next().unwrap().value(), &[0; 2230]);
         }
         {
             let (key, mut value_iter) = iter.next().unwrap();
-            assert_eq!(key, 539749);
-            assert_eq!(value_iter.next().unwrap(), &[0; 1424]);
+            assert_eq!(key.value(), 539749);
+            assert_eq!(value_iter.next().unwrap().value(), &[0; 1424]);
         }
     }
     tx.abort().unwrap();
@@ -896,7 +894,7 @@ fn non_durable_read_isolation() {
 
     let read_txn = db.begin_read().unwrap();
     let read_table = read_txn.open_table(SLICE_TABLE).unwrap();
-    assert_eq!(b"world", read_table.get(b"hello").unwrap().unwrap());
+    assert_eq!(b"world", read_table.get(b"hello").unwrap().unwrap().value());
 
     let mut write_txn = db.begin_write().unwrap();
     write_txn.set_durability(Durability::None);
@@ -911,11 +909,17 @@ fn non_durable_read_isolation() {
     let read_txn2 = db.begin_read().unwrap();
     let read_table2 = read_txn2.open_table(SLICE_TABLE).unwrap();
     assert!(read_table2.get(b"hello").unwrap().is_none());
-    assert_eq!(b"world2", read_table2.get(b"hello2").unwrap().unwrap());
-    assert_eq!(b"world3", read_table2.get(b"hello3").unwrap().unwrap());
+    assert_eq!(
+        b"world2",
+        read_table2.get(b"hello2").unwrap().unwrap().value()
+    );
+    assert_eq!(
+        b"world3",
+        read_table2.get(b"hello3").unwrap().unwrap().value()
+    );
     assert_eq!(read_table2.len().unwrap(), 2);
 
-    assert_eq!(b"world", read_table.get(b"hello").unwrap().unwrap());
+    assert_eq!(b"world", read_table.get(b"hello").unwrap().unwrap().value());
     assert!(read_table.get(b"hello2").unwrap().is_none());
     assert!(read_table.get(b"hello3").unwrap().is_none());
     assert_eq!(read_table.len().unwrap(), 1);
@@ -939,20 +943,20 @@ fn range_query() {
     let mut iter = table.range(3..7).unwrap();
     for i in 3..7u64 {
         let (key, value) = iter.next().unwrap();
-        assert_eq!(i, key);
-        assert_eq!(i, value);
+        assert_eq!(i, key.value());
+        assert_eq!(i, value.value());
     }
     assert!(iter.next().is_none());
 
     let mut iter = table.range(3..=7).unwrap();
     for i in 3..=7u64 {
         let (key, value) = iter.next().unwrap();
-        assert_eq!(i, key);
-        assert_eq!(i, value);
+        assert_eq!(i, key.value());
+        assert_eq!(i, value.value());
     }
     assert!(iter.next().is_none());
 
-    let total: u64 = table.range(1..=3).unwrap().map(|(_, v)| v).sum();
+    let total: u64 = table.range(1..=3).unwrap().map(|(_, v)| v.value()).sum();
     assert_eq!(total, 6);
 }
 
@@ -974,25 +978,25 @@ fn range_query_reversed() {
     let mut iter = table.range(3..7).unwrap().rev();
     for i in (3..7u64).rev() {
         let (key, value) = iter.next().unwrap();
-        assert_eq!(i, key);
-        assert_eq!(i, value);
+        assert_eq!(i, key.value());
+        assert_eq!(i, value.value());
     }
     assert!(iter.next().is_none());
 
     // Test reversing multiple times
     let mut iter = table.range(3..7).unwrap();
     let (key, _) = iter.next().unwrap();
-    assert_eq!(3, key);
+    assert_eq!(3, key.value());
 
     let mut iter = iter.rev();
     let (key, _) = iter.next().unwrap();
-    assert_eq!(6, key);
+    assert_eq!(6, key.value());
     let (key, _) = iter.next().unwrap();
-    assert_eq!(5, key);
+    assert_eq!(5, key.value());
 
     let mut iter = iter.rev();
     let (key, _) = iter.next().unwrap();
-    assert_eq!(4, key);
+    assert_eq!(4, key.value());
 
     assert!(iter.next().is_none());
 }
@@ -1247,7 +1251,7 @@ fn savepoint() {
 
     let txn = db.begin_read().unwrap();
     let table = txn.open_table(definition).unwrap();
-    assert_eq!(table.get(&0).unwrap().unwrap(), "hello");
+    assert_eq!(table.get(&0).unwrap().unwrap().value(), "hello");
 
     // Test that savepoints can be used multiple times
     let mut txn = db.begin_write().unwrap();
diff --git a/tests/multimap_tests.rs b/tests/multimap_tests.rs
index 7d4fa45..82d3e74 100644
--- a/tests/multimap_tests.rs
+++ b/tests/multimap_tests.rs
@@ -15,7 +15,7 @@ fn get_vec(
     loop {
         let item = iter.next();
         if let Some(item_value) = item {
-            result.push(item_value.to_string());
+            result.push(item_value.value().to_string());
         } else {
             return result;
         }
@@ -107,24 +107,24 @@ fn range_query() {
     {
         let (key, mut values) = iter.next().unwrap();
         for i in 0..5 {
-            assert_eq!(b"0", key);
+            assert_eq!(b"0", key.value());
             let value = values.next().unwrap();
-            assert_eq!(i, value);
+            assert_eq!(i, value.value());
         }
     }
     {
         let (key, mut values) = iter.next().unwrap();
         for i in 5..10 {
-            assert_eq!(b"1", key);
+            assert_eq!(b"1", key.value());
             let value = values.next().unwrap();
-            assert_eq!(i, value);
+            assert_eq!(i, value.value());
         }
     }
     assert!(iter.next().is_none());
 
     let mut total: u64 = 0;
     for (_, values) in table.range(&start..=&end).unwrap() {
-        total += values.sum::<u64>();
+        total += values.map(|x| x.value()).sum::<u64>();
     }
     assert_eq!(total, 45);
 }
@@ -173,8 +173,8 @@ fn delete() {
     {
         let mut table = write_txn.open_multimap_table(STR_TABLE).unwrap();
         let mut iter = table.remove_all("hello").unwrap();
-        assert_eq!("world", iter.next().unwrap());
-        assert_eq!("world3", iter.next().unwrap());
+        assert_eq!("world", iter.next().unwrap().value());
+        assert_eq!("world3", iter.next().unwrap().value());
         assert!(iter.next().is_none());
     }
     write_txn.commit().unwrap();
@@ -274,9 +274,9 @@ fn iter() {
     let mut iter = table.iter().unwrap();
     for i in 0..10 {
         let (k, mut values) = iter.next().unwrap();
-        assert_eq!(k, i);
+        assert_eq!(k.value(), i);
         for j in 0..10 {
-            assert_eq!(values.next().unwrap(), j);
+            assert_eq!(values.next().unwrap().value(), j);
         }
     }
 }