Skip to content

Commit

Permalink
Implement Debug for Table and ReadOnlyTable
Browse files Browse the repository at this point in the history
  • Loading branch information
cberner committed Oct 15, 2023
1 parent 8940f43 commit 187d212
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 5 deletions.
23 changes: 18 additions & 5 deletions src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,12 @@ impl Database {
})?
{
let savepoint_table: ReadOnlyTable<SavepointId, SerializedSavepoint> =
ReadOnlyTable::new(savepoint_table_def.get_root(), PageHint::None, mem)?;
ReadOnlyTable::new(
"internal savepoint table".to_string(),
savepoint_table_def.get_root(),
PageHint::None,
mem,
)?;
for result in savepoint_table.range::<SavepointId>(..)? {
let (_, savepoint_data) = result?;
let savepoint = savepoint_data
Expand Down Expand Up @@ -443,8 +448,12 @@ impl Database {
mem.mark_pages_allocated(freed_pages_iter, true)?;
}

let freed_table: ReadOnlyTable<FreedTableKey, FreedPageList<'static>> =
ReadOnlyTable::new(freed_root, PageHint::None, mem)?;
let freed_table: ReadOnlyTable<FreedTableKey, FreedPageList<'static>> = ReadOnlyTable::new(
"internal freed table".to_string(),
freed_root,
PageHint::None,
mem,
)?;
let lookup_key = FreedTableKey {
transaction_id: oldest_unprocessed_free_transaction.0,
pagination_id: 0,
Expand Down Expand Up @@ -557,8 +566,12 @@ impl Database {
let freed_root = mem.get_freed_root();
// Allow processing of all transactions, since this is the main freed tree
Self::mark_freed_tree(freed_root, mem, TransactionId(0))?;
let freed_table: ReadOnlyTable<FreedTableKey, FreedPageList<'static>> =
ReadOnlyTable::new(freed_root, PageHint::None, mem)?;
let freed_table: ReadOnlyTable<FreedTableKey, FreedPageList<'static>> = ReadOnlyTable::new(
"internal freed table".to_string(),
freed_root,
PageHint::None,
mem,
)?;
// The persistent savepoints might hold references to older freed trees that are partially processed.
// Make sure we don't reprocess those frees, as that would result in a double-free
let oldest_unprocessed_transaction =
Expand Down
59 changes: 59 additions & 0 deletions src/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::types::{RedbKey, RedbValue, RedbValueMutInPlace};
use crate::Result;
use crate::{AccessGuard, StorageError, WriteTransaction};
use std::borrow::Borrow;
use std::fmt::{Debug, Formatter};
use std::ops::RangeBounds;
use std::sync::{Arc, Mutex};

Expand Down Expand Up @@ -249,6 +250,55 @@ impl<'db, 'txn, K: RedbKey + 'static, V: RedbValue + 'static> Drop for Table<'db
}
}

fn debug_helper<K: RedbKey + 'static, V: RedbValue + 'static>(
f: &mut Formatter<'_>,
name: &str,
len: Result<u64>,
first: Result<Option<(AccessGuard<K>, AccessGuard<V>)>>,
last: Result<Option<(AccessGuard<K>, AccessGuard<V>)>>,
) -> std::fmt::Result {
write!(f, "Table [ name: \"{}\", ", name)?;
if let Ok(len) = len {
if len == 0 {
write!(f, "No entries")?;
} else if len == 1 {
if let Ok(first) = first {
let (key, value) = first.as_ref().unwrap();
write!(f, "One key-value: {:?} = {:?}", key.value(), value.value())?;
} else {
write!(f, "I/O Error accessing table!")?;
}
} else {
if let Ok(first) = first {
let (key, value) = first.as_ref().unwrap();
write!(f, "first: {:?} = {:?}, ", key.value(), value.value())?;
} else {
write!(f, "I/O Error accessing table!")?;
}
if len > 2 {
write!(f, "...{} more entries..., ", len - 2)?;
}
if let Ok(last) = last {
let (key, value) = last.as_ref().unwrap();
write!(f, "last: {:?} = {:?}", key.value(), value.value())?;
} else {
write!(f, "I/O Error accessing table!")?;
}
}
} else {
write!(f, "I/O Error accessing table!")?;
}
write!(f, " ]")?;

Ok(())
}

impl<K: RedbKey + 'static, V: RedbValue + 'static> Debug for Table<'_, '_, K, V> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
debug_helper(f, &self.name, self.len(), self.first(), self.last())
}
}

pub trait ReadableTable<K: RedbKey + 'static, V: RedbValue + 'static>: Sealed {
/// Returns the value corresponding to the given key
fn get<'a>(&self, key: impl Borrow<K::SelfType<'a>>) -> Result<Option<AccessGuard<V>>>
Expand Down Expand Up @@ -319,16 +369,19 @@ pub trait ReadableTable<K: RedbKey + 'static, V: RedbValue + 'static>: Sealed {

/// A read-only table
pub struct ReadOnlyTable<'txn, K: RedbKey + 'static, V: RedbValue + 'static> {
name: String,
tree: Btree<'txn, K, V>,
}

impl<'txn, K: RedbKey + 'static, V: RedbValue + 'static> ReadOnlyTable<'txn, K, V> {
pub(crate) fn new(
name: String,
root_page: Option<(PageNumber, Checksum)>,
hint: PageHint,
mem: &'txn TransactionalMemory,
) -> Result<ReadOnlyTable<'txn, K, V>> {
Ok(ReadOnlyTable {
name,
tree: Btree::new(root_page, hint, mem)?,
})
}
Expand Down Expand Up @@ -376,6 +429,12 @@ impl<'txn, K: RedbKey + 'static, V: RedbValue + 'static> ReadableTable<K, V>

impl<K: RedbKey, V: RedbValue> Sealed for ReadOnlyTable<'_, K, V> {}

impl<K: RedbKey + 'static, V: RedbValue + 'static> Debug for ReadOnlyTable<'_, K, V> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
debug_helper(f, &self.name, self.len(), self.first(), self.last())
}
}

pub struct Drain<'a, K: RedbKey + 'static, V: RedbValue + 'static> {
inner: BtreeDrain<'a, K, V>,
}
Expand Down
1 change: 1 addition & 0 deletions src/transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1150,6 +1150,7 @@ impl<'db> ReadTransaction<'db> {
.ok_or_else(|| TableError::TableDoesNotExist(definition.name().to_string()))?;

Ok(ReadOnlyTable::new(
definition.name().to_string(),
header.get_root(),
PageHint::Clean,
self.mem,
Expand Down

0 comments on commit 187d212

Please sign in to comment.