From a4b813881a47bb9d8aa528a9598cfdb052ae231e Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Mon, 6 Jan 2025 19:28:41 +0200 Subject: Move primary_key and secondary_keys configuration to Recordable --- log_db/src/common.rs | 2 ++ log_db/src/lib.rs | 62 ++++++++++++++++++++-------------------------------- log_db/src/record.rs | 9 +++++++- 3 files changed, 34 insertions(+), 39 deletions(-) (limited to 'log_db/src') diff --git a/log_db/src/common.rs b/log_db/src/common.rs index a3ff5c2..4f5751d 100644 --- a/log_db/src/common.rs +++ b/log_db/src/common.rs @@ -242,6 +242,7 @@ impl Display for WriteDurability { #[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] pub enum IndexableValue { + Null, Int(i64), String(String), } @@ -393,6 +394,7 @@ impl Value { pub fn as_indexable(&self) -> Option { match self { + Value::Null => Some(IndexableValue::Null), Value::Int(i) => Some(IndexableValue::Int(*i)), Value::String(s) => Some(IndexableValue::String(s.clone())), _ => None, diff --git a/log_db/src/lib.rs b/log_db/src/lib.rs index 2cfcfbe..0709a8e 100644 --- a/log_db/src/lib.rs +++ b/log_db/src/lib.rs @@ -22,26 +22,25 @@ use std::collections::BTreeMap; use std::fmt::Debug; use std::fs::{self}; use std::io::{self, Read, Seek, SeekFrom, Write}; +use std::marker::PhantomData; use std::path::{Path, PathBuf}; pub struct ConfigBuilder { data_dir: Option, segment_size: Option, - primary_key: Option, - secondary_keys: Option>, write_durability: Option, read_consistency: Option, + _marker: PhantomData, } -impl<'a, R: Recordable> ConfigBuilder { +impl ConfigBuilder { pub fn new() -> ConfigBuilder { - ConfigBuilder:: { + ConfigBuilder { data_dir: None, segment_size: None, - primary_key: None, - secondary_keys: None, write_durability: None, read_consistency: None, + _marker: PhantomData, } } @@ -60,21 +59,6 @@ impl<'a, R: Recordable> ConfigBuilder { self } - /// The primary key of the database, used to construct - /// the primary memtable index. This should be the field - /// that is most frequently queried. - pub fn primary_key(&mut self, primary_key: R::Field) -> &mut Self { - self.primary_key = Some(primary_key); - self - } - - /// The secondary keys of the database, used to construct - /// the secondary memtable indexes. - pub fn secondary_keys(&mut self, secondary_keys: &[R::Field]) -> &mut Self { - self.secondary_keys = Some(secondary_keys.to_vec()); - self - } - /// The write durability policy for the database. /// This determines how writes are persisted to disk. /// The default is WriteDurability::Flush. @@ -93,15 +77,12 @@ impl<'a, R: Recordable> ConfigBuilder { } pub fn initialize(&self) -> Result, DBError> { - let config = Config:: { + let config = Config { + fields: R::schema(), + primary_key: R::primary_key(), + secondary_keys: R::secondary_keys(), data_dir: self.data_dir.clone().unwrap_or("db_data".to_string()), segment_size: self.segment_size.unwrap_or(4 * 1024 * 1024), // 4MB - fields: R::schema(), - primary_key: self.primary_key.clone().ok_or(io::Error::new( - io::ErrorKind::InvalidInput, - "Required config value \"primary_key\" is not set", - ))?, - secondary_keys: self.secondary_keys.clone().unwrap_or(Vec::new()), write_durability: self .write_durability .clone() @@ -118,17 +99,18 @@ impl<'a, R: Recordable> ConfigBuilder { #[derive(Clone)] struct Config { - pub data_dir: String, - pub segment_size: usize, pub fields: Vec<(R::Field, ValueType)>, pub primary_key: R::Field, pub secondary_keys: Vec, + pub data_dir: String, + pub segment_size: usize, pub write_durability: WriteDurability, pub read_consistency: ReadConsistency, } pub struct DB { config: Config, + data_dir: PathBuf, active_metadata_file: fs::File, active_data_file: fs::File, @@ -879,6 +861,12 @@ mod tests { impl Recordable for TestInst1 { type Field = Field; + fn schema() -> Vec<(Field, ValueType)> { + vec![(Field::Id, ValueType::int())] + } + fn primary_key() -> Self::Field { + Field::Id + } fn into_record(self) -> Vec { vec![Value::Int(self.id)] @@ -893,10 +881,6 @@ mod tests { }, } } - - fn schema() -> Vec<(Field, ValueType)> { - vec![(Field::Id, ValueType::int())] - } } struct TestInst2 { @@ -906,6 +890,12 @@ mod tests { impl Recordable for TestInst2 { type Field = Field; + fn primary_key() -> Self::Field { + Field::Id + } + fn secondary_keys() -> Vec { + vec![Field::Name] + } fn into_record(self) -> Vec { vec![Value::Int(self.id), Value::String(self.name)] @@ -944,7 +934,6 @@ mod tests { let mut db = DB::::configure() .data_dir(data_dir.to_str().unwrap()) .segment_size(segment_size) - .primary_key(Field::Id) .initialize() .expect("Failed to create DB"); @@ -1028,7 +1017,6 @@ mod tests { let mut db = DB::::configure() .data_dir(data_dir.to_str().unwrap()) - .primary_key(Field::Id) .initialize() .expect("Failed to create DB"); @@ -1080,8 +1068,6 @@ mod tests { let mut db = DB::::configure() .data_dir(data_dir.to_str().unwrap()) - .primary_key(Field::Id) - .secondary_keys(&[Field::Name]) .initialize() .expect("Failed to create DB"); diff --git a/log_db/src/record.rs b/log_db/src/record.rs index 1b882ed..8d518f0 100644 --- a/log_db/src/record.rs +++ b/log_db/src/record.rs @@ -104,8 +104,15 @@ impl Record { pub trait Recordable { /// The field type of the data structure implementing the `Recordable` trait. type Field: Eq + Clone + Debug; - /// Define the schema of the data structure implementing the `Recordable` trait. + /// Define the schema of the instance implementing the `Recordable` trait. fn schema() -> Vec<(Self::Field, ValueType)>; + /// Define the primary key of the instance implementing the `Recordable` trait. + fn primary_key() -> Self::Field; + /// Define the secondary keys of the instance implementing the `Recordable` trait. + fn secondary_keys() -> Vec { + Vec::new() + } + /// Convert the data structure implementing the `Recordable` trait into a vector of database values. fn into_record(self) -> Vec; /// Convert a vector of database values into the data structure implementing the `Recordable` trait. -- cgit v1.3