Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Debug for Table and ReadOnlyTable #706

Merged
merged 1 commit into from
Oct 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading