use std::{borrow::Cow, ops::Range};
use crate::errors::Error;
use self::allocator::Allocator;
use super::layer::Layer;
pub mod allocator;
#[derive(Debug)]
pub struct StackDB<'l, A: Allocator<'l>> {
alloc: A,
heap_layer: bool,
layers: Vec<Layer<'l, A::LayerStream>>,
}
impl<'l, A: Allocator<'l>> StackDB<'l, A> {
#[inline]
pub fn new(alloc: A) -> Self {
Self {
alloc,
heap_layer: false,
layers: Vec::new(),
}
}
#[inline]
fn get_heap_layer(&mut self) -> Result<&mut Layer<'l, A::LayerStream>, Error> {
if self.heap_layer {
return Ok(self.layers.last_mut().unwrap());
}
self.layers.push(self.alloc.add_layer()?);
self.heap_layer = true;
self.get_heap_layer()
}
#[inline]
pub fn read(&mut self, addr: Range<u64>) -> Result<Box<[u8]>, Error> {
let mut data = vec![0u8; (addr.end-addr.start) as usize].into_boxed_slice();
let mut missing: Vec<Range<u64>> = vec![addr.clone()]; #[inline]
fn write_into(data: &[u8], out: &mut [u8]) {
data.iter()
.enumerate()
.for_each(|(i, b)| out[i] = *b);
}
for layer in self.layers.iter_mut().rev() {
if missing.is_empty() { break };
let mut collisions = Vec::new();
let mut non_collisions = Vec::new();
for miss in missing.iter() {
let mut miss_collisions = layer.check_collisions(miss)?;
miss_collisions.sort_unstable_by_key(|r| r.start); non_collisions.append(&mut layer.check_non_collisions(miss, &miss_collisions).into_vec());
collisions.append(&mut miss_collisions.into_vec());
} missing = non_collisions;
for range in collisions.iter() {
let read = layer.read_unchecked(range)?;
write_into(&read.1[read.0], &mut data[(range.start-addr.start) as usize..(range.end-addr.start) as usize]);
}
}
Ok(data)
}
#[inline]
pub fn rebase(&mut self, buffer_size: u64) -> Result<(), Error> {
if self.layers.is_empty() || self.layers.last().unwrap().bounds.is_none() { return Ok(()) }; self.flush()?;
let old_layers = self.layers.len();
let db_bounds = self.layers.iter()
.filter_map(|x| x.bounds.as_ref())
.fold((u64::MAX, u64::MIN), |x, y| (std::cmp::min(x.0, y.start), std::cmp::max(x.1, y.end)));
let db_bounds = db_bounds.0..db_bounds.1;
let mut idx = db_bounds.start;
while idx < db_bounds.end {
let end = std::cmp::min(db_bounds.end, idx+buffer_size);
let buffer = self.read(idx..end)?;
self.write(idx, &buffer)?;
self.flush()?; idx = end;
}
self.alloc.rebase(old_layers)?;
let mut layers = Vec::with_capacity(self.layers.len()-old_layers);
layers.extend(self.layers.drain(old_layers..));
self.layers = layers;
Ok(())
}
#[inline]
pub fn write(&mut self, addr: u64, data: &[u8]) -> Result<(), Error> {
let layer = self.get_heap_layer()?;
let range = addr..addr + data.len() as u64;
let collisions = layer.check_collisions(&range)?;
let non_collisions = layer.check_non_collisions(&range, &collisions);
for r in non_collisions.iter() {
let r_normal = (r.start-addr)as usize..(r.end-addr)as usize;
let mut data = data[r_normal].to_vec();
data.shrink_to_fit();
layer.write_unchecked(r.start, Cow::Owned(data))?;
}
if !collisions.is_empty() {
self.flush()?;
for r in collisions.iter() {
let r_normal = (r.start-addr)as usize..(r.end-addr)as usize;
self.write(r.start, &data[r_normal])?; }
}
Ok(())
}
#[inline]
pub fn flush(&mut self) -> Result<(), Error> {
if !self.heap_layer { return Ok(()) };
let layer = self.layers.last_mut().unwrap();
if layer.bounds.is_none() { return Ok(()) };
layer.flush()?;
self.heap_layer = false;
Ok(())
}
}