From bea37e2834a5265035b960277ff27e5f8d74d079 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 21 Feb 2025 14:16:24 +0200 Subject: Start working in new schema logic to core --- log_db/src/common.rs | 5 +---- log_db/src/config.rs | 34 +++++++++++++++--------------- log_db/src/engine.rs | 25 +++++++++++++++------- log_db/src/lib.rs | 59 +++++++++++++++++++++++++++++++++++----------------- 4 files changed, 75 insertions(+), 48 deletions(-) (limited to 'log_db/src') diff --git a/log_db/src/common.rs b/log_db/src/common.rs index 9bafdd4..ca9f451 100644 --- a/log_db/src/common.rs +++ b/log_db/src/common.rs @@ -289,10 +289,7 @@ impl Value { } } -pub fn get_secondary_memtable_index_by_field( - sks: &Vec, - field: &Field, -) -> Option { +pub fn get_secondary_memtable_index_by_field(sks: &Vec, field: &str) -> Option { sks.iter().position(|schema_field| schema_field == field) } diff --git a/log_db/src/config.rs b/log_db/src/config.rs index 5b3cf26..ec74164 100644 --- a/log_db/src/config.rs +++ b/log_db/src/config.rs @@ -6,23 +6,23 @@ pub struct Schema { pub secondary_keys: Vec, } -pub struct ConfigBuilder { +pub struct ConfigBuilder { data_dir: Option, segment_size: Option, write_durability: Option, read_consistency: Option, - fields: Option>, - primary_key: Option, - secondary_keys: Option>, + fields: Option>, + primary_key: Option, + secondary_keys: Option>, from_record: Option) -> T>, into_record: Option Vec>, _marker: PhantomData, } -impl ConfigBuilder { - pub fn new() -> ConfigBuilder { +impl ConfigBuilder { + pub fn new() -> ConfigBuilder { ConfigBuilder { data_dir: None, segment_size: None, @@ -71,18 +71,18 @@ impl ConfigBuilder { self } - pub fn fields(mut self, schema: Vec) -> Self { - self.fields = Some(schema); + pub fn fields(mut self, schema: Vec>) -> Self { + self.fields = Some(schema.into_iter().map(|s| s.into()).collect()); self } - pub fn primary_key(mut self, primary_key: F) -> Self { - self.primary_key = Some(primary_key); + pub fn primary_key(mut self, primary_key: impl Into) -> Self { + self.primary_key = Some(primary_key.into()); self } - pub fn secondary_keys(mut self, secondary_keys: Vec) -> Self { - self.secondary_keys = Some(secondary_keys); + pub fn secondary_keys(mut self, secondary_keys: Vec>) -> Self { + self.secondary_keys = Some(secondary_keys.into_iter().map(|s| s.into()).collect()); self } @@ -96,7 +96,7 @@ impl ConfigBuilder { self } - pub fn initialize(self) -> DBResult> { + pub fn initialize(self) -> DBResult> { let schema = self .fields .ok_or_else(|| DBError::ValidationError("Schema not set".to_string()))?; @@ -134,10 +134,10 @@ impl ConfigBuilder { } #[derive(Clone)] -pub struct Config { - pub schema: Vec, - pub primary_key: F, - pub secondary_keys: Vec, +pub struct Config { + pub schema: Vec, + pub primary_key: String, + pub secondary_keys: Vec, pub from_record: fn(Vec) -> T, pub into_record: fn(T) -> Vec, pub data_dir: String, diff --git a/log_db/src/engine.rs b/log_db/src/engine.rs index c2f9a52..b06bfd2 100644 --- a/log_db/src/engine.rs +++ b/log_db/src/engine.rs @@ -1,7 +1,7 @@ use super::*; -pub struct Engine { - pub config: Config, +pub struct Engine { + pub config: Config, pub lock_manager: LockManager, data_dir_path: PathBuf, @@ -19,8 +19,8 @@ pub struct Engine { pub secondary_memtables: Vec, } -impl Engine { - pub fn initialize(config: Config) -> DBResult> { +impl Engine { + pub fn initialize(config: Config) -> DBResult> { info!("Initializing DB..."); // If data_dir does not exist or is empty, create it and any necessary files. // After creation, the directory should always be in a complete state without missing files. @@ -104,7 +104,7 @@ impl Engine { Path::new(&config.data_dir).join(active_metadata_header.uuid.to_string()); let active_data_file = APPEND_MODE.open(&active_data_path)?; - let mut engine = Engine:: { + let mut engine = Engine:: { config, lock_manager, data_dir_path, @@ -247,7 +247,7 @@ impl Engine { pub fn batch_find_by_records<'a>( &mut self, - field: &F, + field: &str, values: impl Iterator, params: &QueryParams, ) -> DBResult> { @@ -378,7 +378,7 @@ impl Engine { pub fn range_by_records>( &mut self, - field: &F, + field: &str, range: B, params: &QueryParams, ) -> DBResult> { @@ -458,7 +458,7 @@ impl Engine { } } - pub fn delete_by_field(&mut self, field: &F, value: &Value) -> DBResult> { + pub fn delete_by_field(&mut self, field: &str, value: &Value) -> DBResult> { let recs: Vec = self .batch_find_by_records(field, std::iter::once(value), &DEFAULT_QUERY_PARAMS)? .into_iter() @@ -737,6 +737,15 @@ mod tests { Name, } + impl Into for Field { + fn into(self) -> String { + match self { + Field::Id => "id".to_owned(), + Field::Name => "name".to_owned(), + } + } + } + #[derive(PartialEq, Eq, Debug, Clone)] struct TestInst2 { id: i64, diff --git a/log_db/src/lib.rs b/log_db/src/lib.rs index 753e41c..fddb344 100644 --- a/log_db/src/lib.rs +++ b/log_db/src/lib.rs @@ -37,17 +37,17 @@ use memtable_primary::PrimaryMemtable; use memtable_secondary::SecondaryMemtable; use record::*; -pub struct DB { - engine: Engine, +pub struct DB { + engine: Engine, } -impl DB { +impl DB { /// Create a new database configuration builder. - pub fn configure() -> ConfigBuilder { + pub fn configure() -> ConfigBuilder { ConfigBuilder::new() } - fn initialize(config: Config) -> DBResult> { + fn initialize(config: Config) -> DBResult> { let engine = Engine::initialize(config)?; Ok(DB { engine }) } @@ -85,9 +85,13 @@ impl DB { } /// Get a collection of records based on an indexed field value. - pub fn find_by(&mut self, field: &F, value: &Value) -> DBResult> { + pub fn find_by(&mut self, field: impl AsRef, value: &Value) -> DBResult> { let recs = self.engine.with_shared_lock(|engine| { - engine.batch_find_by_records(field, std::iter::once(value), &DEFAULT_QUERY_PARAMS) + engine.batch_find_by_records( + field.as_ref(), + std::iter::once(value), + &DEFAULT_QUERY_PARAMS, + ) })?; Ok(recs @@ -99,12 +103,12 @@ impl DB { /// Get a collection of records based on an indexed field value, with additional parameters. pub fn find_by_with_params( &mut self, - field: &F, + field: impl AsRef, value: &Value, params: &QueryParams, ) -> DBResult> { let recs = self.engine.with_shared_lock(|engine| { - engine.batch_find_by_records(field, std::iter::once(value), params) + engine.batch_find_by_records(field.as_ref(), std::iter::once(value), params) })?; Ok(recs @@ -116,9 +120,13 @@ impl DB { /// Get a collection of records based on a sequence of indexed field values. /// Returns a vector of pairs where the first value is an index into the given sequence of values, /// and the second value is the record. - pub fn batch_find_by(&mut self, field: &F, values: &[Value]) -> DBResult> { + pub fn batch_find_by( + &mut self, + field: impl Into, + values: &[Value], + ) -> DBResult> { let recs = self.engine.with_shared_lock(|engine| { - engine.batch_find_by_records(field, values.iter(), &DEFAULT_QUERY_PARAMS) + engine.batch_find_by_records(&field.into(), values.iter(), &DEFAULT_QUERY_PARAMS) })?; Ok(recs @@ -132,12 +140,12 @@ impl DB { /// and the second value is the record. pub fn batch_find_by_with_params( &mut self, - field: &F, + field: impl AsRef, values: &[Value], params: &QueryParams, ) -> DBResult> { let recs = self.engine.with_shared_lock(|engine| { - engine.batch_find_by_records(field, values.iter(), params) + engine.batch_find_by_records(field.as_ref(), values.iter(), params) })?; Ok(recs @@ -149,9 +157,13 @@ impl DB { /// Get a collection of records based on a range of indexed field values. /// This method can be used to run comparison-like queries, e.g. `field >= 10` /// could be expressed as `db.range_by(Field::Id, 10..)`. - pub fn range_by>(&mut self, field: &F, range: B) -> DBResult> { + pub fn range_by>( + &mut self, + field: impl AsRef, + range: B, + ) -> DBResult> { let recs = self.engine.with_shared_lock(|engine| { - engine.range_by_records(field, range, &DEFAULT_QUERY_PARAMS) + engine.range_by_records(field.as_ref(), range, &DEFAULT_QUERY_PARAMS) })?; Ok(recs @@ -165,13 +177,13 @@ impl DB { /// could be expressed as `db.range_by(Field::Id, 10..)`. pub fn range_by_with_params>( &mut self, - field: &F, + field: impl AsRef, range: B, params: &QueryParams, ) -> DBResult> { let recs = self .engine - .with_shared_lock(|engine| engine.range_by_records(field, range, params))?; + .with_shared_lock(|engine| engine.range_by_records(field.as_ref(), range, params))?; Ok(recs .into_iter() @@ -185,10 +197,10 @@ impl DB { /// /// Deletion is done by marking the record as a tombstone. The record will still be present in the log file, /// but will be ignored by reads. Upon compaction, tombstoned records will be removed. - pub fn delete_by(&mut self, field: &F, value: &Value) -> DBResult> { + pub fn delete_by(&mut self, field: impl AsRef, value: &Value) -> DBResult> { let recs = self .engine - .with_exclusive_lock(|engine| engine.delete_by_field(field, value))?; + .with_exclusive_lock(|engine| engine.delete_by_field(field.as_ref(), value))?; Ok(recs .into_iter() @@ -295,6 +307,15 @@ mod tests { Name, } + impl Into for Field { + fn into(self) -> String { + match self { + Field::Id => "id".to_string(), + Field::Name => "name".to_string(), + } + } + } + struct TestInst1 { id: i64, } -- cgit v1.3