use std::{borrow::Borrow, fmt::Debug, ops::RangeBounds};
use armour_derive::armour_metrics;
use fjall::*;
use tracing::instrument;
use crate::logdb::{ItemWithRaw, IterTree, ReadTree, TryIterTree, helpers::*};
use crate::metrics::{counter, histogram};
use crate::{Cid, DbError, DbResult, Entry, Record};
#[derive(Clone)]
pub struct Snapshot {
pub(crate) inner: fjall::Snapshot,
}
impl Snapshot {
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
#[armour_metrics(prefix = "armour_snapshot", name = Item::NAME)]
pub fn get<Item>(
&self,
tree: &ReadTree<Item>,
id: impl Borrow<Item::SelfId> + Debug,
) -> DbResult<Option<Item>>
where
Item: Record<Value = Slice> + Debug,
{
let key = Cid::encode(id.borrow());
let val = self
.inner
.get(&tree.raw.tree, key.as_ref())
.map_err(DbError::from)?;
match val {
Some(val) => Ok(Some(Item::deser_owned(val))),
None => Ok(None),
}
}
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
pub fn get_or_err<Item>(
&self,
tree: &ReadTree<Item>,
id: impl Borrow<Item::SelfId> + Debug,
) -> DbResult<Item>
where
Item: Record<Value = Slice> + Debug,
{
self.get(tree, id)
.and_then(|item| item.ok_or(DbError::NotFound))
}
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
#[armour_metrics(prefix = "armour_snapshot", name = Item::NAME)]
pub fn contains<Item>(
&self,
tree: &ReadTree<Item>,
id: impl Borrow<Item::SelfId> + Debug,
) -> DbResult<bool>
where
Item: Record<Value = Slice> + Debug,
{
let key = Cid::encode(id.borrow());
self.inner
.contains_key(&tree.raw.tree, key.as_ref())
.map_err(DbError::from)
}
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
#[armour_metrics(prefix = "armour_snapshot", name = Item::NAME)]
pub fn size_of<Item>(
&self,
tree: &ReadTree<Item>,
id: impl Borrow<Item::SelfId> + Debug,
) -> DbResult<Option<u32>>
where
Item: Record<Value = Slice> + Debug,
{
let key = Cid::encode(id.borrow());
self.inner
.size_of(&tree.raw.tree, key.as_ref())
.map_err(DbError::from)
}
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
#[armour_metrics(prefix = "armour_snapshot", name = Item::NAME)]
pub fn first<Item>(&self, tree: &ReadTree<Item>) -> DbResult<Option<Entry<Item>>>
where
Item: Record<Value = Slice> + Debug,
{
let val = self.inner.first_key_value(&tree.raw.tree);
match val {
Some(val) => {
let (key, val) = val.into_inner()?;
let id = Item::deser_key(&key);
let value = Item::deser_owned(val);
Ok(Some(Entry::new(id, value)))
}
None => Ok(None),
}
}
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
#[armour_metrics(prefix = "armour_snapshot", name = Item::NAME)]
pub fn last<Item>(&self, tree: &ReadTree<Item>) -> DbResult<Option<Entry<Item>>>
where
Item: Record<Value = Slice> + Debug,
{
let val = self.inner.last_key_value(&tree.raw.tree);
match val {
Some(val) => {
let (key, val) = val.into_inner()?;
let id = Item::deser_key(&key);
let value = Item::deser_owned(val);
Ok(Some(Entry::new(id, value)))
}
None => Ok(None),
}
}
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
pub fn iter<Item>(&self, tree: &ReadTree<Item>) -> IterTree<Entry<Item>>
where
Item: Record<Value = Slice> + Debug,
{
counter!("armour_snapshot_iter_total", "name" => Item::NAME).increment(1);
self.inner
.iter(&tree.raw.tree)
.filter_map(entry_filter_map::<Item>)
}
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
pub fn keys<Item>(&self, tree: &ReadTree<Item>) -> impl DoubleEndedIterator<Item = Item::SelfId>
where
Item: Record<Value = Slice> + Debug,
{
counter!("armour_snapshot_keys_total", "name" => Item::NAME).increment(1);
self.inner
.iter(&tree.raw.tree)
.filter_map(entry_key_filter_map::<Item>)
}
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
pub fn range<Item, K, R>(&self, tree: &ReadTree<Item>, range: R) -> IterTree<Entry<Item>>
where
Item: Record<Value = Slice> + Debug,
K: AsRef<[u8]>,
R: RangeBounds<K> + Debug,
{
counter!("armour_snapshot_range_total", "name" => Item::NAME).increment(1);
self.inner
.range(&tree.raw.tree, range)
.filter_map(entry_filter_map::<Item>)
}
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
pub fn prefix<Item, P>(&self, tree: &ReadTree<Item>, prefix: P) -> IterTree<Entry<Item>>
where
Item: Record<Value = Slice> + Debug,
P: AsRef<[u8]> + Debug,
{
counter!("armour_snapshot_prefix_total", "name" => Item::NAME).increment(1);
self.inner
.prefix(&tree.raw.tree, prefix)
.filter_map(entry_filter_map::<Item>)
}
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
pub fn prefix_key<Item, P>(&self, tree: &ReadTree<Item>, prefix: P) -> IterTree<Item::SelfId>
where
Item: Record<Value = Slice> + Debug,
P: AsRef<[u8]> + Debug,
{
counter!("armour_snapshot_prefix_key_total", "name" => Item::NAME).increment(1);
self.inner
.prefix(&tree.raw.tree, prefix)
.filter_map(entry_key_filter_map::<Item>)
}
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
pub fn try_iter<Item>(&self, tree: &ReadTree<Item>) -> TryIterTree<Entry<Item>>
where
Item: Record<Value = Slice> + Debug,
{
counter!("armour_snapshot_try_iter_total", "name" => Item::NAME).increment(1);
self.inner.iter(&tree.raw.tree).map(entry_map::<Item>)
}
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
pub fn try_range<Item, K, R>(
&self,
tree: &ReadTree<Item>,
range: R,
) -> TryIterTree<ItemWithRaw<Item>>
where
Item: Record<Value = Slice> + Debug,
K: AsRef<[u8]>,
R: RangeBounds<K> + Debug,
{
counter!("armour_snapshot_try_range_total", "name" => Item::NAME).increment(1);
self.inner
.range(&tree.raw.tree, range)
.map(entry_map_with_raw::<Item>)
}
#[instrument(level = "debug", skip_all, fields(name = Item::NAME))]
pub fn try_prefix<Item, P>(&self, tree: &ReadTree<Item>, prefix: P) -> TryIterTree<Entry<Item>>
where
Item: Record<Value = Slice> + Debug,
P: AsRef<[u8]> + Debug,
{
counter!("armour_snapshot_try_prefix_total", "name" => Item::NAME).increment(1);
self.inner
.prefix(&tree.raw.tree, prefix)
.map(entry_map::<Item>)
}
}