mod addr;
mod height;
mod resolution;
pub mod timestamp;
mod tx_heights;
mod tx_index;
mod txin_index;
mod txout_index;
use std::path::Path;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_traversable::Traversable;
use brk_types::{
Date, Day1, Day3, Epoch, Halving, Height, Hour1, Hour4, Hour12, Minute10, Minute30, Month1,
Month3, Month6, Version, Week1, Year1, Year10,
};
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
use crate::internal::db_utils::{finalize_db, open_db};
pub use addr::Vecs as AddrVecs;
pub use height::Vecs as HeightVecs;
pub use resolution::{DatedResolutionVecs, ResolutionVecs};
pub use timestamp::Timestamps;
pub use tx_heights::TxHeights;
pub use tx_index::Vecs as TxIndexVecs;
pub use txin_index::Vecs as TxInIndexVecs;
pub use txout_index::Vecs as TxOutIndexVecs;
pub type Minute10Vecs<M = Rw> = ResolutionVecs<Minute10, M>;
pub type Minute30Vecs<M = Rw> = ResolutionVecs<Minute30, M>;
pub type Hour1Vecs<M = Rw> = ResolutionVecs<Hour1, M>;
pub type Hour4Vecs<M = Rw> = ResolutionVecs<Hour4, M>;
pub type Hour12Vecs<M = Rw> = ResolutionVecs<Hour12, M>;
pub type Day1Vecs<M = Rw> = DatedResolutionVecs<Day1, M>;
pub type Day3Vecs<M = Rw> = DatedResolutionVecs<Day3, M>;
pub type EpochVecs<M = Rw> = ResolutionVecs<Epoch, M>;
pub type HalvingVecs<M = Rw> = ResolutionVecs<Halving, M>;
pub type Week1Vecs<M = Rw> = DatedResolutionVecs<Week1, M>;
pub type Month1Vecs<M = Rw> = DatedResolutionVecs<Month1, M>;
pub type Month3Vecs<M = Rw> = DatedResolutionVecs<Month3, M>;
pub type Month6Vecs<M = Rw> = DatedResolutionVecs<Month6, M>;
pub type Year1Vecs<M = Rw> = DatedResolutionVecs<Year1, M>;
pub type Year10Vecs<M = Rw> = DatedResolutionVecs<Year10, M>;
pub const DB_NAME: &str = "indexes";
#[derive(Traversable)]
pub struct Vecs<M: StorageMode = Rw> {
db: Database,
#[traversable(skip)]
pub tx_heights: TxHeights,
pub addr: AddrVecs,
pub height: HeightVecs<M>,
pub epoch: EpochVecs<M>,
pub halving: HalvingVecs<M>,
pub minute10: Minute10Vecs<M>,
pub minute30: Minute30Vecs<M>,
pub hour1: Hour1Vecs<M>,
pub hour4: Hour4Vecs<M>,
pub hour12: Hour12Vecs<M>,
pub day1: Day1Vecs<M>,
pub day3: Day3Vecs<M>,
pub week1: Week1Vecs<M>,
pub month1: Month1Vecs<M>,
pub month3: Month3Vecs<M>,
pub month6: Month6Vecs<M>,
pub year1: Year1Vecs<M>,
pub year10: Year10Vecs<M>,
pub tx_index: TxIndexVecs<M>,
pub txin_index: TxInIndexVecs,
pub txout_index: TxOutIndexVecs,
pub timestamp: Timestamps<M>,
}
impl Vecs {
pub(crate) fn forced_import(
parent: &Path,
parent_version: Version,
indexer: &Indexer,
) -> Result<Self> {
let db = open_db(parent, DB_NAME, 1_000_000)?;
let version = parent_version;
let addr = AddrVecs::forced_import(version, indexer);
let height = HeightVecs::forced_import(&db, version)?;
let epoch = ResolutionVecs::forced_import(&db, version)?;
let halving = ResolutionVecs::forced_import(&db, version)?;
let minute10 = ResolutionVecs::forced_import(&db, version)?;
let minute30 = ResolutionVecs::forced_import(&db, version)?;
let hour1 = ResolutionVecs::forced_import(&db, version)?;
let hour4 = ResolutionVecs::forced_import(&db, version)?;
let hour12 = ResolutionVecs::forced_import(&db, version)?;
let day1 = Day1Vecs::forced_import(&db, version)?;
let day3 = DatedResolutionVecs::forced_import(&db, version)?;
let week1 = DatedResolutionVecs::forced_import(&db, version)?;
let month1 = DatedResolutionVecs::forced_import(&db, version)?;
let month3 = DatedResolutionVecs::forced_import(&db, version)?;
let month6 = DatedResolutionVecs::forced_import(&db, version)?;
let year1 = DatedResolutionVecs::forced_import(&db, version)?;
let year10 = DatedResolutionVecs::forced_import(&db, version)?;
let tx_index = TxIndexVecs::forced_import(&db, version, indexer)?;
let txin_index = TxInIndexVecs::forced_import(version, indexer);
let txout_index = TxOutIndexVecs::forced_import(version, indexer);
let timestamp = Timestamps::forced_import_from_locals(
&db, version, &minute10, &minute30, &hour1, &hour4, &hour12, &day1, &day3, &week1,
&month1, &month3, &month6, &year1, &year10,
)?;
let this = Self {
tx_heights: TxHeights::init(indexer),
addr,
height,
epoch,
halving,
minute10,
minute30,
hour1,
hour4,
hour12,
day1,
day3,
week1,
month1,
month3,
month6,
year1,
year10,
tx_index,
txin_index,
txout_index,
timestamp,
db,
};
finalize_db(&this.db, &this)?;
Ok(this)
}
pub(crate) fn compute(&mut self, indexer: &Indexer, exit: &Exit) -> Result<()> {
self.db.sync_bg_tasks()?;
let starting_height = indexer.safe_lengths().height;
self.tx_heights.update(indexer, starting_height);
self.timestamp
.compute_monotonic(indexer, starting_height, exit)?;
self.compute_tx_indexes(indexer, exit)?;
self.compute_height_indexes(indexer, exit)?;
let prev_height = starting_height.decremented().unwrap_or_default();
self.compute_timestamp_mappings(indexer, exit)?;
let starting_day1 = self.compute_calendar_mappings(indexer, prev_height, exit)?;
self.compute_period_vecs(indexer, prev_height, starting_day1, exit)?;
self.timestamp.compute_per_resolution(
indexer,
&self.height,
&self.halving,
&self.epoch,
&indexer.safe_lengths(),
exit,
)?;
let exit = exit.clone();
self.db.run_bg(move |db| {
let _lock = exit.lock();
db.compact_deferred_default()
});
Ok(())
}
fn compute_tx_indexes(&mut self, indexer: &Indexer, exit: &Exit) -> Result<()> {
let starting_lengths = indexer.safe_lengths();
let (r1, r2) = rayon::join(
|| {
self.tx_index.input_count.compute_count_from_indexes(
starting_lengths.tx_index,
&indexer.vecs.transactions.first_txin_index,
&indexer.vecs.inputs.outpoint,
exit,
)
},
|| {
self.tx_index.output_count.compute_count_from_indexes(
starting_lengths.tx_index,
&indexer.vecs.transactions.first_txout_index,
&indexer.vecs.outputs.value,
exit,
)
},
);
r1?;
r2?;
Ok(())
}
fn compute_height_indexes(&mut self, indexer: &Indexer, exit: &Exit) -> Result<()> {
let starting_height = indexer.safe_lengths().height;
self.height.tx_index_count.compute_count_from_indexes(
starting_height,
&indexer.vecs.transactions.first_tx_index,
&indexer.vecs.transactions.txid,
exit,
)?;
Ok(())
}
fn compute_timestamp_mappings(&mut self, indexer: &Indexer, exit: &Exit) -> Result<()> {
let starting_height = indexer.safe_lengths().height;
macro_rules! from_timestamp {
($field:ident, $period:ty) => {
self.height.$field.compute_transform(
starting_height,
&self.timestamp.monotonic,
|(h, ts, _)| (h, <$period>::from_timestamp(ts)),
exit,
)?;
};
}
from_timestamp!(minute10, Minute10);
from_timestamp!(minute30, Minute30);
from_timestamp!(hour1, Hour1);
from_timestamp!(hour4, Hour4);
from_timestamp!(hour12, Hour12);
from_timestamp!(day3, Day3);
Ok(())
}
fn compute_calendar_mappings(
&mut self,
indexer: &Indexer,
prev_height: Height,
exit: &Exit,
) -> Result<Day1> {
let starting_height = indexer.safe_lengths().height;
let starting_day1 = self
.height
.day1
.collect_one(prev_height)
.unwrap_or_default();
self.height.day1.compute_transform(
starting_height,
&self.timestamp.monotonic,
|(h, ts, ..)| (h, Day1::try_from(Date::from(ts)).unwrap()),
exit,
)?;
let starting_day1 = if let Some(day1) = self.height.day1.collect_one(prev_height) {
starting_day1.min(day1)
} else {
starting_day1
};
self.compute_epoch(indexer, exit)?;
self.height.week1.compute_transform(
starting_height,
&self.height.day1,
|(h, di, _)| (h, Week1::from(di)),
exit,
)?;
self.height.month1.compute_transform(
starting_height,
&self.height.day1,
|(h, di, _)| (h, Month1::from(di)),
exit,
)?;
self.height.month3.compute_transform(
starting_height,
&self.height.month1,
|(h, mi, _)| (h, Month3::from(mi)),
exit,
)?;
self.height.month6.compute_transform(
starting_height,
&self.height.month1,
|(h, mi, _)| (h, Month6::from(mi)),
exit,
)?;
self.height.year1.compute_transform(
starting_height,
&self.height.month1,
|(h, mi, _)| (h, Year1::from(mi)),
exit,
)?;
self.height.year10.compute_transform(
starting_height,
&self.height.year1,
|(h, yi, _)| (h, Year10::from(yi)),
exit,
)?;
Ok(starting_day1)
}
fn compute_epoch(&mut self, indexer: &Indexer, exit: &Exit) -> Result<()> {
let starting_height = indexer.safe_lengths().height;
self.height
.epoch
.compute_from_index(starting_height, &indexer.vecs.blocks.weight, exit)?;
self.epoch.first_height.inner.compute_first_per_index(
starting_height,
&self.height.epoch,
exit,
)?;
self.height.halving.compute_from_index(
starting_height,
&indexer.vecs.blocks.weight,
exit,
)?;
self.halving.first_height.inner.compute_first_per_index(
starting_height,
&self.height.halving,
exit,
)?;
Ok(())
}
fn compute_period_vecs(
&mut self,
indexer: &Indexer,
prev_height: Height,
starting_day1: Day1,
exit: &Exit,
) -> Result<()> {
let starting_height = indexer.safe_lengths().height;
macro_rules! basic_period {
($period:ident) => {
self.$period.first_height.inner.compute_first_per_index(
starting_height,
&self.height.$period,
exit,
)?;
};
}
basic_period!(minute10);
basic_period!(minute30);
basic_period!(hour1);
basic_period!(hour4);
basic_period!(hour12);
self.day1.first_height.inner.compute_first_per_index(
starting_height,
&self.height.day1,
exit,
)?;
self.day1.date.compute_transform(
starting_day1,
&self.day1.first_height,
|(di, ..)| (di, Date::from(di)),
exit,
)?;
let ts = &self.timestamp.monotonic;
macro_rules! dated_period {
($period:ident) => {{
self.$period.first_height.inner.compute_first_per_index(
starting_height,
&self.height.$period,
exit,
)?;
let start = self
.height
.$period
.collect_one(prev_height)
.unwrap_or_default();
self.$period.date.compute_transform(
start,
&self.$period.first_height,
|(idx, first_h, _)| (idx, Date::from(ts.collect_one(first_h).unwrap())),
exit,
)?;
}};
}
dated_period!(day3);
dated_period!(week1);
dated_period!(month1);
dated_period!(month3);
dated_period!(month6);
dated_period!(year1);
dated_period!(year10);
Ok(())
}
}