use std::path::{Path, PathBuf};
use std::sync::OnceLock;
use ahash::AHashMap;
use crate::common::universal_io::{Populate, UniversalRead, UniversalReadFs, UserData};
use super::iter::Iter;
use super::{PointOffset, PointerUpdates, Tracker, TrackerRead, ValuePointer, read_slot};
use crate::blobstore::Result;
#[derive(Debug)]
pub struct ReadOnlyTracker<S> {
path: PathBuf,
storage: S,
populate: Populate,
}
fn no_pending_updates() -> &'static AHashMap<PointOffset, PointerUpdates> {
static EMPTY: OnceLock<AHashMap<PointOffset, PointerUpdates>> = OnceLock::new();
EMPTY.get_or_init(AHashMap::new)
}
impl<S: UniversalRead> ReadOnlyTracker<S> {
pub fn open<Fs: UniversalReadFs<File = S>>(
fs: &Fs,
base_path: &Path,
populate: Populate,
) -> Result<Self> {
let path = Tracker::<S>::tracker_file_name(base_path);
let storage = Tracker::open_storage(fs, &path, populate, false)?;
Ok(Self {
path,
storage,
populate,
})
}
pub fn live_reload<Fs: UniversalReadFs<File = S>>(&mut self, fs: &Fs) -> Result<()> {
self.storage = Tracker::open_storage(fs, &self.path, self.populate, false)?;
Ok(())
}
pub fn files(&self) -> Vec<PathBuf> {
vec![self.path.clone()]
}
}
impl<S: UniversalRead> TrackerRead<S> for ReadOnlyTracker<S> {
fn max_point_offset(&self) -> Result<PointOffset> {
Ok(Tracker::read_header(&self.storage)?.next_pointer_offset)
}
fn get(&self, point_offset: PointOffset) -> Result<Option<ValuePointer>> {
read_slot(&self.storage, point_offset)
}
fn iter<U, I>(&self, point_offsets: I) -> Result<Iter<'_, U, I, S>>
where
U: UserData,
I: Iterator<Item = (U, PointOffset)>,
{
Iter::new(point_offsets, &self.storage, no_pending_updates())
}
}