global: speed improvement

This commit is contained in:
nym21
2026-04-09 11:52:01 +02:00
parent c5c49f62d1
commit 21a0226a19
20 changed files with 1489 additions and 4942 deletions

View File

@@ -14,6 +14,7 @@ mod month1;
mod month3;
mod month6;
pub mod timestamp;
mod tx_heights;
mod tx_index;
mod txin_index;
mod txout_index;
@@ -50,6 +51,7 @@ pub use month1::Vecs as Month1Vecs;
pub use month3::Vecs as Month3Vecs;
pub use month6::Vecs as Month6Vecs;
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;
@@ -64,6 +66,8 @@ pub struct Vecs<M: StorageMode = Rw> {
db: Database,
#[traversable(skip)]
pub cached_mappings: CachedMappings,
#[traversable(skip)]
pub tx_heights: TxHeights,
pub addr: AddrVecs,
pub height: HeightVecs<M>,
pub epoch: EpochVecs<M>,
@@ -143,6 +147,7 @@ impl Vecs {
let this = Self {
cached_mappings,
tx_heights: TxHeights::init(indexer),
addr,
height,
epoch,
@@ -179,6 +184,8 @@ impl Vecs {
) -> Result<Indexes> {
self.db.sync_bg_tasks()?;
self.tx_heights.update(indexer, starting_indexes.height);
// timestamp_monotonic must be computed first — other mappings read it
self.timestamp
.compute_monotonic(indexer, starting_indexes.height, exit)?;

View File

@@ -0,0 +1,61 @@
use std::sync::Arc;
use brk_indexer::Indexer;
use brk_types::{Height, RangeMap, TxIndex};
use parking_lot::RwLock;
use vecdb::{AnyVec, ReadableVec, VecIndex};
/// Reverse mapping from `TxIndex` → `Height` via binary search on block boundaries.
///
/// Built from `first_tx_index` (the first TxIndex in each block). A floor lookup
/// on any TxIndex gives the block height that contains it.
///
/// Wrapped in `Arc<RwLock<>>` so the compute thread can extend it while
/// query threads read concurrently — the inner `RangeMap` is purely in-memory
/// and wouldn't stay current through mmap like PcoVec/BytesVec do.
#[derive(Clone)]
pub struct TxHeights(Arc<RwLock<RangeMap<TxIndex, Height>>>);
impl TxHeights {
/// Build from the full `first_tx_index` vec at startup.
pub fn init(indexer: &Indexer) -> Self {
let len = indexer.vecs.transactions.first_tx_index.len();
let entries: Vec<TxIndex> = if len > 0 {
indexer
.vecs
.transactions
.first_tx_index
.collect_range_at(0, len)
} else {
Vec::new()
};
Self(Arc::new(RwLock::new(RangeMap::from(entries))))
}
/// Extend with new blocks since last call. Truncates on reorg.
pub fn update(&self, indexer: &Indexer, reorg_height: Height) {
let mut inner = self.0.write();
let reorg_len = reorg_height.to_usize();
if inner.len() > reorg_len {
inner.truncate(reorg_len);
}
let target_len = indexer.vecs.transactions.first_tx_index.len();
let current_len = inner.len();
if current_len < target_len {
let new_entries: Vec<TxIndex> = indexer
.vecs
.transactions
.first_tx_index
.collect_range_at(current_len, target_len);
for entry in new_entries {
inner.push(entry);
}
}
}
/// Look up the block height for a given tx_index.
#[inline]
pub fn get_shared(&self, tx_index: TxIndex) -> Option<Height> {
self.0.read().get_shared(tx_index)
}
}

View File

@@ -12,6 +12,9 @@ use vecdb::{
pub mod major;
pub mod minor;
mod pool_heights;
pub use pool_heights::PoolHeights;
use crate::{
blocks, indexes,
@@ -30,6 +33,8 @@ pub struct Vecs<M: StorageMode = Rw> {
pools: &'static Pools,
pub pool: M::Stored<BytesVec<Height, PoolSlug>>,
#[traversable(skip)]
pub pool_heights: PoolHeights,
pub major: BTreeMap<PoolSlug, major::Vecs<M>>,
pub minor: BTreeMap<PoolSlug, minor::Vecs<M>>,
}
@@ -63,8 +68,12 @@ impl Vecs {
}
}
let pool = BytesVec::forced_import(&db, "pool", version)?;
let pool_heights = PoolHeights::build(&pool);
let this = Self {
pool: BytesVec::forced_import(&db, "pool", version)?,
pool,
pool_heights,
major: major_map,
minor: minor_map,
pools,
@@ -149,8 +158,10 @@ impl Vecs {
let mut output_count_cursor = indexes.tx_index.output_count.cursor();
self.pool.truncate_if_needed_at(min)?;
self.pool_heights.truncate(min);
let len = indexer.vecs.blocks.coinbase_tag.len();
let mut next_height = min;
indexer.vecs.blocks.coinbase_tag.try_for_each_range_at(
min,
@@ -186,6 +197,9 @@ impl Vecs {
.unwrap_or(unknown);
self.pool.push(pool.slug);
self.pool_heights.push(pool.slug, Height::from(next_height));
next_height += 1;
Ok(())
},
)?;

View File

@@ -0,0 +1,39 @@
use std::sync::Arc;
use brk_types::{Height, PoolSlug};
use parking_lot::RwLock;
use rustc_hash::FxHashMap;
use vecdb::{AnyVec, BytesVec, VecIndex};
#[derive(Clone, Default)]
pub struct PoolHeights(Arc<RwLock<FxHashMap<PoolSlug, Vec<Height>>>>);
impl PoolHeights {
pub fn build(pool: &BytesVec<Height, PoolSlug>) -> Self {
let len = pool.len();
let mut map: FxHashMap<PoolSlug, Vec<Height>> = FxHashMap::default();
let reader = pool.reader();
for h in 0..len {
map.entry(reader.get(h))
.or_default()
.push(Height::from(h));
}
Self(Arc::new(RwLock::new(map)))
}
pub fn truncate(&self, min: usize) {
let mut cache = self.0.write();
for heights in cache.values_mut() {
let cut = heights.partition_point(|h| h.to_usize() < min);
heights.truncate(cut);
}
}
pub fn push(&self, slug: PoolSlug, height: Height) {
self.0.write().entry(slug).or_default().push(height);
}
pub fn read(&self) -> parking_lot::RwLockReadGuard<'_, FxHashMap<PoolSlug, Vec<Height>>> {
self.0.read()
}
}