computer: snapshot

This commit is contained in:
nym21
2026-02-27 10:54:36 +01:00
parent 72c17096ea
commit c75421f46e
44 changed files with 1079 additions and 722 deletions

View File

@@ -128,7 +128,7 @@ pub(crate) fn process_blocks(
debug!("txindex_to_height RangeMap built");
// Create reusable iterators for sequential txout/txin reads (16KB buffered)
let txout_iters = TxOutReaders::new(indexer);
let mut txout_iters = TxOutReaders::new(indexer);
let mut txin_iters = TxInReaders::new(indexer, inputs, &mut txindex_to_height);
// Pre-collect first address indexes per type for the block range

View File

@@ -21,32 +21,40 @@ pub struct TxOutData {
pub typeindex: TypeIndex,
}
/// Readers for txout vectors. Uses collect_range for bulk reads.
/// Readers for txout vectors. Reuses internal buffers across blocks.
pub struct TxOutReaders<'a> {
indexer: &'a Indexer,
values_buf: Vec<Sats>,
outputtypes_buf: Vec<OutputType>,
typeindexes_buf: Vec<TypeIndex>,
}
impl<'a> TxOutReaders<'a> {
pub(crate) fn new(indexer: &'a Indexer) -> Self {
Self { indexer }
Self {
indexer,
values_buf: Vec::new(),
outputtypes_buf: Vec::new(),
typeindexes_buf: Vec::new(),
}
}
/// Collect output data for a block range using bulk reads.
/// Collect output data for a block range using bulk reads with buffer reuse.
pub(crate) fn collect_block_outputs(
&self,
&mut self,
first_txoutindex: usize,
output_count: usize,
) -> Vec<TxOutData> {
let end = first_txoutindex + output_count;
let values: Vec<Sats> = self.indexer.vecs.outputs.value.collect_range_at(first_txoutindex, end);
let outputtypes: Vec<OutputType> = self.indexer.vecs.outputs.outputtype.collect_range_at(first_txoutindex, end);
let typeindexes: Vec<TypeIndex> = self.indexer.vecs.outputs.typeindex.collect_range_at(first_txoutindex, end);
self.indexer.vecs.outputs.value.collect_range_into_at(first_txoutindex, end, &mut self.values_buf);
self.indexer.vecs.outputs.outputtype.collect_range_into_at(first_txoutindex, end, &mut self.outputtypes_buf);
self.indexer.vecs.outputs.typeindex.collect_range_into_at(first_txoutindex, end, &mut self.typeindexes_buf);
values
.into_iter()
.zip(outputtypes)
.zip(typeindexes)
.map(|((value, outputtype), typeindex)| TxOutData {
self.values_buf
.iter()
.zip(&self.outputtypes_buf)
.zip(&self.typeindexes_buf)
.map(|((&value, &outputtype), &typeindex)| TxOutData {
value,
outputtype,
typeindex,
@@ -55,11 +63,12 @@ impl<'a> TxOutReaders<'a> {
}
}
/// Readers for txin vectors. Uses collect_range for bulk reads.
/// Readers for txin vectors. Reuses outpoint buffer across blocks.
pub struct TxInReaders<'a> {
indexer: &'a Indexer,
txins: &'a inputs::Vecs,
txindex_to_height: &'a mut RangeMap<TxIndex, Height>,
outpoints_buf: Vec<OutPoint>,
}
impl<'a> TxInReaders<'a> {
@@ -72,11 +81,12 @@ impl<'a> TxInReaders<'a> {
indexer,
txins,
txindex_to_height,
outpoints_buf: Vec::new(),
}
}
/// Collect input data for a block range using bulk reads.
/// Computes prev_height on-the-fly from outpoint using RangeMap lookup.
/// Outpoint buffer is reused across blocks; returned vecs are fresh (caller-owned).
pub(crate) fn collect_block_inputs(
&mut self,
first_txinindex: usize,
@@ -85,11 +95,11 @@ impl<'a> TxInReaders<'a> {
) -> (Vec<Sats>, Vec<Height>, Vec<OutputType>, Vec<TypeIndex>) {
let end = first_txinindex + input_count;
let values: Vec<Sats> = self.txins.spent.value.collect_range_at(first_txinindex, end);
let outpoints: Vec<OutPoint> = self.indexer.vecs.inputs.outpoint.collect_range_at(first_txinindex, end);
self.indexer.vecs.inputs.outpoint.collect_range_into_at(first_txinindex, end, &mut self.outpoints_buf);
let outputtypes: Vec<OutputType> = self.indexer.vecs.inputs.outputtype.collect_range_at(first_txinindex, end);
let typeindexes: Vec<TypeIndex> = self.indexer.vecs.inputs.typeindex.collect_range_at(first_txinindex, end);
let prev_heights: Vec<Height> = outpoints
let prev_heights: Vec<Height> = self.outpoints_buf
.iter()
.map(|outpoint| {
if outpoint.is_coinbase() {

View File

@@ -11,8 +11,6 @@ use brk_types::{
use rustc_hash::FxHashMap;
use vecdb::Bytes;
use crate::utils::OptionExt;
use super::{CachedUnrealizedState, Percentiles, UnrealizedState};
/// Type alias for the price-to-sats map used in cost basis data.
@@ -97,17 +95,17 @@ impl CostBasisData {
pub(crate) fn iter(&self) -> impl Iterator<Item = (CentsCompact, &Sats)> {
self.assert_pending_empty();
self.state.u().base.map.iter().map(|(&k, v)| (k, v))
self.state.as_ref().unwrap().base.map.iter().map(|(&k, v)| (k, v))
}
pub(crate) fn is_empty(&self) -> bool {
self.pending.is_empty() && self.state.u().base.map.is_empty()
self.pending.is_empty() && self.state.as_ref().unwrap().base.map.is_empty()
}
pub(crate) fn first_key_value(&self) -> Option<(CentsCompact, &Sats)> {
self.assert_pending_empty();
self.state
.u()
.as_ref().unwrap()
.base
.map
.first_key_value()
@@ -117,7 +115,7 @@ impl CostBasisData {
pub(crate) fn last_key_value(&self) -> Option<(CentsCompact, &Sats)> {
self.assert_pending_empty();
self.state
.u()
.as_ref().unwrap()
.base
.map
.last_key_value()
@@ -127,13 +125,13 @@ impl CostBasisData {
/// Get the exact cap_raw value (not recomputed from map).
pub(crate) fn cap_raw(&self) -> CentsSats {
self.assert_pending_empty();
self.state.u().cap_raw
self.state.as_ref().unwrap().cap_raw
}
/// Get the exact investor_cap_raw value (not recomputed from map).
pub(crate) fn investor_cap_raw(&self) -> CentsSquaredSats {
self.assert_pending_empty();
self.state.u().investor_cap_raw
self.state.as_ref().unwrap().investor_cap_raw
}
/// Increment with pre-computed typed values.
@@ -181,7 +179,7 @@ impl CostBasisData {
self.percentiles_dirty = true;
}
for (cents, (inc, dec)) in self.pending.drain() {
let entry = self.state.um().base.map.entry(cents).or_default();
let entry = self.state.as_mut().unwrap().base.map.entry(cents).or_default();
*entry += inc;
if *entry < dec {
panic!(
@@ -198,12 +196,12 @@ impl CostBasisData {
}
*entry -= dec;
if *entry == Sats::ZERO {
self.state.um().base.map.remove(&cents);
self.state.as_mut().unwrap().base.map.remove(&cents);
}
}
// Apply raw values
let state = self.state.um();
let state = self.state.as_mut().unwrap();
state.cap_raw += self.pending_raw.cap_inc;
// Check for underflow before subtracting
@@ -271,7 +269,7 @@ impl CostBasisData {
);
}
let map = &self.state.u().base.map;
let map = &self.state.as_ref().unwrap().base.map;
let date_state =
date_price.map(|p| CachedUnrealizedState::compute_full_standalone(p.into(), map));
@@ -336,7 +334,7 @@ impl CostBasisData {
}
}
fs::write(self.path_state(height), self.state.u().serialize()?)?;
fs::write(self.path_state(height), self.state.as_ref().unwrap().serialize()?)?;
Ok(())
}