use std::collections::BTreeMap;
use std::rc::Rc;
use std::time::Duration;
use crate::backends::DefaultLogBackend;
use crate::error::Result;
#[derive(Clone, Debug)]
pub struct ValuePointer {
pub value_offset: u64,
pub value_len: u32,
pub inline_value: Option<Rc<[u8]>>,
}
impl ValuePointer {
pub fn new_on_disk(value_offset: u64, value_len: u32) -> Self {
Self {
value_offset,
value_len,
inline_value: None,
}
}
pub fn with_inline(value_offset: u64, value_len: u32, inline_value: Rc<[u8]>) -> Self {
Self {
value_offset,
value_len,
inline_value: Some(inline_value),
}
}
pub fn len(&self) -> u32 {
self.value_len
}
pub fn is_empty(&self) -> bool {
self.value_len == 0
}
}
pub type KeyMap = BTreeMap<Vec<u8>, ValuePointer>;
pub const TX_COMMIT_MARKER: &[u8] = b"__TX_COMMIT__";
pub const DEFAULT_MAX_KEY_SIZE: usize = 1024; pub const DEFAULT_MAX_VALUE_SIZE: usize = 256 * 1024; pub const LENGTH_FIELD_BYTES: usize = 4;
pub const STORAGE_MAGIC: &[u8; 6] = b"TEGDB\0"; pub const STORAGE_FORMAT_VERSION: u16 = 2; pub const STORAGE_HEADER_SIZE: usize = 64;
#[derive(Debug, Clone)]
pub struct LogConfig {
pub max_key_size: usize,
pub max_value_size: usize,
pub initial_capacity: Option<usize>,
pub preallocate_size: Option<u64>,
pub inline_value_threshold: usize,
pub group_commit_interval: Duration,
}
#[derive(Clone, Debug)]
pub struct WriteOutcome {
pub entry_len: u32,
pub value_offset: u64,
pub value_len: u32,
}
pub trait LogBackend {
fn new(identifier: String, config: &LogConfig) -> Result<Self>
where
Self: Sized;
fn build_key_map(&mut self, config: &LogConfig) -> Result<(KeyMap, u64)>;
fn write_entry(&mut self, key: &[u8], value: &[u8]) -> Result<WriteOutcome>;
fn read_value(&mut self, offset: u64, len: u32) -> Result<Vec<u8>>;
fn sync_all(&mut self) -> Result<()>;
fn set_len(&mut self, size: u64) -> Result<()>;
fn rename_to(&mut self, new_identifier: String) -> Result<()>;
fn current_size(&self) -> Result<u64>;
}
pub struct Log {
backend: DefaultLogBackend,
}
impl Log {
pub fn new(identifier: String, config: &LogConfig) -> Result<Self> {
let backend = DefaultLogBackend::new(identifier, config)?;
Ok(Self { backend })
}
pub fn build_key_map(&mut self, config: &LogConfig) -> Result<(KeyMap, u64)> {
self.backend.build_key_map(config)
}
pub fn write_entry(&mut self, key: &[u8], value: &[u8]) -> Result<WriteOutcome> {
self.backend.write_entry(key, value)
}
pub fn read_value(&mut self, offset: u64, len: u32) -> Result<Vec<u8>> {
self.backend.read_value(offset, len)
}
pub fn sync_all(&mut self) -> Result<()> {
self.backend.sync_all()
}
pub fn set_len(&mut self, size: u64) -> Result<()> {
self.backend.set_len(size)
}
pub fn rename_to(&mut self, new_identifier: String) -> Result<()> {
self.backend.rename_to(new_identifier)
}
pub fn current_size(&self) -> Result<u64> {
self.backend.current_size()
}
}