global: snapshot part 3

This commit is contained in:
nym21
2026-03-20 12:54:26 +01:00
parent b8e57f4788
commit 1d671ea41f
32 changed files with 1561 additions and 1249 deletions
@@ -5,7 +5,10 @@ use vecdb::{Database, EagerVec, Exit, PcoVec, Rw, StorageMode};
use crate::{
indexes,
internal::{AmountPerBlock, CachedWindowStarts, LazyRollingSumsAmountFromHeight, SatsToCents},
internal::{
AmountPerBlock, CachedWindowStarts, LazyRollingAvgsAmountFromHeight,
LazyRollingSumsAmountFromHeight, SatsToCents,
},
prices,
};
@@ -14,6 +17,7 @@ pub struct AmountPerBlockCumulativeWithSums<M: StorageMode = Rw> {
pub base: AmountPerBlock<M>,
pub cumulative: AmountPerBlock<M>,
pub sum: LazyRollingSumsAmountFromHeight,
pub average: LazyRollingAvgsAmountFromHeight,
}
const VERSION: Version = Version::TWO;
@@ -39,11 +43,20 @@ impl AmountPerBlockCumulativeWithSums {
cached_starts,
indexes,
);
let average = LazyRollingAvgsAmountFromHeight::new(
&format!("{name}_average"),
v,
&cumulative.sats.height,
&cumulative.cents.height,
cached_starts,
indexes,
);
Ok(Self {
base,
cumulative,
sum,
average,
})
}
@@ -6,8 +6,9 @@ use vecdb::{Database, EagerVec, Exit, PcoVec, Rw, StorageMode};
use crate::{
indexes,
internal::{
AmountPerBlock, CachedWindowStarts, LazyRollingSumsAmountFromHeight,
RollingDistributionAmountPerBlock, SatsToCents, WindowStarts,
AmountPerBlock, CachedWindowStarts, LazyRollingAvgsAmountFromHeight,
LazyRollingSumsAmountFromHeight, RollingDistributionAmountPerBlock, SatsToCents,
WindowStarts,
},
prices,
};
@@ -17,8 +18,9 @@ pub struct AmountPerBlockFull<M: StorageMode = Rw> {
pub base: AmountPerBlock<M>,
pub cumulative: AmountPerBlock<M>,
pub sum: LazyRollingSumsAmountFromHeight,
pub average: LazyRollingAvgsAmountFromHeight,
#[traversable(flatten)]
pub rolling: RollingDistributionAmountPerBlock<M>,
pub distribution: RollingDistributionAmountPerBlock<M>,
}
const VERSION: Version = Version::TWO;
@@ -34,12 +36,8 @@ impl AmountPerBlockFull {
let v = version + VERSION;
let base = AmountPerBlock::forced_import(db, name, v, indexes)?;
let cumulative = AmountPerBlock::forced_import(
db,
&format!("{name}_cumulative"),
v,
indexes,
)?;
let cumulative =
AmountPerBlock::forced_import(db, &format!("{name}_cumulative"), v, indexes)?;
let sum = LazyRollingSumsAmountFromHeight::new(
&format!("{name}_sum"),
v,
@@ -48,14 +46,22 @@ impl AmountPerBlockFull {
cached_starts,
indexes,
);
let rolling =
RollingDistributionAmountPerBlock::forced_import(db, name, v, indexes)?;
let average = LazyRollingAvgsAmountFromHeight::new(
&format!("{name}_average"),
v,
&cumulative.sats.height,
&cumulative.cents.height,
cached_starts,
indexes,
);
let rolling = RollingDistributionAmountPerBlock::forced_import(db, name, v, indexes)?;
Ok(Self {
base,
cumulative,
sum,
rolling,
average,
distribution: rolling,
})
}
@@ -89,7 +95,7 @@ impl AmountPerBlockFull {
.height
.compute_cumulative(max_from, &self.base.cents.height, exit)?;
self.rolling.compute(
self.distribution.compute(
max_from,
windows,
&self.base.sats.height,
@@ -0,0 +1,124 @@
use brk_traversable::Traversable;
use brk_types::{Bitcoin, Cents, Dollars, Height, Sats, Version};
use derive_more::{Deref, DerefMut};
use vecdb::{DeltaAvg, LazyDeltaVec, LazyVecFrom1, ReadableCloneableVec};
use crate::{
indexes,
internal::{
CachedWindowStarts, CentsUnsignedToDollars, DerivedResolutions, LazyPerBlock,
LazyRollingAvgFromHeight, Resolutions, SatsToBitcoin, Windows,
},
};
/// Single window slot: lazy rolling average for Amount (sats + btc + cents + usd).
#[derive(Clone, Traversable)]
pub struct LazyRollingAvgAmountFromHeight {
pub btc: LazyPerBlock<Bitcoin, Sats>,
pub sats: LazyRollingAvgFromHeight<Sats>,
pub usd: LazyPerBlock<Dollars, Cents>,
pub cents: LazyRollingAvgFromHeight<Cents>,
}
/// Lazy rolling averages for all 4 windows, for Amount (sats + btc + cents + usd).
#[derive(Clone, Deref, DerefMut, Traversable)]
#[traversable(transparent)]
pub struct LazyRollingAvgsAmountFromHeight(pub Windows<LazyRollingAvgAmountFromHeight>);
impl LazyRollingAvgsAmountFromHeight {
pub fn new(
name: &str,
version: Version,
cumulative_sats: &(impl ReadableCloneableVec<Height, Sats> + 'static),
cumulative_cents: &(impl ReadableCloneableVec<Height, Cents> + 'static),
cached_starts: &CachedWindowStarts,
indexes: &indexes::Vecs,
) -> Self {
let cum_sats = cumulative_sats.read_only_boxed_clone();
let cum_cents = cumulative_cents.read_only_boxed_clone();
let make_slot = |suffix: &str, cached_start: &vecdb::CachedVec<Height, Height>| {
let full_name = format!("{name}_{suffix}");
let cached = cached_start.clone();
let starts_version = cached.version();
// Sats lazy rolling avg
let sats_avg = LazyDeltaVec::<Height, Sats, Sats, DeltaAvg>::new(
&format!("{full_name}_sats"),
version,
cum_sats.clone(),
starts_version,
{
let cached = cached.clone();
move || cached.get()
},
);
let sats_resolutions = Resolutions::forced_import(
&format!("{full_name}_sats"),
sats_avg.read_only_boxed_clone(),
version,
indexes,
);
let sats = LazyRollingAvgFromHeight {
height: sats_avg,
resolutions: Box::new(sats_resolutions),
};
// Btc lazy from sats
let btc = LazyPerBlock {
height: LazyVecFrom1::transformed::<SatsToBitcoin>(
&full_name,
version,
sats.height.read_only_boxed_clone(),
),
resolutions: Box::new(DerivedResolutions::from_derived_computed::<SatsToBitcoin>(
&full_name,
version,
&sats.resolutions,
)),
};
// Cents rolling avg
let cents_avg = LazyDeltaVec::<Height, Cents, Cents, DeltaAvg>::new(
&format!("{full_name}_cents"),
version,
cum_cents.clone(),
starts_version,
move || cached.get(),
);
let cents_resolutions = Resolutions::forced_import(
&format!("{full_name}_cents"),
cents_avg.read_only_boxed_clone(),
version,
indexes,
);
let cents = LazyRollingAvgFromHeight {
height: cents_avg,
resolutions: Box::new(cents_resolutions),
};
// Usd lazy from cents
let usd = LazyPerBlock {
height: LazyVecFrom1::transformed::<CentsUnsignedToDollars>(
&format!("{full_name}_usd"),
version,
cents.height.read_only_boxed_clone(),
),
resolutions: Box::new(DerivedResolutions::from_derived_computed::<
CentsUnsignedToDollars,
>(
&format!("{full_name}_usd"), version, &cents.resolutions
)),
};
LazyRollingAvgAmountFromHeight {
btc,
sats,
usd,
cents,
}
};
Self(cached_starts.0.map_with_suffix(make_slot))
}
}
@@ -4,6 +4,7 @@ mod cumulative_sum;
mod full;
mod lazy;
mod lazy_derived_resolutions;
mod lazy_rolling_avg;
mod lazy_rolling_sum;
mod rolling_distribution;
mod with_deltas;
@@ -14,6 +15,7 @@ pub use cumulative_sum::*;
pub use full::*;
pub use lazy::*;
pub use lazy_derived_resolutions::*;
pub use lazy_rolling_avg::*;
pub use lazy_rolling_sum::*;
pub use rolling_distribution::*;
pub use with_deltas::*;
@@ -9,9 +9,7 @@ use vecdb::{
use crate::{
indexes,
internal::{
CachedWindowStarts, NumericValue, PerBlock, RollingComplete, WindowStarts,
},
internal::{CachedWindowStarts, NumericValue, PerBlock, RollingComplete, WindowStarts},
};
#[derive(Traversable)]
@@ -70,8 +68,7 @@ where
f64: From<T>,
A: VecIndex + VecValue + brk_types::CheckedSub<A>,
{
let combined_version =
source.version() + first_indexes.version() + count_indexes.version();
let combined_version = source.version() + first_indexes.version() + count_indexes.version();
let mut index = max_from;
index = {
@@ -121,7 +118,7 @@ where
);
self.sum.height.push(sum_val);
cumulative_val = cumulative_val + sum_val;
cumulative_val += sum_val;
self.cumulative.height.push(cumulative_val);
Ok(())
@@ -17,7 +17,10 @@ use vecdb::{Database, EagerVec, Exit, PcoVec, Rw, StorageMode};
use crate::{
indexes,
internal::{CachedWindowStarts, PerBlock, LazyRollingSumsFromHeight, NumericValue},
internal::{
CachedWindowStarts, LazyRollingAvgsFromHeight, LazyRollingSumsFromHeight, NumericValue,
PerBlock,
},
};
#[derive(Traversable)]
@@ -29,6 +32,7 @@ where
pub base: PerBlock<T, M>,
pub cumulative: PerBlock<C, M>,
pub sum: LazyRollingSumsFromHeight<C>,
pub average: LazyRollingAvgsFromHeight<C>,
}
impl<T, C> PerBlockCumulativeWithSums<T, C>
@@ -53,11 +57,19 @@ where
cached_starts,
indexes,
);
let average = LazyRollingAvgsFromHeight::new(
&format!("{name}_average"),
version,
&cumulative.height,
cached_starts,
indexes,
);
Ok(Self {
base,
cumulative,
sum,
average,
})
}
@@ -21,7 +21,7 @@ where
{
pub base: M::Stored<EagerVec<PcoVec<Height, T>>>,
#[traversable(hidden)]
pub cumulative: M::Stored<EagerVec<PcoVec<Height, f64>>>,
pub cumulative: M::Stored<EagerVec<PcoVec<Height, T>>>,
#[traversable(flatten)]
pub average: LazyRollingAvgsFromHeight<T>,
}
@@ -38,8 +38,8 @@ where
cached_starts: &CachedWindowStarts,
) -> Result<Self> {
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 cumulative: EagerVec<PcoVec<Height, T>> =
EagerVec::forced_import(db, &format!("{name}_cumulative"), version + Version::ONE)?;
let average = LazyRollingAvgsFromHeight::new(
&format!("{name}_average"),
version + Version::ONE,
@@ -12,7 +12,7 @@ pub struct LazyRollingAvgFromHeight<T>
where
T: NumericValue + JsonSchema,
{
pub height: LazyDeltaVec<Height, f64, T, DeltaAvg>,
pub height: LazyDeltaVec<Height, T, T, DeltaAvg>,
#[traversable(flatten)]
pub resolutions: Box<Resolutions<T>>,
}
@@ -12,10 +12,11 @@ use crate::{
use super::LazyRollingAvgFromHeight;
/// Lazy rolling averages for all 4 window durations (24h, 1w, 1m, 1y),
/// derived from an f64 cumulative vec + cached window starts.
/// derived from a cumulative vec + cached window starts.
///
/// Nothing is stored on disk — all values are computed on-the-fly via
/// `LazyDeltaVec<Height, f64, T, DeltaAvg>`: `(cum[h] - cum[start-1]) / (h - start + 1)`.
/// `LazyDeltaVec<Height, T, T, DeltaAvg>`: `(cum[h] - cum[start-1]) / (h - start + 1)`.
/// T is converted to f64 internally for division, then back to T.
#[derive(Clone, Deref, DerefMut, Traversable)]
#[traversable(transparent)]
pub struct LazyRollingAvgsFromHeight<T>(pub Windows<LazyRollingAvgFromHeight<T>>)
@@ -29,7 +30,7 @@ where
pub fn new(
name: &str,
version: Version,
cumulative: &(impl ReadableCloneableVec<Height, f64> + 'static),
cumulative: &(impl ReadableCloneableVec<Height, T> + 'static),
cached_starts: &CachedWindowStarts,
indexes: &indexes::Vecs,
) -> Self {
@@ -39,7 +40,7 @@ where
let full_name = format!("{name}_{suffix}");
let cached = cached_start.clone();
let starts_version = cached.version();
let avg = LazyDeltaVec::<Height, f64, T, DeltaAvg>::new(
let avg = LazyDeltaVec::<Height, T, T, DeltaAvg>::new(
&full_name,
version,
cum_source.clone(),
@@ -10,18 +10,19 @@ use vecdb::{Database, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode};
use crate::{
indexes,
internal::{
CachedWindowStarts, NumericValue, LazyRollingSumsFromHeight, RollingDistribution,
WindowStarts,
CachedWindowStarts, NumericValue, LazyRollingAvgsFromHeight, LazyRollingSumsFromHeight,
RollingDistribution, WindowStarts,
},
};
/// Lazy rolling sums + stored rolling distribution (8 stats × 4 windows).
/// Lazy rolling sums + lazy rolling averages + stored rolling distribution (7 stats × 4 windows).
#[derive(Traversable)]
pub struct RollingComplete<T, M: StorageMode = Rw>
where
T: NumericValue + JsonSchema,
{
pub sum: LazyRollingSumsFromHeight<T>,
pub average: LazyRollingAvgsFromHeight<T>,
#[traversable(flatten)]
pub distribution: RollingDistribution<T, M>,
}
@@ -45,9 +46,20 @@ where
cached_starts,
indexes,
);
let average = LazyRollingAvgsFromHeight::new(
&format!("{name}_average"),
version,
cumulative,
cached_starts,
indexes,
);
let distribution = RollingDistribution::forced_import(db, name, version, indexes)?;
Ok(Self { sum, distribution })
Ok(Self {
sum,
average,
distribution,
})
}
/// Compute rolling distribution stats across all 4 windows.
@@ -6,12 +6,12 @@ use vecdb::{ReadableCloneableVec, UnaryTransform};
use crate::{
indexes,
internal::{
CachedWindowStarts, ComputedVecValue, LazyRollingDistribution, LazyRollingSumsFromHeight,
NumericValue, RollingComplete,
CachedWindowStarts, ComputedVecValue, LazyRollingAvgsFromHeight,
LazyRollingDistribution, LazyRollingSumsFromHeight, NumericValue, RollingComplete,
},
};
/// Lazy analog of `RollingComplete<T>`: lazy rolling sums + lazy rolling distribution.
/// Lazy analog of `RollingComplete<T>`: lazy rolling sums + lazy rolling averages + lazy rolling distribution.
/// Zero stored vecs.
#[derive(Clone, Traversable)]
pub struct LazyRollingComplete<T, S1T>
@@ -20,6 +20,7 @@ where
S1T: ComputedVecValue + JsonSchema,
{
pub sum: LazyRollingSumsFromHeight<T>,
pub average: LazyRollingAvgsFromHeight<T>,
#[traversable(flatten)]
pub distribution: LazyRollingDistribution<T, S1T>,
}
@@ -44,11 +45,22 @@ where
cached_starts,
indexes,
);
let average = LazyRollingAvgsFromHeight::new(
&format!("{name}_average"),
version,
cumulative,
cached_starts,
indexes,
);
let distribution = LazyRollingDistribution::from_rolling_distribution::<F>(
name,
version,
&source.distribution,
);
Self { sum, distribution }
Self {
sum,
average,
distribution,
}
}
}
@@ -12,6 +12,7 @@ impl<T: VecValue> UnaryTransform<T, T> for Identity<T> {
}
}
pub struct HalveSats;
impl UnaryTransform<Sats, Sats> for HalveSats {