use core::mem::size_of;
use subway::skiplist::SkipList;
use crate::errors::Errors;
use crate::options::DharmaOpts;
use crate::persistence::Persistence;
use crate::traits::{ResourceKey, ResourceValue};
pub struct Dharma<K: ResourceKey, V: ResourceValue> {
options: DharmaOpts,
memory: SkipList<K, V>,
persistence: Persistence<K>,
size: usize,
}
impl<'a, K, V> Dharma<K, V>
where
K: ResourceKey,
V: ResourceValue,
{
pub fn create(options: DharmaOpts) -> Result<Dharma<K, V>, Errors> {
let persistence_result = Persistence::create::<V>(options.clone());
return persistence_result.map(move |persistence| Dharma {
memory: SkipList::new(),
size: 0,
persistence,
options,
});
}
pub fn get(&mut self, key: &K) -> Result<Option<V>, Errors> {
let maybe_in_memory = self.memory.get(key);
if maybe_in_memory.is_some() {
let retrieved_value = maybe_in_memory.unwrap();
let marker: V = V::nil();
if marker == retrieved_value {
return Ok(None);
}
return Ok(Some(retrieved_value));
}
self.persistence.get::<V>(key)
}
pub fn put(&mut self, key: K, value: V) -> Result<(), Errors> {
let wal_insert_result = self.persistence.insert(key.clone(), value.clone());
if wal_insert_result.is_ok() {
self.memory.insert(key.clone(), value.clone());
self.size += size_of::<K>() + size_of::<V>();
if self.size >= self.options.memtable_size_in_bytes {
return self.flush();
}
return Ok(());
}
Err(Errors::WAL_WRITE_FAILED)
}
pub fn delete(&mut self, key: K) -> Result<(), Errors> {
let value: V = V::nil();
return self.put(key, value);
}
pub fn recover<T: ResourceKey, U: ResourceValue>(
options: DharmaOpts,
) -> Result<Dharma<T, U>, Errors> {
let data = Persistence::<T>::recover(options.clone())?;
let mut db = Dharma::create(options.clone())?;
for (key, value) in data {
db.put(key, value);
}
return Ok(db);
}
pub fn flush(&mut self) -> Result<(), Errors> {
let flush_memory_result = self.persistence.flush(&self.memory.collect());
if flush_memory_result.is_ok() {
self.reset_memory();
return Ok(());
}
return flush_memory_result;
}
pub fn in_memory_size(&self) -> usize {
self.size
}
fn reset_memory(&mut self) {
self.memory = SkipList::new();
self.size = 0;
}
}
impl<K, V> Drop for Dharma<K, V>
where
K: ResourceKey,
V: ResourceValue,
{
fn drop(&mut self) {
self.flush();
}
}