global: snapshot

This commit is contained in:
nym21
2026-01-13 01:18:27 +01:00
parent 5ffb66c0dc
commit 670aa95494
35 changed files with 10804 additions and 6166 deletions
+2184 -817
View File
File diff suppressed because it is too large Load Diff
@@ -77,11 +77,11 @@ impl Vecs {
where
F: FnOnce(&mut Self) -> &mut EagerVec<PcoVec<Height, Height>>,
{
let mut iter = time.timestamp_fixed.into_iter();
let mut iter = time.timestamp_monotonic.into_iter();
let mut prev = Height::ZERO;
Ok(get_field(self).compute_transform(
starting_indexes.height,
&time.timestamp_fixed,
&time.timestamp_monotonic,
|(h, t, ..)| {
while t.difference_in_days_between(iter.get_unwrap(prev)) >= days {
prev.increment();
+10 -10
View File
@@ -15,24 +15,24 @@ impl Vecs {
starting_height: brk_types::Height,
exit: &Exit,
) -> Result<()> {
let mut prev_timestamp_fixed = None;
self.timestamp_fixed.compute_transform(
let mut prev_timestamp_monotonic = None;
self.timestamp_monotonic.compute_transform(
starting_height,
&indexer.vecs.blocks.timestamp,
|(h, timestamp, height_to_timestamp_fixed_iter)| {
if prev_timestamp_fixed.is_none()
|(h, timestamp, height_to_timestamp_monotonic_iter)| {
if prev_timestamp_monotonic.is_none()
&& let Some(prev_h) = h.decremented()
{
prev_timestamp_fixed.replace(
height_to_timestamp_fixed_iter
prev_timestamp_monotonic.replace(
height_to_timestamp_monotonic_iter
.into_iter()
.get_unwrap(prev_h),
);
}
let timestamp_fixed =
prev_timestamp_fixed.map_or(timestamp, |prev_d| prev_d.max(timestamp));
prev_timestamp_fixed.replace(timestamp_fixed);
(h, timestamp_fixed)
let timestamp_monotonic =
prev_timestamp_monotonic.map_or(timestamp, |prev_d| prev_d.max(timestamp));
prev_timestamp_monotonic.replace(timestamp_monotonic);
(h, timestamp_monotonic)
},
exit,
)?;
@@ -13,7 +13,8 @@ impl Vecs {
indexer: &Indexer,
indexes: &indexes::Vecs,
) -> Result<Self> {
let height_to_timestamp_fixed = EagerVec::forced_import(db, "timestamp_fixed", version)?;
let height_to_timestamp_monotonic =
EagerVec::forced_import(db, "timestamp_monotonic", version)?;
Ok(Self {
date: LazyVecFrom1::init(
@@ -24,13 +25,13 @@ impl Vecs {
timestamp_iter.get_at(height.to_usize()).map(Date::from)
},
),
date_fixed: LazyVecFrom1::init(
"date_fixed",
date_monotonic: LazyVecFrom1::init(
"date_monotonic",
version,
height_to_timestamp_fixed.boxed_clone(),
height_to_timestamp_monotonic.boxed_clone(),
|height: Height, timestamp_iter| timestamp_iter.get(height).map(Date::from),
),
timestamp_fixed: height_to_timestamp_fixed,
timestamp_monotonic: height_to_timestamp_monotonic,
timestamp: ComputedHeightDerivedFirst::forced_import(
db,
"timestamp",
+2 -2
View File
@@ -8,7 +8,7 @@ use crate::internal::ComputedHeightDerivedFirst;
#[derive(Clone, Traversable)]
pub struct Vecs {
pub date: LazyVecFrom1<Height, Date, Height, Timestamp>,
pub date_fixed: LazyVecFrom1<Height, Date, Height, Timestamp>,
pub timestamp_fixed: EagerVec<PcoVec<Height, Timestamp>>,
pub date_monotonic: LazyVecFrom1<Height, Date, Height, Timestamp>,
pub timestamp_monotonic: EagerVec<PcoVec<Height, Timestamp>>,
pub timestamp: ComputedHeightDerivedFirst<Timestamp>,
}
@@ -6,7 +6,7 @@ use vecdb::{Database, IterableCloneableVec};
use super::Vecs;
use crate::{
indexes,
internal::{ComputedHeightDerivedFull, LazyFromHeightFull, WeightToFullness},
internal::{ComputedHeightDerivedFull, LazyFromHeightTransformDistribution, WeightToFullness},
};
impl Vecs {
@@ -24,7 +24,7 @@ impl Vecs {
indexes,
)?;
let fullness = LazyFromHeightFull::from_derived::<WeightToFullness>(
let fullness = LazyFromHeightTransformDistribution::from_derived::<WeightToFullness>(
"block_fullness",
version,
indexer.vecs.blocks.weight.boxed_clone(),
@@ -1,10 +1,10 @@
use brk_traversable::Traversable;
use brk_types::{StoredF32, Weight};
use crate::internal::{ComputedHeightDerivedFull, LazyFromHeightFull};
use crate::internal::{ComputedHeightDerivedFull, LazyFromHeightTransformDistribution};
#[derive(Clone, Traversable)]
pub struct Vecs {
pub weight: ComputedHeightDerivedFull<Weight>,
pub fullness: LazyFromHeightFull<StoredF32, Weight>,
pub fullness: LazyFromHeightTransformDistribution<StoredF32, Weight>,
}
@@ -67,8 +67,8 @@ pub fn process_blocks(
let height_to_output_count = &outputs.count.total_count.height.sum_cum.sum.0;
let height_to_input_count = &inputs.count.height.sum_cum.sum.0;
// From blocks:
let height_to_timestamp = &blocks.time.timestamp_fixed;
let height_to_date = &blocks.time.date_fixed;
let height_to_timestamp = &blocks.time.timestamp_monotonic;
let height_to_date = &blocks.time.date_monotonic;
let dateindex_to_first_height = &indexes.dateindex.first_height;
let dateindex_to_height_count = &indexes.dateindex.height_count;
let txindex_to_output_count = &indexes.txindex.output_count;
@@ -26,7 +26,8 @@ impl ComputeContext {
blocks: &blocks::Vecs,
price: Option<&price::Vecs>,
) -> Self {
let height_to_timestamp: Vec<Timestamp> = blocks.time.timestamp_fixed.into_iter().collect();
let height_to_timestamp: Vec<Timestamp> =
blocks.time.timestamp_monotonic.into_iter().collect();
let height_to_price: Option<Vec<Dollars>> = price
.map(|p| &p.usd.split.close.height)
@@ -9,8 +9,8 @@ use vecdb::{AnyStoredVec, AnyVec, Exit, GenericStoredVec};
use crate::{
indexes,
internal::{
HalfClosePriceTimesSats, HalveDollars, HalveSats, HalveSatsToBitcoin, LazyBinaryValueFromHeightLast,
ValueFromHeightLast,
HalfClosePriceTimesSats, HalveDollars, HalveSats, HalveSatsToBitcoin,
LazyBinaryValueFromHeightLast, ValueFromHeightLast,
},
};
@@ -34,16 +34,16 @@ impl SupplyMetrics {
cfg.price,
)?;
let supply_half = LazyBinaryValueFromHeightLast::from_block_source::<
let supply_halved = LazyBinaryValueFromHeightLast::from_block_source::<
HalveSats,
HalveSatsToBitcoin,
HalfClosePriceTimesSats,
HalveDollars,
>(&cfg.name("supply_half"), &supply, cfg.price, cfg.version);
>(&cfg.name("supply_halved"), &supply, cfg.price, cfg.version);
Ok(Self {
total: supply,
halved: supply_half,
halved: supply_halved,
})
}
+1 -1
View File
@@ -221,7 +221,7 @@ impl Vecs {
(Height::ZERO, vec![])
} else {
// Recover chain_state from stored values
let height_to_timestamp = &blocks.time.timestamp_fixed;
let height_to_timestamp = &blocks.time.timestamp_monotonic;
let height_to_price = price.map(|p| &p.usd.split.close.height);
let mut height_to_timestamp_iter = height_to_timestamp.into_iter();
+35 -27
View File
@@ -19,7 +19,7 @@ use brk_error::Result;
use brk_indexer::Indexer;
use brk_traversable::Traversable;
use brk_types::{DateIndex, Indexes, MonthIndex, Version, WeekIndex};
use vecdb::{Database, Exit, TypedVecIterator, PAGE_SIZE};
use vecdb::{Database, Exit, PAGE_SIZE, TypedVecIterator};
use crate::blocks;
@@ -150,7 +150,7 @@ impl Vecs {
let decremented_starting_height = starting_indexes.height.decremented().unwrap_or_default();
// DateIndex (uses blocks_time.date_fixed computed in blocks::time::compute_early)
// DateIndex (uses blocks_time.date_monotonic computed in blocks::time::compute_early)
let starting_dateindex = self
.height
.dateindex
@@ -160,7 +160,7 @@ impl Vecs {
self.height.dateindex.compute_transform(
starting_indexes.height,
&blocks_time.date_fixed,
&blocks_time.date_monotonic,
|(h, d, ..)| (h, DateIndex::try_from(d).unwrap()),
exit,
)?;
@@ -202,12 +202,14 @@ impl Vecs {
exit,
)?;
self.difficultyepoch.height_count.compute_count_from_indexes(
starting_difficultyepoch,
&self.difficultyepoch.first_height,
&blocks_time.date,
exit,
)?;
self.difficultyepoch
.height_count
.compute_count_from_indexes(
starting_difficultyepoch,
&self.difficultyepoch.first_height,
&blocks_time.date,
exit,
)?;
// Halving epoch
let starting_halvingepoch = self
@@ -355,12 +357,14 @@ impl Vecs {
exit,
)?;
self.quarterindex.monthindex_count.compute_count_from_indexes(
starting_quarterindex,
&self.quarterindex.first_monthindex,
&self.monthindex.identity,
exit,
)?;
self.quarterindex
.monthindex_count
.compute_count_from_indexes(
starting_quarterindex,
&self.quarterindex.first_monthindex,
&self.monthindex.identity,
exit,
)?;
// Semester
let starting_semesterindex = self
@@ -388,12 +392,14 @@ impl Vecs {
exit,
)?;
self.semesterindex.monthindex_count.compute_count_from_indexes(
starting_semesterindex,
&self.semesterindex.first_monthindex,
&self.monthindex.identity,
exit,
)?;
self.semesterindex
.monthindex_count
.compute_count_from_indexes(
starting_semesterindex,
&self.semesterindex.first_monthindex,
&self.monthindex.identity,
exit,
)?;
// Year
let starting_yearindex = self
@@ -454,12 +460,14 @@ impl Vecs {
exit,
)?;
self.decadeindex.yearindex_count.compute_count_from_indexes(
starting_decadeindex,
&self.decadeindex.first_yearindex,
&self.yearindex.identity,
exit,
)?;
self.decadeindex
.yearindex_count
.compute_count_from_indexes(
starting_decadeindex,
&self.decadeindex.first_yearindex,
&self.yearindex.identity,
exit,
)?;
Ok(ComputeIndexes::new(
starting_indexes,
@@ -1,19 +1,19 @@
mod average;
mod distribution;
mod first;
mod full;
mod last;
mod max;
mod min;
mod spread;
mod sum;
mod sum_cum;
pub use average::*;
pub use distribution::*;
pub use first::*;
pub use full::*;
pub use last::*;
pub use max::*;
pub use min::*;
pub use spread::*;
pub use sum::*;
pub use sum_cum::*;
@@ -7,27 +7,27 @@ use brk_types::{
use schemars::JsonSchema;
use vecdb::{IterableBoxedVec, IterableCloneableVec};
use crate::{indexes, internal::LazyDistribution};
use crate::{indexes, internal::LazySpread};
use crate::internal::ComputedVecValue;
#[derive(Clone, Traversable)]
#[traversable(merge)]
pub struct LazyDateDerivedDistribution<T>
pub struct LazyDateDerivedSpread<T>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
{
pub weekindex: LazyDistribution<WeekIndex, T, DateIndex, WeekIndex>,
pub monthindex: LazyDistribution<MonthIndex, T, DateIndex, MonthIndex>,
pub quarterindex: LazyDistribution<QuarterIndex, T, DateIndex, QuarterIndex>,
pub semesterindex: LazyDistribution<SemesterIndex, T, DateIndex, SemesterIndex>,
pub yearindex: LazyDistribution<YearIndex, T, DateIndex, YearIndex>,
pub decadeindex: LazyDistribution<DecadeIndex, T, DateIndex, DecadeIndex>,
pub weekindex: LazySpread<WeekIndex, T, DateIndex, WeekIndex>,
pub monthindex: LazySpread<MonthIndex, T, DateIndex, MonthIndex>,
pub quarterindex: LazySpread<QuarterIndex, T, DateIndex, QuarterIndex>,
pub semesterindex: LazySpread<SemesterIndex, T, DateIndex, SemesterIndex>,
pub yearindex: LazySpread<YearIndex, T, DateIndex, YearIndex>,
pub decadeindex: LazySpread<DecadeIndex, T, DateIndex, DecadeIndex>,
}
const VERSION: Version = Version::ZERO;
impl<T> LazyDateDerivedDistribution<T>
impl<T> LazyDateDerivedSpread<T>
where
T: ComputedVecValue + JsonSchema + 'static,
{
@@ -44,8 +44,12 @@ where
macro_rules! period {
($idx:ident) => {
LazyDistribution::from_distribution(
name, v, average_source.clone(), min_source.clone(), max_source.clone(),
LazySpread::from_distribution(
name,
v,
average_source.clone(),
min_source.clone(),
max_source.clone(),
indexes.$idx.identity.boxed_clone(),
)
};
@@ -0,0 +1,69 @@
//! Lazy transform for Distribution date sources.
//! Like LazyFromDateFull but without sum/cumulative (for ratio/percentage metrics).
use brk_traversable::Traversable;
use brk_types::{
DateIndex, DecadeIndex, MonthIndex, QuarterIndex, SemesterIndex, Version, WeekIndex, YearIndex,
};
use schemars::JsonSchema;
use vecdb::{IterableCloneableVec, UnaryTransform};
use crate::internal::{
ComputedVecValue, Full, LazyDateDerivedFull, LazyTransformDistribution, LazyTransformSpread,
};
const VERSION: Version = Version::ZERO;
/// Distribution stats across date periods. Has average, min, max, percentiles but no sum/cumulative.
#[derive(Clone, Traversable)]
#[traversable(merge)]
pub struct LazyFromDateDistribution<T, S1T = T>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
S1T: ComputedVecValue,
{
pub dateindex: LazyTransformDistribution<DateIndex, T, S1T>,
pub weekindex: LazyTransformSpread<WeekIndex, T, S1T>,
pub monthindex: LazyTransformSpread<MonthIndex, T, S1T>,
pub quarterindex: LazyTransformSpread<QuarterIndex, T, S1T>,
pub semesterindex: LazyTransformSpread<SemesterIndex, T, S1T>,
pub yearindex: LazyTransformSpread<YearIndex, T, S1T>,
pub decadeindex: LazyTransformSpread<DecadeIndex, T, S1T>,
}
impl<T, S1T> LazyFromDateDistribution<T, S1T>
where
T: ComputedVecValue + JsonSchema + 'static,
S1T: ComputedVecValue + JsonSchema,
{
pub fn from_full<F: UnaryTransform<S1T, T>>(
name: &str,
version: Version,
dateindex: &Full<DateIndex, S1T>,
source: &LazyDateDerivedFull<S1T>,
) -> Self {
let v = version + VERSION;
macro_rules! period {
($p:ident) => {
LazyTransformSpread::from_boxed::<F>(
name,
v,
source.$p.average.boxed_clone(),
source.$p.min.boxed_clone(),
source.$p.max.boxed_clone(),
)
};
}
Self {
dateindex: LazyTransformDistribution::from_stats_aggregate::<F>(name, v, dateindex),
weekindex: period!(weekindex),
monthindex: period!(monthindex),
quarterindex: period!(quarterindex),
semesterindex: period!(semesterindex),
yearindex: period!(yearindex),
decadeindex: period!(decadeindex),
}
}
}
@@ -5,6 +5,7 @@ mod binary_sum_cum;
mod first;
mod last;
mod lazy;
mod lazy_distribution;
mod lazy_full;
mod lazy_last;
mod lazy_sum;
@@ -25,6 +26,7 @@ pub use binary_sum_cum::*;
pub use first::*;
pub use last::*;
pub use lazy::*;
pub use lazy_distribution::*;
pub use lazy_full::*;
pub use lazy_last::*;
pub use lazy_sum::*;
@@ -0,0 +1,50 @@
//! Lazy unary transform from height with Distribution aggregation.
//! Like LazyFromHeightFull but without sum/cumulative (for ratio/percentage metrics).
use brk_traversable::Traversable;
use brk_types::{Height, Version};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{IterableBoxedVec, LazyVecFrom1, UnaryTransform};
use crate::internal::{
ComputedHeightDerivedFull, ComputedVecValue, LazyHeightDerivedDistribution, NumericValue,
};
#[derive(Clone, Deref, DerefMut, Traversable)]
#[traversable(merge)]
pub struct LazyFromHeightTransformDistribution<T, S1T = T>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
S1T: ComputedVecValue,
{
#[traversable(rename = "base")]
pub height: LazyVecFrom1<Height, T, Height, S1T>,
#[deref]
#[deref_mut]
pub rest: LazyHeightDerivedDistribution<T, S1T>,
}
const VERSION: Version = Version::ZERO;
impl<T, S1T> LazyFromHeightTransformDistribution<T, S1T>
where
T: ComputedVecValue + JsonSchema + 'static,
S1T: ComputedVecValue + JsonSchema,
{
pub fn from_derived<F: UnaryTransform<S1T, T>>(
name: &str,
version: Version,
height_source: IterableBoxedVec<Height, S1T>,
source: &ComputedHeightDerivedFull<S1T>,
) -> Self
where
S1T: NumericValue,
{
let v = version + VERSION;
Self {
height: LazyVecFrom1::transformed::<F>(name, v, height_source),
rest: LazyHeightDerivedDistribution::from_derived_computed::<F>(name, v, source),
}
}
}
@@ -6,6 +6,7 @@ mod full;
mod last;
mod lazy_distribution;
mod lazy_full;
mod lazy_transform_distribution;
mod lazy_binary_computed_full;
mod lazy_binary_computed_last;
mod lazy_binary_computed_sum;
@@ -36,6 +37,7 @@ pub use full::*;
pub use last::*;
pub use lazy_distribution::*;
pub use lazy_full::*;
pub use lazy_transform_distribution::*;
pub use lazy_binary_computed_full::*;
pub use lazy_binary_computed_last::*;
pub use lazy_binary_computed_sum::*;
@@ -10,9 +10,7 @@ use vecdb::{Database, Exit, IterableBoxedVec, IterableCloneableVec, IterableVec}
use crate::{
ComputeIndexes, indexes,
internal::{
ComputedVecValue, LazyDateDerivedDistribution, Distribution, LazyDistribution, NumericValue,
},
internal::{ComputedVecValue, Distribution, LazyDateDerivedSpread, LazySpread, NumericValue},
};
#[derive(Clone, Deref, DerefMut, Traversable)]
@@ -24,8 +22,8 @@ where
pub dateindex: Distribution<DateIndex, T>,
#[deref]
#[deref_mut]
pub dates: LazyDateDerivedDistribution<T>,
pub difficultyepoch: LazyDistribution<DifficultyEpoch, T, Height, DifficultyEpoch>,
pub dates: LazyDateDerivedSpread<T>,
pub difficultyepoch: LazySpread<DifficultyEpoch, T, Height, DifficultyEpoch>,
}
const VERSION: Version = Version::ZERO;
@@ -44,7 +42,7 @@ where
let dateindex = Distribution::forced_import(db, name, version + VERSION)?;
let v = version + VERSION;
let dates = LazyDateDerivedDistribution::from_sources(
let dates = LazyDateDerivedSpread::from_sources(
name,
v,
dateindex.boxed_average(),
@@ -53,7 +51,7 @@ where
indexes,
);
let difficultyepoch = LazyDistribution::from_distribution(
let difficultyepoch = LazySpread::from_distribution(
name,
v,
height_source.boxed_clone(),
@@ -0,0 +1,82 @@
//! Lazy aggregated Distribution for block-level sources.
//! Like LazyHeightDerivedFull but without sum/cumulative (for ratio/percentage metrics).
use brk_traversable::Traversable;
use brk_types::{DateIndex, DifficultyEpoch, Version};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{IterableCloneableVec, UnaryTransform};
use crate::internal::{
ComputedHeightDerivedFull, ComputedVecValue, Full, LazyDateDerivedFull,
LazyFromDateDistribution, LazyTransformSpread, NumericValue,
};
#[derive(Clone, Deref, DerefMut, Traversable)]
#[traversable(merge)]
pub struct LazyHeightDerivedDistribution<T, S1T = T>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
S1T: ComputedVecValue,
{
#[deref]
#[deref_mut]
pub dates: LazyFromDateDistribution<T, S1T>,
pub difficultyepoch: LazyTransformSpread<DifficultyEpoch, T, S1T>,
}
const VERSION: Version = Version::ZERO;
impl<T, S1T> LazyHeightDerivedDistribution<T, S1T>
where
T: ComputedVecValue + JsonSchema + 'static,
S1T: ComputedVecValue + JsonSchema,
{
pub fn from_computed<F: UnaryTransform<S1T, T>>(
name: &str,
version: Version,
dateindex: &Full<DateIndex, S1T>,
periods: &LazyDateDerivedFull<S1T>,
difficultyepoch: &crate::internal::LazyFull<
DifficultyEpoch,
S1T,
brk_types::Height,
DifficultyEpoch,
>,
) -> Self {
let v = version + VERSION;
Self {
dates: LazyFromDateDistribution::from_full::<F>(name, v, dateindex, periods),
difficultyepoch: LazyTransformSpread::from_boxed::<F>(
name,
v,
difficultyepoch.average.boxed_clone(),
difficultyepoch.min.boxed_clone(),
difficultyepoch.max.boxed_clone(),
),
}
}
pub fn from_derived_computed<F: UnaryTransform<S1T, T>>(
name: &str,
version: Version,
source: &ComputedHeightDerivedFull<S1T>,
) -> Self
where
S1T: NumericValue,
{
let v = version + VERSION;
Self {
dates: LazyFromDateDistribution::from_full::<F>(name, v, &source.dateindex, &source.dates),
difficultyepoch: LazyTransformSpread::from_boxed::<F>(
name,
v,
source.difficultyepoch.average.boxed_clone(),
source.difficultyepoch.min.boxed_clone(),
source.difficultyepoch.max.boxed_clone(),
),
}
}
}
@@ -5,6 +5,7 @@ mod distribution;
mod first;
mod full;
mod last;
mod lazy_distribution;
mod lazy_full;
mod lazy_last;
mod lazy_sum;
@@ -20,6 +21,7 @@ pub use distribution::*;
pub use first::*;
pub use full::*;
pub use last::*;
pub use lazy_distribution::*;
pub use lazy_full::*;
pub use lazy_last::*;
pub use lazy_sum::*;
@@ -16,7 +16,7 @@ use vecdb::{CollectableVec, Database, Exit, IterableCloneableVec};
use crate::{
ComputeIndexes, indexes,
internal::{
ComputedVecValue, LazyDateDerivedDistribution, Distribution, LazyDistribution, MinMaxAverage,
ComputedVecValue, Distribution, LazyDateDerivedSpread, LazySpread, MinMaxAverage,
NumericValue,
},
};
@@ -28,12 +28,12 @@ where
T: ComputedVecValue + PartialOrd + JsonSchema,
{
pub height: Distribution<Height, T>,
pub difficultyepoch: LazyDistribution<DifficultyEpoch, T, Height, DifficultyEpoch>,
pub difficultyepoch: LazySpread<DifficultyEpoch, T, Height, DifficultyEpoch>,
pub dateindex: MinMaxAverage<DateIndex, T>,
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub dates: LazyDateDerivedDistribution<T>,
pub dates: LazyDateDerivedSpread<T>,
}
const VERSION: Version = Version::ZERO;
@@ -53,7 +53,7 @@ where
let v = version + VERSION;
let difficultyepoch =
LazyDistribution::<DifficultyEpoch, T, Height, DifficultyEpoch>::from_distribution(
LazySpread::<DifficultyEpoch, T, Height, DifficultyEpoch>::from_distribution(
name,
v,
height.boxed_average(),
@@ -62,7 +62,7 @@ where
indexes.difficultyepoch.identity.boxed_clone(),
);
let dates = LazyDateDerivedDistribution::from_sources(
let dates = LazyDateDerivedSpread::from_sources(
name,
v,
dateindex.boxed_average(),
@@ -2,22 +2,22 @@
mod average;
mod cumulative;
mod distribution;
mod first;
mod full;
mod last;
mod max;
mod min;
mod full;
mod spread;
mod sum;
mod sum_cum;
pub use average::*;
pub use cumulative::*;
pub use distribution::*;
pub use first::*;
pub use full::*;
pub use last::*;
pub use max::*;
pub use min::*;
pub use full::*;
pub use spread::*;
pub use sum::*;
pub use sum_cum::*;
@@ -11,7 +11,7 @@ use crate::internal::ComputedVecValue;
const VERSION: Version = Version::ZERO;
#[derive(Clone, Traversable)]
pub struct LazyDistribution<I, T, S1I, S2T>
pub struct LazySpread<I, T, S1I, S2T>
where
I: VecIndex,
T: ComputedVecValue + JsonSchema,
@@ -26,7 +26,7 @@ where
pub max: LazyMax<I, T, S1I, S2T>,
}
impl<I, T, S1I, S2T> LazyDistribution<I, T, S1I, S2T>
impl<I, T, S1I, S2T> LazySpread<I, T, S1I, S2T>
where
I: VecIndex,
T: ComputedVecValue + JsonSchema + 'static,
@@ -0,0 +1,64 @@
//! Lazy unary transform for Distribution metrics.
//! Has average, min, max, and percentiles - but no sum/cumulative.
//! Use for ratio/percentage metrics where aggregation doesn't make sense.
use brk_traversable::Traversable;
use brk_types::Version;
use schemars::JsonSchema;
use vecdb::{LazyVecFrom1, UnaryTransform, VecIndex};
use crate::internal::{ComputedVecValue, Full};
use super::LazyPercentiles;
/// Distribution stats: average, min, max, percentiles.
/// Excludes sum and cumulative (meaningless for ratios/percentages).
#[derive(Clone, Traversable)]
pub struct LazyTransformDistribution<I, T, S1T = T>
where
I: VecIndex,
T: ComputedVecValue + PartialOrd + JsonSchema,
S1T: ComputedVecValue,
{
pub average: LazyVecFrom1<I, T, I, S1T>,
pub min: LazyVecFrom1<I, T, I, S1T>,
pub max: LazyVecFrom1<I, T, I, S1T>,
#[traversable(flatten)]
pub percentiles: LazyPercentiles<I, T, S1T>,
}
impl<I, T, S1T> LazyTransformDistribution<I, T, S1T>
where
I: VecIndex,
T: ComputedVecValue + JsonSchema + 'static,
S1T: ComputedVecValue + JsonSchema,
{
pub fn from_stats_aggregate<F: UnaryTransform<S1T, T>>(
name: &str,
version: Version,
source: &Full<I, S1T>,
) -> Self {
Self {
average: LazyVecFrom1::transformed::<F>(
&format!("{name}_average"),
version,
source.boxed_average(),
),
min: LazyVecFrom1::transformed::<F>(
&format!("{name}_min"),
version,
source.boxed_min(),
),
max: LazyVecFrom1::transformed::<F>(
&format!("{name}_max"),
version,
source.boxed_max(),
),
percentiles: LazyPercentiles::from_percentiles::<F>(
name,
version,
&source.distribution.percentiles,
),
}
}
}
@@ -3,9 +3,11 @@ mod binary_last;
mod binary_percentiles;
mod binary_sum;
mod binary_sum_cum;
mod distribution;
mod full;
mod last;
mod percentiles;
mod spread;
mod stats;
mod sum;
mod sum_cum;
@@ -15,9 +17,11 @@ pub use binary_last::*;
pub use binary_percentiles::*;
pub use binary_sum::*;
pub use binary_sum_cum::*;
pub use distribution::*;
pub use full::*;
pub use last::*;
pub use percentiles::*;
pub use spread::*;
pub use stats::*;
pub use sum::*;
pub use sum_cum::*;
@@ -0,0 +1,49 @@
//! Lazy unary transform for Spread metrics.
//! Has average, min, max only - no percentiles, no sum/cumulative.
//! Use for ratio/percentage metrics where you only need basic range info.
use brk_traversable::Traversable;
use brk_types::Version;
use schemars::JsonSchema;
use vecdb::{IterableBoxedVec, LazyVecFrom1, UnaryTransform, VecIndex};
use crate::internal::ComputedVecValue;
/// Spread stats: average, min, max only.
/// Excludes percentiles (no detailed distribution) and sum/cumulative (meaningless for ratios).
#[derive(Clone, Traversable)]
pub struct LazyTransformSpread<I, T, S1T = T>
where
I: VecIndex,
T: ComputedVecValue + PartialOrd + JsonSchema,
S1T: ComputedVecValue,
{
pub average: LazyVecFrom1<I, T, I, S1T>,
pub min: LazyVecFrom1<I, T, I, S1T>,
pub max: LazyVecFrom1<I, T, I, S1T>,
}
impl<I, T, S1T> LazyTransformSpread<I, T, S1T>
where
I: VecIndex,
T: ComputedVecValue + JsonSchema + 'static,
S1T: ComputedVecValue + JsonSchema,
{
pub fn from_boxed<F: UnaryTransform<S1T, T>>(
name: &str,
version: Version,
average_source: IterableBoxedVec<I, S1T>,
min_source: IterableBoxedVec<I, S1T>,
max_source: IterableBoxedVec<I, S1T>,
) -> Self {
Self {
average: LazyVecFrom1::transformed::<F>(
&format!("{name}_average"),
version,
average_source,
),
min: LazyVecFrom1::transformed::<F>(&format!("{name}_min"), version, min_source),
max: LazyVecFrom1::transformed::<F>(&format!("{name}_max"), version, max_source),
}
}
}
@@ -1,7 +1,7 @@
use brk_types::Dollars;
use vecdb::UnaryTransform;
/// Dollars -> Dollars/2 (for supply_half_usd)
/// Dollars -> Dollars/2 (for supply_halved_usd)
pub struct HalveDollars;
impl UnaryTransform<Dollars, Dollars> for HalveDollars {
@@ -1,7 +1,7 @@
use brk_types::Sats;
use vecdb::UnaryTransform;
/// Sats -> Sats/2 (for supply_half)
/// Sats -> Sats/2 (for supply_halved)
pub struct HalveSats;
impl UnaryTransform<Sats, Sats> for HalveSats {
+1 -1
View File
@@ -266,7 +266,7 @@ impl Computer {
) -> Result<()> {
let compute_start = Instant::now();
// Compute blocks.time early (height_to_date, height_to_timestamp_fixed, height_to_date_fixed)
// Compute blocks.time early (height_to_date, height_to_timestamp_monotonic, height_to_date_monotonic)
// These are needed by indexes::block to compute height_to_dateindex
info!("Computing blocks.time (early)...");
let i = Instant::now();
+1 -1
View File
@@ -25,7 +25,7 @@ impl BlocksVecs {
difficulty = PcoVec::forced_import(db, "difficulty", version),
timestamp = PcoVec::forced_import(db, "timestamp", version),
total_size = PcoVec::forced_import(db, "total_size", version),
weight = PcoVec::forced_import(db, "weight", version),
weight = PcoVec::forced_import(db, "block_weight", version),
};
Ok(Self {
blockhash,
+4 -1
View File
@@ -264,7 +264,10 @@ fn generate_field_traversals(infos: &[FieldInfo], merge: bool) -> proc_macro2::T
.filter(|i| matches!(i.attr, FieldAttr::Normal))
.map(|info| {
let field_name = info.name;
let field_name_str = field_name.to_string();
let field_name_str = {
let s = field_name.to_string();
s.strip_prefix('_').map(String::from).unwrap_or(s)
};
// Determine outer key and inner wrap key based on which attrs are present
// When both wrap and rename are present: wrap is outer container, rename is inner key
+3253 -2362
View File
File diff suppressed because it is too large Load Diff
+17 -3
View File
@@ -40,6 +40,12 @@ function getAllMetrics(obj, path = "") {
return metrics;
}
// Endpoints with sparse data (holes at the end) - skip these
const SKIP_ENDPOINTS = new Set([
"distribution.addressesData.empty.by.emptyaddressindex",
"distribution.addressesData.loaded.by.loadedaddressindex",
]);
async function testAllEndpoints() {
const client = new BrkClient({ baseUrl: "http://localhost:3110", timeout: 15000 });
@@ -47,24 +53,31 @@ async function testAllEndpoints() {
console.log(`\nFound ${metrics.length} metrics`);
let success = 0;
let skipped = 0;
for (const { path, metric, indexes } of metrics) {
for (const idxName of indexes) {
const fullPath = `${path}.by.${idxName}`;
if (SKIP_ENDPOINTS.has(fullPath)) {
skipped++;
console.log(`SKIP: ${fullPath} -> sparse data`);
continue;
}
try {
const endpoint = metric.by[idxName];
const res = await endpoint.last(1);
const count = res.data.length;
if (count !== 1) {
console.log(
`FAIL: ${path}.by.${idxName} -> expected 1, got ${count}`,
`FAIL: ${fullPath} -> expected 1, got ${count}`,
);
return;
}
success++;
console.log(`OK: ${path}.by.${idxName} -> ${count} items`);
console.log(`OK: ${fullPath} -> ${count} items`);
} catch (e) {
console.log(
`FAIL: ${path}.by.${idxName} -> ${e instanceof Error ? e.message : e}`,
`FAIL: ${fullPath} -> ${e instanceof Error ? e.message : e}`,
);
return;
}
@@ -73,6 +86,7 @@ async function testAllEndpoints() {
console.log(`\n=== Results ===`);
console.log(`Success: ${success}`);
console.log(`Skipped: ${skipped}`);
}
testAllEndpoints();
File diff suppressed because it is too large Load Diff