diff --git a/crates/db/src/lib.rs b/crates/db/src/lib.rs index eb330e8a..d1fd3487 100644 --- a/crates/db/src/lib.rs +++ b/crates/db/src/lib.rs @@ -41,6 +41,7 @@ pub enum DatabaseType { pub struct DatabaseBuilder { db_type: DatabaseType, path: Option, + memory_size: Option, } pub trait Database { @@ -53,6 +54,7 @@ impl DatabaseBuilder { Self { db_type: DatabaseType::RocksDb, path: None, + memory_size: None, } } @@ -65,6 +67,11 @@ impl DatabaseBuilder { self } + pub fn with_memory_size(&mut self, memory_size_bytes: usize) -> &mut Self { + self.memory_size = Some(memory_size_bytes); + self + } + /// Returns a new database instance. The second value in the result tuple is true if the /// database was newly created, and false if it was already present. pub async fn open_db(&self) -> Result<(Box, bool), String> { @@ -77,7 +84,11 @@ impl DatabaseBuilder { Ok((Box::new(db), fresh)) } DatabaseType::Tuplebox => { - let (db, fresh) = TupleBoxWorldStateSource::open(self.path.clone()).await; + let (db, fresh) = TupleBoxWorldStateSource::open( + self.path.clone(), + self.memory_size.unwrap_or(1 << 48), + ) + .await; Ok((Box::new(db), fresh)) } } diff --git a/crates/db/src/tuplebox/object_relations.rs b/crates/db/src/tuplebox/object_relations.rs index 246b32d3..0176042f 100644 --- a/crates/db/src/tuplebox/object_relations.rs +++ b/crates/db/src/tuplebox/object_relations.rs @@ -224,7 +224,7 @@ mod tests { relations[ObjectParent as usize].secondary_indexed = true; relations[WorldStateRelation::ObjectLocation as usize].secondary_indexed = true; - let db = TupleBox::new(None, &relations, WorldStateSequences::COUNT).await; + let db = TupleBox::new(1 << 24, 4096, None, &relations, WorldStateSequences::COUNT).await; db } diff --git a/crates/db/src/tuplebox/slots/mod.rs b/crates/db/src/tuplebox/slots/mod.rs index 903bc2e4..469116c3 100644 --- a/crates/db/src/tuplebox/slots/mod.rs +++ b/crates/db/src/tuplebox/slots/mod.rs @@ -4,5 +4,3 @@ pub use crate::tuplebox::slots::slotbox::TupleId; mod slotbox; mod slotted_page; - -pub const TUPLEBOX_PAGE_SIZE: usize = 1 << 16; diff --git a/crates/db/src/tuplebox/tb.rs b/crates/db/src/tuplebox/tb.rs index 1e46640f..5bf60246 100644 --- a/crates/db/src/tuplebox/tb.rs +++ b/crates/db/src/tuplebox/tb.rs @@ -12,15 +12,12 @@ use tracing::info; use crate::tuplebox::backing::BackingStoreClient; use crate::tuplebox::base_relation::BaseRelation; use crate::tuplebox::rocks_backing::RocksBackingStore; -use crate::tuplebox::slots::{SlotBox, TUPLEBOX_PAGE_SIZE}; +use crate::tuplebox::slots::SlotBox; use crate::tuplebox::tuples::TxTuple; use crate::tuplebox::tx::transaction::{CommitError, CommitSet, Transaction}; use crate::tuplebox::tx::working_set::WorkingSet; use crate::tuplebox::RelationId; -pub const TUPLEBOX_MEMORY_SIZE: usize = 1 << 36; -pub const TUPLEBOX_MAX_PAGES: usize = TUPLEBOX_MEMORY_SIZE / TUPLEBOX_PAGE_SIZE; - /// Meta-data about a relation #[derive(Clone, Debug)] pub struct RelationInfo { @@ -61,11 +58,13 @@ pub struct TupleBox { impl TupleBox { pub async fn new( + memory_size: usize, + page_size: usize, path: Option, relations: &[RelationInfo], num_sequences: usize, ) -> Arc { - let slotbox = Arc::new(SlotBox::new(TUPLEBOX_PAGE_SIZE, TUPLEBOX_MEMORY_SIZE)); + let slotbox = Arc::new(SlotBox::new(page_size, memory_size)); let mut base_relations = Vec::with_capacity(relations.len()); for (rid, r) in relations.iter().enumerate() { base_relations.push(BaseRelation::new(slotbox.clone(), RelationId(rid), 0)); diff --git a/crates/db/src/tuplebox/tb_worldstate.rs b/crates/db/src/tuplebox/tb_worldstate.rs index 26e8e1d4..f13da521 100644 --- a/crates/db/src/tuplebox/tb_worldstate.rs +++ b/crates/db/src/tuplebox/tb_worldstate.rs @@ -32,13 +32,17 @@ use crate::tuplebox::tuples::TupleError; use crate::tuplebox::tx::transaction::{CommitError, Transaction}; use crate::Database; +// TODO: Totally arbitrary and needs profiling. Needs to be big enough to hold entire props and +// verbs. +const PAGE_SIZE: usize = 32768; + /// An implementation of `WorldState` / `WorldStateSource` that uses the TupleBox as its backing pub struct TupleBoxWorldStateSource { db: Arc, } impl TupleBoxWorldStateSource { - pub async fn open(path: Option) -> (Self, bool) { + pub async fn open(path: Option, memory_size: usize) -> (Self, bool) { let mut relations: Vec = WorldStateRelation::iter() .map(|wsr| { RelationInfo { @@ -54,7 +58,14 @@ impl TupleBoxWorldStateSource { relations[WorldStateRelation::ObjectParent as usize].secondary_indexed = true; // Same with "contents". relations[WorldStateRelation::ObjectLocation as usize].secondary_indexed = true; - let db = TupleBox::new(path, &relations, WorldStateSequences::COUNT).await; + let db = TupleBox::new( + memory_size, + PAGE_SIZE, + path, + &relations, + WorldStateSequences::COUNT, + ) + .await; // Check the db for sys (#0) object to see if this is a fresh DB or not. let fresh_db = { @@ -1091,7 +1102,7 @@ mod tests { relations[WorldStateRelation::ObjectParent as usize].secondary_indexed = true; relations[WorldStateRelation::ObjectLocation as usize].secondary_indexed = true; - let db = TupleBox::new(None, &relations, WorldStateSequences::COUNT).await; + let db = TupleBox::new(1 << 24, 4096, None, &relations, WorldStateSequences::COUNT).await; db } diff --git a/crates/db/src/tuplebox/tx/transaction.rs b/crates/db/src/tuplebox/tx/transaction.rs index 502a8722..45186507 100644 --- a/crates/db/src/tuplebox/tx/transaction.rs +++ b/crates/db/src/tuplebox/tx/transaction.rs @@ -482,6 +482,8 @@ mod tests { async fn test_db() -> Arc { let db = TupleBox::new( + 1 << 24, + 4096, None, &[RelationInfo { name: "test".to_string(), diff --git a/crates/kernel/src/vm/vm_test.rs b/crates/kernel/src/vm/vm_test.rs index 3f838fb2..9aa63c6a 100644 --- a/crates/kernel/src/vm/vm_test.rs +++ b/crates/kernel/src/vm/vm_test.rs @@ -38,7 +38,7 @@ mod tests { // Create an in memory db with a single object (#0) containing a single provided verb. async fn test_db_with_verbs(verbs: &[(&str, &Program)]) -> TupleBoxWorldStateSource { - let (state, _) = TupleBoxWorldStateSource::open(None).await; + let (state, _) = TupleBoxWorldStateSource::open(None, 1 << 30).await; let mut tx = state.new_world_state().await.unwrap(); let sysobj = tx .create_object(SYSTEM_OBJECT, NOTHING, SYSTEM_OBJECT, BitEnum::all()) diff --git a/crates/kernel/testsuite/basic/basic_suite.rs b/crates/kernel/testsuite/basic/basic_suite.rs index 1bddc941..f7270e5f 100644 --- a/crates/kernel/testsuite/basic/basic_suite.rs +++ b/crates/kernel/testsuite/basic/basic_suite.rs @@ -89,7 +89,7 @@ async fn run_basic_test(test_dir: &str) { // Frustratingly the individual test lines are not independent, so we need to run them in a // single database. - let (mut db, _) = TupleBoxWorldStateSource::open(None).await; + let (mut db, _) = TupleBoxWorldStateSource::open(None, 1 << 30).await; load_db(&mut db).await; for (line_num, (input, expected_output)) in zipped.enumerate() { let evaluated = eval(&mut db, input).await;