Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion db/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "db-rs"
version = "0.3.3"
version = "0.3.5"
edition = "2021"
description = "fast, embedded, transactional, key value store"
license = "BSD-3-Clause"
Expand All @@ -12,6 +12,7 @@ clone = []
[dependencies]
serde = { version = "1.0", features = ["derive"] }
bincode = "1.3.3"
uuid = { version = "1.2.2", features = ["v4"] }

[target.'cfg(not(target_family = "wasm"))'.dependencies]
fs2 = "0.4.3"
Expand Down
3 changes: 3 additions & 0 deletions db/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ pub use crate::logger::TxHandle;
pub use crate::list::List;
pub use crate::lookup::LookupTable;
pub use crate::lookup_list::LookupList;
pub use crate::lookup_map::LookupMap;
pub use crate::lookup_set::LookupSet;
pub use crate::single::Single;

Expand All @@ -120,9 +121,11 @@ pub mod list;
pub mod logger;
pub mod lookup;
pub mod lookup_list;
pub mod lookup_map;
pub mod lookup_set;
pub mod single;
pub mod table;
pub mod utils;

pub type TableId = u8;
pub type ByteCount = u32;
8 changes: 7 additions & 1 deletion db/src/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use std::sync::{Arc, Mutex};
use fs2::FileExt;

