Repository: cberner/redb
Pull request #543 (2023-03-29 23:06:42)

Various API and other cleanups


Patch:
diff --git a/benches/common.rs b/benches/common.rs
index cf35144..35153c3 100644
--- a/benches/common.rs
+++ b/benches/common.rs
@@ -142,9 +142,10 @@ impl BenchIterator for RedbBenchIterator<'_> {
     type Output<'a> = RedbAccessGuard<'a> where Self: 'a;
 
     fn next(&mut self) -> Option<(Self::Output<'_>, Self::Output<'_>)> {
-        self.iter
-            .next()
-            .map(|(k, v)| (RedbAccessGuard::new(k), RedbAccessGuard::new(v)))
+        self.iter.next().map(|item| {
+            let (k, v) = item.unwrap();
+            (RedbAccessGuard::new(k), RedbAccessGuard::new(v))
+        })
     }
 }
 
diff --git a/fuzz/fuzz_targets/fuzz_redb.rs b/fuzz/fuzz_targets/fuzz_redb.rs
index 890cea8..de594ab 100644
--- a/fuzz/fuzz_targets/fuzz_redb.rs
+++ b/fuzz/fuzz_targets/fuzz_redb.rs
@@ -114,9 +114,9 @@ fn exec_table_inner(db: Arc<Database>, transactions: &[FuzzTransaction], referen
                                 Box::new(local_reference.range(start..end))
                             };
                         let mut iter: Box<dyn Iterator<Item = (AccessGuard<u64>, AccessGuard<&[u8]>)>> = if *reversed {
-                            Box::new(table.range(start..end).unwrap().rev())
+                            Box::new(table.range(start..end).unwrap().map(|x| x.unwrap()).rev())
                         } else {
-                            Box::new(table.range(start..end).unwrap())
+                            Box::new(table.range(start..end).unwrap().map(|x| x.unwrap()))
                         };
                         while let Some((ref_key, ref_value_len)) = reference_iter.next() {
                             let (key, value) = iter.next().unwrap();
@@ -146,7 +146,7 @@ fn assert_multimap_value_eq(
 ) {
     if let Some(values) = reference {
         for value in values.iter() {
-            assert_eq!(iter.next().unwrap().value().len(), *value);
+            assert_eq!(iter.next().unwrap().unwrap().value().len(), *value);
         }
     }
     assert!(iter.next().is_none());
@@ -251,9 +251,9 @@ fn exec_multimap_table_inner(db: Arc<Database>, transactions: &[FuzzTransaction]
                                 Box::new(local_reference.range(start..end))
                             };
                         let mut iter: Box<dyn Iterator<Item = (AccessGuard<u64>, MultimapValue<&[u8]>)>> = if *reversed {
-                            Box::new(table.range(start..end).unwrap().rev())
+                            Box::new(table.range(start..end).unwrap().map(|x| x.unwrap()).rev())
                         } else {
-                            Box::new(table.range(start..end).unwrap())
+                            Box::new(table.range(start..end).unwrap().map(|x| x.unwrap()))
                         };
                         while let Some((ref_key, ref_values)) = reference_iter.next() {
                             let (key, value_iter) = iter.next().unwrap();
diff --git a/src/db.rs b/src/db.rs
index 8aa0eb5..dcfefe5 100644
--- a/src/db.rs
+++ b/src/db.rs
@@ -275,7 +275,7 @@ impl Database {
         let iter: BtreeRangeIter<&str, InternalTableDefinition> =
             BtreeRangeIter::new::<RangeFull, &str>(.., Some(root), mem)?;
         for entry in iter {
-            let definition = entry.value();
+            let definition = entry?.value();
             if let Some((table_root, table_checksum)) = definition.get_root() {
                 if !RawBtree::new(
                     Some((table_root, table_checksum)),
@@ -342,7 +342,7 @@ impl Database {
 
             // Chain all the other tables to the master table iter
             for entry in iter {
-                let definition = entry.value();
+                let definition = entry?.value();
                 if let Some((table_root, _)) = definition.get_root() {
                     let table_pages_iter = AllPageNumbersBtreeIter::new(
                         table_root,
@@ -361,13 +361,13 @@ impl Database {
                             &mem,
                         )?;
                         for table_page in table_pages_iter {
-                            let page = mem.get_page(table_page)?;
+                            let page = mem.get_page(table_page?)?;
                             let mut subtree_roots = parse_subtree_roots(
                                 &page,
                                 definition.get_fixed_key_size(),
                                 definition.get_fixed_value_size(),
                             );
-                            mem.mark_pages_allocated(subtree_roots.drain(..))?;
+                            mem.mark_pages_allocated(subtree_roots.drain(..).map(Ok))?;
                         }
                     }
                 }
@@ -398,11 +398,6 @@ impl Database {
         })
     }
 
-    // TODO: we could probably remove this method and pass this clone into the Transaction objects
-    pub(crate) fn transaction_tracker(&self) -> Arc<Mutex<TransactionTracker>> {
-        self.transaction_tracker.clone()
-    }
-
     fn allocate_read_transaction(&self) -> Result<TransactionId> {
         let mut guard = self.transaction_tracker.lock().unwrap();
         let id = self.mem.get_last_committed_transaction_id()?;
@@ -462,7 +457,7 @@ impl Database {
     /// write may be in progress at a time. If a write is in progress, this function will block
     /// until it completes.
     pub fn begin_write(&self) -> Result<WriteTransaction> {
-        WriteTransaction::new(self)
+        WriteTransaction::new(self, self.transaction_tracker.clone())
     }
 
     /// Begins a read transaction
@@ -476,7 +471,11 @@ impl Database {
         let id = self.allocate_read_transaction()?;
         #[cfg(feature = "logging")]
         info!("Beginning read transaction id={:?}", id);
-        Ok(ReadTransaction::new(self, id))
+        Ok(ReadTransaction::new(
+            self.get_memory(),
+            self.transaction_tracker.clone(),
+            id,
+        ))
     }
 }
 
diff --git a/src/multimap_table.rs b/src/multimap_table.rs
index 092a42f..52ce9cb 100644
--- a/src/multimap_table.rs
+++ b/src/multimap_table.rs
@@ -313,16 +313,20 @@ impl<'a, V: RedbKey + 'static> MultimapValue<'a, V> {
 }
 
 impl<'a, V: RedbKey + 'static> Iterator for MultimapValue<'a, V> {
-    // TODO: this probably needs to return a Result
-    type Item = AccessGuard<'a, V>;
+    type Item = Result<AccessGuard<'a, V>>;
 
     fn next(&mut self) -> Option<Self::Item> {
         // TODO: optimize out this copy
         let bytes = match self.inner.as_mut().unwrap() {
-            ValueIterState::Subtree(ref mut iter) => iter.next().map(|e| e.key_data())?,
+            ValueIterState::Subtree(ref mut iter) => match iter.next()? {
+                Ok(e) => e.key_data(),
+                Err(err) => {
+                    return Some(Err(err));
+                }
+            },
             ValueIterState::InlineLeaf(ref mut iter) => iter.next_key()?.to_vec(),
         };
-        Some(AccessGuard::with_owned_value(bytes))
+        Some(Ok(AccessGuard::with_owned_value(bytes)))
     }
 }
 
@@ -330,10 +334,15 @@ impl<'a, V: RedbKey + 'static> DoubleEndedIterator for MultimapValue<'a, V> {
     fn next_back(&mut self) -> Option<Self::Item> {
         // 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_data())?,
+            ValueIterState::Subtree(ref mut iter) => match iter.next_back()? {
+                Ok(e) => e.key_data(),
+                Err(err) => {
+                    return Some(Err(err));
+                }
+            },
             ValueIterState::InlineLeaf(ref mut iter) => iter.next_key_back()?.to_vec(),
         };
-        Some(AccessGuard::with_owned_value(bytes))
+        Some(Ok(AccessGuard::with_owned_value(bytes)))
     }
 }
 
@@ -374,18 +383,18 @@ impl<'a, K: RedbKey + 'static, V: RedbKey + 'static> MultimapRange<'a, K, V> {
 }
 
 impl<'a, K: RedbKey + 'static, V: RedbKey + 'static> Iterator for MultimapRange<'a, K, V> {
-    // TODO: this probably needs to return a Result
-    type Item = (AccessGuard<'a, K>, MultimapValue<'a, V>);
+    type Item = Result<(AccessGuard<'a, K>, MultimapValue<'a, V>)>;
 
     fn next(&mut self) -> Option<Self::Item> {
-        let entry = self.inner.next()?;
-        let key = AccessGuard::with_owned_value(entry.key_data());
-        let (page, _, value_range) = entry.into_raw();
-        let collection = AccessGuard::with_page(page, value_range);
-        // TODO: propagate error
-        let iter = DynamicCollection::iter(collection, self.mem).unwrap();
-
-        Some((key, iter))
+        match self.inner.next()? {
+            Ok(entry) => {
+                let key = AccessGuard::with_owned_value(entry.key_data());
+                let (page, _, value_range) = entry.into_raw();
+                let collection = AccessGuard::with_page(page, value_range);
+                Some(DynamicCollection::iter(collection, self.mem).map(|iter| (key, iter)))
+            }
+            Err(err) => Some(Err(err)),
+        }
     }
 }
 
@@ -393,14 +402,15 @@ impl<'a, K: RedbKey + 'static, V: RedbKey + 'static> DoubleEndedIterator
     for MultimapRange<'a, K, V>
 {
     fn next_back(&mut self) -> Option<Self::Item> {
-        let entry = self.inner.next_back()?;
-        let key = AccessGuard::with_owned_value(entry.key_data());
-        let (page, _, value_range) = entry.into_raw();
-        let collection = AccessGuard::with_page(page, value_range);
-        // TODO: propagate error
-        let iter = DynamicCollection::iter(collection, self.mem).unwrap();
-
-        Some((key, iter))
+        match self.inner.next_back()? {
+            Ok(entry) => {
+                let key = AccessGuard::with_owned_value(entry.key_data());
+                let (page, _, value_range) = entry.into_raw();
+                let collection = AccessGuard::with_page(page, value_range);
+                Some(DynamicCollection::iter(collection, self.mem).map(|iter| (key, iter)))
+            }
+            Err(err) => Some(Err(err)),
+        }
     }
 }
 
@@ -724,7 +734,7 @@ impl<'db, 'txn, K: RedbKey + 'static, V: RedbKey + 'static> MultimapTable<'db, '
                     self.mem,
                 )?;
                 for page in all_pages {
-                    pages.push(page);
+                    pages.push(page?);
                 }
             }
             DynamicCollection::iter_free_on_drop(
@@ -779,8 +789,10 @@ impl<'db, 'txn, K: RedbKey + 'static, V: RedbKey + 'static> ReadableMultimapTabl
     /// Returns the number of key-value pairs in the table
     fn len(&self) -> Result<usize> {
         let mut count = 0;
-        for (_, mut values) in self.iter()? {
-            while values.next().is_some() {
+        for item in self.iter()? {
+            let (_, values) = item?;
+            for v in values {
+                v?;
                 count += 1;
             }
         }
@@ -838,12 +850,12 @@ impl<'txn, K: RedbKey + 'static, V: RedbKey + 'static> ReadOnlyMultimapTable<'tx
         root_page: Option<(PageNumber, Checksum)>,
         hint: PageHint,
         mem: &'txn TransactionalMemory,
-    ) -> ReadOnlyMultimapTable<'txn, K, V> {
-        ReadOnlyMultimapTable {
-            tree: Btree::new(root_page, hint, mem),
+    ) -> Result<ReadOnlyMultimapTable<'txn, K, V>> {
+        Ok(ReadOnlyMultimapTable {
+            tree: Btree::new(root_page, hint, mem)?,
             mem,
             _value_type: Default::default(),
-        }
+        })
     }
 }
 
@@ -879,8 +891,10 @@ impl<'txn, K: RedbKey + 'static, V: RedbKey + 'static> ReadableMultimapTable<K,
 
     fn len(&self) -> Result<usize> {
         let mut count = 0;
-        for (_, mut values) in self.iter()? {
-            while values.next().is_some() {
+        for item in self.iter()? {
+            let (_, values) = item?;
+            for v in values {
+                v?;
                 count += 1;
             }
         }
diff --git a/src/table.rs b/src/table.rs
index 275d707..a77e94a 100644
--- a/src/table.rs
+++ b/src/table.rs
@@ -2,7 +2,7 @@ use crate::tree_store::{
     AccessGuardMut, Btree, BtreeDrain, BtreeDrainFilter, BtreeMut, BtreeRangeIter, Checksum,
     PageHint, PageNumber, TransactionalMemory,
 };
-use crate::types::{RedbKey, RedbValue};
+use crate::types::{RedbKey, RedbValue, RedbValueMutInPlace};
 use crate::Result;
 use crate::{AccessGuard, WriteTransaction};
 use std::borrow::Borrow;
@@ -39,10 +39,12 @@ impl<'db, 'txn, K: RedbKey + 'static, V: RedbValue + 'static> Table<'db, 'txn, K
     /// Removes and returns the first key-value pair in the table
     pub fn pop_first(&mut self) -> Result<Option<(AccessGuard<K>, AccessGuard<V>)>> {
         // TODO: optimize this
-        let first = self.iter()?.next();
-        if let Some((ref key, _)) = first {
-            let owned_key = K::as_bytes(key.value().borrow()).as_ref().to_vec();
-            drop(first);
+        let first = self
+            .iter()?
+            .next()
+            .map(|x| x.map(|(key, _)| K::as_bytes(key.value().borrow()).as_ref().to_vec()));
+        if let Some(owned_key) = first {
+            let owned_key = owned_key?;
             let key = K::from_bytes(&owned_key);
             let value = self.remove(&key)?.unwrap();
             drop(key);
@@ -55,10 +57,13 @@ impl<'db, 'txn, K: RedbKey + 'static, V: RedbValue + 'static> Table<'db, 'txn, K
     /// Removes and returns the last key-value pair in the table
     pub fn pop_last(&mut self) -> Result<Option<(AccessGuard<K>, AccessGuard<V>)>> {
         // TODO: optimize this
-        let first = self.iter()?.rev().next();
-        if let Some((ref key, _)) = first {
-            let owned_key = K::as_bytes(key.value().borrow()).as_ref().to_vec();
-            drop(first);
+        let last = self
+            .iter()?
+            .rev()
+            .next()
+            .map(|x| x.map(|(key, _)| K::as_bytes(key.value().borrow()).as_ref().to_vec()));
+        if let Some(owned_key) = last {
+            let owned_key = owned_key?;
             let key = K::from_bytes(&owned_key);
             let value = self.remove(&key)?.unwrap();
             drop(key);
@@ -113,31 +118,32 @@ impl<'db, 'txn, K: RedbKey + 'static, V: RedbValue + 'static> Table<'db, 'txn, K
         self.tree.insert(key.borrow(), value.borrow())
     }
 
-    /// Reserve space to insert a key-value pair
-    /// The returned reference will have length equal to value_length
-    // TODO: return type should be V, not [u8]
-    pub fn insert_reserve<'a>(
+    /// Removes the given key
+    ///
+    /// Returns the old value, if the key was present in the table
+    pub fn remove<'a>(
         &mut self,
         key: impl Borrow<K::SelfType<'a>>,
-        value_length: usize,
-    ) -> Result<AccessGuardMut<K, &[u8]>>
+    ) -> Result<Option<AccessGuard<V>>>
     where
         K: 'a,
     {
-        self.tree.insert_reserve(key.borrow(), value_length)
+        self.tree.remove(key.borrow())
     }
+}
 
-    /// Removes the given key
-    ///
-    /// Returns the old value, if the key was present in the table
-    pub fn remove<'a>(
+impl<'db, 'txn, K: RedbKey + 'static, V: RedbValueMutInPlace + 'static> Table<'db, 'txn, K, V> {
+    /// Reserve space to insert a key-value pair
+    /// The returned reference will have length equal to value_length
+    pub fn insert_reserve<'a>(
         &mut self,
         key: impl Borrow<K::SelfType<'a>>,
-    ) -> Result<Option<AccessGuard<V>>>
+        value_length: usize,
+    ) -> Result<AccessGuardMut<K, V>>
     where
         K: 'a,
     {
-        self.tree.remove(key.borrow())
+        self.tree.insert_reserve(key.borrow(), value_length)
     }
 }
 
@@ -206,7 +212,7 @@ pub trait ReadableTable<K: RedbKey + 'static, V: RedbValue + 'static> {
     /// let read_txn = db.begin_read()?;
     /// let table = read_txn.open_table(TABLE)?;
     /// let mut iter = table.range("a".."c")?;
-    /// let (key, value) = iter.next().unwrap();
+    /// let (key, value) = iter.next().unwrap()?;
     /// assert_eq!("a", key.value());
     /// assert_eq!(0, value.value());
     /// # Ok(())
@@ -239,10 +245,10 @@ impl<'txn, K: RedbKey + 'static, V: RedbValue + 'static> ReadOnlyTable<'txn, K,
         root_page: Option<(PageNumber, Checksum)>,
         hint: PageHint,
         mem: &'txn TransactionalMemory,
-    ) -> ReadOnlyTable<'txn, K, V> {
-        ReadOnlyTable {
-            tree: Btree::new(root_page, hint, mem),
-        }
+    ) -> Result<ReadOnlyTable<'txn, K, V>> {
+        Ok(ReadOnlyTable {
+            tree: Btree::new(root_page, hint, mem)?,
+        })
     }
 }
 
@@ -284,25 +290,28 @@ impl<'a, K: RedbKey + 'static, V: RedbValue + 'static> Drain<'a, K, V> {
 }
 
 impl<'a, K: RedbKey + 'static, V: RedbValue + 'static> Iterator for Drain<'a, K, V> {
-    // TODO: probably needs to be a Result
-    type Item = (AccessGuard<'a, K>, AccessGuard<'a, V>);
+    type Item = Result<(AccessGuard<'a, K>, AccessGuard<'a, V>)>;
 
     fn next(&mut self) -> Option<Self::Item> {
         let entry = self.inner.next()?;
-        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))
+        Some(entry.map(|entry| {
+            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);
+            (key, value)
+        }))
     }
 }
 
 impl<'a, K: RedbKey + 'static, V: RedbValue + 'static> DoubleEndedIterator for Drain<'a, K, V> {
     fn next_back(&mut self) -> Option<Self::Item> {
         let entry = self.inner.next_back()?;
-        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))
+        Some(entry.map(|entry| {
+            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);
+            (key, value)
+        }))
     }
 }
 
