use crate::read_view::{ReadLimits, ScanProjection};
use crate::resources::ByteReservation;
use crate::{Op, StorageError, StorageStatistics, VersionEntry};
use std::collections::BTreeMap;
use std::ops::Bound;
use std::path::Path;
use std::sync::Arc;
pub(crate) trait StorageReadView: Send + Sync {
fn read_value(
&self,
key: &[u8],
ci: u64,
current: bool,
limits: ReadLimits,
projection: ScanProjection,
) -> Result<Option<Vec<u8>>, StorageError>;
fn next_key(
&self,
lower: &Bound<Vec<u8>>,
upper: &Bound<Vec<u8>>,
limits: ReadLimits,
include_history: bool,
) -> Result<Option<Vec<u8>>, StorageError>;
fn current_range<'a>(
&'a self,
start: &[u8],
end: &[u8],
limits: ReadLimits,
projection: ScanProjection,
) -> Result<Box<dyn Iterator<Item = Result<(Vec<u8>, Vec<u8>), StorageError>> + 'a>, StorageError>;
fn native_range<'a>(
&'a self,
_lower: &Bound<Vec<u8>>,
_upper: &Bound<Vec<u8>>,
_limits: ReadLimits,
_projection: ScanProjection,
) -> Result<
Option<Box<dyn Iterator<Item = Result<(Vec<u8>, Vec<u8>), StorageError>> + 'a>>,
StorageError,
> {
Ok(None)
}
fn visible_ci(&self) -> Result<u64, StorageError>;
fn history_floor(&self) -> Result<u64, StorageError>;
fn snapshot_pinned(&self) -> bool {
false
}
}
#[derive(Debug, Default)]
pub struct LoadedState {
pub data: BTreeMap<Vec<u8>, Vec<u8>>,
pub created: BTreeMap<Vec<u8>, u64>,
pub history: BTreeMap<Vec<u8>, Vec<VersionEntry>>,
pub gc_watermark: u64,
}
pub(crate) const COMPACT_BUSY: &str = "compaction busy: read transactions open";
pub(crate) trait StorageBackend: Send + Sync {
fn load(&self) -> Result<LoadedState, String>;
fn load_watermark(&self) -> Result<(u64, u64), String> {
let state = self.load()?;
let lsn = match state.data.get(crate::LAST_APPLIED_KEY) {
Some(value) => crate::wal::decode_last_applied(value)
.map_err(|error| format!("corrupt last-applied watermark: {error}"))?,
None => 0,
};
Ok((lsn, state.gc_watermark))
}
fn apply(&self, ops: &[Op], commit_index: u64) -> Result<(), String>;
fn apply_many(&self, batches: &[(u64, &[Op])]) -> Result<(), String>;
fn retire_before(&self, watermark: u64) -> Result<(), String>;
fn retire_before_batch(
&self,
watermark: u64,
_cursor: Option<Vec<u8>>,
_max_keys: usize,
) -> Result<Option<Vec<u8>>, String> {
self.retire_before(watermark)?;
Ok(None)
}
fn begin_shutdown(&self) {}
fn checkpoint(&self, _durable_lsn: u64) -> Result<(), String> {
Ok(())
}
fn while_writes_paused(&self, run: &mut dyn FnMut()) -> Result<(), String> {
run();
Ok(())
}
fn compact(&self) -> Result<(), String>;
fn storage_stats(&self) -> Result<StorageStatistics, String> {
Err("backend does not provide storage statistics".into())
}
fn read_view(&self) -> Result<Box<dyn StorageReadView>, StorageError>;
fn lock_times(&self) -> crate::BackendLockTimes {
crate::BackendLockTimes::default()
}
fn writer_holds(&self) -> Vec<(crate::WriterHolder, crate::WriterHolds)> {
Vec::new()
}
}
pub(crate) fn open_backend(path: &Path, cache: ByteReservation) -> Result<BackendHandle, String> {
Ok(Arc::new(crate::redb_backend::RedbBackend::open(
path, cache,
)?))
}
pub(crate) type BackendHandle = Arc<dyn StorageBackend>;