computer: snapshot

This commit is contained in:
nym21
2026-02-27 11:17:06 +01:00
parent c75421f46e
commit e7a5ab9450
45 changed files with 559 additions and 611 deletions
@@ -31,7 +31,7 @@ use super::{
},
BIP30_DUPLICATE_HEIGHT_1, BIP30_DUPLICATE_HEIGHT_2, BIP30_ORIGINAL_HEIGHT_1,
BIP30_ORIGINAL_HEIGHT_2, ComputeContext, FLUSH_INTERVAL, TxInReaders, TxOutReaders,
VecsReaders, build_txinindex_to_txindex, build_txoutindex_to_txindex,
IndexToTxIndexBuf, VecsReaders,
};
/// Process all blocks from starting_height to last_height.
@@ -78,7 +78,7 @@ pub(crate) fn process_blocks(
let txindex_to_input_count = &indexes.txindex.input_count;
// From price - use cents for computation:
let height_to_price = &prices.cents.price;
let height_to_price = &prices.price.cents;
// Access pre-computed vectors from context for thread-safe access
let height_to_price_vec = &ctx.height_to_price;
@@ -127,9 +127,11 @@ pub(crate) fn process_blocks(
};
debug!("txindex_to_height RangeMap built");
// Create reusable iterators for sequential txout/txin reads (16KB buffered)
// Create reusable iterators and buffers for per-block reads
let mut txout_iters = TxOutReaders::new(indexer);
let mut txin_iters = TxInReaders::new(indexer, inputs, &mut txindex_to_height);
let mut txout_to_txindex_buf = IndexToTxIndexBuf::new();
let mut txin_to_txindex_buf = IndexToTxIndexBuf::new();
// Pre-collect first address indexes per type for the block range
let first_p2a_vec = indexer
@@ -230,11 +232,11 @@ pub(crate) fn process_blocks(
debug_assert_eq!(ctx.timestamp_at(height), timestamp);
debug_assert_eq!(ctx.price_at(height), block_price);
// Build txindex mappings for this block (pass ReadableVec refs directly)
// Build txindex mappings for this block (reuses internal buffers)
let txoutindex_to_txindex =
build_txoutindex_to_txindex(first_txindex, tx_count, txindex_to_output_count);
txout_to_txindex_buf.build(first_txindex, tx_count, txindex_to_output_count);
let txinindex_to_txindex =
build_txinindex_to_txindex(first_txindex, tx_count, txindex_to_input_count);
txin_to_txindex_buf.build(first_txindex, tx_count, txindex_to_input_count);
// Get first address indexes for this height from pre-collected vecs
let first_addressindexes = ByAddressType {
@@ -125,7 +125,7 @@ impl ComputeContext {
blocks.time.timestamp_monotonic.collect();
let height_to_price: Vec<Cents> =
prices.cents.price.collect();
prices.price.cents.collect();
// Build sparse table for O(1) range max queries on prices
// Used for computing peak price during UTXO holding periods (peak regret)
@@ -7,10 +7,7 @@ mod write;
pub(crate) use block_loop::process_blocks;
pub(crate) use context::{ComputeContext, PriceRangeMax};
pub(crate) use readers::{
TxInReaders, TxOutData, TxOutReaders, VecsReaders, build_txinindex_to_txindex,
build_txoutindex_to_txindex,
};
pub(crate) use readers::{IndexToTxIndexBuf, TxInReaders, TxOutData, TxOutReaders, VecsReaders};
pub(crate) use recover::{StartMode, determine_start_mode, recover_state, reset_state};
/// Flush checkpoint interval (every N blocks).
@@ -153,42 +153,39 @@ impl VecsReaders {
}
}
/// Build txoutindex -> txindex mapping for a block.
pub(crate) fn build_txoutindex_to_txindex(
block_first_txindex: TxIndex,
block_tx_count: u64,
txindex_to_count: &impl ReadableVec<TxIndex, StoredU64>,
) -> Vec<TxIndex> {
build_index_to_txindex(block_first_txindex, block_tx_count, txindex_to_count)
/// Reusable buffers for per-block txindex mapping construction.
pub(crate) struct IndexToTxIndexBuf {
counts: Vec<StoredU64>,
result: Vec<TxIndex>,
}
/// Build txinindex -> txindex mapping for a block.
pub(crate) fn build_txinindex_to_txindex(
block_first_txindex: TxIndex,
block_tx_count: u64,
txindex_to_count: &impl ReadableVec<TxIndex, StoredU64>,
) -> Vec<TxIndex> {
build_index_to_txindex(block_first_txindex, block_tx_count, txindex_to_count)
}
/// Build index -> txindex mapping for a block (shared implementation).
fn build_index_to_txindex(
block_first_txindex: TxIndex,
block_tx_count: u64,
txindex_to_count: &impl ReadableVec<TxIndex, StoredU64>,
) -> Vec<TxIndex> {
let first = block_first_txindex.to_usize();
let counts: Vec<StoredU64> =
txindex_to_count.collect_range_at(first, first + block_tx_count as usize);
let total: u64 = counts.iter().map(|c| u64::from(*c)).sum();
let mut result = Vec::with_capacity(total as usize);
for (offset, count) in counts.iter().enumerate() {
let txindex = TxIndex::from(first + offset);
result.extend(std::iter::repeat_n(txindex, u64::from(*count) as usize));
impl IndexToTxIndexBuf {
pub(crate) fn new() -> Self {
Self {
counts: Vec::new(),
result: Vec::new(),
}
}
result
/// Build index -> txindex mapping for a block, reusing internal buffers.
pub(crate) fn build(
&mut self,
block_first_txindex: TxIndex,
block_tx_count: u64,
txindex_to_count: &impl ReadableVec<TxIndex, StoredU64>,
) -> &[TxIndex] {
let first = block_first_txindex.to_usize();
txindex_to_count.collect_range_into_at(first, first + block_tx_count as usize, &mut self.counts);
let total: u64 = self.counts.iter().map(|c| u64::from(*c)).sum();
self.result.clear();
self.result.reserve(total as usize);
for (offset, count) in self.counts.iter().enumerate() {
let txindex = TxIndex::from(first + offset);
self.result.extend(std::iter::repeat_n(txindex, u64::from(*count) as usize));
}
&self.result
}
}