diff --git a/crates/daemon/src/connections_tb.rs b/crates/daemon/src/connections_tb.rs
index 2f301923..ff742bd3 100644
--- a/crates/daemon/src/connections_tb.rs
+++ b/crates/daemon/src/connections_tb.rs
@@ -12,7 +12,7 @@
// this program. If not, see .
//
-//! An implementation of the connections db that uses tuplebox.
+//! An implementation of the connections db that uses rdb.
use std::collections::HashSet;
use std::path::PathBuf;
@@ -25,7 +25,7 @@ use strum::{Display, EnumCount, EnumIter, IntoEnumIterator};
use tracing::{debug, error, warn};
use uuid::Uuid;
-use moor_db::tuplebox::{RelationId, RelationInfo, Transaction, TupleBox};
+use moor_db::rdb::{RelBox, RelationId, RelationInfo, Transaction};
use moor_kernel::tasks::sessions::SessionError;
use moor_values::util::slice_ref::SliceRef;
use moor_values::var::objid::Objid;
@@ -36,7 +36,7 @@ use crate::connections::{ConnectionsDB, CONNECTION_TIMEOUT_DURATION};
const CONNECTIONS_DB_MEM_SIZE: usize = 1 << 26;
pub struct ConnectionsTb {
- tb: Arc,
+ tb: Arc,
}
impl ConnectionsTb {
@@ -53,7 +53,7 @@ impl ConnectionsTb {
.collect();
relations[ConnectionRelation::ClientConnection as usize].secondary_indexed = true;
- let tb = TupleBox::new(CONNECTIONS_DB_MEM_SIZE, path, &relations, 1).await;
+ let tb = RelBox::new(CONNECTIONS_DB_MEM_SIZE, path, &relations, 1).await;
Self { tb }
}
}
diff --git a/crates/db/benches/tb_single_thread.rs b/crates/db/benches/tb_single_thread.rs
index 303afa0a..b02086c0 100644
--- a/crates/db/benches/tb_single_thread.rs
+++ b/crates/db/benches/tb_single_thread.rs
@@ -16,19 +16,19 @@
//! Does not measure single-item reads, deletes, or updates, or concurrent access.
use criterion::{black_box, criterion_group, criterion_main, Criterion};
+use moor_db::rdb::{RelBox, RelationInfo};
use moor_db::testing::jepsen::{History, Type, Value};
-use moor_db::tuplebox::{RelationInfo, TupleBox};
use moor_values::util::slice_ref::SliceRef;
use std::sync::Arc;
use std::time::{Duration, Instant};
// This is a struct that tells Criterion.rs to use the "futures" crate's current-thread executor
-use moor_db::tuplebox::RelationId;
+use moor_db::rdb::RelationId;
use moor_values::util::{BitArray, Bitset64};
use tokio::runtime::Runtime;
/// Build a test database with a bunch of relations
-async fn test_db() -> Arc {
+async fn test_db() -> Arc {
// Generate 10 test relations that we'll use for testing.
let relations = (0..63)
.map(|i| RelationInfo {
@@ -39,7 +39,7 @@ async fn test_db() -> Arc {
})
.collect::>();
- TupleBox::new(1 << 24, None, &relations, 0).await
+ RelBox::new(1 << 24, None, &relations, 0).await
}
fn from_val(value: i64) -> SliceRef {
@@ -68,7 +68,7 @@ async fn list_append_scan_workload(iters: u64, events: &Vec) -> Duratio
let start = Instant::now();
- black_box(for e in events {
+ for e in events {
match e.r#type {
Type::invoke => {
// Start a transaction.
@@ -114,7 +114,8 @@ async fn list_append_scan_workload(iters: u64, events: &Vec) -> Duratio
tx.rollback().await.unwrap();
}
}
- });
+ }
+ black_box(());
cumulative += start.elapsed();
}
cumulative
@@ -131,7 +132,7 @@ async fn list_append_seek_workload(iters: u64, events: &Vec) -> Duratio
let mut processes: BitArray<_, 256, Bitset64<8>> = BitArray::new();
let start = Instant::now();
- black_box(for e in events {
+ for e in events {
match e.r#type {
Type::invoke => {
// Start a transaction.
@@ -181,7 +182,8 @@ async fn list_append_seek_workload(iters: u64, events: &Vec) -> Duratio
tx.rollback().await.unwrap();
}
}
- });
+ }
+ black_box(());
cumulative += start.elapsed();
}
cumulative
diff --git a/crates/db/src/lib.rs b/crates/db/src/lib.rs
index 54c0e016..8e099c63 100644
--- a/crates/db/src/lib.rs
+++ b/crates/db/src/lib.rs
@@ -18,16 +18,15 @@ use moor_values::model::world_state::WorldStateSource;
use moor_values::model::WorldStateError;
use crate::loader::LoaderInterface;
-use crate::tb_worldstate::TupleBoxWorldStateSource;
+use crate::odb::RelBoxWorldState;
mod db_loader_client;
pub mod db_tx;
mod db_worldstate;
pub mod loader;
-pub mod object_relations;
-pub mod tb_worldstate;
-pub mod tuplebox;
+pub mod rdb;
+pub mod odb;
#[doc(hidden)]
pub mod testing;
@@ -63,8 +62,7 @@ impl DatabaseBuilder {
/// database was newly created, and false if it was already present.
pub async fn open_db(&self) -> Result<(Box, bool), String> {
let (db, fresh) =
- TupleBoxWorldStateSource::open(self.path.clone(), self.memory_size.unwrap_or(1 << 40))
- .await;
+ RelBoxWorldState::open(self.path.clone(), self.memory_size.unwrap_or(1 << 40)).await;
Ok((Box::new(db), fresh))
}
}
diff --git a/crates/db/src/odb/mod.rs b/crates/db/src/odb/mod.rs
new file mode 100644
index 00000000..5bf4c460
--- /dev/null
+++ b/crates/db/src/odb/mod.rs
@@ -0,0 +1,19 @@
+// Copyright (C) 2024 Ryan Daum
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation, version 3.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program. If not, see .
+//
+
+mod object_relations;
+mod rb_worldstate;
+
+pub use object_relations::{WorldStateRelation, WorldStateSequences};
+pub use rb_worldstate::{RelBoxTransaction, RelBoxWorldState};
diff --git a/crates/db/src/object_relations.rs b/crates/db/src/odb/object_relations.rs
similarity index 96%
rename from crates/db/src/object_relations.rs
rename to crates/db/src/odb/object_relations.rs
index a2159bba..b1a686f9 100644
--- a/crates/db/src/object_relations.rs
+++ b/crates/db/src/odb/object_relations.rs
@@ -21,8 +21,8 @@ use moor_values::util::slice_ref::SliceRef;
use moor_values::var::objid::Objid;
use moor_values::AsByteBuffer;
-use crate::tuplebox::TupleError;
-use crate::tuplebox::{RelationId, Transaction};
+use crate::rdb::TupleError;
+use crate::rdb::{RelationId, Transaction};
/// The set of binary relations that are used to represent the world state in the moor system.
#[repr(usize)]
@@ -204,7 +204,7 @@ async fn delete_if_exists(
}
}
-pub async fn delete_composite_if_exists(
+pub async fn delete_composite_if_exists(
tx: &Transaction,
rel: WorldStateRelation,
oid: Objid,
@@ -243,14 +243,14 @@ mod tests {
use moor_values::model::objset::ObjSet;
use moor_values::var::objid::Objid;
- use crate::object_relations::WorldStateRelation::ObjectParent;
- use crate::object_relations::{
+ use crate::odb::object_relations::WorldStateRelation::ObjectParent;
+ use crate::odb::object_relations::{
get_object_by_codomain, get_object_value, insert_object_value, upsert_object_value,
WorldStateRelation, WorldStateSequences,
};
- use crate::tuplebox::{RelationInfo, TupleBox};
+ use crate::rdb::{RelBox, RelationInfo};
- async fn test_db() -> Arc {
+ async fn test_db() -> Arc {
let mut relations: Vec = WorldStateRelation::iter()
.map(|wsr| {
RelationInfo {
@@ -264,7 +264,7 @@ mod tests {
relations[ObjectParent as usize].secondary_indexed = true;
relations[WorldStateRelation::ObjectLocation as usize].secondary_indexed = true;
- TupleBox::new(1 << 24, None, &relations, WorldStateSequences::COUNT).await
+ RelBox::new(1 << 24, None, &relations, WorldStateSequences::COUNT).await
}
/// Test simple relations mapping oid->oid (with secondary index), independent of all other
diff --git a/crates/db/src/tb_worldstate.rs b/crates/db/src/odb/rb_worldstate.rs
similarity index 97%
rename from crates/db/src/tb_worldstate.rs
rename to crates/db/src/odb/rb_worldstate.rs
index 4b044515..ef66e013 100644
--- a/crates/db/src/tb_worldstate.rs
+++ b/crates/db/src/odb/rb_worldstate.rs
@@ -21,7 +21,8 @@ use strum::{EnumCount, IntoEnumIterator};
use tracing::warn;
use uuid::Uuid;
-use crate::tuplebox::TupleError;
+use crate::rdb::TupleError;
+use crate::Database;
use moor_values::model::defset::{HasUuid, Named};
use moor_values::model::objects::{ObjAttrs, ObjFlag};
use moor_values::model::objset::ObjSet;
@@ -40,19 +41,19 @@ use moor_values::{AsByteBuffer, NOTHING, SYSTEM_OBJECT};
use crate::db_tx::DbTransaction;
use crate::db_worldstate::DbTxWorldState;
use crate::loader::LoaderInterface;
-use crate::object_relations::{
+use crate::odb::object_relations;
+use crate::odb::object_relations::{
get_all_object_keys_matching, WorldStateRelation, WorldStateSequences,
};
-use crate::tuplebox::{CommitError, Transaction};
-use crate::tuplebox::{RelationInfo, TupleBox};
-use crate::{object_relations, Database};
+use crate::rdb::{CommitError, Transaction};
+use crate::rdb::{RelBox, RelationInfo};
-/// An implementation of `WorldState` / `WorldStateSource` that uses the TupleBox as its backing
-pub struct TupleBoxWorldStateSource {
- db: Arc,
+/// An implementation of `WorldState` / `WorldStateSource` that uses the rdb as its backing
+pub struct RelBoxWorldState {
+ db: Arc,
}
-impl TupleBoxWorldStateSource {
+impl RelBoxWorldState {
pub async fn open(path: Option, memory_size: usize) -> (Self, bool) {
let mut relations: Vec = WorldStateRelation::iter()
.map(|wsr| {
@@ -69,7 +70,7 @@ 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(memory_size, path, &relations, WorldStateSequences::COUNT).await;
+ let db = RelBox::new(memory_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 = {
@@ -83,19 +84,19 @@ impl TupleBoxWorldStateSource {
}
#[async_trait]
-impl WorldStateSource for TupleBoxWorldStateSource {
+impl WorldStateSource for RelBoxWorldState {
async fn new_world_state(&self) -> Result, WorldStateError> {
- let tx = TupleBoxTransaction::new(self.db.clone());
+ let tx = RelBoxTransaction::new(self.db.clone());
return Ok(Box::new(DbTxWorldState { tx: Box::new(tx) }));
}
}
-pub struct TupleBoxTransaction {
+pub struct RelBoxTransaction {
tx: Transaction,
}
#[async_trait]
-impl DbTransaction for TupleBoxTransaction {
+impl DbTransaction for RelBoxTransaction {
async fn get_players(&self) -> Result {
// TODO: this is going to be not-at-all performant in the long run, and we'll need a way to
// cache this or index it better
@@ -304,7 +305,7 @@ impl DbTransaction for TupleBoxTransaction {
for p in old_props.iter() {
if old_ancestors.contains(&p.definer()) {
delort_props.push(p.uuid());
- object_relations::delete_composite_if_exists::(
+ object_relations::delete_composite_if_exists(
&self.tx,
WorldStateRelation::ObjectPropertyValue,
o,
@@ -343,7 +344,7 @@ impl DbTransaction for TupleBoxTransaction {
for p in old_props.iter() {
if old_ancestors.contains(&p.definer()) {
inherited_props.push(p.uuid());
- object_relations::delete_composite_if_exists::(
+ object_relations::delete_composite_if_exists(
&self.tx,
WorldStateRelation::ObjectPropertyValue,
c,
@@ -1003,8 +1004,8 @@ impl DbTransaction for TupleBoxTransaction {
}
}
-impl TupleBoxTransaction {
- pub fn new(db: Arc) -> Self {
+impl RelBoxTransaction {
+ pub fn new(db: Arc) -> Self {
let tx = db.start_tx();
Self { tx }
}
@@ -1082,9 +1083,9 @@ impl TupleBoxTransaction {
}
}
-impl Database for TupleBoxWorldStateSource {
+impl Database for RelBoxWorldState {
fn loader_client(&mut self) -> Result, WorldStateError> {
- let tx = TupleBoxTransaction::new(self.db.clone());
+ let tx = RelBoxTransaction::new(self.db.clone());
Ok(Box::new(DbTxWorldState { tx: Box::new(tx) }))
}
@@ -1111,11 +1112,11 @@ mod tests {
use moor_values::NOTHING;
use crate::db_tx::DbTransaction;
- use crate::object_relations::{WorldStateRelation, WorldStateSequences};
- use crate::tb_worldstate::TupleBoxTransaction;
- use crate::tuplebox::{RelationInfo, TupleBox};
+ use crate::odb::object_relations::{WorldStateRelation, WorldStateSequences};
+ use crate::odb::rb_worldstate::RelBoxTransaction;
+ use crate::rdb::{RelBox, RelationInfo};
- async fn test_db() -> Arc {
+ async fn test_db() -> Arc {
let mut relations: Vec = WorldStateRelation::iter()
.map(|wsr| {
RelationInfo {
@@ -1129,13 +1130,13 @@ mod tests {
relations[WorldStateRelation::ObjectParent as usize].secondary_indexed = true;
relations[WorldStateRelation::ObjectLocation as usize].secondary_indexed = true;
- TupleBox::new(1 << 24, None, &relations, WorldStateSequences::COUNT).await
+ RelBox::new(1 << 24, None, &relations, WorldStateSequences::COUNT).await
}
#[tokio::test]
async fn test_create_object() {
let db = test_db().await;
- let tx = TupleBoxTransaction::new(db.clone());
+ let tx = RelBoxTransaction::new(db.clone());
let oid = tx
.create_object(
None,
@@ -1158,7 +1159,7 @@ mod tests {
assert_eq!(tx.commit().await, Ok(CommitResult::Success));
// Verify existence in a new transaction.
- let tx = TupleBoxTransaction::new(db);
+ let tx = RelBoxTransaction::new(db);
assert!(tx.object_valid(oid).await.unwrap());
assert_eq!(tx.get_object_owner(oid).await.unwrap(), NOTHING);
}
@@ -1166,7 +1167,7 @@ mod tests {
#[tokio::test]
async fn test_create_object_fixed_id() {
let db = test_db().await;
- let tx = TupleBoxTransaction::new(db);
+ let tx = RelBoxTransaction::new(db);
// Force at 1.
let oid = tx
.create_object(Some(Objid(1)), ObjAttrs::default())
@@ -1182,7 +1183,7 @@ mod tests {
#[tokio::test]
async fn test_parent_children() {
let db = test_db().await;
- let tx = TupleBoxTransaction::new(db);
+ let tx = RelBoxTransaction::new(db);
// Single parent/child relationship.
let a = tx
@@ -1281,7 +1282,7 @@ mod tests {
#[tokio::test]
async fn test_descendants() {
let db = test_db().await;
- let tx = TupleBoxTransaction::new(db);
+ let tx = RelBoxTransaction::new(db);
let a = tx
.create_object(
@@ -1373,7 +1374,7 @@ mod tests {
#[tokio::test]
async fn test_location_contents() {
let db = test_db().await;
- let tx = TupleBoxTransaction::new(db.clone());
+ let tx = RelBoxTransaction::new(db.clone());
let a = tx
.create_object(
@@ -1483,7 +1484,7 @@ mod tests {
#[tokio::test]
async fn test_object_move_commits() {
let db = test_db().await;
- let tx = TupleBoxTransaction::new(db.clone());
+ let tx = RelBoxTransaction::new(db.clone());
let a = tx
.create_object(
@@ -1541,7 +1542,7 @@ mod tests {
assert_eq!(tx.commit().await, Ok(CommitResult::Success));
- let tx = TupleBoxTransaction::new(db.clone());
+ let tx = RelBoxTransaction::new(db.clone());
assert_eq!(tx.get_object_location(b).await.unwrap(), a);
assert_eq!(tx.get_object_location(c).await.unwrap(), a);
let contents = tx
@@ -1565,7 +1566,7 @@ mod tests {
assert_eq!(tx.get_object_contents(c).await.unwrap(), ObjSet::from(&[b]));
assert_eq!(tx.commit().await, Ok(CommitResult::Success));
- let tx = TupleBoxTransaction::new(db.clone());
+ let tx = RelBoxTransaction::new(db.clone());
assert_eq!(tx.get_object_location(b).await.unwrap(), c);
assert_eq!(tx.get_object_location(c).await.unwrap(), a);
assert_eq!(tx.get_object_contents(a).await.unwrap(), ObjSet::from(&[c]));
@@ -1576,7 +1577,7 @@ mod tests {
#[tokio::test]
async fn test_simple_property() {
let db = test_db().await;
- let tx = TupleBoxTransaction::new(db);
+ let tx = RelBoxTransaction::new(db);
let oid = tx
.create_object(
@@ -1612,7 +1613,7 @@ mod tests {
#[tokio::test]
async fn test_verb_add_update() {
let db = test_db().await;
- let tx = TupleBoxTransaction::new(db.clone());
+ let tx = RelBoxTransaction::new(db.clone());
let oid = tx
.create_object(
None,
@@ -1666,7 +1667,7 @@ mod tests {
// Now commit, and try to resolve again.
assert_eq!(tx.commit().await, Ok(CommitResult::Success));
- let tx = TupleBoxTransaction::new(db);
+ let tx = RelBoxTransaction::new(db);
let vh = tx.resolve_verb(oid, "test2".into(), None).await.unwrap();
assert_eq!(vh.names(), vec!["test2"]);
assert_eq!(tx.commit().await, Ok(CommitResult::Success));
@@ -1675,7 +1676,7 @@ mod tests {
#[tokio::test]
async fn test_transitive_property_resolution() {
let db = test_db().await;
- let tx = TupleBoxTransaction::new(db);
+ let tx = RelBoxTransaction::new(db);
let a = tx
.create_object(
@@ -1748,7 +1749,7 @@ mod tests {
#[tokio::test]
async fn test_transitive_property_resolution_clear_property() {
let db = test_db().await;
- let tx = TupleBoxTransaction::new(db);
+ let tx = RelBoxTransaction::new(db);
let a = tx
.create_object(
@@ -1809,7 +1810,7 @@ mod tests {
#[tokio::test]
async fn test_verb_resolve() {
let db = test_db().await;
- let tx = TupleBoxTransaction::new(db.clone());
+ let tx = RelBoxTransaction::new(db.clone());
let a = tx
.create_object(
@@ -1884,7 +1885,7 @@ mod tests {
assert_eq!(tx.commit().await, Ok(CommitResult::Success));
// Verify existence in a new transaction.
- let tx = TupleBoxTransaction::new(db);
+ let tx = RelBoxTransaction::new(db);
assert_eq!(
tx.resolve_verb(a, "test".into(), None)
.await
@@ -1905,7 +1906,7 @@ mod tests {
#[tokio::test]
async fn test_verb_resolve_inherited() {
let db = test_db().await;
- let tx = TupleBoxTransaction::new(db);
+ let tx = RelBoxTransaction::new(db);
let a = tx
.create_object(
@@ -1975,7 +1976,7 @@ mod tests {
#[tokio::test]
async fn test_verb_resolve_wildcard() {
let db = test_db().await;
- let tx = TupleBoxTransaction::new(db);
+ let tx = RelBoxTransaction::new(db);
let a = tx
.create_object(
None,
diff --git a/crates/db/src/tuplebox/backing.rs b/crates/db/src/rdb/backing.rs
similarity index 97%
rename from crates/db/src/tuplebox/backing.rs
rename to crates/db/src/rdb/backing.rs
index dce14294..76dfb7d0 100644
--- a/crates/db/src/tuplebox/backing.rs
+++ b/crates/db/src/rdb/backing.rs
@@ -18,7 +18,7 @@
use tokio::sync::mpsc::UnboundedSender;
-use crate::tuplebox::tx::WorkingSet;
+use crate::rdb::tx::WorkingSet;
pub struct BackingStoreClient {
sender: UnboundedSender,
diff --git a/crates/db/src/tuplebox/base_relation.rs b/crates/db/src/rdb/base_relation.rs
similarity index 99%
rename from crates/db/src/tuplebox/base_relation.rs
rename to crates/db/src/rdb/base_relation.rs
index 75d2635f..59796667 100644
--- a/crates/db/src/tuplebox/base_relation.rs
+++ b/crates/db/src/rdb/base_relation.rs
@@ -16,8 +16,8 @@ use std::collections::HashSet;
use moor_values::util::slice_ref::SliceRef;
-use crate::tuplebox::tuples::TupleRef;
-use crate::tuplebox::RelationId;
+use crate::rdb::tuples::TupleRef;
+use crate::rdb::RelationId;
/// Represents a 'canonical' base binary relation, which is a set of tuples of domain, codomain,
/// with a default (hash) index on the domain and an optional (hash) index on the codomain.
diff --git a/crates/db/src/tuplebox/coldstorage.rs b/crates/db/src/rdb/coldstorage.rs
similarity index 95%
rename from crates/db/src/tuplebox/coldstorage.rs
rename to crates/db/src/rdb/coldstorage.rs
index 89b92a5d..34c87bae 100644
--- a/crates/db/src/tuplebox/coldstorage.rs
+++ b/crates/db/src/rdb/coldstorage.rs
@@ -29,16 +29,17 @@ use tokio::sync::mpsc::UnboundedReceiver;
use tokio_eventfd::EventFd;
use tracing::{debug, error, info, warn};
-use crate::tuplebox::backing::{BackingStoreClient, WriterMessage};
-use crate::tuplebox::base_relation::BaseRelation;
-use crate::tuplebox::page_storage::{PageStore, PageStoreMutation};
-use crate::tuplebox::tb::RelationInfo;
-use crate::tuplebox::tuples::TxTuple;
-use crate::tuplebox::tuples::{PageId, SlotBox, SlotId, TupleId};
-use crate::tuplebox::tx::WorkingSet;
-use crate::tuplebox::RelationId;
-
-/// Uses WAL + custom page store as the persistent backing store & write-ahead-log for the tuplebox.
+use crate::rdb::backing::{BackingStoreClient, WriterMessage};
+use crate::rdb::base_relation::BaseRelation;
+use crate::rdb::page_storage::{PageStore, PageStoreMutation};
+use crate::rdb::paging::TupleBox;
+use crate::rdb::paging::{PageId, SlotId};
+use crate::rdb::relbox::RelationInfo;
+use crate::rdb::tuples::{TupleId, TxTuple};
+use crate::rdb::tx::WorkingSet;
+use crate::rdb::RelationId;
+
+/// Uses WAL + custom page store as the persistent backing store & write-ahead-log for the rdb.
pub struct ColdStorage {}
define_layout!(sequence_page, LittleEndian, {
@@ -63,7 +64,7 @@ impl ColdStorage {
_schema: &[RelationInfo],
relations: &mut [BaseRelation],
sequences: &mut Vec,
- slot_box: Arc,
+ tuple_box: Arc,
) -> BackingStoreClient {
let eventfd = EventFd::new(0, false).unwrap();
@@ -90,7 +91,7 @@ impl ColdStorage {
let sequence_page = sequence_page::View::new(&sequence_page[..]);
let num_sequences = sequence_page.num_sequences().read();
assert_eq!(num_sequences, sequences.len() as u64,
- "Number of sequences in the sequence page does not match the number of sequences in the tuplebox");
+ "Number of sequences in the sequence page does not match the number of sequences in the rdb");
let sequences_bytes = sequence_page.sequences().to_vec();
let sequence_size = sequence::SIZE.unwrap() as u64;
for i in 0..num_sequences {
@@ -107,7 +108,7 @@ impl ColdStorage {
let mut restored_slots = HashMap::new();
let mut restored_bytes = 0;
for (page_size, page_num, relation_id) in ids {
- let tuple_ids = slot_box
+ let tuple_ids = tuple_box
.clone()
.load_page(relation_id, page_num, |buf| {
ps.read_page_buf(page_num, relation_id, buf)
@@ -145,7 +146,7 @@ impl ColdStorage {
tokio::spawn(Self::listen_loop(
writer_receive,
wal,
- slot_box.clone(),
+ tuple_box.clone(),
page_storage.clone(),
eventfd,
));
@@ -157,7 +158,7 @@ impl ColdStorage {
async fn listen_loop(
mut writer_receive: UnboundedReceiver,
wal: WriteAheadLog,
- slot_box: Arc,
+ tuple_box: Arc,
ps: Arc>,
mut event_fd: EventFd,
) {
@@ -167,7 +168,7 @@ impl ColdStorage {
writer_message = writer_receive.recv() => {
match writer_message {
Some(WriterMessage::Commit(ts, ws, sequences)) => {
- Self::perform_writes(wal.clone(), slot_box.clone(), ts, ws, sequences).await;
+ Self::perform_writes(wal.clone(), tuple_box.clone(), ts, ws, sequences).await;
}
Some(WriterMessage::Shutdown) => {
// Flush the WAL
@@ -195,7 +196,7 @@ impl ColdStorage {
/// the changes durable.
async fn perform_writes(
wal: WriteAheadLog,
- slot_box: Arc,
+ tuple_box: Arc,
ts: u64,
ws: WorkingSet,
sequences: Vec,
@@ -260,7 +261,7 @@ impl ColdStorage {
for (page_id, r) in &dirty_pages {
// Get the slotboxy page for this tuple.
- let Ok(page) = slot_box.page_for(*page_id) else {
+ let Ok(page) = tuple_box.page_for(*page_id) else {
// If the slot or page is already gone, ce la vie, we don't need to sync it.
continue;
};
diff --git a/crates/db/src/tuplebox/mod.rs b/crates/db/src/rdb/mod.rs
similarity index 96%
rename from crates/db/src/tuplebox/mod.rs
rename to crates/db/src/rdb/mod.rs
index 340e1570..9bdb3b75 100644
--- a/crates/db/src/tuplebox/mod.rs
+++ b/crates/db/src/rdb/mod.rs
@@ -29,11 +29,12 @@ mod coldstorage;
mod page_storage;
mod pool;
-mod tb;
+mod paging;
+mod relbox;
mod tuples;
mod tx;
-pub use tb::{RelationInfo, TupleBox};
+pub use relbox::{RelBox, RelationInfo};
pub use tuples::TupleError;
pub use tx::{CommitError, Transaction};
diff --git a/crates/db/src/tuplebox/page_storage.rs b/crates/db/src/rdb/page_storage.rs
similarity index 99%
rename from crates/db/src/tuplebox/page_storage.rs
rename to crates/db/src/rdb/page_storage.rs
index 02aadd69..ea16800c 100644
--- a/crates/db/src/tuplebox/page_storage.rs
+++ b/crates/db/src/rdb/page_storage.rs
@@ -14,8 +14,8 @@
// TODO: there's no way this is "robust" enough to be used in production
-use crate::tuplebox::tuples::PageId;
-use crate::tuplebox::RelationId;
+use crate::rdb::paging::PageId;
+use crate::rdb::RelationId;
use io_uring::squeue::Flags;
use io_uring::types::Fd;
use io_uring::{opcode, IoUring};
diff --git a/crates/db/src/rdb/paging/mod.rs b/crates/db/src/rdb/paging/mod.rs
new file mode 100644
index 00000000..b2219eb2
--- /dev/null
+++ b/crates/db/src/rdb/paging/mod.rs
@@ -0,0 +1,17 @@
+use thiserror::Error;
+
+mod slotted_page;
+mod tuple_box;
+mod tuple_ptr;
+
+pub use slotted_page::SlotId;
+pub use tuple_box::{PageId, TupleBox};
+pub use tuple_ptr::TuplePtr;
+
+#[derive(Debug, Clone, Error)]
+pub enum TupleBoxError {
+ #[error("Page is full, cannot insert slot of size {0} with {1} bytes remaining")]
+ BoxFull(usize, usize),
+ #[error("Tuple not found at index {0}")]
+ TupleNotFound(usize),
+}
diff --git a/crates/db/src/tuplebox/tuples/slotted_page.rs b/crates/db/src/rdb/paging/slotted_page.rs
similarity index 86%
rename from crates/db/src/tuplebox/tuples/slotted_page.rs
rename to crates/db/src/rdb/paging/slotted_page.rs
index 867eb05e..04a39c3b 100644
--- a/crates/db/src/tuplebox/tuples/slotted_page.rs
+++ b/crates/db/src/rdb/paging/slotted_page.rs
@@ -35,7 +35,7 @@ use std::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst};
use atomic_wait::{wait, wake_all, wake_one};
use tracing::error;
-use crate::tuplebox::tuples::slotbox::SlotBoxError;
+use crate::rdb::paging::TupleBoxError;
pub type SlotId = u32;
@@ -45,7 +45,7 @@ pub type SlotId = u32;
// identical, and we can just start using them right away in a null-state without doing any
// initialization.
#[repr(C, align(8))]
-struct SlottedPageHeader {
+struct PageHeader {
// The number of bytes used in the page
used_bytes: u32,
// The length of our slots index in bytes. Starts at initial zero.
@@ -65,7 +65,7 @@ struct SlottedPageHeader {
_pin: std::marker::PhantomPinned,
}
-impl SlottedPageHeader {
+impl PageHeader {
/// Explicit unlock. Used by both the guard
fn unlock_for_writes(self: Pin<&mut Self>) {
self.lock_state.store(0, Release);
@@ -99,7 +99,7 @@ impl SlottedPageHeader {
header.used_bytes += size as u32;
header.num_slots += 1;
header.content_length += padded_size as u32;
- header.index_length += std::mem::size_of::() as u32;
+ header.index_length += std::mem::size_of::() as u32;
new_slot
}
}
@@ -116,7 +116,7 @@ impl SlottedPageHeader {
}
#[repr(C, align(8))]
-struct SlotIndexEntry {
+struct IndexEntry {
used: bool,
// The number of live references to this slot
refcount: u16,
@@ -131,7 +131,7 @@ struct SlotIndexEntry {
_pin: std::marker::PhantomPinned,
}
-impl SlotIndexEntry {
+impl IndexEntry {
// Update accounting for the presence of a new entry.
fn alloc(
mut self: Pin<&mut Self>,
@@ -203,15 +203,15 @@ pub fn slot_page_empty_size(page_size: usize) -> usize {
}
pub const fn slot_page_overhead() -> usize {
- std::mem::size_of::()
+ std::mem::size_of::()
}
pub const fn slot_index_overhead() -> usize {
- std::mem::size_of::()
+ std::mem::size_of::()
}
impl<'a> SlottedPage<'a> {
- pub fn for_page(base_address: *mut u8, page_size: usize) -> Self {
+ pub(crate) fn for_page(base_address: *mut u8, page_size: usize) -> Self {
Self {
base_address,
page_size: page_size as u32,
@@ -221,24 +221,24 @@ impl<'a> SlottedPage<'a> {
/// How much space is available in this page?
#[allow(dead_code)]
- pub fn free_space_bytes(&self) -> usize {
+ pub(crate) fn free_space_bytes(&self) -> usize {
let header = self.header();
- let used = (header.num_slots * std::mem::size_of::() as u32) as usize
+ let used = (header.num_slots * std::mem::size_of::() as u32) as usize
+ header.used_bytes as usize
- + std::mem::size_of::();
+ + std::mem::size_of::();
(self.page_size as usize).saturating_sub(used)
}
/// How many bytes are available for appending to this page (i.e. not counting the space
/// we could re-use, via e.g. used_bytes)
- pub fn available_content_bytes(&self) -> usize {
+ pub(crate) fn available_content_bytes(&self) -> usize {
let header = self.header();
let content_length = header.content_length as usize;
let index_length = header.index_length as usize;
- let header_size = std::mem::size_of::();
+ let header_size = std::mem::size_of::();
- let avail = index_length + content_length + header_size;
- (self.page_size as usize).saturating_sub(avail)
+ let consumed = index_length + content_length + header_size;
+ (self.page_size as usize).saturating_sub(consumed)
}
/// Add the slot into the page, copying it into the memory region, and returning the slot id
@@ -247,11 +247,11 @@ impl<'a> SlottedPage<'a> {
&self,
size: usize,
initial_value: Option<&[u8]>,
- ) -> Result<(SlotId, usize, Pin<&'a mut [u8]>), SlotBoxError> {
+ ) -> Result<(SlotId, usize, Pin<&'a mut [u8]>), TupleBoxError> {
// See if we can use an existing slot to put the slot in, or if there's any fit at all.
let (can_fit, fit_slot) = self.find_fit(size);
if !can_fit {
- return Err(SlotBoxError::BoxFull(size, self.available_content_bytes()));
+ return Err(TupleBoxError::BoxFull(size, self.available_content_bytes()));
}
let header = self.header_mut();
if let Some(fit_slot) = fit_slot {
@@ -290,9 +290,9 @@ impl<'a> SlottedPage<'a> {
let content_start_position = (content_start_position + 7) & !7;
// If the content start bleeds over into the index (+ our new entry), then we can't fit the slot.
- let index_entry_size = std::mem::size_of::();
+ let index_entry_size = std::mem::size_of::();
if content_start_position <= current_index_end + index_entry_size {
- return Err(SlotBoxError::BoxFull(
+ return Err(TupleBoxError::BoxFull(
size + index_entry_size,
self.available_content_bytes(),
));
@@ -362,14 +362,14 @@ impl<'a> SlottedPage<'a> {
}
/// Copy the contents of this page into a slice.
- pub fn save_into(&self, buf: &mut [u8]) {
+ pub(crate) fn save_into(&self, buf: &mut [u8]) {
let _ = self.read_lock();
let memory_as_slice =
unsafe { std::slice::from_raw_parts_mut(self.base_address, self.page_size as usize) };
buf.copy_from_slice(memory_as_slice);
}
- fn remove_slot(&self, slot_id: SlotId) -> Result<(usize, usize, bool), SlotBoxError> {
+ fn remove_slot(&self, slot_id: SlotId) -> Result<(usize, usize, bool), TupleBoxError> {
// TODO: slots at start of content-length can be removed by shrinking the content-length
// portion.
@@ -392,21 +392,21 @@ impl<'a> SlottedPage<'a> {
Ok((self.available_content_bytes(), slot_size, is_empty))
}
- pub(crate) fn refcount(&self, slot_id: SlotId) -> Result {
+ pub(crate) fn refcount(&self, slot_id: SlotId) -> Result {
let index_entry = self.get_index_entry(slot_id);
if !index_entry.used {
- return Err(SlotBoxError::TupleNotFound(slot_id as usize));
+ return Err(TupleBoxError::TupleNotFound(slot_id as usize));
}
Ok(index_entry.refcount)
}
- pub(crate) fn upcount(&self, slot_id: SlotId) -> Result<(), SlotBoxError> {
+ pub(crate) fn upcount(&self, slot_id: SlotId) -> Result<(), TupleBoxError> {
let mut index_entry = self.get_index_entry_mut(slot_id);
unsafe { index_entry.as_mut().get_unchecked_mut() }.refcount += 1;
Ok(())
}
- pub(crate) fn dncount(&self, slot_id: SlotId) -> Result {
+ pub(crate) fn dncount(&self, slot_id: SlotId) -> Result {
let mut index_entry = self.get_index_entry_mut(slot_id);
unsafe { index_entry.as_mut().get_unchecked_mut() }.refcount -= 1;
if index_entry.refcount == 0 {
@@ -415,7 +415,8 @@ impl<'a> SlottedPage<'a> {
Ok(false)
}
- fn get_slot(&self, slot_id: SlotId) -> Result, SlotBoxError> {
+ #[allow(dead_code)]
+ pub(crate) fn get_slot(&self, slot_id: SlotId) -> Result, TupleBoxError> {
// Check that the index is in bounds
let num_slots = self.header().num_slots as SlotId;
if slot_id >= num_slots {
@@ -423,14 +424,14 @@ impl<'a> SlottedPage<'a> {
"slot_id {} is out of bounds for page with {} slots",
slot_id, num_slots
);
- return Err(SlotBoxError::TupleNotFound(slot_id as usize));
+ return Err(TupleBoxError::TupleNotFound(slot_id as usize));
}
// Read the index entry;
let index_entry = self.get_index_entry(slot_id);
if !index_entry.used {
error!("slot_id {} is not used, invalid tuple", slot_id);
- return Err(SlotBoxError::TupleNotFound(slot_id as usize));
+ return Err(TupleBoxError::TupleNotFound(slot_id as usize));
}
let offset = index_entry.offset as usize;
let length = index_entry.used_bytes as usize;
@@ -443,17 +444,17 @@ impl<'a> SlottedPage<'a> {
Ok(unsafe { Pin::new_unchecked(&memory_as_slice[offset..offset + length]) })
}
- fn get_slot_mut(&self, slot_id: SlotId) -> Result, SlotBoxError> {
+ fn get_slot_mut(&self, slot_id: SlotId) -> Result, TupleBoxError> {
// Check that the index is in bounds
let num_slots = self.header().num_slots as SlotId;
if slot_id >= num_slots {
- return Err(SlotBoxError::TupleNotFound(slot_id as usize));
+ return Err(TupleBoxError::TupleNotFound(slot_id as usize));
}
// Read the index entry;
let index_entry = self.get_index_entry(slot_id);
if !index_entry.used {
- return Err(SlotBoxError::TupleNotFound(slot_id as usize));
+ return Err(TupleBoxError::TupleNotFound(slot_id as usize));
}
let offset = index_entry.offset as usize;
let length = index_entry.used_bytes as usize;
@@ -550,27 +551,27 @@ impl<'a> SlottedPage<'a> {
}
#[inline]
- fn header(&self) -> Pin<&SlottedPageHeader> {
+ fn header(&self) -> Pin<&PageHeader> {
// Cast the base address to a pointear to the header
- let header_ptr = self.base_address as *const SlottedPageHeader;
+ let header_ptr = self.base_address as *const PageHeader;
unsafe { Pin::new_unchecked(&*header_ptr) }
}
#[inline]
- fn header_mut(&self) -> Pin<&mut SlottedPageHeader> {
+ fn header_mut(&self) -> Pin<&mut PageHeader> {
// Cast the base address to a pointer to the header
- let header_ptr = self.base_address as *mut SlottedPageHeader;
+ let header_ptr = self.base_address as *mut PageHeader;
unsafe { Pin::new_unchecked(&mut *header_ptr) }
}
/// Return the offset, size of the slot at the given index.
- fn offset_of(&self, tid: SlotId) -> Result<(usize, usize), SlotBoxError> {
+ fn offset_of(&self, tid: SlotId) -> Result<(usize, usize), TupleBoxError> {
// Check that the index is in bounds
let num_slots = self.header().num_slots as SlotId;
if tid >= num_slots {
- return Err(SlotBoxError::TupleNotFound(tid as usize));
+ return Err(TupleBoxError::TupleNotFound(tid as usize));
}
// Read the index entry;
@@ -602,7 +603,7 @@ impl<'a> SlottedPage<'a> {
let index_length = header.index_length as isize;
let content_length = header.content_length as isize;
- let header_size = std::mem::size_of::() as isize;
+ let header_size = std::mem::size_of::() as isize;
let total_needed = index_length + content_length + header_size;
// Align to 8-byte boundary cuz that's what we'll actually need.
@@ -615,9 +616,9 @@ impl<'a> SlottedPage<'a> {
(avail >= size as isize, None)
}
- fn get_index_entry(&self, slot_id: SlotId) -> Pin<&SlotIndexEntry> {
- let index_offset = std::mem::size_of::()
- + ((slot_id as usize) * std::mem::size_of::());
+ fn get_index_entry(&self, slot_id: SlotId) -> Pin<&IndexEntry> {
+ let index_offset = std::mem::size_of::()
+ + ((slot_id as usize) * std::mem::size_of::());
let base_address = self.base_address;
@@ -630,13 +631,13 @@ impl<'a> SlottedPage<'a> {
"slot {} is not 8-byte aligned",
slot_id
);
- Pin::new_unchecked(&*(slot_address as *const SlotIndexEntry))
+ Pin::new_unchecked(&*(slot_address as *const IndexEntry))
}
}
- fn get_index_entry_mut(&self, slot_id: SlotId) -> Pin<&mut SlotIndexEntry> {
- let index_offset = std::mem::size_of::()
- + ((slot_id as usize) * std::mem::size_of::());
+ fn get_index_entry_mut(&self, slot_id: SlotId) -> Pin<&mut IndexEntry> {
+ let index_offset = std::mem::size_of::()
+ + ((slot_id as usize) * std::mem::size_of::());
let base_address = self.base_address;
unsafe {
@@ -648,7 +649,7 @@ impl<'a> SlottedPage<'a> {
"slot {} is not 8-byte aligned",
slot_id
);
- Pin::new_unchecked(&mut *(slot_address as *mut SlotIndexEntry))
+ Pin::new_unchecked(&mut *(slot_address as *mut IndexEntry))
}
}
}
@@ -661,12 +662,8 @@ pub struct PageWriteGuard<'a> {
}
impl<'a> PageWriteGuard<'a> {
- pub fn get_slot_mut(&mut self, slot_id: SlotId) -> Result, SlotBoxError> {
- let sp = SlottedPage {
- base_address: self.base_address,
- page_size: self.page_size,
- _marker: Default::default(),
- };
+ pub fn get_slot_mut(&mut self, slot_id: SlotId) -> Result, TupleBoxError> {
+ let sp = SlottedPage::for_page(self.base_address, self.page_size as usize);
sp.get_slot_mut(slot_id)
}
@@ -675,38 +672,25 @@ impl<'a> PageWriteGuard<'a> {
&mut self,
size: usize,
initial_value: Option<&[u8]>,
- ) -> Result<(SlotId, usize, Pin<&'a mut [u8]>), SlotBoxError> {
- let sp = SlottedPage {
- base_address: self.base_address,
- page_size: self.page_size,
- _marker: Default::default(),
- };
+ ) -> Result<(SlotId, usize, Pin<&'a mut [u8]>), TupleBoxError> {
+ let sp = SlottedPage::for_page(self.base_address, self.page_size as usize);
sp.allocate(size, initial_value)
}
- pub fn remove_slot(&mut self, slot_id: SlotId) -> Result<(usize, usize, bool), SlotBoxError> {
- let sp = SlottedPage {
- base_address: self.base_address,
- page_size: self.page_size,
- _marker: Default::default(),
- };
+ pub fn remove_slot(&mut self, slot_id: SlotId) -> Result<(usize, usize, bool), TupleBoxError> {
+ let sp = SlottedPage::for_page(self.base_address, self.page_size as usize);
sp.remove_slot(slot_id)
}
#[inline(always)]
- pub fn upcount(&mut self, slot_id: SlotId) -> Result<(), SlotBoxError> {
- let sp = SlottedPage {
- base_address: self.base_address,
- page_size: self.page_size,
- _marker: Default::default(),
- };
+ pub fn upcount(&mut self, slot_id: SlotId) -> Result<(), TupleBoxError> {
+ let sp = SlottedPage::for_page(self.base_address, self.page_size as usize);
sp.upcount(slot_id)
}
#[inline]
- fn header_mut(&self) -> Pin<&mut SlottedPageHeader> {
- let header_ptr = self.base_address as *mut SlottedPageHeader;
-
+ fn header_mut(&self) -> Pin<&mut PageHeader> {
+ let header_ptr = self.base_address as *mut PageHeader;
unsafe { Pin::new_unchecked(&mut *header_ptr) }
}
}
@@ -728,19 +712,16 @@ pub struct PageReadGuard<'a> {
impl<'a> PageReadGuard<'a> {
#[inline(always)]
- fn header(&self) -> Pin<&SlottedPageHeader> {
- let header_ptr = self.base_address as *const SlottedPageHeader;
+ fn header(&self) -> Pin<&PageHeader> {
+ let header_ptr = self.base_address as *const PageHeader;
unsafe { Pin::new_unchecked(&*header_ptr) }
}
#[inline(always)]
- pub fn get_slot(&self, slot_id: SlotId) -> Result, SlotBoxError> {
- let sp = SlottedPage {
- base_address: self.base_address as _,
- page_size: self.page_size as _,
- _marker: Default::default(),
- };
+ #[allow(dead_code)]
+ pub(crate) fn get_slot(&self, slot_id: SlotId) -> Result, TupleBoxError> {
+ let sp = SlottedPage::for_page(self.base_address as *mut u8, self.page_size as usize);
sp.get_slot(slot_id)
}
}
@@ -762,10 +743,8 @@ impl<'a> Drop for PageReadGuard<'a> {
#[cfg(test)]
mod tests {
- use crate::tuplebox::tuples::slotbox::SlotBoxError;
- use crate::tuplebox::tuples::slotted_page::{
- slot_page_empty_size, SlotId, SlotIndexEntry, SlottedPage,
- };
+ use crate::rdb::paging::slotted_page::{slot_page_empty_size, IndexEntry, SlotId, SlottedPage};
+ use crate::rdb::paging::TupleBoxError;
fn random_fill(page: &SlottedPage) -> Vec<(SlotId, Vec)> {
let mut collected_slots = vec![];
@@ -775,12 +754,12 @@ mod tests {
let result = page.allocate(size, Some(&vec![123; size]));
// If avail can't fit the size of the slot plus the index entry, then we should be
// getting an error.
- if avail < size + std::mem::size_of::() {
- assert!(matches!(result, Err(SlotBoxError::BoxFull(_, _))));
+ if avail < size + std::mem::size_of::() {
+ assert!(matches!(result, Err(TupleBoxError::BoxFull(_, _))));
break;
}
// Sometimes we can cease allocation because that's how the cookie crumbles with padding,
- if matches!(result, Err(SlotBoxError::BoxFull(_, _))) {
+ if matches!(result, Err(TupleBoxError::BoxFull(_, _))) {
break;
}
// Otherwise, we should be getting a slot id and a new avail that is smaller than the
@@ -845,7 +824,7 @@ mod tests {
page.remove_slot(*tid).unwrap();
assert!(matches!(
page.get_slot(*tid),
- Err(SlotBoxError::TupleNotFound(_))
+ Err(TupleBoxError::TupleNotFound(_))
));
removed_slots.push(*tid);
}
diff --git a/crates/db/src/tuplebox/tuples/slotbox.rs b/crates/db/src/rdb/paging/tuple_box.rs
similarity index 82%
rename from crates/db/src/tuplebox/tuples/slotbox.rs
rename to crates/db/src/rdb/paging/tuple_box.rs
index fa27df7f..3ac66ead 100644
--- a/crates/db/src/tuplebox/tuples/slotbox.rs
+++ b/crates/db/src/rdb/paging/tuple_box.rs
@@ -16,8 +16,8 @@
// most common case of fixed-size tuples.
// TODO: implement the ability to expire and page-out tuples based on LRU or random/second
// chance eviction (ala leanstore). will require separate PageIds from Bids, and will
-// involve rewriting SlotPtr on the fly to point to a new page when restored.
-// SlotPtr will also get a new field for last-access-time, so that we can do our eviction
+// involve rewriting TuplePtr on the fly to point to a new page when restored.
+// TuplePtr will also get a new field for last-access-time, so that we can do our eviction
// TODO: store indexes in here, too (custom paged datastructure impl)
// TODO: verify locking/concurrency safety of this thing -- loom test, stateright, or jepsen, etc.
// TODO: there is still some really gross stuff in here about the management of free space in
@@ -26,8 +26,6 @@
// to be a sporadic failure where we end up with a "Page not found" error in the allocator on
// free, meaning the page was not found in the used pages list.
// whether any of this is worth futzing with after the fixed-size impl is done, I don't know.
-// TODO: rename me, _I_ am the tuplebox. The "slots" are just where my tuples get stored. tho once
-// indexes are in here, things will get confusing (everything here assumes pages hold tuples)
use std::cmp::max;
use std::collections::HashMap;
@@ -36,35 +34,24 @@ use std::sync::atomic::Ordering::SeqCst;
use std::sync::{Arc, Mutex};
use moor_values::util::{BitArray, Bitset64};
-use thiserror::Error;
-use tracing::{error, warn};
-
-use crate::tuplebox::pool::{Bid, BufferPool, PagerError};
-pub use crate::tuplebox::tuples::slotted_page::SlotId;
-use crate::tuplebox::tuples::slotted_page::{
- slot_index_overhead, slot_page_empty_size, SlottedPage,
-};
-use crate::tuplebox::tuples::tuple_ptr::TuplePtr;
-use crate::tuplebox::tuples::{TupleId, TupleRef};
-use crate::tuplebox::RelationId;
+use tracing::warn;
+
+use crate::rdb::paging::slotted_page::{slot_index_overhead, slot_page_empty_size, SlottedPage};
+use crate::rdb::paging::tuple_ptr::TuplePtr;
+use crate::rdb::paging::TupleBoxError;
+use crate::rdb::pool::{Bid, BufferPool, PagerError};
+use crate::rdb::tuples::{TupleId, TupleRef};
+use crate::rdb::RelationId;
pub type PageId = usize;
-/// A SlotBox is a collection of (variable sized) pages, each of which is a collection of slots, each of which is holds
+/// A TupleBox is a collection of (variable sized) pages, each of which is a collection of slots, each of which is holds
/// dynamically sized tuples.
-pub struct SlotBox {
+pub struct TupleBox {
inner: Mutex,
}
-#[derive(Debug, Clone, Error)]
-pub enum SlotBoxError {
- #[error("Page is full, cannot insert slot of size {0} with {1} bytes remaining")]
- BoxFull(usize, usize),
- #[error("Tuple not found at index {0}")]
- TupleNotFound(usize),
-}
-
-impl SlotBox {
+impl TupleBox {
pub fn new(virt_size: usize) -> Self {
let pool = BufferPool::new(virt_size).expect("Could not create buffer pool");
let inner = Mutex::new(Inner::new(pool));
@@ -73,23 +60,32 @@ impl SlotBox {
/// Allocates a new slot for a tuple, somewhere in one of the pages we managed.
/// Does not allow tuples from different relations to mix on the same page.
+ #[inline(always)]
pub fn allocate(
self: Arc,
size: usize,
relation_id: RelationId,
initial_value: Option<&[u8]>,
- ) -> Result {
+ ) -> Result {
let mut inner = self.inner.lock().unwrap();
inner.do_alloc(size, relation_id, initial_value, &self)
}
+ #[inline(always)]
+ pub fn get(&self, id: TupleId) -> Result {
+ let mut inner = self.inner.lock().unwrap();
+ inner.do_get(id)
+ }
+
+ /// Restore a page for `relation_id` from secondary storage, returning references to all the
+ /// tuples discovered in it as a result.
pub(crate) fn load_page)>(
self: Arc,
relation_id: RelationId,
id: PageId,
mut lf: LF,
- ) -> Result, SlotBoxError> {
+ ) -> Result, TupleBoxError> {
let mut inner = self.inner.lock().unwrap();
// Re-allocate the page.
@@ -100,16 +96,16 @@ impl SlotBox {
lf(buf);
});
- // Now make sure we have swizrefs for all of them.
+ // Now make sure we have pointers for all of them.
let mut refs = vec![];
for (slot, buflen, addr) in slot_ids.into_iter() {
let tuple_id = TupleId { page: id, slot };
let swizref = Box::pin(TuplePtr::create(self.clone(), tuple_id, addr, buflen));
- inner.swizrefs.insert(tuple_id, swizref);
- let swizref = inner.swizrefs.get_mut(&tuple_id).unwrap();
- let sp = unsafe { Pin::into_inner_unchecked(swizref.as_mut()) };
+ inner.tuple_ptrs.insert(tuple_id, swizref);
+ let tuple_ptr = inner.tuple_ptrs.get_mut(&tuple_id).unwrap();
+ let sp = unsafe { Pin::into_inner_unchecked(tuple_ptr.as_mut()) };
let ptr = sp as *mut TuplePtr;
- let tuple_ref = TupleRef::at_ptr(ptr);
+ let tuple_ref = TupleRef::at_tptr(ptr);
refs.push(tuple_ref);
}
// The allocator needs to know that this page is used.
@@ -118,26 +114,26 @@ impl SlotBox {
}
#[inline(always)]
- pub(crate) fn page_for<'a>(&self, id: PageId) -> Result, SlotBoxError> {
+ pub(crate) fn page_for<'a>(&self, id: PageId) -> Result, TupleBoxError> {
let inner = self.inner.lock().unwrap();
inner.page_for(id)
}
- pub fn refcount(&self, id: TupleId) -> Result {
+ pub fn refcount(&self, id: TupleId) -> Result {
let inner = self.inner.lock().unwrap();
let page_handle = inner.page_for(id.page)?;
page_handle.refcount(id.slot)
}
#[inline(always)]
- pub fn upcount(&self, id: TupleId) -> Result<(), SlotBoxError> {
+ pub fn upcount(&self, id: TupleId) -> Result<(), TupleBoxError> {
let inner = self.inner.lock().unwrap();
let page_handle = inner.page_for(id.page)?;
page_handle.upcount(id.slot)
}
#[inline(always)]
- pub fn dncount(&self, id: TupleId) -> Result<(), SlotBoxError> {
+ pub fn dncount(&self, id: TupleId) -> Result<(), TupleBoxError> {
let mut inner = self.inner.lock().unwrap();
let page_handle = inner.page_for(id.page)?;
if page_handle.dncount(id.slot)? {
@@ -146,47 +142,11 @@ impl SlotBox {
Ok(())
}
- #[inline(always)]
- pub fn get(&self, id: TupleId) -> Result, SlotBoxError> {
- let inner = self.inner.lock().unwrap();
- let page_handle = inner.page_for(id.page)?;
-
- let lock = page_handle.read_lock();
-
- let slc = lock.get_slot(id.slot)?;
- Ok(slc)
- }
-
- pub fn update(
- self: Arc,
- relation_id: RelationId,
- id: TupleId,
- new_value: &[u8],
- ) -> Result