@@ -334,15 +343,16 @@ impl<
         F: for<'f> FnMut(K::SelfType<'f>, V::SelfType<'f>) -> bool,
     > Iterator for DrainFilter<'a, K, V, F>
 {
-    // TODO: probably needs to be a Result
-    type Item = (AccessGuard<'a, K>, AccessGuard<'a, V>);
+    type Item = Result<(AccessGuard<'a, K>, AccessGuard<'a, V>)>;
 
     fn next(&mut self) -> Option<Self::Item> {
         let entry = self.inner.next()?;
-        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))
+        Some(entry.map(|entry| {
+            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);
+            (key, value)
+        }))
     }
 }
 
@@ -355,10 +365,12 @@ impl<
 {
     fn next_back(&mut self) -> Option<Self::Item> {
         let entry = self.inner.next_back()?;
-        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))
+        Some(entry.map(|entry| {
+            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);
+            (key, value)
+        }))
     }
 }
 
@@ -373,30 +385,29 @@ impl<'a, K: RedbKey + 'static, V: RedbValue + 'static> Range<'a, K, V> {
 }
 
 impl<'a, K: RedbKey + 'static, V: RedbValue + 'static> Iterator for Range<'a, K, V> {
-    // TODO: this probably needs to return a Result
-    type Item = (AccessGuard<'a, K>, AccessGuard<'a, V>);
+    type Item = Result<(AccessGuard<'a, K>, AccessGuard<'a, V>)>;
 
     fn next(&mut self) -> Option<Self::Item> {
-        if let Some(entry) = self.inner.next() {
-            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
-        }
+        self.inner.next().map(|x| {
+            x.map(|entry| {
+                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);
+                (key, value)
+            })
+        })
     }
 }
 
 impl<'a, K: RedbKey + 'static, V: RedbValue + 'static> DoubleEndedIterator for Range<'a, K, V> {
     fn next_back(&mut self) -> Option<Self::Item> {
-        if let Some(entry) = self.inner.next_back() {
-            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
-        }
+        self.inner.next_back().map(|x| {
+            x.map(|entry| {
+                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);
+                (key, value)
+            })
+        })
     }
 }
