aboutsummaryrefslogtreecommitdiffstats
path: root/log_db/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'log_db/src/lib.rs')
-rw-r--r--log_db/src/lib.rs112
1 files changed, 53 insertions, 59 deletions
diff --git a/log_db/src/lib.rs b/log_db/src/lib.rs
index b7229fe..006056c 100644
--- a/log_db/src/lib.rs
+++ b/log_db/src/lib.rs
@@ -8,7 +8,6 @@ use std::fmt::Debug;
use std::fmt::Display;
use std::fs::{self, metadata, File};
use std::io::{self, Read, Seek, SeekFrom, Write};
-use std::marker::PhantomData;
use std::ops::*;
use std::path::{Path, PathBuf};
use std::thread;
@@ -23,10 +22,14 @@ mod lock;
mod log_reader_forward;
mod memtable_primary;
mod memtable_secondary;
+mod record;
mod row;
+mod schema;
pub use common::{DBError, DBResult, OwnedBounds, QueryParams, Value, DEFAULT_QUERY_PARAMS};
-pub use config::{ReadConsistency, Schema, WriteDurability};
+pub use config::{ReadConsistency, WriteDurability};
+pub use record::Record;
+pub use schema::Schema;
use common::*;
use config::*;
@@ -37,25 +40,28 @@ use memtable_primary::PrimaryMemtable;
use memtable_secondary::SecondaryMemtable;
use row::*;
-pub struct DB<T> {
- engine: Engine<T>,
+pub struct DB {
+ engine: Engine,
}
-impl<T> DB<T> {
+impl DB {
/// Create a new database configuration builder.
- pub fn configure() -> ConfigBuilder<T> {
+ pub fn configure() -> ConfigBuilder {
ConfigBuilder::new()
}
- fn initialize(config: Config<T>) -> DBResult<DB<T>> {
+ fn initialize(config: Config) -> DBResult<DB> {
let engine = Engine::initialize(config)?;
Ok(DB { engine })
}
/// Insert a record into the database. If the primary key value already exists,
/// the existing record will be replaced by the supplied one.
- pub fn upsert(&mut self, recordable: T) -> DBResult<()> {
- let row = Row::from(&(self.engine.config.into_record)(recordable));
+ pub fn upsert(&mut self, record: impl Into<Record>) -> DBResult<()> {
+ let row = Row {
+ values: record.into().into(),
+ tombstone: false,
+ };
debug!("Upserting record: {:?}", row);
self.engine
@@ -66,7 +72,7 @@ impl<T> DB<T> {
/// Get a record by its primary index value.
/// E.g. `db.get(Value::Int(10))`.
- pub fn get(&mut self, value: &Value) -> DBResult<Option<T>> {
+ pub fn get(&mut self, value: &Value) -> DBResult<Option<Record>> {
let tagged_rows = self.engine.with_shared_lock(|engine| {
engine.batch_find_by_records(
// TODO: This clone is only here to appease the borrow checker
@@ -81,12 +87,12 @@ impl<T> DB<T> {
Ok(tagged_rows
.into_iter()
.next()
- .map(|(_, row)| (self.engine.config.from_record)(row.values)))
+ .map(|(_, row)| Record::from(row)))
}
/// Get a collection of records based on an indexed field value.
- pub fn find_by(&mut self, field: impl AsRef<str>, value: &Value) -> DBResult<Vec<T>> {
- let recs = self.engine.with_shared_lock(|engine| {
+ pub fn find_by(&mut self, field: impl AsRef<str>, value: &Value) -> DBResult<Vec<Record>> {
+ let tagged_rows = self.engine.with_shared_lock(|engine| {
engine.batch_find_by_records(
field.as_ref(),
std::iter::once(value),
@@ -94,9 +100,9 @@ impl<T> DB<T> {
)
})?;
- Ok(recs
+ Ok(tagged_rows
.into_iter()
- .map(|(_, rec)| (self.engine.config.from_record)(rec.values))
+ .map(|(_, row)| Record::from(row))
.collect())
}
@@ -106,15 +112,12 @@ impl<T> DB<T> {
field: impl AsRef<str>,
value: &Value,
params: &QueryParams,
- ) -> DBResult<Vec<T>> {
+ ) -> DBResult<Vec<Record>> {
let recs = self.engine.with_shared_lock(|engine| {
engine.batch_find_by_records(field.as_ref(), std::iter::once(value), params)
})?;
- Ok(recs
- .into_iter()
- .map(|(_, rec)| (self.engine.config.from_record)(rec.values))
- .collect())
+ Ok(recs.into_iter().map(|(_, row)| Record::from(row)).collect())
}
/// Get a collection of records based on a sequence of indexed field values.
@@ -124,14 +127,14 @@ impl<T> DB<T> {
&mut self,
field: impl Into<String>,
values: &[Value],
- ) -> DBResult<Vec<(usize, T)>> {
+ ) -> DBResult<Vec<(usize, Record)>> {
let recs = self.engine.with_shared_lock(|engine| {
engine.batch_find_by_records(&field.into(), values.iter(), &DEFAULT_QUERY_PARAMS)
})?;
Ok(recs
.into_iter()
- .map(|(tag, rec)| (tag, (self.engine.config.from_record)(rec.values)))
+ .map(|(tag, row)| (tag, Record::from(row)))
.collect())
}
@@ -143,14 +146,14 @@ impl<T> DB<T> {
field: impl AsRef<str>,
values: &[Value],
params: &QueryParams,
- ) -> DBResult<Vec<(usize, T)>> {
+ ) -> DBResult<Vec<(usize, Record)>> {
let recs = self.engine.with_shared_lock(|engine| {
engine.batch_find_by_records(field.as_ref(), values.iter(), params)
})?;
Ok(recs
.into_iter()
- .map(|(tag, rec)| (tag, (self.engine.config.from_record)(rec.values)))
+ .map(|(tag, row)| (tag, Record::from(row)))
.collect())
}
@@ -161,15 +164,12 @@ impl<T> DB<T> {
&mut self,
field: impl AsRef<str>,
range: B,
- ) -> DBResult<Vec<T>> {
+ ) -> DBResult<Vec<Record>> {
let recs = self.engine.with_shared_lock(|engine| {
engine.range_by_records(field.as_ref(), range, &DEFAULT_QUERY_PARAMS)
})?;
- Ok(recs
- .into_iter()
- .map(|rec| (self.engine.config.from_record)(rec.values))
- .collect())
+ Ok(recs.into_iter().map(|row| Record::from(row)).collect())
}
/// Get a collection of records based on a range of indexed field values, with additional parameters.
@@ -180,15 +180,12 @@ impl<T> DB<T> {
field: impl AsRef<str>,
range: B,
params: &QueryParams,
- ) -> DBResult<Vec<T>> {
+ ) -> DBResult<Vec<Record>> {
let recs = self
.engine
.with_shared_lock(|engine| engine.range_by_records(field.as_ref(), range, params))?;
- Ok(recs
- .into_iter()
- .map(|rec| (self.engine.config.from_record)(rec.values))
- .collect())
+ Ok(recs.into_iter().map(|row| Record::from(row)).collect())
}
/// Delete records by a field value.
@@ -197,19 +194,19 @@ impl<T> DB<T> {
///
/// 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: impl AsRef<str>, value: &Value) -> DBResult<Vec<T>> {
+ pub fn delete_by(&mut self, field: impl AsRef<str>, value: &Value) -> DBResult<Vec<Record>> {
let recs = self
.engine
.with_exclusive_lock(|engine| engine.delete_by_field(field.as_ref(), value))?;
Ok(recs
.into_iter()
- .map(|rec| (self.engine.config.from_record)(rec.values))
+ .map(|row| Record::from(row.values))
.collect())
}
/// Delete record by primary key.
- pub fn delete(&mut self, pk: &Value) -> DBResult<Option<T>> {
+ pub fn delete(&mut self, pk: &Value) -> DBResult<Option<Record>> {
let recs = self.engine.with_exclusive_lock(|engine| {
engine
// TODO: This clone is only here to appease the borrow checker
@@ -218,10 +215,7 @@ impl<T> DB<T> {
assert!(recs.len() <= 1);
- Ok(recs
- .into_iter()
- .next()
- .map(|rec| (self.engine.config.from_record)(rec.values)))
+ Ok(recs.into_iter().next().map(|row| Record::from(row.values)))
}
/// Check if there are any pending tasks and do them. Tasks include:
@@ -320,12 +314,14 @@ mod tests {
id: i64,
}
- impl TestInst1 {
- fn into_record(self) -> Vec<Value> {
- vec![Value::Int(self.id)]
+ impl From<TestInst1> for Record {
+ fn from(inst: TestInst1) -> Self {
+ vec![Value::Int(inst.id)].into()
}
+ }
- fn from_record(record: Vec<Value>) -> Self {
+ impl From<Record> for TestInst1 {
+ fn from(record: Record) -> Self {
let mut it = record.into_iter();
TestInst1 {
id: match it.next().unwrap() {
@@ -341,12 +337,14 @@ mod tests {
name: String,
}
- impl TestInst2 {
- fn into_record(self) -> Vec<Value> {
- vec![Value::Int(self.id), Value::String(self.name)]
+ impl From<TestInst2> for Record {
+ fn from(inst: TestInst2) -> Self {
+ vec![Value::Int(inst.id), Value::String(inst.name)].into()
}
+ }
- fn from_record(record: Vec<Value>) -> Self {
+ impl From<Record> for TestInst2 {
+ fn from(record: Record) -> Self {
let mut it = record.into_iter();
TestInst2 {
id: match it.next().unwrap() {
@@ -373,8 +371,6 @@ mod tests {
.data_dir(data_dir.to_str().unwrap())
.fields(vec![Field::Id])
.primary_key(Field::Id)
- .from_record(TestInst1::from_record)
- .into_record(TestInst1::into_record)
.segment_size(segment_size)
.initialize()
.expect("Failed to create DB");
@@ -436,17 +432,19 @@ mod tests {
);
// Check that the records can be read
- let inst0 = db
+ let inst0: TestInst1 = db
.get(&Value::Int(0 as i64))
.expect("Failed to get record")
- .expect("Record not found");
+ .expect("Record not found")
+ .into();
assert!(inst0.id == 0);
- let inst1 = db
+ let inst1: TestInst1 = db
.get(&Value::Int(1 as i64))
.expect("Failed to get record")
- .expect("Record not found");
+ .expect("Record not found")
+ .into();
assert!(inst1.id == 1);
}
@@ -460,8 +458,6 @@ mod tests {
.data_dir(data_dir.to_str().unwrap())
.fields(vec![Field::Id])
.primary_key(Field::Id)
- .from_record(TestInst1::from_record)
- .into_record(TestInst1::into_record)
.initialize()
.expect("Failed to create DB");
@@ -515,8 +511,6 @@ mod tests {
.fields(vec![Field::Id, Field::Name])
.primary_key(Field::Id)
.secondary_keys(vec![Field::Name])
- .from_record(TestInst2::from_record)
- .into_record(TestInst2::into_record)
.initialize()
.expect("Failed to create DB");