use super::index::*;
use crate::store::{BlockWriter, BranchCache, ReadOnlyStore};
use core::{fmt::Debug, hash::Hash, iter::FromIterator, ops::Range};
use libipld::cbor::DagCbor;
use std::{fmt::Display, sync::Arc};
mod index_iter;
#[cfg(feature = "metrics")]
mod prom;
mod read;
mod stream;
mod write;
pub(crate) use index_iter::IndexIter;
#[cfg(feature = "metrics")]
pub(crate) use prom::register;
#[cfg(feature = "metrics")]
use prometheus::Registry;
pub(crate) use read::{ChunkVisitor, TreeIter};
pub trait TreeTypes: Debug + Send + Sync + Clone + 'static {
type Key: Debug + PartialEq + Send;
type Summary: Debug + PartialEq + Send;
type KeySeq: CompactSeq<Item = Self::Key>
+ DagCbor
+ Clone
+ Debug
+ FromIterator<Self::Key>
+ Send
+ Sync
+ Summarizable<Self::Summary>;
type SummarySeq: CompactSeq<Item = Self::Summary>
+ DagCbor
+ Clone
+ Debug
+ FromIterator<Self::Summary>
+ Send
+ Sync
+ Summarizable<Self::Summary>;
type Link: Display + Debug + Hash + Eq + Clone + Copy + Send + Sync + DagCbor;
const NONCE: &'static [u8; 24] = &[0u8; 24];
}
#[derive(Debug)]
pub struct ForestInner<T: TreeTypes, R> {
pub(crate) store: R,
pub(crate) branch_cache: BranchCache<T>,
#[cfg(feature = "metrics")]
pub(crate) registry: Registry,
}
#[derive(Debug)]
pub struct Forest<TT: TreeTypes, R>(Arc<ForestInner<TT, R>>);
impl<TT: TreeTypes, R> Clone for Forest<TT, R> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<TT: TreeTypes, R: Clone> Forest<TT, R> {
pub fn new(store: R, branch_cache: BranchCache<TT>) -> Self {
Self(Arc::new(ForestInner {
store,
branch_cache,
#[cfg(feature = "metrics")]
registry: Registry::new(),
}))
}
pub fn transaction<W: BlockWriter<TT::Link>>(
&self,
f: impl FnOnce(R) -> (R, W),
) -> Transaction<TT, R, W> {
let (reader, writer) = f(self.0.as_ref().store.clone());
Transaction {
read: Self::new(reader, self.branch_cache.clone()),
writer,
}
}
}
impl<T: TreeTypes, R> std::ops::Deref for Forest<T, R> {
type Target = ForestInner<T, R>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
pub struct Transaction<T: TreeTypes, R, W> {
read: Forest<T, R>,
writer: W,
}
impl<T: TreeTypes, R, W> Transaction<T, R, W> {
pub fn into_writer(self) -> W {
self.writer
}
pub fn writer(&self) -> &W {
&self.writer
}
}
impl<T: TreeTypes, R, W> Transaction<T, R, W>
where
R: ReadOnlyStore<T::Link>,
W: BlockWriter<T::Link>,
{
pub fn new(read: Forest<T, R>, writer: W) -> Self {
Self { read, writer }
}
}
impl<T: TreeTypes, R, W> std::ops::Deref for Transaction<T, R, W> {
type Target = Forest<T, R>;
fn deref(&self) -> &Self::Target {
&self.read
}
}
#[derive(Debug, Clone)]
pub struct Secrets {
index_key: chacha20::Key,
value_key: chacha20::Key,
}
impl Secrets {
pub fn new(index_key: chacha20::Key, value_key: chacha20::Key) -> Self {
Self {
index_key,
value_key,
}
}
pub fn index_key(&self) -> &chacha20::Key {
&self.index_key
}
pub fn value_key(&self) -> &chacha20::Key {
&self.value_key
}
}
impl Default for Secrets {
fn default() -> Self {
Self {
index_key: [0; 32].into(),
value_key: [0; 32].into(),
}
}
}
#[derive(Debug, Clone)]
pub struct Config {
pub max_summary_branches: usize,
pub max_key_branches: usize,
pub max_leaf_count: usize,
pub target_leaf_size: usize,
pub max_uncompressed_leaf_size: usize,
pub zstd_level: i32,
}
impl Config {
pub fn debug() -> Self {
Self {
target_leaf_size: 10000,
max_leaf_count: 10,
max_key_branches: 4,
max_summary_branches: 4,
zstd_level: 0,
max_uncompressed_leaf_size: 16 * 1024 * 1024,
}
}
pub fn debug_fast() -> Self {
Self {
target_leaf_size: 1 << 14,
max_leaf_count: 1 << 14,
max_summary_branches: 32,
max_key_branches: 32,
zstd_level: 0,
max_uncompressed_leaf_size: 16 * 1024 * 1024,
}
}
pub fn branch_sealed<T: TreeTypes>(&self, items: &[Index<T>], level: u32) -> bool {
assert!(level > 0);
if items.iter().any(|x| !x.sealed()) {
return false;
}
if items.iter().any(|x| x.level() != level - 1) {
return false;
}
if level == 1 {
items.len() >= self.max_key_branches
} else {
items.len() >= self.max_summary_branches
}
}
pub fn validate(&self) -> anyhow::Result<()> {
anyhow::ensure!(self.max_summary_branches > 1);
anyhow::ensure!(self.max_key_branches > 0);
anyhow::ensure!(self.target_leaf_size > 0 && self.target_leaf_size <= 1024 * 1024);
anyhow::ensure!(self.max_uncompressed_leaf_size <= 16 * 1024 * 1024);
anyhow::ensure!(self.zstd_level >= 1 && self.zstd_level <= 22);
Ok(())
}
}
pub(crate) enum BranchResult {
Sealed(usize),
Unsealed(usize),
Skip(usize),
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub(crate) enum CreateMode {
Packed,
Unpacked,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FilteredChunk<V, E> {
pub range: Range<u64>,
pub data: Vec<V>,
pub extra: E,
}