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
}
}
@@ -697,15 +697,26 @@ impl RealizedBase {
.min(self.investor_price_cents.height.len());
let end = others.iter().map(|o| o.cap_raw.len()).min().unwrap_or(0);
// Pre-collect all cohort data to avoid per-element BytesVec reads in nested loop
let cap_ranges: Vec<Vec<CentsSats>> = others
.iter()
.map(|o| o.cap_raw.collect_range_at(start, end))
.collect();
let investor_cap_ranges: Vec<Vec<CentsSquaredSats>> = others
.iter()
.map(|o| o.investor_cap_raw.collect_range_at(start, end))
.collect();
for i in start..end {
let height = Height::from(i);
let local_i = i - start;
let mut sum_cap = CentsSats::ZERO;
let mut sum_investor_cap = CentsSquaredSats::ZERO;
for o in others.iter() {
sum_cap += o.cap_raw.collect_one_at(i).unwrap();
sum_investor_cap += o.investor_cap_raw.collect_one_at(i).unwrap();
for idx in 0..others.len() {
sum_cap += cap_ranges[idx][local_i];
sum_investor_cap += investor_cap_ranges[idx][local_i];
}
self.cap_raw.truncate_push(height, sum_cap)?;
@@ -842,14 +853,14 @@ impl RealizedBase {
self.realized_price_extra.compute_ratio(
starting_indexes,
&prices.usd.price,
&prices.price.usd,
&self.realized_price.usd.height,
exit,
)?;
self.investor_price_extra.compute_ratio(
starting_indexes,
&prices.usd.price,
&prices.price.usd,
&self.investor_price.usd.height,
exit,
)?;
@@ -331,31 +331,38 @@ impl UnrealizedBase {
.min()
.unwrap_or(0);
// Pre-collect all cohort data to avoid per-element BytesVec reads in nested loop
let invested_profit_ranges: Vec<Vec<CentsSats>> = others
.iter()
.map(|o| o.invested_capital_in_profit_raw.collect_range_at(start, end))
.collect();
let invested_loss_ranges: Vec<Vec<CentsSats>> = others
.iter()
.map(|o| o.invested_capital_in_loss_raw.collect_range_at(start, end))
.collect();
let investor_profit_ranges: Vec<Vec<CentsSquaredSats>> = others
.iter()
.map(|o| o.investor_cap_in_profit_raw.collect_range_at(start, end))
.collect();
let investor_loss_ranges: Vec<Vec<CentsSquaredSats>> = others
.iter()
.map(|o| o.investor_cap_in_loss_raw.collect_range_at(start, end))
.collect();
for i in start..end {
let height = Height::from(i);
let local_i = i - start;
let mut sum_invested_profit = CentsSats::ZERO;
let mut sum_invested_loss = CentsSats::ZERO;
let mut sum_investor_profit = CentsSquaredSats::ZERO;
let mut sum_investor_loss = CentsSquaredSats::ZERO;
for o in others.iter() {
sum_invested_profit += o
.invested_capital_in_profit_raw
.collect_one_at(i)
.unwrap();
sum_invested_loss += o
.invested_capital_in_loss_raw
.collect_one_at(i)
.unwrap();
sum_investor_profit += o
.investor_cap_in_profit_raw
.collect_one_at(i)
.unwrap();
sum_investor_loss += o
.investor_cap_in_loss_raw
.collect_one_at(i)
.unwrap();
for idx in 0..others.len() {
sum_invested_profit += invested_profit_ranges[idx][local_i];
sum_invested_loss += invested_loss_ranges[idx][local_i];
sum_investor_profit += investor_profit_ranges[idx][local_i];
sum_investor_loss += investor_loss_ranges[idx][local_i];
}
self.invested_capital_in_profit_raw
@@ -383,7 +390,7 @@ impl UnrealizedBase {
starting_indexes.height,
&self.investor_cap_in_loss_raw,
&self.invested_capital_in_loss_raw,
&prices.cents.price,
&prices.price.cents,
|(h, investor_cap, invested_cap, spot, ..)| {
if invested_cap.inner() == 0 {
return (h, Dollars::ZERO);
@@ -403,7 +410,7 @@ impl UnrealizedBase {
starting_indexes.height,
&self.investor_cap_in_profit_raw,
&self.invested_capital_in_profit_raw,
&prices.cents.price,
&prices.price.cents,
|(h, investor_cap, invested_cap, spot, ..)| {
if invested_cap.inner() == 0 {
return (h, Dollars::ZERO);
+1 -1
View File
@@ -249,7 +249,7 @@ impl Vecs {
// Recover chain_state from stored values
debug!("recovering chain_state from stored values");
let height_to_timestamp = &blocks.time.timestamp_monotonic;
let height_to_price = &prices.cents.price;
let height_to_price = &prices.price.cents;
let end = usize::from(recovered_height);
let timestamp_data: Vec<_> = height_to_timestamp.collect_range_at(0, end);