diff --git a/src/transactions.rs b/src/transactions.rs
index 8024d47..06a4b4f 100644
--- a/src/transactions.rs
+++ b/src/transactions.rs
@@ -1,7 +1,7 @@
 use crate::transaction_tracker::{TransactionId, TransactionTracker};
 use crate::tree_store::{
-    Btree, BtreeMut, FreedTableKey, InternalTableDefinition, PageHint, PageNumber, TableTree,
-    TableType, TransactionalMemory,
+    Btree, BtreeMut, FreedPageList, FreedTableKey, InternalTableDefinition, PageHint, PageNumber,
+    TableTree, TableType, TransactionalMemory,
 };
 use crate::types::{RedbKey, RedbValue};
 use crate::{
@@ -13,7 +13,6 @@ use crate::{
 use log::{info, warn};
 use std::cmp::min;
 use std::collections::HashMap;
-use std::mem::size_of;
 use std::ops::RangeFull;
 use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::{Arc, Mutex, MutexGuard, RwLock};
@@ -100,10 +99,9 @@ pub struct WriteTransaction<'db> {
     mem: &'db TransactionalMemory,
     transaction_id: TransactionId,
     table_tree: RwLock<TableTree<'db>>,
-    // TODO: change the value type to Vec<PageNumber>
     // The table of freed pages by transaction. FreedTableKey -> binary.
     // The binary blob is a length-prefixed array of PageNumber
-    freed_tree: Mutex<BtreeMut<'db, FreedTableKey, &'static [u8]>>,
+    freed_tree: Mutex<BtreeMut<'db, FreedTableKey, FreedPageList<'static>>>,
     freed_pages: Arc<Mutex<Vec<PageNumber>>>,
     open_tables: Mutex<HashMap<String, &'static panic::Location<'static>>>,
     completed: bool,
@@ -113,7 +111,10 @@ pub struct WriteTransaction<'db> {
 }
 
 impl<'db> WriteTransaction<'db> {
-    pub(crate) fn new(db: &'db Database) -> Result<Self> {
+    pub(crate) fn new(
+        db: &'db Database,
+        transaction_tracker: Arc<Mutex<TransactionTracker>>,
+    ) -> Result<Self> {
         let mut live_write_transaction = db.live_write_transaction.lock().unwrap();
         assert!(live_write_transaction.is_none());
         let transaction_id = db.increment_transaction_id();
@@ -126,7 +127,7 @@ impl<'db> WriteTransaction<'db> {
         let freed_pages = Arc::new(Mutex::new(vec![]));
         Ok(Self {
             db,
-            transaction_tracker: db.transaction_tracker(),
+            transaction_tracker,
             mem: db.get_memory(),
             transaction_id,
             table_tree: RwLock::new(TableTree::new(
@@ -167,7 +168,8 @@ impl<'db> WriteTransaction<'db> {
         let root = self.mem.get_data_root();
         let freed_root = self.mem.get_freed_root();
         let savepoint = Savepoint::new(
-            self.db,
+            self.db.get_memory(),
+            self.transaction_tracker.clone(),
             id,
             transaction_id,
             root,
@@ -184,7 +186,7 @@ impl<'db> WriteTransaction<'db> {
     pub fn restore_savepoint(&mut self, savepoint: &Savepoint) -> Result {
         // Ensure that user does not try to restore a Savepoint that is from a different Database
         assert_eq!(
-            self.db.transaction_tracker().as_ref() as *const _,
+            self.transaction_tracker.as_ref() as *const _,
             savepoint.db_address()
         );
 
@@ -239,7 +241,7 @@ impl<'db> WriteTransaction<'db> {
             .range::<RangeFull, FreedTableKey>(..)?
             .next()
         {
-            entry.key().transaction_id
+            entry?.key().transaction_id
         } else {
             self.transaction_id.0
         };
@@ -255,7 +257,7 @@ impl<'db> WriteTransaction<'db> {
         };
         let mut to_remove = vec![];
         for entry in freed_tree.range(..lookup_key)? {
-            to_remove.push(entry.key());
+            to_remove.push(entry?.key());
         }
         for key in to_remove {
             freed_tree.remove(&key)?;
@@ -517,15 +519,11 @@ impl<'db> WriteTransaction<'db> {
         let mut to_remove = vec![];
         let mut freed_tree = self.freed_tree.lock().unwrap();
         for entry in freed_tree.range(..lookup_key)? {
+            let entry = entry?;
             to_remove.push(entry.key());
             let value = entry.value();
-            let length: usize = u64::from_le_bytes(value[..size_of::<u64>()].try_into().unwrap())
-                .try_into()
-                .unwrap();
-            // 1..=length because the array is length prefixed
-            for i in 1..=length {
-                let page = PageNumber::from_le_bytes(value[i * 8..(i + 1) * 8].try_into().unwrap());
-                self.mem.free(page);
+            for i in 0..value.len() {
+                self.mem.free(value.get(i));
             }
         }
 
@@ -544,7 +542,7 @@ impl<'db> WriteTransaction<'db> {
         let mut freed_tree = self.freed_tree.lock().unwrap();
         while !self.freed_pages.lock().unwrap().is_empty() {
             let chunk_size = 100;
-            let buffer_size = size_of::<u64>() + 8 * chunk_size;
+            let buffer_size = FreedPageList::required_bytes(chunk_size);
             let key = FreedTableKey {
                 transaction_id: self.transaction_id.0,
                 pagination_id: pagination_counter,
@@ -553,11 +551,9 @@ impl<'db> WriteTransaction<'db> {
 
             let mut freed_pages = self.freed_pages.lock().unwrap();
             let len = freed_pages.len();
-            access_guard.as_mut()[..8]
-                .copy_from_slice(&min(len as u64, chunk_size as u64).to_le_bytes());
-            for (i, page) in freed_pages.drain(len - min(len, chunk_size)..).enumerate() {
-                access_guard.as_mut()[(i + 1) * 8..(i + 2) * 8]
-                    .copy_from_slice(&page.to_le_bytes());
+            access_guard.as_mut().clear();
+            for page in freed_pages.drain(len - min(len, chunk_size)..) {
+                access_guard.as_mut().push_back(page);
             }
             drop(access_guard);
 
@@ -602,7 +598,7 @@ impl<'db> WriteTransaction<'db> {
         {
             eprintln!("Master tree:");
             let master_tree: Btree<&str, InternalTableDefinition> =
-                Btree::new(Some(page), PageHint::None, self.mem);
+                Btree::new(Some(page), PageHint::None, self.mem)?;
             master_tree.print_debug(true)?;
         }
 
@@ -627,17 +623,23 @@ impl<'a> Drop for WriteTransaction<'a> {
 ///
 /// Read-only transactions may exist concurrently with writes
 pub struct ReadTransaction<'a> {
-    db: &'a Database,
+    transaction_tracker: Arc<Mutex<TransactionTracker>>,
+    mem: &'a TransactionalMemory,
     tree: TableTree<'a>,
     transaction_id: TransactionId,
 }
 
 impl<'db> ReadTransaction<'db> {
-    pub(crate) fn new(db: &'db Database, transaction_id: TransactionId) -> Self {
-        let root_page = db.get_memory().get_data_root();
+    pub(crate) fn new(
+        mem: &'db TransactionalMemory,
+        transaction_tracker: Arc<Mutex<TransactionTracker>>,
+        transaction_id: TransactionId,
+    ) -> Self {
+        let root_page = mem.get_data_root();
         Self {
-            db,
-            tree: TableTree::new(root_page, db.get_memory(), Default::default()),
+            transaction_tracker,
+            mem,
+            tree: TableTree::new(root_page, mem, Default::default()),
             transaction_id,
         }
     }
@@ -652,11 +654,7 @@ impl<'db> ReadTransaction<'db> {
             .get_table::<K, V>(definition.name(), TableType::Normal)?
             .ok_or_else(|| Error::TableDoesNotExist(definition.name().to_string()))?;
 
-        Ok(ReadOnlyTable::new(
-            header.get_root(),
-            PageHint::Clean,
-            self.db.get_memory(),
-        ))
+        ReadOnlyTable::new(header.get_root(), PageHint::Clean, self.mem)
     }
 
     /// Open the given table
@@ -669,11 +667,7 @@ impl<'db> ReadTransaction<'db> {
             .get_table::<K, V>(definition.name(), TableType::Multimap)?
             .ok_or_else(|| Error::TableDoesNotExist(definition.name().to_string()))?;
 
-        Ok(ReadOnlyMultimapTable::new(
-            header.get_root(),
-            PageHint::Clean,
-            self.db.get_memory(),
-        ))
+        ReadOnlyMultimapTable::new(header.get_root(), PageHint::Clean, self.mem)
     }
 
     /// List all the tables
@@ -693,8 +687,7 @@ impl<'db> ReadTransaction<'db> {
 
 impl<'a> Drop for ReadTransaction<'a> {
     fn drop(&mut self) {
-        self.db
-            .transaction_tracker()
+        self.transaction_tracker
             .lock()
             .unwrap()
             .deallocate_read_transaction(self.transaction_id);
diff --git a/src/tree_store/btree.rs b/src/tree_store/btree.rs
index 411a3b5..2621b6f 100644
--- a/src/tree_store/btree.rs
+++ b/src/tree_store/btree.rs
@@ -6,7 +6,7 @@ use crate::tree_store::btree_iters::BtreeDrain;
 use crate::tree_store::btree_mutator::MutateHelper;
 use crate::tree_store::page_store::{Page, PageImpl, TransactionalMemory};
 use crate::tree_store::{AccessGuardMut, BtreeDrainFilter, BtreeRangeIter, PageHint, PageNumber};
-use crate::types::{RedbKey, RedbValue};
+use crate::types::{RedbKey, RedbValue, RedbValueMutInPlace};
 use crate::{AccessGuard, Result};
 #[cfg(feature = "logging")]
 use log::trace;
@@ -76,35 +76,6 @@ impl<'a, K: RedbKey + 'a, V: RedbValue + 'a> BtreeMut<'a, K, V> {
         Ok(old_value)
     }
 
-    /// Reserve space to insert a key-value pair
-    /// The returned reference will have length equal to value_length
-    // TODO: return type should be V, not [u8]
-    pub(crate) fn insert_reserve(
-        &mut self,
-        key: &K::SelfType<'_>,
-        value_length: usize,
-    ) -> Result<AccessGuardMut<'a, K, &[u8]>> {
-        #[cfg(feature = "logging")]
-        trace!(
-            "Btree(root={:?}): Inserting {:?} with {} reserved bytes for the value",
-            &self.root,
-            key,
-            value_length
-        );
-        let mut root = self.root.lock().unwrap();
-        let mut freed_pages = self.freed_pages.lock().unwrap();
-        let value = vec![0u8; value_length];
-        let mut operation = MutateHelper::<K, &[u8]>::new(
-            &mut root,
-            FreePolicy::Uncommitted,
-            self.mem,
-            freed_pages.as_mut(),
-        );
-        let (_, mut guard) = operation.insert(key, &value.as_slice())?;
-        guard.set_root_for_drop(self.root.clone());
-        Ok(guard)
-    }
-
     pub(crate) fn remove(&mut self, key: &K::SelfType<'_>) -> Result<Option<AccessGuard<V>>> {
         #[cfg(feature = "logging")]
         trace!("Btree(root={:?}): Deleting {:?}", &self.root, key);
@@ -135,7 +106,7 @@ impl<'a, K: RedbKey + 'a, V: RedbValue + 'a> BtreeMut<'a, K, V> {
 
     #[allow(dead_code)]
     pub(crate) fn print_debug(&self, include_values: bool) -> Result {
-        self.read_tree().print_debug(include_values)
+        self.read_tree()?.print_debug(include_values)
     }
 
     pub(crate) fn stats(&self) -> Result<BtreeStats> {
@@ -147,12 +118,12 @@ impl<'a, K: RedbKey + 'a, V: RedbValue + 'a> BtreeMut<'a, K, V> {
         )
     }
 
-    fn read_tree(&self) -> Btree<'a, K, V> {
+    fn read_tree(&self) -> Result<Btree<'a, K, V>> {
         Btree::new(self.get_root(), PageHint::None, self.mem)
     }
 
     pub(crate) fn get(&self, key: &K::SelfType<'_>) -> Result<Option<AccessGuard<'_, V>>> {
-        self.read_tree().get(key)
+        self.read_tree()?.get(key)
     }
 
     pub(crate) fn range<'a0, T: RangeBounds<KR> + 'a0, KR: Borrow<K::SelfType<'a0>> + 'a0>(
@@ -162,7 +133,7 @@ impl<'a, K: RedbKey + 'a, V: RedbValue + 'a> BtreeMut<'a, K, V> {
     where
         'a: 'a0,
     {
-        self.read_tree().range(range)
+        self.read_tree()?.range(range)
     }
 
     pub(crate) fn drain<
@@ -185,7 +156,7 @@ impl<'a, K: RedbKey + 'a, V: RedbValue + 'a> BtreeMut<'a, K, V> {
             MutateHelper::new(&mut root, FreePolicy::Never, self.mem, &mut free_on_drop);
         for entry in iter {
             // TODO: optimize so that we don't have to call safe_delete in a loop
-            assert!(operation.safe_delete(entry.key().borrow())?.is_some());
+            assert!(operation.safe_delete(entry?.key().borrow())?.is_some());
         }
 
         let result = BtreeDrain::new(
@@ -220,6 +191,7 @@ impl<'a, K: RedbKey + 'a, V: RedbValue + 'a> BtreeMut<'a, K, V> {
             MutateHelper::new(&mut root, FreePolicy::Never, self.mem, &mut free_on_drop);
         for entry in iter {
             // TODO: optimize so that we don't have to call safe_delete in a loop
+            let entry = entry?;
             if predicate(entry.key(), entry.value()) {
                 assert!(operation.safe_delete(entry.key().borrow())?.is_some());
             }
@@ -237,7 +209,38 @@ impl<'a, K: RedbKey + 'a, V: RedbValue + 'a> BtreeMut<'a, K, V> {
     }
 
     pub(crate) fn len(&self) -> Result<usize> {
-        self.read_tree().len()
+        self.read_tree()?.len()
+    }
+}
+
+impl<'a, K: RedbKey + 'a, V: RedbValueMutInPlace + 'a> BtreeMut<'a, K, V> {
+    /// Reserve space to insert a key-value pair
+    /// The returned reference will have length equal to value_length
+    pub(crate) fn insert_reserve(
+        &mut self,
+        key: &K::SelfType<'_>,
+        value_length: usize,
+    ) -> Result<AccessGuardMut<'a, K, V>> {
+        #[cfg(feature = "logging")]
+        trace!(
+            "Btree(root={:?}): Inserting {:?} with {} reserved bytes for the value",
+            &self.root,
+            key,
+            value_length
+        );
+        let mut root = self.root.lock().unwrap();
+        let mut freed_pages = self.freed_pages.lock().unwrap();
+        let mut value = vec![0u8; value_length];
+        V::initialize(&mut value);
+        let mut operation = MutateHelper::<K, V>::new(
+            &mut root,
+            FreePolicy::Uncommitted,
+            self.mem,
+            freed_pages.as_mut(),
+        );
+        let (_, mut guard) = operation.insert(key, &V::from_bytes(&value))?;
+        guard.set_root_for_drop(self.root.clone());
+        Ok(guard)
     }
 }
 
@@ -325,19 +328,20 @@ impl<'a, K: RedbKey, V: RedbValue> Btree<'a, K, V> {
         root: Option<(PageNumber, Checksum)>,
         hint: PageHint,
         mem: &'a TransactionalMemory,
-    ) -> Self {
-        let cached_root = root.map(|(root, _)| {
-            // TODO: propagate error
-            mem.get_page_extended(root, hint).unwrap()
-        });
-        Self {
+    ) -> Result<Self> {
+        let cached_root = if let Some((r, _)) = root {
+            Some(mem.get_page_extended(r, hint)?)
+        } else {
+            None
+        };
+        Ok(Self {
             mem,
             cached_root,
             root,
             hint,
             _key_type: Default::default(),
             _value_type: Default::default(),
-        }
+        })
     }
 
     pub(crate) fn get(&self, key: &K::SelfType<'_>) -> Result<Option<AccessGuard<'a, V>>> {
@@ -383,13 +387,14 @@ impl<'a, K: RedbKey, V: RedbValue> Btree<'a, K, V> {
     }
 
     pub(crate) fn len(&self) -> Result<usize> {
-        let mut iter: BtreeRangeIter<K, V> = BtreeRangeIter::new::<RangeFull, K::SelfType<'_>>(
+        let iter: BtreeRangeIter<K, V> = BtreeRangeIter::new::<RangeFull, K::SelfType<'_>>(
             ..,
             self.root.map(|(p, _)| p),
             self.mem,
         )?;
         let mut count = 0;
-        while iter.next().is_some() {
+        for v in iter {
+            v?;
             count += 1;
         }
         Ok(count)
diff --git a/src/tree_store/btree_base.rs b/src/tree_store/btree_base.rs
index bc076f5..a55db5b 100644
--- a/src/tree_store/btree_base.rs
+++ b/src/tree_store/btree_base.rs
@@ -1,6 +1,6 @@
 use crate::tree_store::page_store::{ChecksumType, Page, PageImpl, PageMut, TransactionalMemory};
 use crate::tree_store::{page_store, PageNumber};
-use crate::types::{RedbKey, RedbValue};
+use crate::types::{RedbKey, RedbValue, RedbValueMutInPlace};
 use crate::Result;
 use std::cmp::Ordering;
 use std::marker::PhantomData;
@@ -289,10 +289,9 @@ impl<'a, K: RedbKey, V: RedbValue> AccessGuardMut<'a, K, V> {
     }
 }
 
-// TODO: this should return a RedbValue typed reference
-impl<'a, K: RedbKey, V: RedbValue> AsMut<[u8]> for AccessGuardMut<'a, K, V> {
-    fn as_mut(&mut self) -> &mut [u8] {
-        &mut self.page.memory_mut()[self.offset..(self.offset + self.len)]
+impl<'a, K: RedbKey, V: RedbValueMutInPlace> AsMut<V::BaseRefType> for AccessGuardMut<'a, K, V> {
+    fn as_mut(&mut self) -> &mut V::BaseRefType {
+        V::from_bytes_mut(&mut self.page.memory_mut()[self.offset..(self.offset + self.len)])
     }
 }
 
diff --git a/src/tree_store/btree_iters.rs b/src/tree_store/btree_iters.rs
index 3e87ce0..246e7df 100644
--- a/src/tree_store/btree_iters.rs
+++ b/src/tree_store/btree_iters.rs
@@ -221,7 +221,7 @@ impl<'a> AllPageNumbersBtreeIter<'a> {
 }
 
 impl<'a> Iterator for AllPageNumbersBtreeIter<'a> {
-    type Item = PageNumber;
+    type Item = Result<PageNumber>;
 
     fn next(&mut self) -> Option<Self::Item> {
         loop {
@@ -232,10 +232,16 @@ impl<'a> Iterator for AllPageNumbersBtreeIter<'a> {
                 Leaf { entry, .. } => entry == 0,
                 Internal { child, .. } => child == 0,
             };
-            // TODO: propagate this error
-            self.next = state.next(false, self.manager).unwrap();
+            match state.next(false, self.manager) {
+                Ok(next) => {
+                    self.next = next;
+                }
+                Err(err) => {
+                    return Some(Err(err));
+                }
+            }
             if once {
-                return Some(value);
+                return Some(Ok(value));
             }
         }
     }
@@ -265,7 +271,7 @@ impl<'a, K: RedbKey + 'a, V: RedbValue + 'a> BtreeDrain<'a, K, V> {
 }
 
 impl<'a, K: RedbKey + 'a, V: RedbValue + 'a> Iterator for BtreeDrain<'a, K, V> {
-    type Item = EntryGuard<'a, K, V>;
+    type Item = Result<EntryGuard<'a, K, V>>;
 
     fn next(&mut self) -> Option<Self::Item> {
         self.inner.next()
@@ -339,11 +345,11 @@ impl<
         F: for<'f> FnMut(K::SelfType<'f>, V::SelfType<'f>) -> bool,
     > Iterator for BtreeDrainFilter<'a, K, V, F>
 {
-    type Item = EntryGuard<'a, K, V>;
+    type Item = Result<EntryGuard<'a, K, V>>;
 
     fn next(&mut self) -> Option<Self::Item> {
         let mut item = self.inner.next();
-        while let Some(ref entry) = item {
+        while let Some(Ok(ref entry)) = item {
             if (self.predicate)(entry.key(), entry.value()) {
                 break;
             }
@@ -362,7 +368,7 @@ impl<
 {
     fn next_back(&mut self) -> Option<Self::Item> {
         let mut item = self.inner.next_back();
-        while let Some(ref entry) = item {
+        while let Some(Ok(ref entry)) = item {
             if (self.predicate)(entry.key(), entry.value()) {
                 break;
             }
@@ -481,7 +487,7 @@ impl<'a, K: RedbKey + 'a, V: RedbValue + 'a> BtreeRangeIter<'a, K, V> {
 }
 
 impl<'a, K: RedbKey + 'a, V: RedbValue + 'a> Iterator for BtreeRangeIter<'a, K, V> {
-    type Item = EntryGuard<'a, K, V>;
+    type Item = Result<EntryGuard<'a, K, V>>;
 
     fn next(&mut self) -> Option<Self::Item> {
         if let (
@@ -507,8 +513,14 @@ impl<'a, K: RedbKey + 'a, V: RedbValue + 'a> Iterator for BtreeRangeIter<'a, K,
 
         loop {
             if !self.include_left {
-                // TODO: propagate this error
-                self.left = self.left.take()?.next(false, self.manager).unwrap();
+                match self.left.take()?.next(false, self.manager) {
+                    Ok(left) => {
+                        self.left = left;
+                    }
+                    Err(err) => {
+                        return Some(Err(err));
+                    }
+                }
             }
             // Return None if the next state is None
             self.left.as_ref()?;
@@ -536,7 +548,7 @@ impl<'a, K: RedbKey + 'a, V: RedbValue + 'a> Iterator for BtreeRangeIter<'a, K,
 
             self.include_left = false;
             if self.left.as_ref().unwrap().get_entry::<K, V>().is_some() {
-                return self.left.as_ref().map(|s| s.get_entry().unwrap());
+                return self.left.as_ref().map(|s| s.get_entry().unwrap()).map(Ok);
             }
         }
     }
@@ -567,8 +579,14 @@ impl<'a, K: RedbKey + 'a, V: RedbValue + 'a> DoubleEndedIterator for BtreeRangeI
 
         loop {
             if !self.include_right {
-                // TODO: propagate this error
-                self.right = self.right.take()?.next(true, self.manager).unwrap();
+                match self.right.take()?.next(true, self.manager) {
+                    Ok(right) => {
+                        self.right = right;
+                    }
+                    Err(err) => {
+                        return Some(Err(err));
+                    }
+                }
             }
             // Return None if the next state is None
             self.right.as_ref()?;
@@ -596,7 +614,7 @@ impl<'a, K: RedbKey + 'a, V: RedbValue + 'a> DoubleEndedIterator for BtreeRangeI
 
             self.include_right = false;
             if self.right.as_ref().unwrap().get_entry::<K, V>().is_some() {
-                return self.right.as_ref().map(|s| s.get_entry().unwrap());
+                return self.right.as_ref().map(|s| s.get_entry().unwrap()).map(Ok);
             }
         }
     }
diff --git a/src/tree_store/mod.rs b/src/tree_store/mod.rs
index 8eb3d80..680adbb 100644
--- a/src/tree_store/mod.rs
+++ b/src/tree_store/mod.rs
@@ -16,4 +16,6 @@ pub use page_store::Savepoint;
 pub(crate) use page_store::{
     Page, PageHint, PageNumber, TransactionalMemory, FILE_FORMAT_VERSION, PAGE_SIZE,
 };
-pub(crate) use table_tree::{FreedTableKey, InternalTableDefinition, TableTree, TableType};
+pub(crate) use table_tree::{
+    FreedPageList, FreedTableKey, InternalTableDefinition, TableTree, TableType,
+};
diff --git a/src/tree_store/page_store/header.rs b/src/tree_store/page_store/header.rs
index 6313149..700732b 100644
--- a/src/tree_store/page_store/header.rs
+++ b/src/tree_store/page_store/header.rs
@@ -579,9 +579,11 @@ mod test {
             .create(tmpfile.path())
             .unwrap();
 
+        let def: TableDefinition<&str, &[u8]> = TableDefinition::new("x");
+
         let write_txn = db.begin_write().unwrap();
         {
-            let mut table = write_txn.open_table(X).unwrap();
+            let mut table = write_txn.open_table(def).unwrap();
             let mut value = table.insert_reserve("hello", 5).unwrap();
             value.as_mut().copy_from_slice(b"world");
         }
@@ -589,7 +591,7 @@ mod test {
 
         let write_txn = db.begin_write().unwrap();
         {
-            let mut table = write_txn.open_table(X).unwrap();
+            let mut table = write_txn.open_table(def).unwrap();
             let mut value = table.insert_reserve("hello2", 5).unwrap();
             value.as_mut().copy_from_slice(b"world");
         }
diff --git a/src/tree_store/page_store/page_manager.rs b/src/tree_store/page_store/page_manager.rs
index 75ee825..edfa3be 100644
--- a/src/tree_store/page_store/page_manager.rs
+++ b/src/tree_store/page_store/page_manager.rs
@@ -35,7 +35,7 @@ const MIN_DESIRED_USABLE_BYTES: usize = 1024 * 1024;
 const NUM_REGIONS: u32 = 1000;
 
 // TODO: set to 1, when version 1.0 is released
-pub(crate) const FILE_FORMAT_VERSION: u8 = 109;
+pub(crate) const FILE_FORMAT_VERSION: u8 = 110;
 
 fn ceil_log2(x: usize) -> usize {
     if x.is_power_of_two() {
@@ -672,11 +672,12 @@ impl TransactionalMemory {
 
     pub(crate) fn mark_pages_allocated(
         &self,
-        allocated_pages: impl Iterator<Item = PageNumber>,
+        allocated_pages: impl Iterator<Item = Result<PageNumber>>,
     ) -> Result<()> {
         let mut state = self.state.lock().unwrap();
 
         for page_number in allocated_pages {
+            let page_number = page_number?;
             let region_index = page_number.region;
             let mut region = state.get_region_mut(region_index);
             region.allocator_mut().record_alloc(
diff --git a/src/tree_store/page_store/savepoint.rs b/src/tree_store/page_store/savepoint.rs
index 57c6381..e2c0e4c 100644
--- a/src/tree_store/page_store/savepoint.rs
+++ b/src/tree_store/page_store/savepoint.rs
@@ -1,7 +1,6 @@
 use crate::transaction_tracker::{SavepointId, TransactionId, TransactionTracker};
 use crate::tree_store::page_store::ChecksumType;
-use crate::tree_store::{Checksum, PageNumber};
-use crate::Database;
+use crate::tree_store::{Checksum, PageNumber, TransactionalMemory};
 use std::sync::{Arc, Mutex};
 
 pub struct Savepoint {
@@ -19,7 +18,8 @@ pub struct Savepoint {
 
 impl Savepoint {
     pub(crate) fn new(
-        db: &Database,
+        mem: &TransactionalMemory,
+        transaction_tracker: Arc<Mutex<TransactionTracker>>,
         id: SavepointId,
         transaction_id: TransactionId,
         root: Option<(PageNumber, Checksum)>,
@@ -29,12 +29,12 @@ impl Savepoint {
         Self {
             id,
             transaction_id,
-            version: db.get_memory().get_version(),
-            checksum_type: db.get_memory().checksum_type(),
+            version: mem.get_version(),
+            checksum_type: mem.checksum_type(),
             root,
             freed_root,
             regional_allocators,
-            transaction_tracker: db.transaction_tracker(),
+            transaction_tracker,
         }
     }
 
diff --git a/src/tree_store/table_tree.rs b/src/tree_store/table_tree.rs
index c778d26..2f7de31 100644
--- a/src/tree_store/table_tree.rs
+++ b/src/tree_store/table_tree.rs
@@ -2,10 +2,11 @@ use crate::tree_store::btree::btree_stats;
 use crate::tree_store::btree_base::Checksum;
 use crate::tree_store::btree_iters::AllPageNumbersBtreeIter;
 use crate::tree_store::{BtreeMut, BtreeRangeIter, PageNumber, TransactionalMemory};
-use crate::types::{RedbKey, RedbValue, TypeName};
+use crate::types::{RedbKey, RedbValue, RedbValueMutInPlace, TypeName};
 use crate::{DatabaseStats, Error, Result};
 use std::cmp::max;
 use std::collections::HashMap;
+use std::mem;
 use std::mem::size_of;
 use std::ops::RangeFull;
 use std::sync::{Arc, Mutex};
@@ -73,6 +74,100 @@ impl RedbKey for FreedTableKey {
     }
 }
 
+// Format:
+// 2 bytes: length
+// length * size_of(PageNumber): array of page numbers
+#[derive(Debug)]
+pub(crate) struct FreedPageList<'a> {
+    data: &'a [u8],
+}
+
+impl<'a> FreedPageList<'a> {
+    pub(crate) fn required_bytes(len: usize) -> usize {
+        2 + PageNumber::serialized_size() * len
+    }
+
+    pub(crate) fn len(&self) -> usize {
+        u16::from_le_bytes(self.data[..size_of::<u16>()].try_into().unwrap()).into()
+    }
+
+    pub(crate) fn get(&self, index: usize) -> PageNumber {
+        let start = size_of::<u16>() + PageNumber::serialized_size() * index;
+        PageNumber::from_le_bytes(
+            self.data[start..(start + PageNumber::serialized_size())]
+                .try_into()
+                .unwrap(),
+        )
+    }
+}
+
+#[derive(Debug)]
+#[repr(transparent)]
+pub(crate) struct FreedPageListMut {
+    data: [u8],
+}
+
+impl FreedPageListMut {
+    pub(crate) fn push_back(&mut self, value: PageNumber) {
+        let len = u16::from_le_bytes(self.data[..size_of::<u16>()].try_into().unwrap());
+        self.data[..size_of::<u16>()].copy_from_slice(&(len + 1).to_le_bytes());
+        let len: usize = len.into();
+        let start = size_of::<u16>() + PageNumber::serialized_size() * len;
+        self.data[start..(start + PageNumber::serialized_size())]
+            .copy_from_slice(&value.to_le_bytes());
+    }
+
+    pub(crate) fn clear(&mut self) {
+        self.data[..size_of::<u16>()].fill(0);
+    }
+}
+
+impl RedbValue for FreedPageList<'_> {
+    type SelfType<'a> = FreedPageList<'a>
+        where
+            Self: 'a;
+    type AsBytes<'a> = &'a [u8]
+        where
+            Self: 'a;
+
+    fn fixed_width() -> Option<usize> {
+        None
+    }
+
+    fn from_bytes<'a>(data: &'a [u8]) -> Self::SelfType<'a>
+    where
+        Self: 'a,
+    {
+        FreedPageList { data }
+    }
+
+    fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> &'b [u8]
+    where
+        Self: 'a,
+        Self: 'b,
+    {
+        value.data
+    }
+
+    fn type_name() -> TypeName {
+        TypeName::internal("redb::FreedPageList")
+    }
+}
+
+impl RedbValueMutInPlace for FreedPageList<'_> {
+    type BaseRefType = FreedPageListMut;
+
+    fn initialize(data: &mut [u8]) {
+        assert!(data.len() >= 8);
+        // Set the length to zero
+        data[..8].fill(0);
+    }
+
+    fn from_bytes_mut(data: &mut [u8]) -> &mut Self::BaseRefType {
+        unsafe { mem::transmute(data) }
+    }
+}
+
 #[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)]
 pub(crate) enum TableType {
     Normal,
@@ -288,12 +383,19 @@ pub struct TableNameIter<'a> {
 }
 
 impl<'a> Iterator for TableNameIter<'a> {
-    type Item = String;
+    type Item = Result<String>;
 
     fn next(&mut self) -> Option<Self::Item> {
         for entry in self.inner.by_ref() {
-            if entry.value().table_type == self.table_type {
-                return Some(entry.key().to_string());
+            match entry {
+                Ok(entry) => {
+                    if entry.value().table_type == self.table_type {
+                        return Some(Ok(entry.key().to_string()));
+                    }
+                }
+                Err(err) => {
+                    return Some(Err(err));
+                }
             }
         }
         None
@@ -358,7 +460,11 @@ impl<'txn> TableTree<'txn> {
             inner: iter,
             table_type,
         };
-        Ok(iter.collect())
+        let mut result = vec![];
+        for table in iter {
+            result.push(table?);
+        }
+        Ok(result)
     }
 
     pub(crate) fn get_table_untyped(
@@ -451,7 +557,7 @@ impl<'txn> TableTree<'txn> {
                 )?;
                 let mut freed_pages = self.freed_pages.lock().unwrap();
                 for page_number in iter {
-                    freed_pages.push(page_number);
+                    freed_pages.push(page_number?);
                 }
             }
 
@@ -502,6 +608,7 @@ impl<'txn> TableTree<'txn> {
         let mut total_fragmented = master_tree_stats.fragmented_bytes;
 
         for entry in self.tree.range::<RangeFull, &str>(..)? {
+            let entry = entry?;
             let mut definition = entry.value();
             if let Some(updated_root) = self.pending_table_updates.get(entry.key()) {
                 definition.table_root = *updated_root;
diff --git a/src/types.rs b/src/types.rs
index 260f92c..b90c9fe 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -99,6 +99,31 @@ pub trait RedbValue: Debug {
     fn type_name() -> TypeName;
 }
 
+/// Implementing this trait indicates that the type can be mutated in-place as a &mut [u8].
+/// This enables the .insert_reserve() method on Table
+pub trait RedbValueMutInPlace: RedbValue {
+    /// The base type such that &mut [u8] can be safely transmuted to &mut BaseRefType
+    type BaseRefType: Debug + ?Sized;
+
+    // Initialize `data` to a valid value. This method will be called (at some point, not necessarily immediately)
+    // before from_bytes_mut() is called on a slice.
+    fn initialize(data: &mut [u8]);
+
+    fn from_bytes_mut(data: &mut [u8]) -> &mut Self::BaseRefType;
+}
+
+impl RedbValueMutInPlace for &[u8] {
+    type BaseRefType = [u8];
+
+    fn initialize(_data: &mut [u8]) {
+        // no-op. All values are valid.
+    }
+
+    fn from_bytes_mut(data: &mut [u8]) -> &mut Self::BaseRefType {
+        data
+    }
+}
+
 pub trait RedbKey: RedbValue {
     /// Compare data1 with data2
     fn compare(data1: &[u8], data2: &[u8]) -> Ordering;


Test patch:
diff --git a/tests/basic_tests.rs b/tests/basic_tests.rs
index 41655b4..28c3345 100644
--- a/tests/basic_tests.rs
+++ b/tests/basic_tests.rs
@@ -86,13 +86,15 @@ fn drain() {
     {
         let mut table = write_txn.open_table(U64_TABLE).unwrap();
         assert_eq!(table.len().unwrap(), 10);
-        for (i, (k, v)) in table.drain(0..5).unwrap().enumerate() {
+        for (i, item) in table.drain(0..5).unwrap().enumerate() {
+            let (k, v) = item.unwrap();
             assert_eq!(i as u64, k.value());
             assert_eq!(i as u64, v.value());
         }
         assert_eq!(table.len().unwrap(), 5);
         let mut i = 5u64;
-        for (k, v) in table.range(0..10).unwrap() {
+        for item in table.range(0..10).unwrap() {
+            let (k, v) = item.unwrap();
             assert_eq!(i, k.value());
             assert_eq!(i, v.value());
             i += 1;
@@ -141,13 +143,15 @@ fn drain_filter() {
     {
         let mut table = write_txn.open_table(U64_TABLE).unwrap();
         assert_eq!(table.len().unwrap(), 10);
-        for (i, (k, v)) in table.drain_filter(0.., |x, _| x < 5).unwrap().enumerate() {
+        for (i, item) in table.drain_filter(0.., |x, _| x < 5).unwrap().enumerate() {
+            let (k, v) = item.unwrap();
             assert_eq!(i as u64, k.value());
             assert_eq!(i as u64, v.value());
         }
         assert_eq!(table.len().unwrap(), 5);
         let mut i = 5u64;
-        for (k, v) in table.range(0..10).unwrap() {
+        for item in table.range(0..10).unwrap() {
+            let (k, v) = item.unwrap();
             assert_eq!(i, k.value());
             assert_eq!(i, v.value());
             i += 1;
@@ -698,18 +702,22 @@ fn insert_overwrite() {
 fn insert_reserve() {
     let tmpfile: NamedTempFile = NamedTempFile::new().unwrap();
     let db = Database::create(tmpfile.path()).unwrap();
+    let def: TableDefinition<&str, &[u8]> = TableDefinition::new("x");
     let value = "world";
     let write_txn = db.begin_write().unwrap();
     {
-        let mut table = write_txn.open_table(STR_TABLE).unwrap();
+        let mut table = write_txn.open_table(def).unwrap();
         let mut reserved = table.insert_reserve("hello", value.len()).unwrap();
         reserved.as_mut().copy_from_slice(value.as_bytes());
     }
     write_txn.commit().unwrap();
 
     let read_txn = db.begin_read().unwrap();
-    let table = read_txn.open_table(STR_TABLE).unwrap();
-    assert_eq!(value, table.get("hello").unwrap().unwrap().value());
+    let table = read_txn.open_table(def).unwrap();
+    assert_eq!(
+        value.as_bytes(),
+        table.get("hello").unwrap().unwrap().value()
+    );
 }
 
 #[test]
@@ -868,7 +876,11 @@ fn u64_type() {
     let table = read_txn.open_table(U64_TABLE).unwrap();
     assert_eq!(
         2u64,
-        table.range(0..2).unwrap().map(|(_, x)| x.value()).sum()
+        table
+            .range(0..2)
+            .unwrap()
+            .map(|item| item.unwrap().1.value())
+            .sum()
     );
     assert_eq!(1, table.get(&0).unwrap().unwrap().value());
 }
@@ -894,7 +906,7 @@ fn i128_type() {
     assert_eq!(-2, table.get(&-1).unwrap().unwrap().value());
     let mut iter: Range<i128, i128> = table.range::<i128>(..).unwrap();
     for i in -11..10 {
-        assert_eq!(iter.next().unwrap().1.value(), i);
+        assert_eq!(iter.next().unwrap().unwrap().1.value(), i);
     }
     assert!(iter.next().is_none());
 }
@@ -937,11 +949,11 @@ fn str_type() {
     assert_eq!("world", table.get("hello").unwrap().unwrap().value());
 
     let mut iter = table.iter().unwrap();
-    assert_eq!(iter.next().unwrap().1.value(), "world");
+    assert_eq!(iter.next().unwrap().unwrap().1.value(), "world");
     assert!(iter.next().is_none());
 
     let mut iter: Range<&str, &str> = table.range("a".."z").unwrap();
-    assert_eq!(iter.next().unwrap().1.value(), "world");
+    assert_eq!(iter.next().unwrap().unwrap().1.value(), "world");
     assert!(iter.next().is_none());
 }
 
@@ -1005,7 +1017,7 @@ fn array_type() {
     assert_eq!(b"world_123", table.get(hello).unwrap().unwrap().value());
 
     let mut iter: Range<&[u8; 5], &[u8; 9]> = table.range::<&[u8; 5]>(..).unwrap();
-    assert_eq!(iter.next().unwrap().1.value(), b"world_123");
+    assert_eq!(iter.next().unwrap().unwrap().1.value(), b"world_123");
     assert!(iter.next().is_none());
 }
 
@@ -1030,7 +1042,7 @@ fn range_lifetime() {
         let start = "hello".to_string();
         table.range::<&str>(start.as_str()..).unwrap()
     };
-    assert_eq!(iter.next().unwrap().1.value(), "world");
+    assert_eq!(iter.next().unwrap().unwrap().1.value(), "world");
     assert!(iter.next().is_none());
 }
 
@@ -1055,7 +1067,7 @@ fn drain_lifetime() {
         let start = "hello".to_string();
         table.drain::<&str>(start.as_str()..).unwrap()
     };
-    assert_eq!(iter.next().unwrap().1.value(), "world");
+    assert_eq!(iter.next().unwrap().unwrap().1.value(), "world");
     assert!(iter.next().is_none());
 }
 
@@ -1080,7 +1092,7 @@ fn drain_filter_lifetime() {
         let start = "hello".to_string();
         table.drain_filter(start.as_str().., |_, _| true).unwrap()
     };
-    assert_eq!(iter.next().unwrap().1.value(), "world");
+    assert_eq!(iter.next().unwrap().unwrap().1.value(), "world");
     assert!(iter.next().is_none());
 }
 
@@ -1147,7 +1159,7 @@ fn custom_ordering() {
     let end = ReverseKey(vec![3u8]);
     let mut iter = table.range(start..=end).unwrap();
     for i in (3..=7u8).rev() {
-        let (key, value) = iter.next().unwrap();
+        let (key, value) = iter.next().unwrap().unwrap();
         assert_eq!(&[i], key.value().0.as_slice());
         assert_eq!("value", value.value());
     }
@@ -1177,17 +1189,17 @@ fn owned_get_signatures() {
 
     let mut iter: Range<u32, u32> = table.range::<u32>(..).unwrap();
     for i in 0..10 {
-        assert_eq!(iter.next().unwrap().1.value(), i + 1);
+        assert_eq!(iter.next().unwrap().unwrap().1.value(), i + 1);
     }
     assert!(iter.next().is_none());
     let mut iter: Range<u32, u32> = table.range(0..10).unwrap();
     for i in 0..10 {
-        assert_eq!(iter.next().unwrap().1.value(), i + 1);
+        assert_eq!(iter.next().unwrap().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.value(), i + 1);
+        assert_eq!(iter.next().unwrap().unwrap().1.value(), i + 1);
     }
     assert!(iter.next().is_none());
 }
@@ -1217,26 +1229,26 @@ fn ref_get_signatures() {
     let end = vec![10u8];
     let mut iter = table.range::<&[u8]>(..).unwrap();
     for i in 0..10 {
-        assert_eq!(iter.next().unwrap().1.value(), &[i + 1]);
+        assert_eq!(iter.next().unwrap().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.value(), &[i + 1]);
+        assert_eq!(iter.next().unwrap().unwrap().1.value(), &[i + 1]);
     }
     assert!(iter.next().is_none());
     drop(iter);
 
     let mut iter = table.range(start.as_slice()..end.as_slice()).unwrap();
     for i in 0..10 {
-        assert_eq!(iter.next().unwrap().1.value(), &[i + 1]);
+        assert_eq!(iter.next().unwrap().unwrap().1.value(), &[i + 1]);
     }
     assert!(iter.next().is_none());
 
     let mut iter = table.range([0u8].as_slice()..[10u8].as_slice()).unwrap();
     for i in 0..10u8 {
-        assert_eq!(iter.next().unwrap().1.value(), [i + 1].as_slice());
+        assert_eq!(iter.next().unwrap().unwrap().1.value(), [i + 1].as_slice());
     }
     assert!(iter.next().is_none());
 }
@@ -1279,7 +1291,7 @@ fn iter() {
     let table = read_txn.open_table(U64_TABLE).unwrap();
     let mut iter = table.iter().unwrap();
     for i in 0..10 {
-        let (k, v) = iter.next().unwrap();
+        let (k, v) = iter.next().unwrap().unwrap();
         assert_eq!(i, k.value());
         assert_eq!(i, v.value());
     }
diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs
index 5644e33..3e965c9 100644
--- a/tests/integration_tests.rs
+++ b/tests/integration_tests.rs
@@ -460,8 +460,8 @@ fn regression7() {
         t.remove(&145227).unwrap();
 
         let mut iter = t.range(138763..(138763 + 232359)).unwrap().rev();
-        assert_eq!(iter.next().unwrap().0.value(), 153701);
-        assert_eq!(iter.next().unwrap().0.value(), 146255);
+        assert_eq!(iter.next().unwrap().unwrap().0.value(), 153701);
+        assert_eq!(iter.next().unwrap().unwrap().0.value(), 146255);
         assert!(iter.next().is_none());
     }
     tx.commit().unwrap();
@@ -509,8 +509,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.value(), 118749);
-        assert_eq!(iter.next().unwrap().0.value(), 130571);
+        assert_eq!(iter.next().unwrap().unwrap().0.value(), 118749);
+        assert_eq!(iter.next().unwrap().unwrap().0.value(), 130571);
         assert!(iter.next().is_none());
     }
     tx.commit().unwrap();
@@ -670,14 +670,14 @@ fn regression14() {
 
         let mut iter = t.range(514043..(514043 + 514043)).unwrap().rev();
         {
-            let (key, mut value_iter) = iter.next().unwrap();
+            let (key, mut value_iter) = iter.next().unwrap().unwrap();
             assert_eq!(key.value(), 776971);
-            assert_eq!(value_iter.next().unwrap().value(), &[0; 2230]);
+            assert_eq!(value_iter.next().unwrap().unwrap().value(), &[0; 2230]);
         }
         {
-            let (key, mut value_iter) = iter.next().unwrap();
+            let (key, mut value_iter) = iter.next().unwrap().unwrap();
             assert_eq!(key.value(), 539749);
-            assert_eq!(value_iter.next().unwrap().value(), &[0; 1424]);
+            assert_eq!(value_iter.next().unwrap().unwrap().value(), &[0; 1424]);
         }
     }
     tx.abort().unwrap();
@@ -929,7 +929,7 @@ fn range_query() {
     let table = read_txn.open_table(U64_TABLE).unwrap();
     let mut iter = table.range(3..7).unwrap();
     for i in 3..7u64 {
-        let (key, value) = iter.next().unwrap();
+        let (key, value) = iter.next().unwrap().unwrap();
         assert_eq!(i, key.value());
         assert_eq!(i, value.value());
     }
@@ -937,13 +937,17 @@ fn range_query() {
 
     let mut iter = table.range(3..=7).unwrap();
     for i in 3..=7u64 {
-        let (key, value) = iter.next().unwrap();
+        let (key, value) = iter.next().unwrap().unwrap();
         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.value()).sum();
+    let total: u64 = table
+        .range(1..=3)
+        .unwrap()
+        .map(|item| item.unwrap().1.value())
+        .sum();
     assert_eq!(total, 6);
 }
 
@@ -964,7 +968,7 @@ fn range_query_reversed() {
     let table = read_txn.open_table(U64_TABLE).unwrap();
     let mut iter = table.range(3..7).unwrap().rev();
     for i in (3..7u64).rev() {
-        let (key, value) = iter.next().unwrap();
+        let (key, value) = iter.next().unwrap().unwrap();
         assert_eq!(i, key.value());
         assert_eq!(i, value.value());
     }
@@ -972,17 +976,17 @@ fn range_query_reversed() {
 
     // Test reversing multiple times
     let mut iter = table.range(3..7).unwrap();
-    let (key, _) = iter.next().unwrap();
+    let (key, _) = iter.next().unwrap().unwrap();
     assert_eq!(3, key.value());
 
     let mut iter = iter.rev();
-    let (key, _) = iter.next().unwrap();
+    let (key, _) = iter.next().unwrap().unwrap();
     assert_eq!(6, key.value());
-    let (key, _) = iter.next().unwrap();
+    let (key, _) = iter.next().unwrap().unwrap();
     assert_eq!(5, key.value());
 
     let mut iter = iter.rev();
-    let (key, _) = iter.next().unwrap();
+    let (key, _) = iter.next().unwrap().unwrap();
     assert_eq!(4, key.value());
 
     assert!(iter.next().is_none());
diff --git a/tests/multimap_tests.rs b/tests/multimap_tests.rs
index 99159f6..f8cf272 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.value().to_string());
+            result.push(item_value.unwrap().value().to_string());
         } else {
             return result;
         }
@@ -105,26 +105,27 @@ fn range_query() {
     let mut iter = table.range(start..=end).unwrap();
 
     {
-        let (key, mut values) = iter.next().unwrap();
+        let (key, mut values) = iter.next().unwrap().unwrap();
         for i in 0..5 {
             assert_eq!(b"0", key.value());
-            let value = values.next().unwrap();
+            let value = values.next().unwrap().unwrap();
             assert_eq!(i, value.value());
         }
     }
     {
-        let (key, mut values) = iter.next().unwrap();
+        let (key, mut values) = iter.next().unwrap().unwrap();
         for i in 5..10 {
             assert_eq!(b"1", key.value());
-            let value = values.next().unwrap();
+            let value = values.next().unwrap().unwrap();
             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.map(|x| x.value()).sum::<u64>();
+    for item in table.range(start..=end).unwrap() {
+        let (_, values) = item.unwrap();
+        total += values.map(|x| x.unwrap().value()).sum::<u64>();
     }
     assert_eq!(total, 45);
 }
@@ -150,7 +151,17 @@ fn range_lifetime() {
         let start = "hello".to_string();
         table.range::<&str>(start.as_str()..).unwrap()
     };
-    assert_eq!(iter.next().unwrap().1.next().unwrap().value(), "world");
+    assert_eq!(
+        iter.next()
+            .unwrap()
+            .unwrap()
+            .1
+            .next()
+            .unwrap()
+            .unwrap()
+            .value(),
+        "world"
+    );
     assert!(iter.next().is_none());
 }
 
@@ -198,8 +209,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().value());
-        assert_eq!("world3", iter.next().unwrap().value());
+        assert_eq!("world", iter.next().unwrap().unwrap().value());
+        assert_eq!("world3", iter.next().unwrap().unwrap().value());
         assert!(iter.next().is_none());
     }
     write_txn.commit().unwrap();
@@ -298,10 +309,10 @@ fn iter() {
     let table = read_txn.open_multimap_table(U64_TABLE).unwrap();
     let mut iter = table.iter().unwrap();
     for i in 0..10 {
-        let (k, mut values) = iter.next().unwrap();
+        let (k, mut values) = iter.next().unwrap().unwrap();
         assert_eq!(k.value(), i);
         for j in 0..10 {
-            assert_eq!(values.next().unwrap().value(), j);
+            assert_eq!(values.next().unwrap().unwrap().value(), j);
         }
     }
 }