use crate::{
index::Factory as IndexFactory,
journal::{
authenticated,
contiguous::{fixed, variable, Contiguous, Mutable},
},
merkle::{self, full, Location},
qmdb::{
self,
any::{
db::Db,
operation::{update::Update, Operation},
ordered::{
fixed::{
Db as OrderedFixedDb, Operation as OrderedFixedOp, Update as OrderedFixedUpdate,
},
variable::{
Db as OrderedVariableDb, Operation as OrderedVariableOp,
Update as OrderedVariableUpdate,
},
},
unordered::{
fixed::{
Db as UnorderedFixedDb, Operation as UnorderedFixedOp,
Update as UnorderedFixedUpdate,
},
variable::{
Db as UnorderedVariableDb, Operation as UnorderedVariableOp,
Update as UnorderedVariableUpdate,
},
},
FixedConfig, FixedValue, VariableConfig, VariableValue,
},
metrics::Metrics,
operation::{Committable, Key},
},
translator::Translator,
Context,
};
use commonware_codec::{Codec, CodecShared, Read as CodecRead};
use commonware_cryptography::Hasher;
use commonware_parallel::Strategy;
use commonware_utils::{range::NonEmptyRange, Array};
use core::num::NonZeroUsize;
#[cfg(test)]
pub(crate) mod tests;
#[allow(clippy::too_many_arguments)]
async fn build_db<F, E, U, I, H, C, T, S>(
context: E,
merkle_config: full::Config<S>,
log: C,
translator: T,
pinned_nodes: Option<Vec<H::Digest>>,
range: NonEmptyRange<Location<F>>,
apply_batch_size: usize,
cache_size: Option<NonZeroUsize>,
) -> Result<Db<F, E, C, I, H, U, { crate::qmdb::any::BITMAP_CHUNK_BYTES }, S>, qmdb::Error<F>>
where
F: merkle::Family,
E: Context,
U: Update + Send + Sync + 'static,
I: IndexFactory<T, Value = Location<F>>,
H: Hasher,
T: Translator,
C: Mutable<Item = Operation<F, U>>,
S: Strategy,
Operation<F, U>: Codec + Committable + CodecShared,
{
let hasher = qmdb::hasher::<H>();
let merkle = full::Merkle::<F, _, _, S>::init_sync(
context.child("merkle"),
full::SyncConfig {
config: merkle_config,
range: range.clone(),
pinned_nodes,
},
)
.await?;
let index = I::new(context.child("index"), translator);
let log = authenticated::Journal::<F, _, _, _, S>::from_components(
merkle,
log,
hasher,
apply_batch_size as u64,
)
.await?;
let metrics = Metrics::new(context);
let db = Db::init_from_log(index, log, None, cache_size, metrics).await?;
Ok(db)
}
macro_rules! impl_sync_database {
($db:ident, $op:ident, $update:ident,
$journal:ty, $config:ty,
$key_bound:path, $value_bound:ident
$(; $($where_extra:tt)+)?) => {
impl<F, E, K, V, H, T, S> qmdb::sync::Database for $db<F, E, K, V, H, T, S>
where
F: merkle::Family,
E: Context,
K: $key_bound,
V: $value_bound + 'static,
H: Hasher,
T: Translator,
S: Strategy,
$($($where_extra)+)?
{
type Family = F;
type Context = E;
type Op = $op<F, K, V>;
type Journal = $journal;
type Hasher = H;
type Config = $config;
type Digest = H::Digest;
async fn from_sync_result(
context: Self::Context,
config: Self::Config,
log: Self::Journal,
pinned_nodes: Option<Vec<Self::Digest>>,
range: NonEmptyRange<Location<F>>,
apply_batch_size: usize,
) -> Result<Self, qmdb::Error<F>> {
let merkle_config = config.merkle_config.clone();
let translator = config.translator.clone();
let cache_size = config.init_cache_size;
build_db::<F, _, $update<K, V>, _, H, _, T, S>(
context,
merkle_config,
log,
translator,
pinned_nodes,
range,
apply_batch_size,
cache_size,
)
.await
}
async fn local_boundary_nodes(
context: Self::Context,
config: &Self::Config,
target: &qmdb::sync::Target<Self::Family, Self::Digest>,
journal: &Self::Journal,
) -> Result<Option<Vec<Self::Digest>>, qmdb::Error<F>> {
if target.range.start() == Location::new(0)
|| !qmdb::sync::journal_covers_range(journal.bounds(), &target.range)
{
return Ok(None);
}
qmdb::sync::local_boundary_nodes::<F, _, H, S>(
context,
config.merkle_config.clone(),
target,
target.range.start(),
)
.await
}
fn root(&self) -> Self::Digest {
crate::qmdb::any::db::Db::root(self)
}
}
};
}
impl_sync_database!(
UnorderedFixedDb, UnorderedFixedOp, UnorderedFixedUpdate,
fixed::Journal<E, Self::Op>, FixedConfig<T, S>,
Array, FixedValue
);
impl_sync_database!(
UnorderedVariableDb, UnorderedVariableOp, UnorderedVariableUpdate,
variable::Journal<E, Self::Op>,
VariableConfig<T, <UnorderedVariableOp<F, K, V> as CodecRead>::Cfg, S>,
Key, VariableValue;
UnorderedVariableOp<F, K, V>: CodecShared
);
impl_sync_database!(
OrderedFixedDb, OrderedFixedOp, OrderedFixedUpdate,
fixed::Journal<E, Self::Op>, FixedConfig<T, S>,
Array, FixedValue
);
impl_sync_database!(
OrderedVariableDb, OrderedVariableOp, OrderedVariableUpdate,
variable::Journal<E, Self::Op>,
VariableConfig<T, <OrderedVariableOp<F, K, V> as CodecRead>::Cfg, S>,
Key, VariableValue;
OrderedVariableOp<F, K, V>: CodecShared
);