global: snapshot

This commit is contained in:
nym21
2026-03-16 18:38:16 +01:00
parent ae067739ce
commit 5848d25612
55 changed files with 1366 additions and 1384 deletions
@@ -10,13 +10,13 @@ use crate::internal::{ComputedVecValue, algo::compute_aggregations};
use super::Distribution;
/// Full stats aggregate: distribution + sum + cumulative
/// Full stats aggregate: sum + cumulative + distribution
#[derive(Traversable)]
pub struct DistributionFull<I: VecIndex, T: ComputedVecValue + JsonSchema, M: StorageMode = Rw> {
#[traversable(flatten)]
pub distribution: Distribution<I, T, M>,
pub sum: M::Stored<EagerVec<PcoVec<I, T>>>,
pub cumulative: M::Stored<EagerVec<PcoVec<I, T>>>,
#[traversable(flatten)]
pub distribution: Distribution<I, T, M>,
}
impl<I: VecIndex, T: ComputedVecValue + JsonSchema> DistributionFull<I, T> {
@@ -12,75 +12,14 @@ use crate::{
},
};
/// One window slot: 8 distribution stats, each a AmountPerBlock.
/// Rolling distribution across 4 windows, stat-first naming.
///
/// Tree: `average.sats.height`, `min.sats.height`, etc.
#[derive(Traversable)]
pub struct RollingDistributionSlot<M: StorageMode = Rw> {
#[traversable(flatten)]
pub distribution: DistributionStats<AmountPerBlock<M>>,
}
impl RollingDistributionSlot {
pub(crate) fn forced_import(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
Ok(Self {
distribution: DistributionStats::try_from_fn(|suffix| {
AmountPerBlock::forced_import(db, &format!("{name}_{suffix}"), version, indexes)
})?,
})
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn compute(
&mut self,
max_from: Height,
starts: &impl ReadableVec<Height, Height>,
sats_source: &impl ReadableVec<Height, Sats>,
cents_source: &impl ReadableVec<Height, Cents>,
exit: &Exit,
sats_cache: &mut Option<(usize, Vec<f64>)>,
cents_cache: &mut Option<(usize, Vec<f64>)>,
) -> Result<()> {
let d = &mut self.distribution;
macro_rules! compute_unit {
($unit:ident, $source:expr, $cache:expr) => {
compute_rolling_distribution_from_starts(
max_from,
starts,
$source,
&mut d.average.$unit.height,
&mut d.min.$unit.height,
&mut d.max.$unit.height,
&mut d.pct10.$unit.height,
&mut d.pct25.$unit.height,
&mut d.median.$unit.height,
&mut d.pct75.$unit.height,
&mut d.pct90.$unit.height,
exit,
$cache,
)?
};
}
compute_unit!(sats, sats_source, sats_cache);
compute_unit!(cents, cents_source, cents_cache);
Ok(())
}
}
/// Rolling distribution across 4 windows, window-first.
///
/// Tree: `_24h.average.sats.height`, `_24h.min.sats.height`, etc.
/// Tree: `average._24h.sats.height`, `max._24h.sats.height`, etc.
/// Series: `{name}_average_24h`, `{name}_max_24h`, etc.
#[derive(Deref, DerefMut, Traversable)]
#[traversable(transparent)]
pub struct RollingDistributionAmountPerBlock<M: StorageMode = Rw>(
pub Windows<RollingDistributionSlot<M>>,
pub DistributionStats<Windows<AmountPerBlock<M>>>,
);
impl RollingDistributionAmountPerBlock {
@@ -90,13 +29,15 @@ impl RollingDistributionAmountPerBlock {
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
Ok(Self(Windows::try_from_fn(|suffix| {
RollingDistributionSlot::forced_import(
db,
&format!("{name}_{suffix}"),
version,
indexes,
)
Ok(Self(DistributionStats::try_from_fn(|stat_suffix| {
Windows::try_from_fn(|window_suffix| {
AmountPerBlock::forced_import(
db,
&format!("{name}_{stat_suffix}_{window_suffix}"),
version,
indexes,
)
})
})?))
}
@@ -110,22 +51,38 @@ impl RollingDistributionAmountPerBlock {
) -> Result<()> {
let mut sats_cache = None;
let mut cents_cache = None;
for (slot, starts) in self
.0
.as_mut_array_largest_first()
.into_iter()
.zip(windows.as_array_largest_first())
{
slot.compute(
max_from,
*starts,
sats_source,
cents_source,
exit,
&mut sats_cache,
&mut cents_cache,
)?;
macro_rules! compute_window {
($w:ident, $starts:expr) => {{
macro_rules! compute_unit {
($unit:ident, $source:expr, $cache:expr) => {
compute_rolling_distribution_from_starts(
max_from,
$starts,
$source,
&mut self.0.average.$w.$unit.height,
&mut self.0.min.$w.$unit.height,
&mut self.0.max.$w.$unit.height,
&mut self.0.pct10.$w.$unit.height,
&mut self.0.pct25.$w.$unit.height,
&mut self.0.median.$w.$unit.height,
&mut self.0.pct75.$w.$unit.height,
&mut self.0.pct90.$w.$unit.height,
exit,
$cache,
)?
};
}
compute_unit!(sats, sats_source, &mut sats_cache);
compute_unit!(cents, cents_source, &mut cents_cache);
}};
}
// Largest window first: its cache covers all smaller windows.
compute_window!(_1y, windows._1y);
compute_window!(_1m, windows._1m);
compute_window!(_1w, windows._1w);
compute_window!(_24h, windows._24h);
Ok(())
}
}
@@ -19,7 +19,7 @@ pub struct PerBlockRollingAverage<T, M: StorageMode = Rw>
where
T: NumericValue + JsonSchema,
{
pub height: M::Stored<EagerVec<PcoVec<Height, T>>>,
pub base: M::Stored<EagerVec<PcoVec<Height, T>>>,
#[traversable(hidden)]
pub cumulative: M::Stored<EagerVec<PcoVec<Height, f64>>>,
#[traversable(flatten)]
@@ -37,7 +37,7 @@ where
indexes: &indexes::Vecs,
cached_starts: &CachedWindowStarts,
) -> Result<Self> {
let height: EagerVec<PcoVec<Height, T>> = EagerVec::forced_import(db, name, version)?;
let base: EagerVec<PcoVec<Height, T>> = EagerVec::forced_import(db, name, version)?;
let cumulative: EagerVec<PcoVec<Height, f64>> =
EagerVec::forced_import(db, &format!("{name}_cumulative"), version)?;
let average = LazyRollingAvgsFromHeight::new(
@@ -49,7 +49,7 @@ where
);
Ok(Self {
height,
base,
cumulative,
average,
})
@@ -62,14 +62,14 @@ where
exit: &Exit,
compute_height: impl FnOnce(&mut EagerVec<PcoVec<Height, T>>) -> Result<()>,
) -> Result<()> {
compute_height(&mut self.height)?;
compute_height(&mut self.base)?;
self.compute_rest(max_from, exit)
}
/// Compute cumulative from already-populated height data. Rolling averages are lazy.
pub(crate) fn compute_rest(&mut self, max_from: Height, exit: &Exit) -> Result<()> {
self.cumulative
.compute_cumulative(max_from, &self.height, exit)?;
.compute_cumulative(max_from, &self.base, exit)?;
Ok(())
}
}
@@ -21,8 +21,7 @@ where
{
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub inner: PerBlock<S, M>,
pub base: PerBlock<S, M>,
pub delta: LazyRollingDeltasFromHeight<S, C, B>,
}
@@ -40,16 +39,16 @@ where
indexes: &indexes::Vecs,
cached_starts: &CachedWindowStarts,
) -> Result<Self> {
let inner = PerBlock::forced_import(db, name, version, indexes)?;
let base = PerBlock::forced_import(db, name, version, indexes)?;
let delta = LazyRollingDeltasFromHeight::new(
&format!("{name}_delta"),
version + delta_version_offset,
&inner.height,
&base.height,
cached_starts,
indexes,
);
Ok(Self { inner, delta })
Ok(Self { base, delta })
}
}
@@ -37,14 +37,14 @@ impl<B: BpsType> PercentPerBlockRollingAverage<B> {
let ratio = LazyPerBlock::from_height_source::<B::ToRatio>(
&format!("{name}_ratio"),
version,
bps.height.read_only_boxed_clone(),
bps.base.read_only_boxed_clone(),
indexes,
);
let percent = LazyPerBlock::from_height_source::<B::ToPercent>(
name,
version,
bps.height.read_only_boxed_clone(),
bps.base.read_only_boxed_clone(),
indexes,
);