diff --git a/storage_engine/src/error.rs b/storage_engine/src/error.rs index 10a74ae..2c7817c 100644 --- a/storage_engine/src/error.rs +++ b/storage_engine/src/error.rs @@ -15,6 +15,7 @@ pub enum DecodeErrorKind { EntryData, EntryIsDeleted, EntryHeaderWithDataSizes, + CorruptedData, } // ===Errors=== diff --git a/storage_engine/src/index.rs b/storage_engine/src/index.rs index c28c91e..628b136 100644 --- a/storage_engine/src/index.rs +++ b/storage_engine/src/index.rs @@ -1,18 +1,20 @@ use std::marker::PhantomData; -use tokio::io::{AsyncReadExt, AsyncWriteExt, AsyncSeekExt, SeekFrom}; -use tokio::fs::{File, OpenOptions, DirBuilder}; use std::path::Path; +use tokio::fs::{DirBuilder, File, OpenOptions}; +use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt, SeekFrom}; -use std::collections::{BTreeMap}; use async_trait::async_trait; +use std::collections::{BTreeMap, HashSet}; +use std::hash::Hash; +use crate::binary_coding::{decode, decode_sequence, encode, encode_sequence}; use bincode; use bincode::{Decode, Encode}; -use crate::binary_coding::{encode, decode, encode_sequence, decode_sequence}; use tokio::fs; -use crate::error::Error; +use crate::error::{DecodeErrorKind, Error}; +use bincode::error::DecodeError; use std::mem::size_of; type Result = std::result::Result; @@ -23,67 +25,126 @@ type Result = std::result::Result; #[derive(Debug)] pub struct Index { file: File, - // None means index is asleep on disk. - in_memory: Option>, - header: IndexHeader, + data: BTreeMap>, key_type: PhantomData, value_type: PhantomData, } #[derive(Debug)] -pub struct IndexHeader { -} +pub struct IndexHeader {} -use crate::storage_engine::FilePosition; +impl Index +where + K: Encode + Decode + Ord, + V: Encode + Decode + Clone + Eq + Hash, +{ + pub async fn new(file_name: &str) -> Result> { + let file: File = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(file_name) + .await?; -#[async_trait] -pub trait SomethingSupportingLeq { - async fn less_than_eq(&mut self, file_position0: FilePosition, file_position1: FilePosition) -> std::result::Result; -} + let data = BTreeMap::new(); -impl Index { - // TODO: delete - // pub async fn new(file_name: &str, less_than_eq: &F) -> Result> - // where F: Fn(&mut Store, K, K) -> Fut, - // Store: SomethingSupportingLeq, - // Fut: Future>, - // { - // todo!() - // } - pub async fn new(file_name: &str) -> Result> - { - todo!() + Ok(Index { + file, + data, + key_type: PhantomData::, + value_type: PhantomData::, + }) } pub async fn connect(file_name: &str) -> Result> { - todo!() + let mut file: File = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(file_name) + .await?; + + let mut bytes = vec![]; + file.read_to_end(&mut bytes).await?; + + let data = Index::decode_tree(&bytes) + .map_err(|e| Error::DecodeError(DecodeErrorKind::CorruptedData, e))?; + + Ok(Index { + file, + data, + key_type: PhantomData::, + value_type: PhantomData::, + }) } - // Saves the in-memory index to disk and deallocates. - pub async fn sleep() -> Result> { - todo!() + pub async fn insert(&mut self, k: K, v: V) -> Result<()> { + self.data.entry(k).or_insert_with(HashSet::new).insert(v); + Ok(()) } - // Loads the index into memory - pub async fn wake() -> Result> { - todo!() + pub async fn lookup(&self, k: K) -> Result>> { + let hashset = self.data.get(&k).unwrap(); + Ok(Some(hashset.clone())) } - pub async fn insert() -> Result<()> - where K: Encode, V: Encode - { - todo!() + pub async fn delete(&mut self, k: K, v: V) -> Result> { + Ok(Some( + self.data.entry(k).or_insert_with(HashSet::new).remove(&v), + )) } - pub async fn lookup(&mut self, store: &mut Store, k: K) -> Result> - where K: Encode + Decode, - Store: SomethingSupportingLeq, - { - let x = store.less_than_eq(123, 123).await?; - todo!() + fn encode(&self) -> Result> { + let mut encoded = Vec::new(); + encoded.extend(encode(&self.data)?); + Ok(encoded) } - pub async fn delete(&mut self, k: K) -> Result> { - todo!() + fn decode_tree(data: &[u8]) -> std::result::Result>, DecodeError> { + let data: BTreeMap> = decode(data)?.0; + Ok(data) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn encode_decode() { + let mut index: Index = Index { + file: File::from_std(std::fs::File::create("test").unwrap()), + data: BTreeMap::new(), + key_type: PhantomData::, + value_type: PhantomData::, + }; + + index.insert("foo".to_string(), 123).await.unwrap(); + index.insert("foo".to_string(), 124).await.unwrap(); + index.insert("bar".to_string(), 125).await.unwrap(); + index.insert("bar".to_string(), 126).await.unwrap(); + + let lookup = index.lookup("foo".to_string()).await.unwrap().unwrap(); + assert_eq!(lookup.len(), 2); + assert!(lookup.contains(&123)); + assert!(lookup.contains(&124)); + println!("lookup {:?}", lookup); + + let encoded = index.encode().unwrap(); + let decoded = Index::::decode_tree(&encoded).unwrap(); + let decoded = Index { + file: File::from_std(std::fs::File::create("test").unwrap()), + data: decoded, + key_type: PhantomData::, + value_type: PhantomData::, + }; + + let lookup = decoded.lookup("foo".to_string()).await.unwrap().unwrap(); + assert_eq!(lookup.len(), 2); + assert!(lookup.contains(&123)); + assert!(lookup.contains(&124)); + println!("lookup {:?}", lookup); + + println!("{encoded:?}") } } diff --git a/storage_engine/src/storage_engine.rs b/storage_engine/src/storage_engine.rs index 4284f74..e27c8a4 100644 --- a/storage_engine/src/storage_engine.rs +++ b/storage_engine/src/storage_engine.rs @@ -53,15 +53,6 @@ pub async fn less_than_eq(store: &mut Store, file_position0: FilePosition, todo!() } -#[async_trait] -impl SomethingSupportingLeq for Store - where T: Send -{ - async fn less_than_eq(&mut self, file_position0: FilePosition, file_position1: FilePosition) -> std::result::Result { - Ok(true) - } -} - pub const ROWS_FILE_NAME: &'static str = "rows"; impl Store {