Skip to content

Commit

Permalink
Add API to retrieve stats for a table without knowing its type
Browse files Browse the repository at this point in the history
  • Loading branch information
cberner committed Nov 25, 2023
1 parent 682cea3 commit fa35061
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 3 deletions.
8 changes: 6 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,13 @@ pub use error::{
TransactionError,
};
pub use multimap_table::{
MultimapRange, MultimapTable, MultimapValue, ReadOnlyMultimapTable, ReadableMultimapTable,
MultimapRange, MultimapTable, MultimapValue, ReadOnlyMultimapTable,
ReadOnlyUntypedMultimapTable, ReadableMultimapTable,
};
pub use table::{
Drain, DrainFilter, Range, ReadOnlyTable, ReadOnlyUntypedTable, ReadableTable, Table,
TableStats,
};
pub use table::{Drain, DrainFilter, Range, ReadOnlyTable, ReadableTable, Table, TableStats};
pub use transactions::{DatabaseStats, Durability, ReadTransaction, WriteTransaction};
pub use tree_store::{AccessGuard, AccessGuardMut, Savepoint};
pub use types::{RedbKey, RedbValue, TypeName};
Expand Down
48 changes: 48 additions & 0 deletions src/multimap_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1174,6 +1174,54 @@ pub trait ReadableMultimapTable<K: RedbKey + 'static, V: RedbKey + 'static>: Sea
}
}

/// A read-only untyped multimap table
pub struct ReadOnlyUntypedMultimapTable<'txn> {
tree: RawBtree<'txn>,
fixed_key_size: Option<usize>,
fixed_value_size: Option<usize>,
mem: &'txn TransactionalMemory,
}

impl<'txn> ReadOnlyUntypedMultimapTable<'txn> {
pub(crate) fn new(
root_page: Option<(PageNumber, Checksum)>,
fixed_key_size: Option<usize>,
fixed_value_size: Option<usize>,
mem: &'txn TransactionalMemory,
) -> Self {
Self {
tree: RawBtree::new(
root_page,
fixed_key_size,
DynamicCollection::<()>::fixed_width_with(fixed_value_size),
mem,
),
fixed_key_size,
fixed_value_size,
mem,
}
}

/// Retrieves information about storage usage for the table
pub fn stats(&self) -> Result<TableStats> {
let tree_stats = multimap_btree_stats(
self.tree.get_root().map(|(p, _)| p),
self.mem,
self.fixed_key_size,
self.fixed_value_size,
)?;

Ok(TableStats {
tree_height: tree_stats.tree_height,
leaf_pages: tree_stats.leaf_pages,
branch_pages: tree_stats.branch_pages,
stored_leaf_bytes: tree_stats.stored_leaf_bytes,
metadata_bytes: tree_stats.metadata_bytes,
fragmented_bytes: tree_stats.fragmented_bytes,
})
}
}

/// A read-only multimap table
pub struct ReadOnlyMultimapTable<'txn, K: RedbKey + 'static, V: RedbKey + 'static> {
tree: Btree<'txn, K, &'static DynamicCollection<V>>,
Expand Down
34 changes: 33 additions & 1 deletion src/table.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::sealed::Sealed;
use crate::tree_store::{
AccessGuardMut, Btree, BtreeDrain, BtreeDrainFilter, BtreeMut, BtreeRangeIter, Checksum,
PageHint, PageNumber, TransactionalMemory, MAX_VALUE_LENGTH,
PageHint, PageNumber, RawBtree, TransactionalMemory, MAX_VALUE_LENGTH,
};
use crate::types::{RedbKey, RedbValue, RedbValueMutInPlace};
use crate::{AccessGuard, StorageError, WriteTransaction};
Expand Down Expand Up @@ -373,6 +373,38 @@ pub trait ReadableTable<K: RedbKey + 'static, V: RedbValue + 'static>: Sealed {
}
}

/// A read-only untyped table
pub struct ReadOnlyUntypedTable<'txn> {
tree: RawBtree<'txn>,
}

