mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-24 06:39:58 -07:00
global: perf + resource imprv
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -18,3 +18,8 @@ _*
|
|||||||
|
|
||||||
# Logs
|
# Logs
|
||||||
.log
|
.log
|
||||||
|
|
||||||
|
# Profiling
|
||||||
|
profile.json.gz
|
||||||
|
flamegraph.svg
|
||||||
|
*.trace
|
||||||
|
|||||||
2
crates/brk/.gitignore
vendored
2
crates/brk/.gitignore
vendored
@@ -1,2 +0,0 @@
|
|||||||
profile.json.gz
|
|
||||||
flamegraph.svg
|
|
||||||
@@ -13,7 +13,8 @@ pub fn main() -> color_eyre::Result<()> {
|
|||||||
|
|
||||||
brk_logger::init(Some(Path::new(".log")));
|
brk_logger::init(Some(Path::new(".log")));
|
||||||
|
|
||||||
let bitcoin_dir = default_bitcoin_path();
|
// let bitcoin_dir = default_bitcoin_path();
|
||||||
|
let bitcoin_dir = Path::new("/Volumes/WD_BLACK/bitcoin");
|
||||||
|
|
||||||
let rpc = Box::leak(Box::new(bitcoincore_rpc::Client::new(
|
let rpc = Box::leak(Box::new(bitcoincore_rpc::Client::new(
|
||||||
"http://localhost:8332",
|
"http://localhost:8332",
|
||||||
@@ -23,11 +24,11 @@ pub fn main() -> color_eyre::Result<()> {
|
|||||||
|
|
||||||
// Can't increase main thread's stack programatically, thus we need to use another thread
|
// Can't increase main thread's stack programatically, thus we need to use another thread
|
||||||
thread::Builder::new()
|
thread::Builder::new()
|
||||||
.stack_size(32 * 1024 * 1024)
|
.stack_size(256 * 1024 * 1024)
|
||||||
.spawn(move || -> color_eyre::Result<()> {
|
.spawn(move || -> color_eyre::Result<()> {
|
||||||
let parser = Parser::new(bitcoin_dir.join("blocks"), rpc);
|
let parser = Parser::new(bitcoin_dir.join("blocks"), rpc);
|
||||||
|
|
||||||
let _outputs_dir = default_brk_path().join("outputs");
|
let _outputs_dir = Path::new("/Volumes/WD_BLACK/brk").join("outputs");
|
||||||
let outputs_dir = _outputs_dir.as_path();
|
let outputs_dir = _outputs_dir.as_path();
|
||||||
// let outputs_dir = Path::new("../../_outputs");
|
// let outputs_dir = Path::new("../../_outputs");
|
||||||
|
|
||||||
|
|||||||
2
crates/brk_computer/flamegraph.sh
Executable file
2
crates/brk_computer/flamegraph.sh
Executable file
@@ -0,0 +1,2 @@
|
|||||||
|
cargo build --profile profiling
|
||||||
|
flamegraph -- ../../target/profiling/examples/main
|
||||||
2
crates/brk_computer/samply.sh
Executable file
2
crates/brk_computer/samply.sh
Executable file
@@ -0,0 +1,2 @@
|
|||||||
|
cargo build --example main --profile profiling
|
||||||
|
samply record ../../target/profiling/examples/main
|
||||||
@@ -1,30 +1,6 @@
|
|||||||
use std::mem;
|
|
||||||
|
|
||||||
use derive_deref::{Deref, DerefMut};
|
use derive_deref::{Deref, DerefMut};
|
||||||
|
|
||||||
use super::ByAddressType;
|
use super::ByAddressType;
|
||||||
|
|
||||||
#[derive(Debug, Default, Deref, DerefMut)]
|
#[derive(Debug, Default, Deref, DerefMut)]
|
||||||
pub struct AddressTypeToVec<T>(ByAddressType<Vec<T>>);
|
pub struct AddressTypeToVec<T>(ByAddressType<Vec<T>>);
|
||||||
|
|
||||||
impl<T> AddressTypeToVec<T> {
|
|
||||||
pub fn merge(&mut self, mut other: Self) {
|
|
||||||
Self::merge_(&mut self.p2pk65, &mut other.p2pk65);
|
|
||||||
Self::merge_(&mut self.p2pk33, &mut other.p2pk33);
|
|
||||||
Self::merge_(&mut self.p2pkh, &mut other.p2pkh);
|
|
||||||
Self::merge_(&mut self.p2sh, &mut other.p2sh);
|
|
||||||
Self::merge_(&mut self.p2wpkh, &mut other.p2wpkh);
|
|
||||||
Self::merge_(&mut self.p2wsh, &mut other.p2wsh);
|
|
||||||
Self::merge_(&mut self.p2tr, &mut other.p2tr);
|
|
||||||
Self::merge_(&mut self.p2a, &mut other.p2a);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn merge_(own: &mut Vec<T>, other: &mut Vec<T>) {
|
|
||||||
if own.len() >= other.len() {
|
|
||||||
own.append(other);
|
|
||||||
} else {
|
|
||||||
other.append(own);
|
|
||||||
mem::swap(own, other);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use std::{cmp::Ordering, collections::BTreeMap, mem, path::Path, thread};
|
use std::{cmp::Ordering, collections::BTreeMap, mem, ops::ControlFlow, path::Path, thread};
|
||||||
|
|
||||||
use brk_core::{
|
use brk_core::{
|
||||||
AddressData, ByAddressType, CheckedSub, DateIndex, Dollars, EmptyAddressData, Height,
|
AddressData, ByAddressType, CheckedSub, DateIndex, Dollars, EmptyAddressData, Height,
|
||||||
@@ -8,7 +8,7 @@ use brk_exit::Exit;
|
|||||||
use brk_indexer::Indexer;
|
use brk_indexer::Indexer;
|
||||||
use brk_vec::{
|
use brk_vec::{
|
||||||
AnyCollectableVec, AnyVec, CollectableVec, Computation, EagerVec, Format, GenericStoredVec,
|
AnyCollectableVec, AnyVec, CollectableVec, Computation, EagerVec, Format, GenericStoredVec,
|
||||||
StoredIndex, StoredVec, UnsafeSlice, VecIterator,
|
StoredIndex, StoredVec, VecIterator,
|
||||||
};
|
};
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use log::info;
|
use log::info;
|
||||||
@@ -57,7 +57,7 @@ use range_map::*;
|
|||||||
use r#trait::CohortVecs;
|
use r#trait::CohortVecs;
|
||||||
pub use withaddressdatasource::WithAddressDataSource;
|
pub use withaddressdatasource::WithAddressDataSource;
|
||||||
|
|
||||||
const VERSION: Version = Version::new(12);
|
const VERSION: Version = Version::new(18);
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Vecs {
|
pub struct Vecs {
|
||||||
@@ -497,11 +497,11 @@ impl Vecs {
|
|||||||
let dateindex_to_first_height = &indexes.dateindex_to_first_height;
|
let dateindex_to_first_height = &indexes.dateindex_to_first_height;
|
||||||
let dateindex_to_height_count = &indexes.dateindex_to_height_count;
|
let dateindex_to_height_count = &indexes.dateindex_to_height_count;
|
||||||
|
|
||||||
let inputindex_to_outputindex_mmap = inputindex_to_outputindex.mmap().load();
|
|
||||||
let outputindex_to_value_mmap = outputindex_to_value.mmap().load();
|
let outputindex_to_value_mmap = outputindex_to_value.mmap().load();
|
||||||
let outputindex_to_outputtype_mmap = outputindex_to_outputtype.mmap().load();
|
let outputindex_to_outputtype_mmap = outputindex_to_outputtype.mmap().load();
|
||||||
let outputindex_to_typeindex_mmap = outputindex_to_typeindex.mmap().load();
|
let outputindex_to_typeindex_mmap = outputindex_to_typeindex.mmap().load();
|
||||||
|
|
||||||
|
let mut inputindex_to_outputindex_iter = inputindex_to_outputindex.into_iter();
|
||||||
let mut height_to_first_outputindex_iter = height_to_first_outputindex.into_iter();
|
let mut height_to_first_outputindex_iter = height_to_first_outputindex.into_iter();
|
||||||
let mut height_to_first_inputindex_iter = height_to_first_inputindex.into_iter();
|
let mut height_to_first_inputindex_iter = height_to_first_inputindex.into_iter();
|
||||||
let mut height_to_first_p2aaddressindex_iter = height_to_first_p2aaddressindex.into_iter();
|
let mut height_to_first_p2aaddressindex_iter = height_to_first_p2aaddressindex.into_iter();
|
||||||
@@ -701,6 +701,8 @@ impl Vecs {
|
|||||||
.try_for_each(|_height| -> color_eyre::Result<()> {
|
.try_for_each(|_height| -> color_eyre::Result<()> {
|
||||||
height = _height;
|
height = _height;
|
||||||
|
|
||||||
|
info!("Processing chain at {height}...");
|
||||||
|
|
||||||
self.utxo_vecs
|
self.utxo_vecs
|
||||||
.as_mut_separate_vecs()
|
.as_mut_separate_vecs()
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
@@ -711,8 +713,6 @@ impl Vecs {
|
|||||||
.iter_mut()
|
.iter_mut()
|
||||||
.for_each(|(_, v)| v.state.reset_single_iteration_values());
|
.for_each(|(_, v)| v.state.reset_single_iteration_values());
|
||||||
|
|
||||||
info!("Processing chain at {height}...");
|
|
||||||
|
|
||||||
let timestamp = height_to_timestamp_fixed_iter.unwrap_get_inner(height);
|
let timestamp = height_to_timestamp_fixed_iter.unwrap_get_inner(height);
|
||||||
let price = height_to_close_iter
|
let price = height_to_close_iter
|
||||||
.as_mut()
|
.as_mut()
|
||||||
@@ -754,357 +754,229 @@ impl Vecs {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (
|
let (
|
||||||
(mut height_to_sent, addresstype_to_typedindex_to_sent_data),
|
mut transacted,
|
||||||
(mut transacted, addresstype_to_typedindex_to_received_data),
|
addresstype_to_typedindex_to_received_data,
|
||||||
) = thread::scope(|s| {
|
mut height_to_sent,
|
||||||
if chain_state_starting_height <= height {
|
addresstype_to_typedindex_to_sent_data,
|
||||||
s.spawn(|| {
|
) = thread::scope(|scope| {
|
||||||
self.utxo_vecs.tick_tock_next_block(&chain_state, timestamp);
|
scope.spawn(|| {
|
||||||
});
|
self.utxo_vecs.tick_tock_next_block(&chain_state, timestamp);
|
||||||
}
|
|
||||||
|
|
||||||
let sent_handle = s.spawn(|| {
|
|
||||||
// Skip coinbase
|
|
||||||
(first_inputindex + 1..first_inputindex + *input_count)
|
|
||||||
.into_par_iter()
|
|
||||||
.map(InputIndex::from)
|
|
||||||
.map(|inputindex| {
|
|
||||||
let outputindex = inputindex_to_outputindex
|
|
||||||
.get_or_read(
|
|
||||||
inputindex,
|
|
||||||
&inputindex_to_outputindex_mmap,
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.unwrap()
|
|
||||||
.into_owned();
|
|
||||||
|
|
||||||
let value = outputindex_to_value
|
|
||||||
.get_or_read(outputindex, &outputindex_to_value_mmap)
|
|
||||||
.unwrap()
|
|
||||||
.unwrap()
|
|
||||||
.into_owned();
|
|
||||||
|
|
||||||
let input_type = outputindex_to_outputtype
|
|
||||||
.get_or_read(
|
|
||||||
outputindex,
|
|
||||||
&outputindex_to_outputtype_mmap,
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.unwrap()
|
|
||||||
.into_owned();
|
|
||||||
|
|
||||||
let prev_height =
|
|
||||||
*outputindex_range_to_height.get(outputindex).unwrap();
|
|
||||||
|
|
||||||
if input_type.is_unspendable() {
|
|
||||||
unreachable!()
|
|
||||||
} else if input_type.is_not_address() {
|
|
||||||
return (
|
|
||||||
prev_height,
|
|
||||||
value,
|
|
||||||
input_type,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let typeindex = outputindex_to_typeindex
|
|
||||||
.get_or_read(
|
|
||||||
outputindex,
|
|
||||||
&outputindex_to_typeindex_mmap,
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.unwrap()
|
|
||||||
.into_owned();
|
|
||||||
|
|
||||||
let addressdata_opt = if input_type.is_address()
|
|
||||||
&& *first_addressindexes.get(input_type).unwrap()
|
|
||||||
> typeindex
|
|
||||||
&& !addresstype_to_typeindex_to_addressdata
|
|
||||||
.get(input_type)
|
|
||||||
.unwrap()
|
|
||||||
.contains_key(&typeindex)
|
|
||||||
&& let Some(address_data) = stores
|
|
||||||
.get_addressdata(input_type, typeindex)
|
|
||||||
.unwrap()
|
|
||||||
// Otherwise it was empty and got funds in the same block before sending them
|
|
||||||
{
|
|
||||||
Some(WithAddressDataSource::FromAddressDataStore(
|
|
||||||
address_data,
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
(
|
|
||||||
prev_height,
|
|
||||||
value,
|
|
||||||
input_type,
|
|
||||||
Some((typeindex, addressdata_opt)),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.fold(
|
|
||||||
|| {
|
|
||||||
(
|
|
||||||
BTreeMap::<Height, Transacted>::default(),
|
|
||||||
HeightToAddressTypeToVec::<(
|
|
||||||
TypeIndex,
|
|
||||||
Sats,
|
|
||||||
Option<WithAddressDataSource<AddressData>>,
|
|
||||||
)>::default(
|
|
||||||
),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|(mut tree, mut tree2),
|
|
||||||
(
|
|
||||||
height,
|
|
||||||
value,
|
|
||||||
input_type,
|
|
||||||
address_data_opt,
|
|
||||||
)| {
|
|
||||||
tree.entry(height)
|
|
||||||
.or_default()
|
|
||||||
.iterate(value, input_type);
|
|
||||||
if let Some((typeindex, addressdata_opt)) =
|
|
||||||
address_data_opt
|
|
||||||
{
|
|
||||||
tree2
|
|
||||||
.entry(height)
|
|
||||||
.or_default()
|
|
||||||
.get_mut(input_type)
|
|
||||||
.unwrap()
|
|
||||||
.push((typeindex, value, addressdata_opt));
|
|
||||||
}
|
|
||||||
(tree, tree2)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.reduce(
|
|
||||||
|| {
|
|
||||||
(
|
|
||||||
BTreeMap::<Height, Transacted>::default(),
|
|
||||||
HeightToAddressTypeToVec::<(
|
|
||||||
TypeIndex,
|
|
||||||
Sats,
|
|
||||||
Option<WithAddressDataSource<AddressData>>,
|
|
||||||
)>::default(
|
|
||||||
),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|(first_tree, first_tree2), (second_tree, second_tree2)| {
|
|
||||||
let (mut tree_source, tree_to_consume) =
|
|
||||||
if first_tree.len() > second_tree.len() {
|
|
||||||
(first_tree, second_tree)
|
|
||||||
} else {
|
|
||||||
(second_tree, first_tree)
|
|
||||||
};
|
|
||||||
tree_to_consume.into_iter().for_each(|(k, v)| {
|
|
||||||
*tree_source.entry(k).or_default() += v;
|
|
||||||
});
|
|
||||||
|
|
||||||
let (mut tree_source2, tree_to_consume2) =
|
|
||||||
if first_tree2.len() > second_tree2.len() {
|
|
||||||
(first_tree2, second_tree2)
|
|
||||||
} else {
|
|
||||||
(second_tree2, first_tree2)
|
|
||||||
};
|
|
||||||
tree_to_consume2.0.into_iter().for_each(|(k, v)| {
|
|
||||||
tree_source2.entry(k).or_default().merge(v);
|
|
||||||
});
|
|
||||||
|
|
||||||
(tree_source, tree_source2)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let received_output = (first_outputindex
|
let received = scope.spawn(|| {
|
||||||
..first_outputindex + *output_count)
|
let mut transacted = Transacted::default();
|
||||||
.into_par_iter()
|
|
||||||
.map(OutputIndex::from)
|
|
||||||
.map(|outputindex| {
|
|
||||||
let value = outputindex_to_value
|
|
||||||
.get_or_read(outputindex, &outputindex_to_value_mmap)
|
|
||||||
.unwrap()
|
|
||||||
.unwrap()
|
|
||||||
.into_owned();
|
|
||||||
|
|
||||||
let output_type = outputindex_to_outputtype
|
let mut addresstype_to_typedindex_to_received_data = AddressTypeToVec::<
|
||||||
.get_or_read(outputindex, &outputindex_to_outputtype_mmap)
|
(TypeIndex, Sats, Option<WithAddressDataSource<AddressData>>),
|
||||||
.unwrap()
|
>::default(
|
||||||
.unwrap()
|
);
|
||||||
.into_owned();
|
|
||||||
|
|
||||||
if output_type.is_not_address() {
|
let _ = (first_outputindex..first_outputindex + *output_count)
|
||||||
return (value, output_type, None);
|
.map(OutputIndex::from)
|
||||||
}
|
.try_for_each(|outputindex| -> ControlFlow<()> {
|
||||||
|
let value = outputindex_to_value
|
||||||
|
.unwrap_read(outputindex, &outputindex_to_value_mmap);
|
||||||
|
|
||||||
let typeindex = outputindex_to_typeindex
|
let output_type = outputindex_to_outputtype
|
||||||
.get_or_read(outputindex, &outputindex_to_typeindex_mmap)
|
.unwrap_read(outputindex, &outputindex_to_outputtype_mmap);
|
||||||
.unwrap()
|
|
||||||
.unwrap()
|
|
||||||
.into_owned();
|
|
||||||
|
|
||||||
let addressdata_opt = if *first_addressindexes
|
transacted.iterate(value, output_type);
|
||||||
.get(output_type)
|
|
||||||
.unwrap()
|
if output_type.is_not_address() {
|
||||||
<= typeindex
|
return ControlFlow::Continue(());
|
||||||
{
|
}
|
||||||
Some(WithAddressDataSource::New(AddressData::default()))
|
|
||||||
} else if !addresstype_to_typeindex_to_addressdata
|
let typeindex = outputindex_to_typeindex
|
||||||
.get(output_type)
|
.unwrap_read(outputindex, &outputindex_to_typeindex_mmap);
|
||||||
.unwrap()
|
|
||||||
.contains_key(&typeindex)
|
let addressdata_opt = if *first_addressindexes
|
||||||
&& !addresstype_to_typeindex_to_emptyaddressdata
|
.get(output_type)
|
||||||
|
.unwrap()
|
||||||
|
<= typeindex
|
||||||
|
{
|
||||||
|
Some(WithAddressDataSource::New(AddressData::default()))
|
||||||
|
} else if !addresstype_to_typeindex_to_addressdata
|
||||||
.get(output_type)
|
.get(output_type)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.contains_key(&typeindex)
|
.contains_key(&typeindex)
|
||||||
{
|
&& !addresstype_to_typeindex_to_emptyaddressdata
|
||||||
Some(
|
.get(output_type)
|
||||||
if let Some(addressdata) =
|
|
||||||
stores.get_addressdata(output_type, typeindex).unwrap()
|
|
||||||
{
|
|
||||||
WithAddressDataSource::FromAddressDataStore(addressdata)
|
|
||||||
} else if let Some(emptyaddressdata) = stores
|
|
||||||
.get_emptyaddressdata(output_type, typeindex)
|
|
||||||
.unwrap()
|
.unwrap()
|
||||||
{
|
.contains_key(&typeindex)
|
||||||
WithAddressDataSource::FromEmptyAddressDataStore(
|
{
|
||||||
emptyaddressdata.into(),
|
Some(
|
||||||
)
|
if let Some(addressdata) = stores
|
||||||
} else {
|
.get_addressdata(output_type, typeindex)
|
||||||
WithAddressDataSource::New(AddressData::default())
|
.unwrap()
|
||||||
},
|
{
|
||||||
)
|
WithAddressDataSource::FromAddressDataStore(
|
||||||
|
addressdata,
|
||||||
|
)
|
||||||
|
} else if let Some(emptyaddressdata) = stores
|
||||||
|
.get_emptyaddressdata(output_type, typeindex)
|
||||||
|
.unwrap()
|
||||||
|
{
|
||||||
|
WithAddressDataSource::FromEmptyAddressDataStore(
|
||||||
|
emptyaddressdata.into(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
unreachable!("I think ?")
|
||||||
|
},
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
addresstype_to_typedindex_to_received_data
|
||||||
|
.get_mut(output_type)
|
||||||
|
.unwrap()
|
||||||
|
.push((typeindex, value, addressdata_opt));
|
||||||
|
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
});
|
||||||
|
|
||||||
|
(transacted, addresstype_to_typedindex_to_received_data)
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut height_to_sent = BTreeMap::<Height, Transacted>::default();
|
||||||
|
|
||||||
|
let mut addresstype_to_typedindex_to_sent_data = HeightToAddressTypeToVec::<
|
||||||
|
(TypeIndex, Sats, Option<WithAddressDataSource<AddressData>>),
|
||||||
|
>::default(
|
||||||
|
);
|
||||||
|
|
||||||
|
// Skip coinbase
|
||||||
|
let _ = (first_inputindex + 1..first_inputindex + *input_count)
|
||||||
|
.map(InputIndex::from)
|
||||||
|
.try_for_each(|inputindex| -> ControlFlow<()> {
|
||||||
|
let outputindex =
|
||||||
|
inputindex_to_outputindex_iter.unwrap_get_inner(inputindex);
|
||||||
|
|
||||||
|
let value = outputindex_to_value
|
||||||
|
.unwrap_read(outputindex, &outputindex_to_value_mmap);
|
||||||
|
|
||||||
|
let input_type = outputindex_to_outputtype
|
||||||
|
.unwrap_read(outputindex, &outputindex_to_outputtype_mmap);
|
||||||
|
|
||||||
|
let prev_height =
|
||||||
|
*outputindex_range_to_height.get(outputindex).unwrap();
|
||||||
|
|
||||||
|
height_to_sent
|
||||||
|
.entry(prev_height)
|
||||||
|
.or_default()
|
||||||
|
.iterate(value, input_type);
|
||||||
|
|
||||||
|
if input_type.is_not_address() {
|
||||||
|
return ControlFlow::Continue(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let typeindex = outputindex_to_typeindex
|
||||||
|
.unwrap_read(outputindex, &outputindex_to_typeindex_mmap);
|
||||||
|
|
||||||
|
let addressdata_opt = if *first_addressindexes
|
||||||
|
.get(input_type)
|
||||||
|
.unwrap()
|
||||||
|
> typeindex
|
||||||
|
&& !addresstype_to_typeindex_to_addressdata
|
||||||
|
.get(input_type)
|
||||||
|
.unwrap()
|
||||||
|
.contains_key(&typeindex)
|
||||||
|
&& let Some(address_data) =
|
||||||
|
stores.get_addressdata(input_type, typeindex).unwrap()
|
||||||
|
// Otherwise it was empty and got funds in the same block before sending them
|
||||||
|
{
|
||||||
|
Some(WithAddressDataSource::FromAddressDataStore(address_data))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
(
|
addresstype_to_typedindex_to_sent_data
|
||||||
value,
|
.entry(prev_height)
|
||||||
output_type,
|
.or_default()
|
||||||
Some((typeindex, addressdata_opt)),
|
.get_mut(input_type)
|
||||||
)
|
.unwrap()
|
||||||
})
|
.push((typeindex, value, addressdata_opt));
|
||||||
.fold(
|
|
||||||
|| {
|
|
||||||
(
|
|
||||||
Transacted::default(),
|
|
||||||
AddressTypeToVec::<(
|
|
||||||
TypeIndex,
|
|
||||||
Sats,
|
|
||||||
Option<WithAddressDataSource<AddressData>>,
|
|
||||||
)>::default(),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|(mut transacted, mut vecs),
|
|
||||||
(
|
|
||||||
value,
|
|
||||||
output_type,
|
|
||||||
typeindex_with_addressdata_opt,
|
|
||||||
)| {
|
|
||||||
transacted.iterate(value, output_type);
|
|
||||||
if let Some(vec) = vecs.get_mut(output_type) {
|
|
||||||
let (typeindex, addressdata_opt) =
|
|
||||||
typeindex_with_addressdata_opt.unwrap();
|
|
||||||
vec.push((typeindex, value, addressdata_opt));
|
|
||||||
}
|
|
||||||
|
|
||||||
(transacted, vecs)
|
ControlFlow::Continue(())
|
||||||
},
|
});
|
||||||
)
|
|
||||||
.reduce(
|
|
||||||
|| {
|
|
||||||
(
|
|
||||||
Transacted::default(),
|
|
||||||
AddressTypeToVec::<(
|
|
||||||
TypeIndex,
|
|
||||||
Sats,
|
|
||||||
Option<WithAddressDataSource<AddressData>>,
|
|
||||||
)>::default(),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|(transacted, mut vecs), (other_transacted, other_vecs)| {
|
|
||||||
vecs.merge(other_vecs);
|
|
||||||
|
|
||||||
(transacted + other_transacted, vecs)
|
let (transacted, addresstype_to_typedindex_to_received_data) =
|
||||||
},
|
received.join().unwrap();
|
||||||
);
|
|
||||||
|
|
||||||
(sent_handle.join().unwrap(), received_output)
|
(
|
||||||
|
transacted,
|
||||||
|
addresstype_to_typedindex_to_received_data,
|
||||||
|
height_to_sent,
|
||||||
|
addresstype_to_typedindex_to_sent_data,
|
||||||
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
if chain_state_starting_height > height {
|
thread::scope(|scope| {
|
||||||
dbg!(chain_state_starting_height, height);
|
|
||||||
panic!("temp, just making sure")
|
|
||||||
}
|
|
||||||
|
|
||||||
unspendable_supply += transacted
|
|
||||||
.by_type
|
|
||||||
.unspendable
|
|
||||||
.as_vec()
|
|
||||||
.into_iter()
|
|
||||||
.map(|state| state.value)
|
|
||||||
.sum::<Sats>()
|
|
||||||
+ height_to_unclaimed_rewards_iter.unwrap_get_inner(height);
|
|
||||||
|
|
||||||
opreturn_supply += transacted.by_type.unspendable.opreturn.value;
|
|
||||||
|
|
||||||
if height == Height::new(0) {
|
|
||||||
transacted = Transacted::default();
|
|
||||||
unspendable_supply += Sats::FIFTY_BTC;
|
|
||||||
} else if height == Height::new(91_842) || height == Height::new(91_880) {
|
|
||||||
// Need to destroy invalid coinbases due to duplicate txids
|
|
||||||
if height == Height::new(91_842) {
|
|
||||||
height_to_sent.entry(Height::new(91_812)).or_default()
|
|
||||||
} else {
|
|
||||||
height_to_sent.entry(Height::new(91_722)).or_default()
|
|
||||||
}
|
|
||||||
.iterate(Sats::FIFTY_BTC, OutputType::P2PK65);
|
|
||||||
};
|
|
||||||
|
|
||||||
thread::scope(|scope| -> Result<()> {
|
|
||||||
scope.spawn(|| {
|
scope.spawn(|| {
|
||||||
// Push current block state before processing sends and receives
|
addresstype_to_typedindex_to_received_data.process_received(
|
||||||
chain_state.push(BlockState {
|
&mut self.address_vecs,
|
||||||
supply: transacted.spendable_supply.clone(),
|
&mut addresstype_to_typeindex_to_addressdata,
|
||||||
|
&mut addresstype_to_typeindex_to_emptyaddressdata,
|
||||||
price,
|
price,
|
||||||
timestamp,
|
&mut addresstype_to_address_count,
|
||||||
});
|
&mut addresstype_to_empty_address_count,
|
||||||
|
);
|
||||||
|
|
||||||
self.utxo_vecs.receive(transacted, height, price);
|
addresstype_to_typedindex_to_sent_data
|
||||||
|
.process_sent(
|
||||||
let unsafe_chain_state = UnsafeSlice::new(&mut chain_state);
|
&mut self.address_vecs,
|
||||||
|
&mut addresstype_to_typeindex_to_addressdata,
|
||||||
height_to_sent.par_iter().for_each(|(height, sent)| unsafe {
|
&mut addresstype_to_typeindex_to_emptyaddressdata,
|
||||||
(*unsafe_chain_state.get(height.unwrap_to_usize())).supply -=
|
price,
|
||||||
&sent.spendable_supply;
|
&mut addresstype_to_address_count,
|
||||||
});
|
&mut addresstype_to_empty_address_count,
|
||||||
|
height_to_close_vec.as_ref(),
|
||||||
self.utxo_vecs.send(height_to_sent, chain_state.as_slice());
|
&height_to_timestamp_fixed_vec,
|
||||||
|
height,
|
||||||
|
timestamp,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
});
|
});
|
||||||
|
|
||||||
addresstype_to_typedindex_to_received_data.process_received(
|
if chain_state_starting_height > height {
|
||||||
&mut self.address_vecs,
|
dbg!(chain_state_starting_height, height);
|
||||||
&mut addresstype_to_typeindex_to_addressdata,
|
panic!("temp, just making sure")
|
||||||
&mut addresstype_to_typeindex_to_emptyaddressdata,
|
}
|
||||||
price,
|
|
||||||
&mut addresstype_to_address_count,
|
|
||||||
&mut addresstype_to_empty_address_count,
|
|
||||||
);
|
|
||||||
|
|
||||||
addresstype_to_typedindex_to_sent_data.process_sent(
|
unspendable_supply += transacted
|
||||||
&mut self.address_vecs,
|
.by_type
|
||||||
&mut addresstype_to_typeindex_to_addressdata,
|
.unspendable
|
||||||
&mut addresstype_to_typeindex_to_emptyaddressdata,
|
.as_vec()
|
||||||
|
.into_iter()
|
||||||
|
.map(|state| state.value)
|
||||||
|
.sum::<Sats>()
|
||||||
|
+ height_to_unclaimed_rewards_iter.unwrap_get_inner(height);
|
||||||
|
|
||||||
|
opreturn_supply += transacted.by_type.unspendable.opreturn.value;
|
||||||
|
|
||||||
|
if height == Height::new(0) {
|
||||||
|
transacted = Transacted::default();
|
||||||
|
unspendable_supply += Sats::FIFTY_BTC;
|
||||||
|
} else if height == Height::new(91_842) || height == Height::new(91_880) {
|
||||||
|
// Need to destroy invalid coinbases due to duplicate txids
|
||||||
|
if height == Height::new(91_842) {
|
||||||
|
height_to_sent.entry(Height::new(91_812)).or_default()
|
||||||
|
} else {
|
||||||
|
height_to_sent.entry(Height::new(91_722)).or_default()
|
||||||
|
}
|
||||||
|
.iterate(Sats::FIFTY_BTC, OutputType::P2PK65);
|
||||||
|
};
|
||||||
|
// Push current block state before processing sends and receives
|
||||||
|
chain_state.push(BlockState {
|
||||||
|
supply: transacted.spendable_supply.clone(),
|
||||||
price,
|
price,
|
||||||
&mut addresstype_to_address_count,
|
|
||||||
&mut addresstype_to_empty_address_count,
|
|
||||||
height_to_close_vec.as_ref(),
|
|
||||||
&height_to_timestamp_fixed_vec,
|
|
||||||
height,
|
|
||||||
timestamp,
|
timestamp,
|
||||||
)?;
|
});
|
||||||
|
|
||||||
Ok(())
|
self.utxo_vecs.receive(transacted, height, price);
|
||||||
})?;
|
|
||||||
|
self.utxo_vecs.send(height_to_sent, &mut chain_state);
|
||||||
|
});
|
||||||
|
|
||||||
let mut separate_utxo_vecs = self.utxo_vecs.as_mut_separate_vecs();
|
let mut separate_utxo_vecs = self.utxo_vecs.as_mut_separate_vecs();
|
||||||
|
|
||||||
@@ -1168,10 +1040,17 @@ impl Vecs {
|
|||||||
info!("Flushing...");
|
info!("Flushing...");
|
||||||
exit.block();
|
exit.block();
|
||||||
self.flush_states(height, &chain_state, exit)?;
|
self.flush_states(height, &chain_state, exit)?;
|
||||||
|
|
||||||
|
// Maybe keep some from the end for both
|
||||||
|
let addresstype_to_typeindex_to_addressdata_to_consume =
|
||||||
|
mem::take(&mut addresstype_to_typeindex_to_addressdata);
|
||||||
|
let addresstype_to_typeindex_to_emptyaddressdata_to_consume =
|
||||||
|
mem::take(&mut addresstype_to_typeindex_to_emptyaddressdata);
|
||||||
|
|
||||||
stores.commit(
|
stores.commit(
|
||||||
height,
|
height,
|
||||||
mem::take(&mut addresstype_to_typeindex_to_addressdata),
|
addresstype_to_typeindex_to_addressdata_to_consume,
|
||||||
mem::take(&mut addresstype_to_typeindex_to_emptyaddressdata),
|
addresstype_to_typeindex_to_emptyaddressdata_to_consume,
|
||||||
)?;
|
)?;
|
||||||
exit.release();
|
exit.release();
|
||||||
}
|
}
|
||||||
@@ -1565,7 +1444,7 @@ impl HeightToAddressTypeToVec<(TypeIndex, Sats, Option<WithAddressDataSource<Add
|
|||||||
|
|
||||||
let blocks_old = height.unwrap_to_usize() - prev_height.unwrap_to_usize();
|
let blocks_old = height.unwrap_to_usize() - prev_height.unwrap_to_usize();
|
||||||
|
|
||||||
let days_old = prev_timestamp.difference_in_days_between_float(timestamp);
|
let days_old = timestamp.difference_in_days_between_float(prev_timestamp);
|
||||||
|
|
||||||
let older_than_hour = timestamp
|
let older_than_hour = timestamp
|
||||||
.checked_sub(prev_timestamp)
|
.checked_sub(prev_timestamp)
|
||||||
|
|||||||
@@ -1342,17 +1342,15 @@ impl Vecs {
|
|||||||
|
|
||||||
self.age_range
|
self.age_range
|
||||||
.as_mut_vec()
|
.as_mut_vec()
|
||||||
.into_par_iter()
|
.into_iter()
|
||||||
.for_each(|(filter, v)| {
|
.map(|(filter, v)| (filter, &mut v.state))
|
||||||
let state = &mut v.state;
|
.for_each(|(filter, state)| {
|
||||||
|
|
||||||
let _ = chain_state
|
let _ = chain_state
|
||||||
.iter()
|
.iter()
|
||||||
.try_for_each(|block_state| -> ControlFlow<()> {
|
.try_for_each(|block_state| -> ControlFlow<()> {
|
||||||
let prev_days_old = block_state
|
let prev_days_old =
|
||||||
.timestamp
|
prev_timestamp.difference_in_days_between(block_state.timestamp);
|
||||||
.difference_in_days_between(prev_timestamp);
|
let days_old = timestamp.difference_in_days_between(block_state.timestamp);
|
||||||
let days_old = block_state.timestamp.difference_in_days_between(timestamp);
|
|
||||||
|
|
||||||
if prev_days_old == days_old {
|
if prev_days_old == days_old {
|
||||||
return ControlFlow::Continue(());
|
return ControlFlow::Continue(());
|
||||||
@@ -1375,7 +1373,7 @@ impl Vecs {
|
|||||||
pub fn send(
|
pub fn send(
|
||||||
&mut self,
|
&mut self,
|
||||||
height_to_sent: BTreeMap<Height, Transacted>,
|
height_to_sent: BTreeMap<Height, Transacted>,
|
||||||
chain_state: &[BlockState],
|
chain_state: &mut [BlockState],
|
||||||
) {
|
) {
|
||||||
let mut time_based_vecs = self
|
let mut time_based_vecs = self
|
||||||
.0
|
.0
|
||||||
@@ -1388,21 +1386,17 @@ impl Vecs {
|
|||||||
let last_timestamp = chain_state.last().unwrap().timestamp;
|
let last_timestamp = chain_state.last().unwrap().timestamp;
|
||||||
let current_price = chain_state.last().unwrap().price;
|
let current_price = chain_state.last().unwrap().price;
|
||||||
|
|
||||||
// dbg!(&height_to_sent);
|
|
||||||
|
|
||||||
height_to_sent.into_iter().for_each(|(height, sent)| {
|
height_to_sent.into_iter().for_each(|(height, sent)| {
|
||||||
|
chain_state[height.unwrap_to_usize()].supply -= &sent.spendable_supply;
|
||||||
|
|
||||||
let block_state = chain_state.get(height.unwrap_to_usize()).unwrap();
|
let block_state = chain_state.get(height.unwrap_to_usize()).unwrap();
|
||||||
let prev_price = block_state.price;
|
let prev_price = block_state.price;
|
||||||
|
|
||||||
let blocks_old = chain_state.len() - 1 - height.unwrap_to_usize();
|
let blocks_old = chain_state.len() - 1 - height.unwrap_to_usize();
|
||||||
|
|
||||||
let days_old = block_state
|
let days_old = last_timestamp.difference_in_days_between(block_state.timestamp);
|
||||||
.timestamp
|
let days_old_float =
|
||||||
.difference_in_days_between(last_timestamp);
|
last_timestamp.difference_in_days_between_float(block_state.timestamp);
|
||||||
|
|
||||||
let days_old_float = block_state
|
|
||||||
.timestamp
|
|
||||||
.difference_in_days_between_float(last_timestamp);
|
|
||||||
|
|
||||||
let older_than_hour = last_timestamp
|
let older_than_hour = last_timestamp
|
||||||
.checked_sub(block_state.timestamp)
|
.checked_sub(block_state.timestamp)
|
||||||
|
|||||||
@@ -21,12 +21,12 @@ impl AddressData {
|
|||||||
(self.realized_cap / Bitcoin::from(self.amount())).round_to_4_digits()
|
(self.realized_cap / Bitcoin::from(self.amount())).round_to_4_digits()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub fn has_0_sats(&self) -> bool {
|
pub fn has_0_sats(&self) -> bool {
|
||||||
self.amount() == Sats::ZERO
|
self.amount() == Sats::ZERO
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub fn has_0_utxos(&self) -> bool {
|
pub fn has_0_utxos(&self) -> bool {
|
||||||
self.outputs_len == 0
|
self.outputs_len == 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -243,7 +243,7 @@ impl Mul<Sats> for Dollars {
|
|||||||
self
|
self
|
||||||
} else {
|
} else {
|
||||||
Self::from(Cents::from(
|
Self::from(Cents::from(
|
||||||
u128::from(rhs) * u128::from(Cents::from(self)) / u128::from(Sats::ONE_BTC),
|
u128::from(rhs) * u128::from(Cents::from(self)) / Sats::ONE_BTC_U128,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ impl Sats {
|
|||||||
pub const ONE_BTC: Self = Self(1_00_000_000);
|
pub const ONE_BTC: Self = Self(1_00_000_000);
|
||||||
pub const MAX: Self = Self(u64::MAX);
|
pub const MAX: Self = Self(u64::MAX);
|
||||||
pub const FIFTY_BTC: Self = Self(50_00_000_000);
|
pub const FIFTY_BTC: Self = Self(50_00_000_000);
|
||||||
|
pub const ONE_BTC_U128: u128 = 1_00_000_000;
|
||||||
|
|
||||||
pub fn new(sats: u64) -> Self {
|
pub fn new(sats: u64) -> Self {
|
||||||
Self(sats)
|
Self(sats)
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
use std::{
|
use std::ops::{Add, AddAssign, Div};
|
||||||
cmp::Ordering,
|
|
||||||
ops::{Add, AddAssign, Div},
|
|
||||||
};
|
|
||||||
|
|
||||||
use derive_deref::Deref;
|
use derive_deref::Deref;
|
||||||
use jiff::{civil::date, tz::TimeZone};
|
use jiff::{civil::date, tz::TimeZone};
|
||||||
@@ -29,7 +26,9 @@ use super::Date;
|
|||||||
)]
|
)]
|
||||||
pub struct Timestamp(u32);
|
pub struct Timestamp(u32);
|
||||||
|
|
||||||
const ONE_DAY_IN_SEC: i64 = 24 * 60 * 60;
|
const ONE_HOUR_IN_SEC: u32 = 60 * 60;
|
||||||
|
const ONE_DAY_IN_SEC: u32 = 24 * 60 * 60;
|
||||||
|
const ONE_DAY_IN_SEC_F64: f64 = ONE_DAY_IN_SEC as f64;
|
||||||
|
|
||||||
impl Timestamp {
|
impl Timestamp {
|
||||||
pub const ZERO: Self = Self(0);
|
pub const ZERO: Self = Self(0);
|
||||||
@@ -50,34 +49,25 @@ impl Timestamp {
|
|||||||
Self::from(trunc_date_time.to_zoned(TimeZone::UTC).unwrap().timestamp())
|
Self::from(trunc_date_time.to_zoned(TimeZone::UTC).unwrap().timestamp())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn difference_in_days_between(&self, other: Self) -> usize {
|
#[inline]
|
||||||
match self.cmp(&other) {
|
pub fn difference_in_days_between(&self, older: Self) -> usize {
|
||||||
Ordering::Equal => 0,
|
// if self.0 < older.0 {
|
||||||
Ordering::Greater => other.difference_in_days_between(*self),
|
// unreachable!()
|
||||||
Ordering::Less => {
|
// }
|
||||||
(jiff::Timestamp::from(*self)
|
((self.0 - older.0) / ONE_DAY_IN_SEC) as usize
|
||||||
.duration_until(jiff::Timestamp::from(other))
|
|
||||||
.as_secs()
|
|
||||||
/ ONE_DAY_IN_SEC) as usize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn difference_in_days_between_float(&self, other: Self) -> f64 {
|
#[inline]
|
||||||
match self.cmp(&other) {
|
pub fn difference_in_days_between_float(&self, older: Self) -> f64 {
|
||||||
Ordering::Equal => 0.0,
|
// if self.0 < older.0 {
|
||||||
Ordering::Greater => other.difference_in_days_between_float(*self),
|
// unreachable!()
|
||||||
Ordering::Less => {
|
// }
|
||||||
jiff::Timestamp::from(*self)
|
(self.0 - older.0) as f64 / ONE_DAY_IN_SEC_F64
|
||||||
.duration_until(jiff::Timestamp::from(other))
|
|
||||||
.as_secs() as f64
|
|
||||||
/ ONE_DAY_IN_SEC as f64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_more_than_hour(&self) -> bool {
|
pub fn is_more_than_hour(&self) -> bool {
|
||||||
jiff::Timestamp::from(*self).as_second() >= 60 * 60
|
self.0 >= ONE_HOUR_IN_SEC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use color_eyre::owo_colors::OwoColorize;
|
|||||||
use env_logger::{Builder, Env};
|
use env_logger::{Builder, Env};
|
||||||
use jiff::{Timestamp, tz};
|
use jiff::{Timestamp, tz};
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub fn init(path: Option<&Path>) {
|
pub fn init(path: Option<&Path>) {
|
||||||
let file = path.map(|path| {
|
let file = path.map(|path| {
|
||||||
let _ = fs::remove_file(path);
|
let _ = fs::remove_file(path);
|
||||||
|
|||||||
@@ -17,14 +17,14 @@ impl XORIndex {
|
|||||||
bytes
|
bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub fn byte(&mut self, mut byte: u8, xor_bytes: &XORBytes) -> u8 {
|
pub fn byte(&mut self, mut byte: u8, xor_bytes: &XORBytes) -> u8 {
|
||||||
byte ^= xor_bytes[self.0];
|
byte ^= xor_bytes[self.0];
|
||||||
self.increment();
|
self.increment();
|
||||||
byte
|
byte
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub fn increment(&mut self) {
|
pub fn increment(&mut self) {
|
||||||
self.0 += 1;
|
self.0 += 1;
|
||||||
if self.0 == XOR_LEN {
|
if self.0 == XOR_LEN {
|
||||||
@@ -32,7 +32,7 @@ impl XORIndex {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub fn add_assign(&mut self, i: usize) {
|
pub fn add_assign(&mut self, i: usize) {
|
||||||
self.0 = (self.0 + i) % XOR_LEN;
|
self.0 = (self.0 + i) % XOR_LEN;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,10 @@ where
|
|||||||
{
|
{
|
||||||
const SIZE_OF_T: usize = size_of::<T>();
|
const SIZE_OF_T: usize = size_of::<T>();
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn unwrap_read(&self, index: I, mmap: &Mmap) -> T {
|
||||||
|
self.read(index, mmap).unwrap().unwrap()
|
||||||
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
fn read(&self, index: I, mmap: &Mmap) -> Result<Option<T>> {
|
fn read(&self, index: I, mmap: &Mmap) -> Result<Option<T>> {
|
||||||
self.read_(index.to_usize()?, mmap)
|
self.read_(index.to_usize()?, mmap)
|
||||||
|
|||||||
@@ -120,12 +120,12 @@ where
|
|||||||
zstd::encode_all(bytes.as_slice(), DEFAULT_COMPRESSION_LEVEL).unwrap()
|
zstd::encode_all(bytes.as_slice(), DEFAULT_COMPRESSION_LEVEL).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
fn index_to_page_index(index: usize) -> usize {
|
fn index_to_page_index(index: usize) -> usize {
|
||||||
index / Self::PER_PAGE
|
index / Self::PER_PAGE
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
fn page_index_to_index(page_index: usize) -> usize {
|
fn page_index_to_index(page_index: usize) -> usize {
|
||||||
page_index * Self::PER_PAGE
|
page_index * Self::PER_PAGE
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ use crate::{
|
|||||||
|
|
||||||
const ONE_KIB: usize = 1024;
|
const ONE_KIB: usize = 1024;
|
||||||
const ONE_MIB: usize = ONE_KIB * ONE_KIB;
|
const ONE_MIB: usize = ONE_KIB * ONE_KIB;
|
||||||
const MAX_CACHE_SIZE: usize = 210 * ONE_MIB;
|
const MAX_CACHE_SIZE: usize = 256 * ONE_MIB;
|
||||||
const DCA_AMOUNT: Dollars = Dollars::mint(100.0);
|
const DCA_AMOUNT: Dollars = Dollars::mint(100.0);
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|||||||
@@ -29,6 +29,11 @@ where
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn unwrap_read(&self, index: I, mmap: &Mmap) -> T {
|
||||||
|
self.0.unwrap_read(index, mmap)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_or_read(&self, index: I, mmap: &Mmap) -> Result<Option<Cow<T>>> {
|
pub fn get_or_read(&self, index: I, mmap: &Mmap) -> Result<Option<Cow<T>>> {
|
||||||
self.0.get_or_read(index, mmap)
|
self.0.get_or_read(index, mmap)
|
||||||
|
|||||||
Reference in New Issue
Block a user