use std::{
fs, io,
path::{Path, PathBuf},
};
use brk_error::{Error, Result};
use brk_types::Version;
use fjall::Keyspace;
use super::Height;
#[derive(Debug, Clone)]
pub struct StoreMeta {
pathbuf: PathBuf,
version: Version,
height: Option<Height>,
}
impl StoreMeta {
pub fn checked_open<F>(
path: &Path,
version: Version,
open_partition_handle: F,
) -> Result<(Self, Keyspace)>
where
F: Fn() -> Result<Keyspace>,
{
fs::create_dir_all(path)?;
let partition = open_partition_handle()?;
if let Ok(prev_version) = Version::try_from(Self::path_version_(path).as_path())
&& version != prev_version
{
return Err(Error::VersionMismatch {
path: path.to_path_buf(),
expected: usize::from(version),
found: usize::from(prev_version),
});
}
let slf = Self {
pathbuf: path.to_owned(),
version,
height: Height::try_from(Self::path_height_(path).as_path()).ok(),
};
slf.version.write(&slf.path_version())?;
Ok((slf, partition))
}
pub fn version(&self) -> Version {
self.version
}
pub fn export(&mut self, height: Height) -> io::Result<()> {
self.height = Some(height);
height.write(&self.path_height())
}
pub fn path(&self) -> &Path {
&self.pathbuf
}
fn path_version(&self) -> PathBuf {
Self::path_version_(&self.pathbuf)
}
fn path_version_(path: &Path) -> PathBuf {
path.join("version")
}
#[inline]
pub fn height(&self) -> Option<Height> {
self.height
}
#[inline]
pub fn needs(&self, height: Height) -> bool {
self.height.is_none_or(|self_height| height > self_height)
}
#[inline]
pub fn has(&self, height: Height) -> bool {
!self.needs(height)
}
pub fn reset(&mut self) -> io::Result<()> {
self.height = None;
let path = self.path_height();
if path.exists() {
fs::remove_file(&path)?;
}
Ok(())
}
fn path_height(&self) -> PathBuf {
Self::path_height_(&self.pathbuf)
}
fn path_height_(path: &Path) -> PathBuf {
path.join("height")
}
}