impl<'txn> ReadOnlyUntypedTable<'txn> {
pub(crate) fn new(
root_page: Option<(PageNumber, Checksum)>,
fixed_key_size: Option<usize>,
fixed_value_size: Option<usize>,
mem: &'txn TransactionalMemory,
) -> Self {
Self {
tree: RawBtree::new(root_page, fixed_key_size, fixed_value_size, mem),
}
}

/// Retrieves information about storage usage for the table
pub fn stats(&self) -> Result<TableStats> {
let tree_stats = self.tree.stats()?;

Ok(TableStats {
tree_height: tree_stats.tree_height,
leaf_pages: tree_stats.leaf_pages,
branch_pages: tree_stats.branch_pages,
stored_leaf_bytes: tree_stats.stored_leaf_bytes,
metadata_bytes: tree_stats.metadata_bytes,
fragmented_bytes: tree_stats.fragmented_bytes,
})
}
}

/// A read-only table
pub struct ReadOnlyTable<'txn, K: RedbKey + 'static, V: RedbValue + 'static> {
name: String,
Expand Down
38 changes: 38 additions & 0 deletions src/transactions.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::error::CommitError;
use crate::multimap_table::ReadOnlyUntypedMultimapTable;
use crate::sealed::Sealed;
use crate::table::ReadOnlyUntypedTable;
use crate::transaction_tracker::{SavepointId, TransactionId, TransactionTracker};
use crate::tree_store::{
Btree, BtreeMut, Checksum, FreedPageList, FreedTableKey, InternalTableDefinition, PageHint,
Expand Down Expand Up @@ -1185,6 +1187,24 @@ impl<'db> ReadTransaction<'db> {
)?)
}

/// Open the given table without a type
pub fn open_untyped_table(
&self,
handle: impl TableHandle,
) -> Result<ReadOnlyUntypedTable, TableError> {
let header = self
.tree
.get_table_untyped(handle.name(), TableType::Normal)?
.ok_or_else(|| TableError::TableDoesNotExist(handle.name().to_string()))?;

Ok(ReadOnlyUntypedTable::new(
header.get_root(),
header.get_fixed_key_size(),
header.get_fixed_value_size(),
self.mem,
))
}

/// Open the given table
pub fn open_multimap_table<K: RedbKey + 'static, V: RedbKey + 'static>(
&self,
Expand All @@ -1202,6 +1222,24 @@ impl<'db> ReadTransaction<'db> {
)?)
}

/// Open the given table without a type
pub fn open_untyped_multimap_table(
&self,
handle: impl MultimapTableHandle,
) -> Result<ReadOnlyUntypedMultimapTable, TableError> {
let header = self
.tree
.get_table_untyped(handle.name(), TableType::Multimap)?
.ok_or_else(|| TableError::TableDoesNotExist(handle.name().to_string()))?;

Ok(ReadOnlyUntypedMultimapTable::new(
header.get_root(),
header.get_fixed_key_size(),
header.get_fixed_value_size(),
self.mem,
))
}

/// List all the tables
pub fn list_tables(&self) -> Result<impl Iterator<Item = UntypedTableHandle>> {
self.tree
Expand Down
13 changes: 13 additions & 0 deletions src/tree_store/btree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,19 @@ impl<'a> RawBtree<'a> {
}
}

pub(crate) fn get_root(&self) -> Option<(PageNumber, Checksum)> {
self.root
}

pub(crate) fn stats(&self) -> Result<BtreeStats> {
btree_stats(
self.root.map(|(p, _)| p),
self.mem,
self.fixed_key_size,
self.fixed_value_size,
)
}

pub(crate) fn verify_checksum(&self) -> Result<bool> {
if let Some((root, checksum)) = self.root {
self.verify_checksum_helper(root, checksum)
Expand Down
20 changes: 20 additions & 0 deletions tests/basic_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,26 @@ fn len() {
assert_eq!(table.len().unwrap(), 3);
}

#[test]
fn table_stats() {
let tmpfile = create_tempfile();
let db = Database::create(tmpfile.path()).unwrap();
let write_txn = db.begin_write().unwrap();
{
let mut table = write_txn.open_table(STR_TABLE).unwrap();
table.insert("hello", "world").unwrap();
table.insert("hello2", "world2").unwrap();
table.insert("hi", "world").unwrap();
}
write_txn.commit().unwrap();

let read_txn = db.begin_read().unwrap();
let table = read_txn.open_table(STR_TABLE).unwrap();
let untyped_table = read_txn.open_untyped_table(STR_TABLE).unwrap();
assert_eq!(table.stats().unwrap().tree_height(), 1);
assert_eq!(untyped_table.stats().unwrap().tree_height(), 1);
}

#[test]
fn in_memory() {
let db = Database::builder()
Expand Down

0 comments on commit fa35061

Please sign in to comment.