pub struct LogFormat<'a> {
pub index: usize,
pub table_id: TableId,
pub bytes: &'a [u8],
}
Expand Down Expand Up @@ -77,7 +78,10 @@ impl Logger {
let mut entries = vec![];

while index < buffer.len() {
let index_capture = index + 2;
println!("{index}, {index_capture}");
if buffer.len() < index + 4 + 1 {
eprintln!("size missing!");
self.inner.lock()?.incomplete_write = true;
return Ok(entries);
}
Expand All @@ -93,16 +97,18 @@ impl Logger {
index += 4;

if buffer.len() < index + size {
eprintln!("expected {} found {}", index + size, buffer.len());
self.inner.lock()?.incomplete_write = true;
return Ok(entries);
}

if table_id == 0 {
println!("TABLE_ID == 0");
continue;
}

let bytes = &buffer[index..index + size];
entries.push(LogFormat { table_id, bytes });
entries.push(LogFormat { index: index_capture, table_id, bytes });
index += size;
}

Expand Down
155 changes: 155 additions & 0 deletions db/src/lookup_map.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
use crate::table::Table;
use crate::{DbResult, Logger, TableId};
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::hash::Hash;

/// A special case of [crate::lookup::LookupTable] where the value of the [HashMap] is another `HashMap<K2, V>`.
#[derive(Debug)]
#[cfg_attr(feature = "clone", derive(Clone))]
pub struct LookupMap<K1, K2, V>
where
K1: Hash + Eq + Serialize,
K2: Hash + Eq + Serialize,
V: Serialize + DeserializeOwned,
{
table_id: TableId,
inner: HashMap<K1, HashMap<K2, V>>,
pub logger: Logger,
}

#[derive(Serialize, Deserialize)]
pub enum LogEntry<K1, K2, V> {
Insert(K1, K2, V),
Remove(K1, K2),
CreateKey(K1),
ClearKey(K1),
Clear,
}

impl<K1, K2, V> Table for LookupMap<K1, K2, V>
where
K1: Hash + Eq + Serialize + DeserializeOwned,
K2: Hash + Eq + Serialize + DeserializeOwned,
V: Serialize + DeserializeOwned,
{
fn init(table_id: TableId, logger: Logger) -> Self {
Self { table_id, inner: HashMap::default(), logger }
}

fn handle_event(&mut self, bytes: &[u8]) -> DbResult<()> {
match bincode::deserialize::<LogEntry<K1, K2, V>>(bytes)? {
LogEntry::Insert(k1, k2, v) => {
self.insert_inner(k1, k2, v);
}
LogEntry::Remove(k1, k2) => {
if let Some(map) = self.inner.get_mut(&k1) {
map.remove(&k2);
};
}
LogEntry::CreateKey(k1) => {
self.inner.insert(k1, HashMap::new());
}
LogEntry::ClearKey(k1) => {
self.inner.remove(&k1);
}
LogEntry::Clear => {
self.inner.clear();
}
};

Ok(())
}

fn compact_repr(&self) -> DbResult<Vec<u8>> {
let mut repr = vec![];
for (k1, values) in &self.inner {
if values.is_empty() {
let data = bincode::serialize(&LogEntry::<&K1, &K2, &V>::CreateKey(k1))?;
let mut data = Logger::log_entry(self.table_id, data);
repr.append(&mut data);
continue;
}
for (k2, v) in values {
let data = bincode::serialize(&LogEntry::Insert(k1, k2, v))?;
let mut data = Logger::log_entry(self.table_id, data);
repr.append(&mut data);
}
}

Ok(repr)
}
}

impl<K1, K2, V> LookupMap<K1, K2, V>
where
K1: Hash + Eq + Serialize + DeserializeOwned,
K2: Hash + Eq + Serialize + DeserializeOwned,
V: Serialize + DeserializeOwned,
{
pub(crate) fn insert_inner(&mut self, k1: K1, k2: K2, v: V) -> Option<V> {
if let Some(map) = self.inner.get_mut(&k1) {
map.insert(k2, v)
} else {
let mut map = HashMap::new();
map.insert(k2, v);
self.inner.insert(k1, map);
None
}
}

pub fn insert(&mut self, k1: K1, k2: K2, v: V) -> DbResult<Option<V>> {
let log_entry = LogEntry::Insert(&k1, &k2, &v);
let data = bincode::serialize(&log_entry)?;
let ret = self.insert_inner(k1, k2, v);

self.logger.write(self.table_id, data)?;
Ok(ret)
}

pub fn create_key(&mut self, key: K1) -> DbResult<Option<HashMap<K2, V>>> {
let log_entry = LogEntry::<&K1, K2, &V>::CreateKey(&key);
let data = bincode::serialize(&log_entry)?;

let ret = self.inner.insert(key, HashMap::new());

self.logger.write(self.table_id, data)?;
Ok(ret)
}

pub fn remove(&mut self, k1: &K1, k2: &K2) -> DbResult<Option<V>> {
if let Some(map) = self.inner.get_mut(k1) {
let log_entry = LogEntry::Remove::<&K1, &K2, V>(k1, k2);
let data = bincode::serialize(&log_entry)?;
self.logger.write(self.table_id, data)?;
Ok(map.remove(k2))
} else {
Ok(None)
}
}

pub fn clear_key(&mut self, k1: &K1) -> DbResult<Option<HashMap<K2, V>>> {
let log_entry = LogEntry::ClearKey::<&K1, K2, V>(k1);
let data = bincode::serialize(&log_entry)?;

let ret = self.inner.remove(k1);

self.logger.write(self.table_id, data)?;

Ok(ret)
}

pub fn get(&self) -> &HashMap<K1, HashMap<K2, V>> {
&self.inner
}

pub fn clear(&mut self) -> DbResult<()> {
self.inner.clear();
let log_entry = LogEntry::<K1, K2, V>::Clear;
let data = bincode::serialize(&log_entry)?;
self.logger.write(self.table_id, data)?;

Ok(())
}
}
5 changes: 5 additions & 0 deletions db/src/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
use uuid::Uuid;

pub fn random_test_dir() -> String {
format!("/tmp/{}", Uuid::new_v4())
}
4 changes: 2 additions & 2 deletions db/tests/clone_feature_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
mod clone_feature {
use std::fs;

use db_rs::*;
use db_rs::{utils::random_test_dir, *};
use db_rs_derive::Schema;

#[derive(Schema, Clone)]
Expand All @@ -17,7 +17,7 @@ mod clone_feature {

#[test]
fn test() {
let dir = "/tmp/o/";
let dir = &random_test_dir();
drop(fs::remove_dir_all(dir));
let mut db = CloneFT::init(Config::in_folder(dir)).unwrap();
db.table1.insert(5, "test".to_string()).unwrap();
Expand Down
10 changes: 5 additions & 5 deletions db/tests/list_tests.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use db_rs::{Config, Db, List};
use db_rs::{utils::random_test_dir, Config, Db, List};
use db_rs_derive::Schema;
use std::fs;

Expand All @@ -11,7 +11,7 @@ struct Schema {

#[test]
fn list_test() {
let dir = "/tmp/j/";
let dir = &random_test_dir();
drop(fs::remove_dir_all(dir));
let mut db = Schema::init(Config::in_folder(dir)).unwrap();
db.list1.push("a".to_string()).unwrap();
Expand All @@ -26,7 +26,7 @@ fn list_test() {

#[test]
fn list_test2() {
let dir = "/tmp/k/";
let dir = &random_test_dir();
drop(fs::remove_dir_all(dir));
let mut db = Schema::init(Config::in_folder(dir)).unwrap();
db.list1.push("a".to_string()).unwrap();
Expand Down Expand Up @@ -56,7 +56,7 @@ fn list_test2() {

#[test]
fn list_test3() {
let dir = "/tmp/kk/";
let dir = &random_test_dir();
drop(fs::remove_dir_all(dir));
let mut db = Schema::init(Config::in_folder(dir)).unwrap();
db.list1.push("a".to_string()).unwrap();
Expand Down Expand Up @@ -90,7 +90,7 @@ fn list_test3() {

#[test]
fn list_test_clear() {
let dir = "/tmp/kkk/";
let dir = &random_test_dir();
drop(fs::remove_dir_all(dir));
let mut db = Schema::init(Config::in_folder(dir)).unwrap();
db.list1.push("a".to_string()).unwrap();
Expand Down
7 changes: 4 additions & 3 deletions db/tests/log_tests.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use db_rs::compacter::BackgroundCompacter;
use db_rs::utils::random_test_dir;
use db_rs::{CancelSig, Config, Db, LookupTable, Single};
use db_rs_derive::Schema;
use std::fs::{remove_dir_all, OpenOptions};
Expand All @@ -15,7 +16,7 @@ pub struct LogTests {

#[test]
fn log_compaction() {
let dir = "/tmp/e";
let dir = &random_test_dir();
drop(remove_dir_all(dir));

let mut db = LogTests::init(Config::in_folder(dir)).unwrap();
Expand Down Expand Up @@ -43,7 +44,7 @@ fn log_compaction() {

#[test]
fn inter_log() {
let dir = "/tmp/f";
let dir = &random_test_dir();
drop(remove_dir_all(dir));

let mut db = LogTests::init(Config::in_folder(dir)).unwrap();
Expand Down Expand Up @@ -93,7 +94,7 @@ fn no_io_tests() {
#[test]
#[ignore] // ignored so tests don't get stuck here
fn auto_log_compacter() {
let dir = "/tmp/fa";
let dir = &random_test_dir();
drop(remove_dir_all(dir));
let db = Arc::new(Mutex::new(LogTests::init(Config::in_folder(dir)).unwrap()));
let cancel = CancelSig::default();
Expand Down
7 changes: 4 additions & 3 deletions db/tests/lookup_list_tests.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use db_rs::utils::random_test_dir;
use db_rs::Db;
use db_rs::{Config, LookupList};
use db_rs_derive::Schema;
Expand All @@ -14,7 +15,7 @@ pub struct LookupSchema {

#[test]
fn test() {
let dir = "/tmp/o/";
let dir = &random_test_dir();
drop(fs::remove_dir_all(dir));
let mut db = LookupSchema::init(Config::in_folder(dir)).unwrap();
db.table1.push(5, "test".to_string()).unwrap();
Expand All @@ -28,7 +29,7 @@ fn test() {

#[test]
fn test2() {
let dir = "/tmp/p/";
let dir = &random_test_dir();

drop(fs::remove_dir_all(dir));
let mut db = LookupSchema::init(Config::in_folder(dir)).unwrap();
Expand Down Expand Up @@ -77,7 +78,7 @@ fn test2() {

#[test]
fn test3() {
let dir = "/tmp/q/";
let dir = &random_test_dir();

drop(fs::remove_dir_all(dir));
let mut db = LookupSchema::init(Config::in_folder(dir)).unwrap();
Expand Down
Loading