computer: part 1

This commit is contained in:
nym21
2025-03-19 12:01:54 +01:00
parent ad761e388d
commit 29c10f8854
39 changed files with 1567 additions and 570 deletions

View File

@@ -5,10 +5,7 @@ use brk_core::default_bitcoin_path;
use brk_exit::Exit;
use brk_fetcher::Fetcher;
use brk_indexer::Indexer;
use brk_parser::{
Parser,
rpc::{self},
};
use brk_parser::{Parser, rpc};
pub fn main() -> color_eyre::Result<()> {
color_eyre::install()?;

View File

@@ -3,13 +3,13 @@ use std::{
cmp::Ordering,
fmt::Debug,
io,
ops::{Add, Deref, DerefMut, Sub},
ops::{Add, Sub},
path::{Path, PathBuf},
};
use brk_core::CheckedSub;
use brk_exit::Exit;
use brk_vec::{Compressed, Error, Result, StoredIndex, StoredType, Version};
use brk_vec::{AnyStorableVec, Compressed, Error, Result, StoredIndex, StoredType, Version};
const FLUSH_EVERY: usize = 10_000;
@@ -24,7 +24,11 @@ where
I: StoredIndex,
T: StoredType,
{
pub fn import(path: &Path, version: Version, compressed: Compressed) -> brk_vec::Result<Self> {
pub fn forced_import(
path: &Path,
version: Version,
compressed: Compressed,
) -> brk_vec::Result<Self> {
let vec = brk_vec::StorableVec::forced_import(path, version, compressed)?;
Ok(Self {
@@ -33,24 +37,19 @@ where
})
}
#[inline]
pub fn i_to_usize(index: I) -> Result<usize> {
index.try_into().map_err(|_| Error::FailedKeyTryIntoUsize)
}
fn safe_truncate_if_needed(&mut self, index: I, exit: &Exit) -> Result<()> {
if exit.triggered() {
return Ok(());
}
exit.block();
self.truncate_if_needed(index)?;
self.vec.truncate_if_needed(index)?;
exit.release();
Ok(())
}
#[inline]
fn push_and_flush_if_needed(&mut self, index: I, value: T, exit: &Exit) -> Result<()> {
match self.len().cmp(&Self::i_to_usize(index)?) {
pub fn forced_push_at(&mut self, index: I, value: T, exit: &Exit) -> Result<()> {
match self.len().cmp(&index.to_usize()?) {
Ordering::Less => {
return Err(Error::IndexTooHigh);
}
@@ -58,11 +57,11 @@ where
if ord == Ordering::Greater {
self.safe_truncate_if_needed(index, exit)?;
}
self.push(value);
self.vec.push(value);
}
}
if self.pushed_len() >= FLUSH_EVERY {
if self.vec.pushed_len() >= FLUSH_EVERY {
Ok(self.safe_flush(exit)?)
} else {
Ok(())
@@ -74,20 +73,48 @@ where
return Ok(());
}
exit.block();
self.flush()?;
self.vec.flush()?;
exit.release();
Ok(())
}
fn version(&self) -> Version {
self.vec.version()
}
fn len(&self) -> usize {
self.vec.len()
}
pub fn vec(&self) -> &brk_vec::StorableVec<I, T> {
&self.vec
}
pub fn mut_vec(&mut self) -> &mut brk_vec::StorableVec<I, T> {
&mut self.vec
}
pub fn any_vec(&self) -> &dyn AnyStorableVec {
&self.vec
}
pub fn get(&mut self, index: I) -> Result<Option<&T>> {
self.vec.get(index)
}
pub fn collect_range(&self, from: Option<i64>, to: Option<i64>) -> Result<Vec<T>> {
self.vec.collect_range(from, to)
}
#[inline]
fn path_computed_version(&self) -> PathBuf {
self.path().join("computed_version")
self.vec.path().join("computed_version")
}
fn validate_computed_version_or_reset_file(&mut self, version: Version) -> Result<()> {
let path = self.path_computed_version();
if version.validate(path.as_ref()).is_err() {
self.reset()?;
self.vec.reset()?;
}
version.write(path.as_ref())?;
Ok(())
@@ -112,7 +139,7 @@ where
let index = max_from.min(A::from(self.len()));
other.iter_from_cloned(index, |(a, b, other)| {
let (i, v) = t((a, b, self, other));
self.push_and_flush_if_needed(i, v, exit)
self.forced_push_at(i, v, exit)
})?;
Ok(self.safe_flush(exit)?)
@@ -132,11 +159,11 @@ where
Version::from(0) + self.version() + other.version(),
)?;
let index = max_from.min(self.read_last()?.cloned().unwrap_or_default());
let index = max_from.min(self.vec.get_last()?.cloned().unwrap_or_default());
other.iter_from(index, |(v, i, ..)| {
let i = *i;
if self.read(i).unwrap().is_none_or(|old_v| *old_v > v) {
self.push_and_flush_if_needed(i, v, exit)
if self.get(i).unwrap().is_none_or(|old_v| *old_v > v) {
self.forced_push_at(i, v, exit)
} else {
Ok(())
}
@@ -162,10 +189,10 @@ where
let index = max_from.min(T::from(self.len()));
first_indexes.iter_from(index, |(value, first_index, ..)| {
let first_index = Self::i_to_usize(*first_index)?;
let last_index = Self::i_to_usize(*last_indexes.read(value)?.unwrap())?;
let first_index = (first_index).to_usize()?;
let last_index = (last_indexes.get(value)?.unwrap()).to_usize()?;
(first_index..last_index)
.try_for_each(|index| self.push_and_flush_if_needed(I::from(index), value, exit))
.try_for_each(|index| self.forced_push_at(I::from(index), value, exit))
})?;
Ok(self.safe_flush(exit)?)
@@ -190,13 +217,13 @@ where
let mut prev_index: Option<I> = None;
first_indexes.iter_from(index, |(i, v, ..)| {
if let Some(prev_index) = prev_index.take() {
self.push_and_flush_if_needed(prev_index, v.checked_sub(one).unwrap(), exit)?;
self.forced_push_at(prev_index, v.checked_sub(one).unwrap(), exit)?;
}
prev_index.replace(i);
Ok(())
})?;
if let Some(prev_index) = prev_index {
self.push_and_flush_if_needed(
self.forced_push_at(
prev_index,
T::from(final_len).checked_sub(one).unwrap(),
exit,
@@ -215,7 +242,7 @@ where
) -> Result<()>
where
T: From<T2>,
T2: StoredType + Copy + Add<usize, Output = T2> + Sub<T2, Output = T2> + TryInto<T>,
T2: StoredType + Copy + Add<usize, Output = T2> + CheckedSub<T2> + TryInto<T> + Default,
<T2 as TryInto<T>>::Error: error::Error + 'static,
{
self.validate_computed_version_or_reset_file(
@@ -224,9 +251,11 @@ where
let index = max_from.min(I::from(self.len()));
first_indexes.iter_from(index, |(i, first_index, ..)| {
let last_index = last_indexes.read(i)?.unwrap();
let count = *last_index + 1_usize - *first_index;
self.push_and_flush_if_needed(i, count.into(), exit)
let last_index = last_indexes.get(i)?.unwrap();
let count = (*last_index + 1_usize)
.checked_sub(*first_index)
.unwrap_or_default();
self.forced_push_at(i, count.into(), exit)
})?;
Ok(self.safe_flush(exit)?)
@@ -250,11 +279,7 @@ where
let index = max_from.min(I::from(self.len()));
self_to_other.iter_from(index, |(i, other, ..)| {
self.push_and_flush_if_needed(
i,
T::from(other_to_self.read(*other)?.unwrap() == &i),
exit,
)
self.forced_push_at(i, T::from(other_to_self.get(*other)?.unwrap() == &i), exit)
})?;
Ok(self.safe_flush(exit)?)
@@ -278,26 +303,15 @@ where
let index = max_from.min(I::from(self.len()));
first_indexes.iter_from(index, |(index, first_index, ..)| {
let last_index = last_indexes.read(index)?.unwrap();
let last_index = last_indexes.get(index)?.unwrap();
let count = *last_index + 1_usize - *first_index;
self.push_and_flush_if_needed(index, count.into(), exit)
self.forced_push_at(index, count.into(), exit)
})?;
Ok(self.safe_flush(exit)?)
}
}
impl<I, T> Deref for StorableVec<I, T> {
type Target = brk_vec::StorableVec<I, T>;
fn deref(&self) -> &Self::Target {
&self.vec
}
}
impl<I, T> DerefMut for StorableVec<I, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.vec
}
}
impl<I, T> Clone for StorableVec<I, T>
where
I: StoredIndex,

View File

@@ -0,0 +1,99 @@
use std::{fs, path::Path};
use brk_core::{CheckedSub, Height, Timestamp};
use brk_exit::Exit;
use brk_indexer::Indexer;
use brk_vec::{AnyStorableVec, Compressed, Version};
use super::{
Indexes, StorableVec, indexes,
stats::{StorableVecGeneatorByIndex, StorableVecGeneatorOptions},
};
#[derive(Clone)]
pub struct Vecs {
pub height_to_block_interval: StorableVec<Height, Timestamp>,
pub indexes_to_block_interval_stats: StorableVecGeneatorByIndex<Timestamp>,
pub dateindex_to_block_count: StorableVec<Height, u16>,
pub dateindex_to_total_block_count: StorableVec<Height, u32>,
}
impl Vecs {
pub fn forced_import(path: &Path, compressed: Compressed) -> color_eyre::Result<Self> {
fs::create_dir_all(path)?;
Ok(Self {
height_to_block_interval: StorableVec::forced_import(
&path.join("height_to_block_interval"),
Version::from(1),
compressed,
)?,
indexes_to_block_interval_stats: StorableVecGeneatorByIndex::forced_import(
&path.join("block_interval"),
compressed,
StorableVecGeneatorOptions::default()
.add_percentiles()
.add_minmax()
.add_average(),
)?,
dateindex_to_block_count: StorableVec::forced_import(
&path.join("dateindex_to_block_count"),
Version::from(1),
compressed,
)?,
dateindex_to_total_block_count: StorableVec::forced_import(
&path.join("dateindex_to_total_block_count"),
Version::from(1),
compressed,
)?,
})
}
pub fn compute(
&mut self,
indexer: &mut Indexer,
indexes: &mut indexes::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> color_eyre::Result<()> {
let indexer_vecs = indexer.mut_vecs();
self.height_to_block_interval.compute_transform(
starting_indexes.height,
indexer_vecs.height_to_timestamp.mut_vec(),
|(height, timestamp, height_to_timestamp, ..)| {
let interval = height.decremented().map_or(Timestamp::ZERO, |prev_h| {
let prev_timestamp = *height_to_timestamp.get(prev_h).unwrap().unwrap();
if prev_timestamp >= timestamp {
Timestamp::ZERO
} else {
timestamp.checked_sub(prev_timestamp).unwrap()
}
});
(height, interval)
},
exit,
)?;
self.indexes_to_block_interval_stats.compute(
&mut self.height_to_block_interval,
indexer,
indexes,
starting_indexes,
);
Ok(())
}
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStorableVec> {
[
vec![
self.height_to_block_interval.any_vec(),
self.dateindex_to_block_count.any_vec(),
self.dateindex_to_total_block_count.any_vec(),
],
self.indexes_to_block_interval_stats.as_any_vecs(),
]
.concat()
}
}

View File

@@ -3,7 +3,7 @@ use std::{fs, ops::Deref, path::Path};
use brk_core::{Date, Dateindex, Height, Txindex, Txinindex, Txoutindex};
use brk_exit::Exit;
use brk_indexer::Indexer;
use brk_vec::{AnyStorableVec, Compressed, Value, Version};
use brk_vec::{AnyStorableVec, Compressed, Version};
use super::StorableVec;
@@ -25,62 +25,62 @@ pub struct Vecs {
}
impl Vecs {
pub fn import(path: &Path, compressed: Compressed) -> color_eyre::Result<Self> {
pub fn forced_import(path: &Path, compressed: Compressed) -> color_eyre::Result<Self> {
fs::create_dir_all(path)?;
Ok(Self {
dateindex_to_date: StorableVec::import(
dateindex_to_date: StorableVec::forced_import(
&path.join("dateindex_to_date"),
Version::from(1),
compressed,
)?,
dateindex_to_dateindex: StorableVec::import(
dateindex_to_dateindex: StorableVec::forced_import(
&path.join("dateindex_to_dateindex"),
Version::from(1),
compressed,
)?,
dateindex_to_first_height: StorableVec::import(
dateindex_to_first_height: StorableVec::forced_import(
&path.join("dateindex_to_first_height"),
Version::from(1),
compressed,
)?,
dateindex_to_last_height: StorableVec::import(
dateindex_to_last_height: StorableVec::forced_import(
&path.join("dateindex_to_last_height"),
Version::from(1),
compressed,
)?,
height_to_real_date: StorableVec::import(
height_to_real_date: StorableVec::forced_import(
&path.join("height_to_real_date"),
Version::from(1),
compressed,
)?,
height_to_fixed_date: StorableVec::import(
height_to_fixed_date: StorableVec::forced_import(
&path.join("height_to_fixed_date"),
Version::from(1),
compressed,
)?,
height_to_dateindex: StorableVec::import(
height_to_dateindex: StorableVec::forced_import(
&path.join("height_to_dateindex"),
Version::from(1),
compressed,
)?,
height_to_height: StorableVec::import(
height_to_height: StorableVec::forced_import(
&path.join("height_to_height"),
Version::from(1),
compressed,
)?,
height_to_last_txindex: StorableVec::import(
height_to_last_txindex: StorableVec::forced_import(
&path.join("height_to_last_txindex"),
Version::from(1),
compressed,
)?,
txindex_to_last_txinindex: StorableVec::import(
txindex_to_last_txinindex: StorableVec::forced_import(
&path.join("txindex_to_last_txinindex"),
Version::from(1),
compressed,
)?,
txindex_to_last_txoutindex: StorableVec::import(
txindex_to_last_txoutindex: StorableVec::forced_import(
&path.join("txindex_to_last_txoutindex"),
Version::from(1),
compressed,
@@ -103,25 +103,25 @@ impl Vecs {
self.height_to_height.compute_transform(
starting_indexes.height,
&mut indexer_vecs.height_to_timestamp,
indexer_vecs.height_to_timestamp.mut_vec(),
|(h, ..)| (h, h),
exit,
)?;
self.height_to_real_date.compute_transform(
starting_indexes.height,
&mut indexer_vecs.height_to_timestamp,
indexer_vecs.height_to_timestamp.mut_vec(),
|(h, t, ..)| (h, Date::from(t)),
exit,
)?;
self.height_to_fixed_date.compute_transform(
starting_indexes.height,
&mut self.height_to_real_date,
self.height_to_real_date.mut_vec(),
|(h, d, s, ..)| {
let d = h
.decremented()
.and_then(|h| s.read(h).ok())
.and_then(|h| s.get(h).ok())
.flatten()
.map_or(d, |prev_d| {
let prev_d = *prev_d;
@@ -134,7 +134,7 @@ impl Vecs {
self.height_to_dateindex.compute_transform(
starting_indexes.height,
&mut self.height_to_fixed_date,
self.height_to_fixed_date.mut_vec(),
|(h, d, ..)| (h, Dateindex::try_from(d).unwrap()),
exit,
)?;
@@ -142,34 +142,34 @@ impl Vecs {
let starting_dateindex = self
.height_to_dateindex
.get(starting_indexes.height.decremented().unwrap_or_default())?
.map(Value::into_inner)
.copied()
.unwrap_or_default();
self.dateindex_to_first_height
.compute_inverse_more_to_less(
starting_indexes.height,
&mut self.height_to_dateindex,
self.height_to_dateindex.mut_vec(),
exit,
)?;
self.dateindex_to_last_height
.compute_last_index_from_first(
starting_dateindex,
&mut self.dateindex_to_first_height,
self.dateindex_to_first_height.mut_vec(),
height_count,
exit,
)?;
self.dateindex_to_dateindex.compute_transform(
starting_dateindex,
&mut self.dateindex_to_first_height,
self.dateindex_to_first_height.mut_vec(),
|(di, ..)| (di, di),
exit,
)?;
self.dateindex_to_date.compute_transform(
starting_dateindex,
&mut self.dateindex_to_dateindex,
self.dateindex_to_dateindex.mut_vec(),
|(di, ..)| (di, Date::from(di)),
exit,
)?;
@@ -177,7 +177,7 @@ impl Vecs {
self.txindex_to_last_txinindex
.compute_last_index_from_first(
starting_indexes.txindex,
&mut indexer_vecs.txindex_to_first_txinindex,
indexer_vecs.txindex_to_first_txinindex.mut_vec(),
txinindexes_count,
exit,
)?;
@@ -185,14 +185,14 @@ impl Vecs {
self.txindex_to_last_txoutindex
.compute_last_index_from_first(
starting_indexes.txindex,
&mut indexer_vecs.txindex_to_first_txoutindex,
indexer_vecs.txindex_to_first_txoutindex.mut_vec(),
txoutindexes_count,
exit,
)?;
self.height_to_last_txindex.compute_last_index_from_first(
starting_indexes.height,
&mut indexer_vecs.height_to_first_txindex,
indexer_vecs.height_to_first_txindex.mut_vec(),
txindexes_count,
exit,
)?;
@@ -202,17 +202,17 @@ impl Vecs {
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStorableVec> {
vec![
&*self.dateindex_to_date,
&*self.dateindex_to_dateindex,
&*self.dateindex_to_first_height,
&*self.dateindex_to_last_height,
&*self.height_to_dateindex,
&*self.height_to_fixed_date,
&*self.height_to_height,
&*self.height_to_last_txindex,
&*self.height_to_real_date,
&*self.txindex_to_last_txinindex,
&*self.txindex_to_last_txoutindex,
self.dateindex_to_date.any_vec(),
self.dateindex_to_dateindex.any_vec(),
self.dateindex_to_first_height.any_vec(),
self.dateindex_to_last_height.any_vec(),
self.height_to_dateindex.any_vec(),
self.height_to_fixed_date.any_vec(),
self.height_to_height.any_vec(),
self.height_to_last_txindex.any_vec(),
self.height_to_real_date.any_vec(),
self.txindex_to_last_txinindex.any_vec(),
self.txindex_to_last_txoutindex.any_vec(),
]
}
}

View File

@@ -6,7 +6,7 @@ use brk_core::{
use brk_exit::Exit;
use brk_fetcher::Fetcher;
use brk_indexer::Indexer;
use brk_vec::{AnyStorableVec, Compressed, Value, Version};
use brk_vec::{AnyStorableVec, Compressed, Version};
use super::{Indexes, StorableVec, indexes};
@@ -37,116 +37,116 @@ pub struct Vecs {
}
impl Vecs {
pub fn import(path: &Path, compressed: Compressed) -> color_eyre::Result<Self> {
pub fn forced_import(path: &Path, compressed: Compressed) -> color_eyre::Result<Self> {
fs::create_dir_all(path)?;
Ok(Self {
dateindex_to_ohlc_in_cents: StorableVec::import(
dateindex_to_ohlc_in_cents: StorableVec::forced_import(
&path.join("dateindex_to_ohlc_in_cents"),
Version::from(1),
compressed,
)?,
dateindex_to_ohlc: StorableVec::import(
dateindex_to_ohlc: StorableVec::forced_import(
&path.join("dateindex_to_ohlc"),
Version::from(1),
compressed,
)?,
dateindex_to_close_in_cents: StorableVec::import(
dateindex_to_close_in_cents: StorableVec::forced_import(
&path.join("dateindex_to_close_in_cents"),
Version::from(1),
compressed,
)?,
dateindex_to_close: StorableVec::import(
dateindex_to_close: StorableVec::forced_import(
&path.join("dateindex_to_close"),
Version::from(1),
compressed,
)?,
dateindex_to_high_in_cents: StorableVec::import(
dateindex_to_high_in_cents: StorableVec::forced_import(
&path.join("dateindex_to_high_in_cents"),
Version::from(1),
compressed,
)?,
dateindex_to_high: StorableVec::import(
dateindex_to_high: StorableVec::forced_import(
&path.join("dateindex_to_high"),
Version::from(1),
compressed,
)?,
dateindex_to_low_in_cents: StorableVec::import(
dateindex_to_low_in_cents: StorableVec::forced_import(
&path.join("dateindex_to_low_in_cents"),
Version::from(1),
compressed,
)?,
dateindex_to_low: StorableVec::import(
dateindex_to_low: StorableVec::forced_import(
&path.join("dateindex_to_low"),
Version::from(1),
compressed,
)?,
dateindex_to_open_in_cents: StorableVec::import(
dateindex_to_open_in_cents: StorableVec::forced_import(
&path.join("dateindex_to_open_in_cents"),
Version::from(1),
compressed,
)?,
dateindex_to_open: StorableVec::import(
dateindex_to_open: StorableVec::forced_import(
&path.join("dateindex_to_open"),
Version::from(1),
compressed,
)?,
dateindex_to_sats_per_dollar: StorableVec::import(
dateindex_to_sats_per_dollar: StorableVec::forced_import(
&path.join("dateindex_to_sats_per_dollar"),
Version::from(1),
compressed,
)?,
height_to_ohlc_in_cents: StorableVec::import(
height_to_ohlc_in_cents: StorableVec::forced_import(
&path.join("height_to_ohlc_in_cents"),
Version::from(1),
compressed,
)?,
height_to_ohlc: StorableVec::import(
height_to_ohlc: StorableVec::forced_import(
&path.join("height_to_ohlc"),
Version::from(1),
compressed,
)?,
height_to_close_in_cents: StorableVec::import(
height_to_close_in_cents: StorableVec::forced_import(
&path.join("height_to_close_in_cents"),
Version::from(1),
compressed,
)?,
height_to_close: StorableVec::import(
height_to_close: StorableVec::forced_import(
&path.join("height_to_close"),
Version::from(1),
compressed,
)?,
height_to_high_in_cents: StorableVec::import(
height_to_high_in_cents: StorableVec::forced_import(
&path.join("height_to_high_in_cents"),
Version::from(1),
compressed,
)?,
height_to_high: StorableVec::import(
height_to_high: StorableVec::forced_import(
&path.join("height_to_high"),
Version::from(1),
compressed,
)?,
height_to_low_in_cents: StorableVec::import(
height_to_low_in_cents: StorableVec::forced_import(
&path.join("height_to_low_in_cents"),
Version::from(1),
compressed,
)?,
height_to_low: StorableVec::import(
height_to_low: StorableVec::forced_import(
&path.join("height_to_low"),
Version::from(1),
compressed,
)?,
height_to_open_in_cents: StorableVec::import(
height_to_open_in_cents: StorableVec::forced_import(
&path.join("height_to_open_in_cents"),
Version::from(1),
compressed,
)?,
height_to_open: StorableVec::import(
height_to_open: StorableVec::forced_import(
&path.join("height_to_open"),
Version::from(1),
compressed,
)?,
height_to_sats_per_dollar: StorableVec::import(
height_to_sats_per_dollar: StorableVec::forced_import(
&path.join("height_to_sats_per_dollar"),
Version::from(1),
compressed,
@@ -166,19 +166,14 @@ impl Vecs {
self.height_to_ohlc_in_cents.compute_transform(
starting_indexes.height,
&mut indexer_vecs.height_to_timestamp,
indexer_vecs.height_to_timestamp.mut_vec(),
|(h, t, _, height_to_timestamp)| {
let ohlc = fetcher
.get_height(
h,
t,
h.decremented().map(|prev_h| {
height_to_timestamp
.get(prev_h)
.unwrap()
.map(Value::into_inner)
.unwrap()
}),
h.decremented()
.map(|prev_h| *height_to_timestamp.get(prev_h).unwrap().unwrap()),
)
.unwrap();
(h, ohlc)
@@ -188,77 +183,77 @@ impl Vecs {
self.height_to_open_in_cents.compute_transform(
starting_indexes.height,
&mut self.height_to_ohlc_in_cents,
self.height_to_ohlc_in_cents.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.open),
exit,
)?;
self.height_to_high_in_cents.compute_transform(
starting_indexes.height,
&mut self.height_to_ohlc_in_cents,
self.height_to_ohlc_in_cents.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.high),
exit,
)?;
self.height_to_low_in_cents.compute_transform(
starting_indexes.height,
&mut self.height_to_ohlc_in_cents,
self.height_to_ohlc_in_cents.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.low),
exit,
)?;
self.height_to_close_in_cents.compute_transform(
starting_indexes.height,
&mut self.height_to_ohlc_in_cents,
self.height_to_ohlc_in_cents.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.close),
exit,
)?;
self.height_to_ohlc.compute_transform(
starting_indexes.height,
&mut self.height_to_ohlc_in_cents,
self.height_to_ohlc_in_cents.mut_vec(),
|(di, ohlc, ..)| (di, OHLCDollars::from(ohlc)),
exit,
)?;
self.height_to_open.compute_transform(
starting_indexes.height,
&mut self.height_to_ohlc,
self.height_to_ohlc.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.open),
exit,
)?;
self.height_to_high.compute_transform(
starting_indexes.height,
&mut self.height_to_ohlc,
self.height_to_ohlc.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.high),
exit,
)?;
self.height_to_low.compute_transform(
starting_indexes.height,
&mut self.height_to_ohlc,
self.height_to_ohlc.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.low),
exit,
)?;
self.height_to_close.compute_transform(
starting_indexes.height,
&mut self.height_to_ohlc,
self.height_to_ohlc.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.close),
exit,
)?;
self.height_to_sats_per_dollar.compute_transform(
starting_indexes.height,
&mut self.height_to_close,
self.height_to_close.mut_vec(),
|(di, close, ..)| (di, Close::from(Sats::ONE_BTC / *close)),
exit,
)?;
self.dateindex_to_ohlc_in_cents.compute_transform(
starting_indexes.dateindex,
&mut indexes.dateindex_to_date,
indexes.dateindex_to_date.mut_vec(),
|(di, d, ..)| {
let ohlc = fetcher.get_date(d).unwrap();
(di, ohlc)
@@ -268,70 +263,70 @@ impl Vecs {
self.dateindex_to_open_in_cents.compute_transform(
starting_indexes.dateindex,
&mut self.dateindex_to_ohlc_in_cents,
self.dateindex_to_ohlc_in_cents.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.open),
exit,
)?;
self.dateindex_to_high_in_cents.compute_transform(
starting_indexes.dateindex,
&mut self.dateindex_to_ohlc_in_cents,
self.dateindex_to_ohlc_in_cents.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.high),
exit,
)?;
self.dateindex_to_low_in_cents.compute_transform(
starting_indexes.dateindex,
&mut self.dateindex_to_ohlc_in_cents,
self.dateindex_to_ohlc_in_cents.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.low),
exit,
)?;
self.dateindex_to_close_in_cents.compute_transform(
starting_indexes.dateindex,
&mut self.dateindex_to_ohlc_in_cents,
self.dateindex_to_ohlc_in_cents.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.close),
exit,
)?;
self.dateindex_to_ohlc.compute_transform(
starting_indexes.dateindex,
&mut self.dateindex_to_ohlc_in_cents,
self.dateindex_to_ohlc_in_cents.mut_vec(),
|(di, ohlc, ..)| (di, OHLCDollars::from(ohlc)),
exit,
)?;
self.dateindex_to_open.compute_transform(
starting_indexes.dateindex,
&mut self.dateindex_to_ohlc,
self.dateindex_to_ohlc.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.open),
exit,
)?;
self.dateindex_to_high.compute_transform(
starting_indexes.dateindex,
&mut self.dateindex_to_ohlc,
self.dateindex_to_ohlc.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.high),
exit,
)?;
self.dateindex_to_low.compute_transform(
starting_indexes.dateindex,
&mut self.dateindex_to_ohlc,
self.dateindex_to_ohlc.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.low),
exit,
)?;
self.dateindex_to_close.compute_transform(
starting_indexes.dateindex,
&mut self.dateindex_to_ohlc,
self.dateindex_to_ohlc.mut_vec(),
|(di, ohlc, ..)| (di, ohlc.close),
exit,
)?;
self.dateindex_to_sats_per_dollar.compute_transform(
starting_indexes.dateindex,
&mut self.dateindex_to_close,
self.dateindex_to_close.mut_vec(),
|(di, close, ..)| (di, Close::from(Sats::ONE_BTC / *close)),
exit,
)?;
@@ -341,28 +336,28 @@ impl Vecs {
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStorableVec> {
vec![
&*self.dateindex_to_close,
&*self.dateindex_to_close_in_cents,
&*self.dateindex_to_high,
&*self.dateindex_to_high_in_cents,
&*self.dateindex_to_low,
&*self.dateindex_to_low_in_cents,
&*self.dateindex_to_ohlc,
&*self.dateindex_to_ohlc_in_cents,
&*self.dateindex_to_open,
&*self.dateindex_to_open_in_cents,
&*self.dateindex_to_sats_per_dollar,
&*self.height_to_close,
&*self.height_to_close_in_cents,
&*self.height_to_high,
&*self.height_to_high_in_cents,
&*self.height_to_low,
&*self.height_to_low_in_cents,
&*self.height_to_ohlc,
&*self.height_to_ohlc_in_cents,
&*self.height_to_open,
&*self.height_to_open_in_cents,
&*self.height_to_sats_per_dollar,
self.dateindex_to_close.any_vec(),
self.dateindex_to_close_in_cents.any_vec(),
self.dateindex_to_high.any_vec(),
self.dateindex_to_high_in_cents.any_vec(),
self.dateindex_to_low.any_vec(),
self.dateindex_to_low_in_cents.any_vec(),
self.dateindex_to_ohlc.any_vec(),
self.dateindex_to_ohlc_in_cents.any_vec(),
self.dateindex_to_open.any_vec(),
self.dateindex_to_open_in_cents.any_vec(),
self.dateindex_to_sats_per_dollar.any_vec(),
self.height_to_close.any_vec(),
self.height_to_close_in_cents.any_vec(),
self.height_to_high.any_vec(),
self.height_to_high_in_cents.any_vec(),
self.height_to_low.any_vec(),
self.height_to_low_in_cents.any_vec(),
self.height_to_ohlc.any_vec(),
self.height_to_ohlc_in_cents.any_vec(),
self.height_to_open.any_vec(),
self.height_to_open_in_cents.any_vec(),
self.height_to_sats_per_dollar.any_vec(),
]
}
}

View File

@@ -6,8 +6,10 @@ use brk_indexer::Indexer;
use brk_vec::{AnyStorableVec, Compressed};
mod base;
mod blocks;
mod indexes;
mod marketprice;
mod stats;
mod transactions;
use base::*;
@@ -15,6 +17,7 @@ use indexes::*;
#[derive(Clone)]
pub struct Vecs {
pub blocks: blocks::Vecs,
pub indexes: indexes::Vecs,
pub transactions: transactions::Vecs,
pub marketprice: Option<marketprice::Vecs>,
@@ -25,9 +28,10 @@ impl Vecs {
fs::create_dir_all(path)?;
Ok(Self {
indexes: indexes::Vecs::import(path, compressed)?,
transactions: transactions::Vecs::import(path, compressed)?,
marketprice: fetch.then(|| marketprice::Vecs::import(path, compressed).unwrap()),
blocks: blocks::Vecs::forced_import(path, compressed)?,
indexes: indexes::Vecs::forced_import(path, compressed)?,
transactions: transactions::Vecs::forced_import(path, compressed)?,
marketprice: fetch.then(|| marketprice::Vecs::forced_import(path, compressed).unwrap()),
})
}
@@ -40,6 +44,9 @@ impl Vecs {
) -> color_eyre::Result<()> {
let starting_indexes = self.indexes.compute(indexer, starting_indexes, exit)?;
self.blocks
.compute(indexer, &mut self.indexes, &starting_indexes, exit)?;
self.transactions
.compute(indexer, &mut self.indexes, &starting_indexes, exit)?;

View File

@@ -0,0 +1,396 @@
use std::path::Path;
use brk_exit::Exit;
use brk_vec::{AnyStorableVec, Compressed, Result, StoredIndex, Version};
use crate::storage::vecs::base::StorableVec;
use super::StoredType;
#[derive(Clone, Debug)]
pub struct StorableVecGeneator<I, T>
where
I: StoredIndex,
T: StoredType,
{
// first: Option<StorableVec<I, T>>,
average: Option<StorableVec<I, T>>,
sum: Option<StorableVec<I, T>>,
max: Option<StorableVec<I, T>>,
_90p: Option<StorableVec<I, T>>,
_75p: Option<StorableVec<I, T>>,
median: Option<StorableVec<I, T>>,
_25p: Option<StorableVec<I, T>>,
_10p: Option<StorableVec<I, T>>,
min: Option<StorableVec<I, T>>,
last: Option<StorableVec<I, T>>,
}
impl<I, T> StorableVecGeneator<I, T>
where
I: StoredIndex,
T: StoredType,
{
pub fn forced_import(
path: &Path,
compressed: Compressed,
options: StorableVecGeneatorOptions,
) -> color_eyre::Result<Self> {
let name = path.file_name().unwrap().to_str().unwrap().to_string();
// let prefix = |s: &str| path.with_file_name(format!("{s}_{name}"));
let suffix = |s: &str| path.with_file_name(format!("{name}_{s}"));
let s = Self {
// first: options.first.then(|| {
// StorableVec::forced_import(&prefix("first"), Version::from(1), compressed).unwrap()
// }),
last: options
.last
.then(|| StorableVec::forced_import(path, Version::from(1), compressed).unwrap()),
min: options.min.then(|| {
StorableVec::forced_import(&suffix("min"), Version::from(1), compressed).unwrap()
}),
max: options.max.then(|| {
StorableVec::forced_import(&suffix("max"), Version::from(1), compressed).unwrap()
}),
median: options.median.then(|| {
StorableVec::forced_import(&suffix("median"), Version::from(1), compressed).unwrap()
}),
average: options.average.then(|| {
StorableVec::forced_import(&suffix("average"), Version::from(1), compressed)
.unwrap()
}),
sum: options.sum.then(|| {
StorableVec::forced_import(&suffix("sum"), Version::from(1), compressed).unwrap()
}),
_90p: options._90p.then(|| {
StorableVec::forced_import(&suffix("90p"), Version::from(1), compressed).unwrap()
}),
_75p: options._75p.then(|| {
StorableVec::forced_import(&suffix("75p"), Version::from(1), compressed).unwrap()
}),
_25p: options._25p.then(|| {
StorableVec::forced_import(&suffix("25p"), Version::from(1), compressed).unwrap()
}),
_10p: options._10p.then(|| {
StorableVec::forced_import(&suffix("10p"), Version::from(1), compressed).unwrap()
}),
};
Ok(s)
}
pub fn compute<I2>(
&mut self,
max_from: I,
source: &mut StorableVec<I2, T>,
first_indexes: &mut brk_vec::StorableVec<I, I2>,
last_indexes: &mut brk_vec::StorableVec<I, I2>,
exit: &Exit,
) -> Result<()>
where
I2: StoredIndex + StoredType,
T: Ord,
{
let index = self.starting_index(max_from);
first_indexes.iter_from(index, |(i, first_index)| {
let first_index = *first_index;
let last_index = *last_indexes.get(i).unwrap().unwrap();
// if let Some(first) = self.first.as_mut() {
// let v = source.read(first_index).unwrap().unwrap();
// first.forced_push_at(index, v.clone(), exit);
// }
if let Some(last) = self.last.as_mut() {
let v = source.get(last_index).unwrap().unwrap();
last.forced_push_at(index, v.clone(), exit)?;
}
let first_index = first_index.to_usize()?;
let last_index = last_index.to_usize()?;
let needs_sum_or_average = self.sum.is_some() || self.average.is_some();
let needs_sorted = self.max.is_some()
|| self._90p.is_some()
|| self._75p.is_some()
|| self.median.is_some()
|| self._25p.is_some()
|| self._10p.is_some()
|| self.min.is_some();
let needs_values = needs_sorted || needs_sum_or_average;
if needs_values {
let mut values =
source.collect_range(Some(first_index as i64), Some(last_index as i64))?;
if needs_sorted {
values.sort_unstable();
if let Some(max) = self.max.as_mut() {
max.forced_push_at(i, values.last().unwrap().clone(), exit)?;
}
if let Some(_90p) = self._90p.as_mut() {
_90p.forced_push_at(i, Self::get_percentile(&values, 0.90), exit)?;
}
if let Some(_75p) = self._75p.as_mut() {
_75p.forced_push_at(i, Self::get_percentile(&values, 0.75), exit)?;
}
if let Some(median) = self.median.as_mut() {
median.forced_push_at(i, Self::get_percentile(&values, 0.50), exit)?;
}
if let Some(_25p) = self._25p.as_mut() {
_25p.forced_push_at(i, Self::get_percentile(&values, 0.25), exit)?;
}
if let Some(_10p) = self._10p.as_mut() {
_10p.forced_push_at(i, Self::get_percentile(&values, 0.10), exit)?;
}
if let Some(min) = self.min.as_mut() {
min.forced_push_at(i, values.first().unwrap().clone(), exit)?;
}
}
if needs_sum_or_average {
let len = values.len();
if let Some(average) = self.average.as_mut() {
let a = values
.iter()
.map(|v| v.clone() / len)
.fold(T::from(0), |a, b| a + b);
average.forced_push_at(i, a, exit)?;
}
if let Some(sum_vec) = self.sum.as_mut() {
let sum = values.into_iter().fold(T::from(0), |a, b| a + b);
sum_vec.forced_push_at(i, sum, exit)?;
}
}
}
Ok(())
})?;
Ok(())
}
fn get_percentile(sorted: &[T], percentile: f64) -> T {
let len = sorted.len();
if len == 0 {
panic!();
} else if len == 1 {
sorted[0].clone()
} else {
let index = (len - 1) as f64 * percentile;
let fract = index.fract();
if fract != 0.0 {
let left = sorted.get(index as usize).unwrap().clone();
let right = sorted.get(index.ceil() as usize).unwrap().clone();
left / 2 + right / 2
} else {
sorted.get(index as usize).unwrap().clone()
}
}
}
fn starting_index(&self, max_from: I) -> I {
max_from.min(I::from(
self.as_any_vecs()
.into_iter()
.map(|v| v.len())
.min()
.unwrap(),
))
}
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStorableVec> {
let mut v: Vec<&dyn AnyStorableVec> = vec![];
// if let Some(first) = self.first.as_ref() {
// v.push(first.any_vec());
// }
if let Some(last) = self.last.as_ref() {
v.push(last.any_vec());
}
if let Some(min) = self.min.as_ref() {
v.push(min.any_vec());
}
if let Some(max) = self.max.as_ref() {
v.push(max.any_vec());
}
if let Some(median) = self.median.as_ref() {
v.push(median.any_vec());
}
if let Some(average) = self.average.as_ref() {
v.push(average.any_vec());
}
if let Some(sum) = self.sum.as_ref() {
v.push(sum.any_vec());
}
if let Some(_90p) = self._90p.as_ref() {
v.push(_90p.any_vec());
}
if let Some(_75p) = self._75p.as_ref() {
v.push(_75p.any_vec());
}
if let Some(_25p) = self._25p.as_ref() {
v.push(_25p.any_vec());
}
if let Some(_10p) = self._10p.as_ref() {
v.push(_10p.any_vec());
}
v
}
}
#[derive(Default, Clone, Copy)]
pub struct StorableVecGeneatorOptions {
average: bool,
sum: bool,
max: bool,
_90p: bool,
_75p: bool,
median: bool,
_25p: bool,
_10p: bool,
min: bool,
// first: bool,
last: bool,
}
impl StorableVecGeneatorOptions {
// pub fn add_first(mut self) -> Self {
// self.first = true;
// self
// }
pub fn add_last(mut self) -> Self {
self.last = true;
self
}
pub fn add_min(mut self) -> Self {
self.min = true;
self
}
pub fn add_max(mut self) -> Self {
self.max = true;
self
}
pub fn add_median(mut self) -> Self {
self.median = true;
self
}
pub fn add_average(mut self) -> Self {
self.average = true;
self
}
pub fn add_sum(mut self) -> Self {
self.sum = true;
self
}
pub fn add_90p(mut self) -> Self {
self._90p = true;
self
}
pub fn add_75p(mut self) -> Self {
self._75p = true;
self
}
pub fn add_25p(mut self) -> Self {
self._25p = true;
self
}
pub fn add_10p(mut self) -> Self {
self._10p = true;
self
}
pub fn rm_min(mut self) -> Self {
self.min = false;
self
}
pub fn rm_max(mut self) -> Self {
self.max = false;
self
}
pub fn rm_median(mut self) -> Self {
self.median = false;
self
}
pub fn rm_average(mut self) -> Self {
self.average = false;
self
}
pub fn rm_sum(mut self) -> Self {
self.sum = false;
self
}
pub fn rm_90p(mut self) -> Self {
self._90p = false;
self
}
pub fn rm_75p(mut self) -> Self {
self._75p = false;
self
}
pub fn rm_25p(mut self) -> Self {
self._25p = false;
self
}
pub fn rm_10p(mut self) -> Self {
self._10p = false;
self
}
pub fn add_minmax(mut self) -> Self {
self.min = true;
self.max = true;
self
}
pub fn add_percentiles(mut self) -> Self {
self._90p = true;
self._75p = true;
self.median = true;
self._25p = true;
self._10p = true;
self
}
pub fn remove_percentiles(mut self) -> Self {
self._90p = false;
self._75p = false;
self.median = false;
self._25p = false;
self._10p = false;
self
}
}

View File

@@ -0,0 +1,72 @@
use std::path::Path;
use brk_core::{
Dateindex, Decadeindex, Difficultyepoch, Halvingepoch, Height, Monthindex, Weekindex, Yearindex,
};
use brk_indexer::{Indexer, Indexes};
use brk_vec::{AnyStorableVec, Compressed};
use crate::storage::vecs::{base::StorableVec, indexes};
use super::{StorableVecGeneator, StorableVecGeneatorOptions, StoredType};
#[derive(Clone)]
pub struct StorableVecGeneatorByIndex<T>
where
T: StoredType,
{
pub dateindex: StorableVecGeneator<Dateindex, T>,
pub weekindex: StorableVecGeneator<Weekindex, T>,
pub difficultyepoch: StorableVecGeneator<Difficultyepoch, T>,
pub monthindex: StorableVecGeneator<Monthindex, T>,
pub yearindex: StorableVecGeneator<Yearindex, T>,
pub halvingepoch: StorableVecGeneator<Halvingepoch, T>,
pub decadeindex: StorableVecGeneator<Decadeindex, T>,
}
impl<T> StorableVecGeneatorByIndex<T>
where
T: StoredType,
{
pub fn forced_import(
path: &Path,
compressed: Compressed,
options: StorableVecGeneatorOptions,
) -> color_eyre::Result<Self> {
let dateindex = StorableVecGeneator::forced_import(path, compressed, options)?;
let options = options.remove_percentiles();
Ok(Self {
dateindex,
weekindex: StorableVecGeneator::forced_import(path, compressed, options)?,
difficultyepoch: StorableVecGeneator::forced_import(path, compressed, options)?,
monthindex: StorableVecGeneator::forced_import(path, compressed, options)?,
yearindex: StorableVecGeneator::forced_import(path, compressed, options)?,
halvingepoch: StorableVecGeneator::forced_import(path, compressed, options)?,
decadeindex: StorableVecGeneator::forced_import(path, compressed, options)?,
})
}
pub fn compute(
&mut self,
source: &mut StorableVec<Height, T>,
indexer: &mut Indexer,
indexes: &mut indexes::Vecs,
starting_indexes: &Indexes,
) {
}
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStorableVec> {
[
self.dateindex.as_any_vecs(),
self.weekindex.as_any_vecs(),
self.difficultyepoch.as_any_vecs(),
self.monthindex.as_any_vecs(),
self.yearindex.as_any_vecs(),
self.halvingepoch.as_any_vecs(),
self.decadeindex.as_any_vecs(),
]
.concat()
}
}

View File

@@ -0,0 +1,7 @@
mod generic;
mod grouped;
mod stored_type;
pub use generic::*;
pub use grouped::*;
pub use stored_type::*;

View File

@@ -0,0 +1,11 @@
use std::ops::{Add, Div};
pub trait StoredType
where
Self: brk_vec::StoredType + From<usize> + Div<usize, Output = Self> + Add<Output = Self>,
{
}
impl<T> StoredType for T where
T: brk_vec::StoredType + From<usize> + Div<usize, Output = Self> + Add<Output = Self>
{
}

View File

@@ -9,7 +9,6 @@ use super::{Indexes, StorableVec, indexes};
#[derive(Clone)]
pub struct Vecs {
// pub height_to_block_interval: StorableVec<Height, Timestamp>,
// pub height_to_fee: StorableVec<Txindex, Sats>,
// pub height_to_inputcount: StorableVec<Height, u32>,
// pub height_to_maxfeerate: StorableVec<Height, Feerate>,
@@ -22,24 +21,30 @@ pub struct Vecs {
// pub txindex_to_fee: StorableVec<Txindex, Sats>,
pub txindex_to_is_coinbase: StorableVec<Txindex, bool>,
// pub txindex_to_feerate: StorableVec<Txindex, Feerate>,
// pub txindex_to_inputs_count: StorableVec<Txindex, u32>,
pub txindex_to_inputs_count: StorableVec<Txindex, u32>,
// pub txindex_to_inputs_sum: StorableVec<Txindex, Sats>,
// pub txindex_to_outputs_count: StorableVec<Txindex, u32>,
pub txindex_to_outputs_count: StorableVec<Txindex, u32>,
// pub txindex_to_outputs_sum: StorableVec<Txindex, Sats>,
// pub txinindex_to_value: StorableVec<Txinindex, Sats>,
}
impl Vecs {
pub fn import(path: &Path, compressed: Compressed) -> color_eyre::Result<Self> {
pub fn forced_import(path: &Path, compressed: Compressed) -> color_eyre::Result<Self> {
fs::create_dir_all(path)?;
Ok(Self {
// height_to_block_interval: StorableVec::forced_import(&path.join("height_to_block_interval"), Version::from(1))?,
// height_to_fee: StorableVec::forced_import(&path.join("height_to_fee"), Version::from(1))?,
// height_to_inputcount: StorableVec::forced_import(&path.join("height_to_inputcount"), Version::from(1))?,
// height_to_input_count: StorableVec::forced_import(
// &path.join("height_to_input_count"),
// Version::from(1),
// )?,
// height_to_maxfeerate: StorableVec::forced_import(&path.join("height_to_maxfeerate"), Version::from(1))?,
// height_to_medianfeerate: StorableVec::forced_import(&path.join("height_to_medianfeerate"), Version::from(1))?,
// height_to_minfeerate: StorableVec::forced_import(&path.join("height_to_minfeerate"), Version::from(1))?,
// height_to_outputcount: StorableVec::forced_import(&path.join("height_to_outputcount"), Version::from(1))?,
// height_to_output_count: StorableVec::forced_import(
// &path.join("height_to_output_count"),
// Version::from(1),
// )?,
// height_to_subsidy: StorableVec::forced_import(&path.join("height_to_subsidy"), Version::from(1))?,
// height_to_totalfees: StorableVec::forced_import(&path.join("height_to_totalfees"), Version::from(1))?,
// height_to_txcount: StorableVec::forced_import(&path.join("height_to_txcount"), Version::from(1))?,
@@ -47,28 +52,35 @@ impl Vecs {
// &path.join("txindex_to_fee"),
// Version::from(1),
// )?,
txindex_to_is_coinbase: StorableVec::import(
txindex_to_is_coinbase: StorableVec::forced_import(
&path.join("txindex_to_is_coinbase"),
Version::from(1),
compressed,
)?,
// txindex_to_feerate: StorableVec::forced_import(&path.join("txindex_to_feerate"), Version::from(1))?,
// txindex_to_inputs_count: StorableVec::forced_import(
// &path.join("txindex_to_inputs_count"),
// Version::from(1),
// )?,
txindex_to_inputs_count: StorableVec::forced_import(
&path.join("txindex_to_inputs_count"),
Version::from(1),
compressed,
)?,
// txindex_to_inputs_sum: StorableVec::forced_import(
// &path.join("txindex_to_inputs_sum"),
// Version::from(1),
// )?,
// txindex_to_outputs_count: StorableVec::forced_import(
// &path.join("txindex_to_outputs_count"),
// Version::from(1),
// )?,
txindex_to_outputs_count: StorableVec::forced_import(
&path.join("txindex_to_outputs_count"),
Version::from(1),
compressed,
)?,
// txindex_to_outputs_sum: StorableVec::forced_import(
// &path.join("txindex_to_outputs_sum"),
// Version::from(1),
// )?,
// txinindex_to_value: StorableVec::forced_import(
// &path.join("txinindex_to_value"),
// Version::from(1),
// compressed,
// )?,
})
}
@@ -81,27 +93,43 @@ impl Vecs {
) -> color_eyre::Result<()> {
let indexer_vecs = indexer.mut_vecs();
// self.vecs.txindex_to_inputs_count.compute_count_from_indexes(
// starting_indexes.txindex,
// &mut indexer.vecs().txindex_to_first_txinindex,
// &mut self.vecs.txindex_to_last_txinindex,
// exit,
// )?;
self.txindex_to_inputs_count.compute_count_from_indexes(
starting_indexes.txindex,
indexer_vecs.txindex_to_first_txinindex.mut_vec(),
indexes.txindex_to_last_txinindex.mut_vec(),
exit,
)?;
// self.vecs.txindex_to_outputs_count.compute_count_from_indexes(
// starting_indexes.txindex,
// &mut indexer.vecs().txindex_to_first_txoutindex,
// &mut self.vecs.txindex_to_last_txoutindex,
// exit,
// )?;
self.txindex_to_outputs_count.compute_count_from_indexes(
starting_indexes.txindex,
indexer_vecs.txindex_to_first_txoutindex.mut_vec(),
indexes.txindex_to_last_txoutindex.mut_vec(),
exit,
)?;
self.txindex_to_is_coinbase.compute_is_first_ordered(
starting_indexes.txindex,
&mut indexer_vecs.txindex_to_height,
&mut indexer_vecs.height_to_first_txindex,
indexer_vecs.txindex_to_height.mut_vec(),
indexer_vecs.height_to_first_txindex.mut_vec(),
exit,
)?;
// self.txinindex_to_value.compute_transform(
// starting_indexes.txinindex,
// indexer_vecs.txinindex_to_txoutindex.mut_vec(),
// |(txinindex, txoutindex, slf, other)| {
// let value =
// if let Ok(Some(value)) = indexer_vecs.txoutindex_to_value.read(txoutindex) {
// *value
// } else {
// dbg!(txinindex, txoutindex, slf.len(), other.len());
// panic!()
// };
// (txinindex, value)
// },
// exit,
// )?;
// self.vecs.txindex_to_fee.compute_transform(
// &mut self.vecs.txindex_to_height,
// &mut indexer.vecs().height_to_first_txindex,
@@ -128,6 +156,10 @@ impl Vecs {
}
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStorableVec> {
vec![&*self.txindex_to_is_coinbase]
vec![
self.txindex_to_is_coinbase.any_vec(),
self.txindex_to_inputs_count.any_vec(),
self.txindex_to_outputs_count.any_vec(),
]
}
}

View File

@@ -0,0 +1,48 @@
use std::{fmt::Debug, ops::Add};
use serde::{Deserialize, Serialize};
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Default,
Serialize,
Deserialize,
FromBytes,
Immutable,
IntoBytes,
KnownLayout,
)]
pub struct Decadeindex(u8);
impl From<u8> for Decadeindex {
fn from(value: u8) -> Self {
Self(value)
}
}
impl From<usize> for Decadeindex {
fn from(value: usize) -> Self {
Self(value as u8)
}
}
impl From<Decadeindex> for usize {
fn from(value: Decadeindex) -> Self {
value.0 as usize
}
}
impl Add<usize> for Decadeindex {
type Output = Self;
fn add(self, rhs: usize) -> Self::Output {
Self::from(self.0 + rhs as u8)
}
}

View File

@@ -0,0 +1,48 @@
use std::{fmt::Debug, ops::Add};
use serde::{Deserialize, Serialize};
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Default,
Serialize,
Deserialize,
FromBytes,
Immutable,
IntoBytes,
KnownLayout,
)]
pub struct Difficultyepoch(u16);
impl From<u16> for Difficultyepoch {
fn from(value: u16) -> Self {
Self(value)
}
}
impl From<usize> for Difficultyepoch {
fn from(value: usize) -> Self {
Self(value as u16)
}
}
impl From<Difficultyepoch> for usize {
fn from(value: Difficultyepoch) -> Self {
value.0 as usize
}
}
impl Add<usize> for Difficultyepoch {
type Output = Self;
fn add(self, rhs: usize) -> Self::Output {
Self::from(self.0 + rhs as u16)
}
}

View File

@@ -0,0 +1,48 @@
use std::{fmt::Debug, ops::Add};
use serde::{Deserialize, Serialize};
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Default,
Serialize,
Deserialize,
FromBytes,
Immutable,
IntoBytes,
KnownLayout,
)]
pub struct Halvingepoch(u8);
impl From<u8> for Halvingepoch {
fn from(value: u8) -> Self {
Self(value)
}
}
impl From<usize> for Halvingepoch {
fn from(value: usize) -> Self {
Self(value as u8)
}
}
impl From<Halvingepoch> for usize {
fn from(value: Halvingepoch) -> Self {
value.0 as usize
}
}
impl Add<usize> for Halvingepoch {
type Output = Self;
fn add(self, rhs: usize) -> Self::Output {
Self::from(self.0 + rhs as u8)
}
}

View File

@@ -67,7 +67,7 @@ impl PartialEq<u64> for Height {
}
impl Add<Height> for Height {
type Output = Height;
type Output = Self;
fn add(self, rhs: Height) -> Self::Output {
Self::from(self.0 + rhs.0)
@@ -75,7 +75,7 @@ impl Add<Height> for Height {
}
impl Add<u32> for Height {
type Output = Height;
type Output = Self;
fn add(self, rhs: u32) -> Self::Output {
Self::from(self.0 + rhs)
@@ -83,7 +83,7 @@ impl Add<u32> for Height {
}
impl Add<usize> for Height {
type Output = Height;
type Output = Self;
fn add(self, rhs: usize) -> Self::Output {
Self::from(self.0 + rhs as u32)
@@ -91,8 +91,8 @@ impl Add<usize> for Height {
}
impl CheckedSub<Height> for Height {
fn checked_sub(self, rhs: Height) -> Option<Self> {
self.0.checked_sub(rhs.0).map(Height::from)
fn checked_sub(self, rhs: Self) -> Option<Self> {
self.0.checked_sub(rhs.0).map(Self::from)
}
}
@@ -115,14 +115,14 @@ impl AddAssign<usize> for Height {
}
impl Rem<Height> for Height {
type Output = Height;
type Output = Self;
fn rem(self, rhs: Height) -> Self::Output {
Self(self.0.rem(rhs.0))
}
}
impl Rem<usize> for Height {
type Output = Height;
type Output = Self;
fn rem(self, rhs: usize) -> Self::Output {
Self(self.0.rem(Height::from(rhs).0))
}

View File

@@ -9,10 +9,14 @@ mod cents;
mod compressed;
mod date;
mod dateindex;
mod decadeindex;
mod difficultyepoch;
mod dollars;
mod feerate;
mod halvingepoch;
mod height;
mod locktime;
mod monthindex;
mod ohlc;
mod sats;
mod timestamp;
@@ -24,7 +28,9 @@ mod txversion;
mod unit;
mod vin;
mod vout;
mod weekindex;
mod weight;
mod yearindex;
pub use addressbytes::*;
pub use addressindex::*;
@@ -37,10 +43,14 @@ pub use cents::*;
pub use compressed::*;
pub use date::*;
pub use dateindex::*;
pub use decadeindex::*;
pub use difficultyepoch::*;
pub use dollars::*;
pub use feerate::*;
pub use halvingepoch::*;
pub use height::*;
pub use locktime::*;
pub use monthindex::*;
pub use ohlc::*;
pub use sats::*;
pub use timestamp::*;
@@ -52,4 +62,6 @@ pub use txversion::*;
pub use unit::*;
pub use vin::*;
pub use vout::*;
pub use weekindex::*;
pub use weight::*;
pub use yearindex::*;

View File

@@ -0,0 +1,48 @@
use std::{fmt::Debug, ops::Add};
use serde::{Deserialize, Serialize};
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Default,
Serialize,
Deserialize,
FromBytes,
Immutable,
IntoBytes,
KnownLayout,
)]
pub struct Monthindex(u16);
impl From<u16> for Monthindex {
fn from(value: u16) -> Self {
Self(value)
}
}
impl From<usize> for Monthindex {
fn from(value: usize) -> Self {
Self(value as u16)
}
}
impl From<Monthindex> for usize {
fn from(value: Monthindex) -> Self {
value.0 as usize
}
}
impl Add<usize> for Monthindex {
type Output = Self;
fn add(self, rhs: usize) -> Self::Output {
Self::from(self.0 + rhs as u16)
}
}

View File

@@ -38,7 +38,7 @@ impl Sats {
}
impl Add for Sats {
type Output = Sats;
type Output = Self;
fn add(self, rhs: Sats) -> Self::Output {
Sats::from(self.0 + rhs.0)
}
@@ -51,8 +51,8 @@ impl AddAssign for Sats {
}
impl CheckedSub<Sats> for Sats {
fn checked_sub(self, rhs: Sats) -> Option<Self> {
self.0.checked_sub(rhs.0).map(Sats::from)
fn checked_sub(self, rhs: Self) -> Option<Self> {
self.0.checked_sub(rhs.0).map(Self::from)
}
}
@@ -63,21 +63,21 @@ impl SubAssign for Sats {
}
impl Mul<Sats> for Sats {
type Output = Sats;
type Output = Self;
fn mul(self, rhs: Sats) -> Self::Output {
Sats::from(self.0 * rhs.0)
}
}
impl Mul<u64> for Sats {
type Output = Sats;
type Output = Self;
fn mul(self, rhs: u64) -> Self::Output {
Sats::from(self.0 * rhs)
}
}
impl Mul<Height> for Sats {
type Output = Sats;
type Output = Self;
fn mul(self, rhs: Height) -> Self::Output {
Sats::from(self.0 * u64::from(rhs))
}

View File

@@ -1,14 +1,36 @@
use std::ops::{Add, Div};
use derive_deref::Deref;
use jiff::{civil::date, tz::TimeZone};
use serde::Serialize;
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
use crate::CheckedSub;
#[derive(
Debug, Deref, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, FromBytes, Immutable, IntoBytes, KnownLayout, Serialize,
Debug,
Deref,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
FromBytes,
Immutable,
IntoBytes,
KnownLayout,
Serialize,
)]
pub struct Timestamp(u32);
impl Timestamp {
pub const ZERO: Self = Self(0);
pub fn new(timestamp: u32) -> Self {
Self(timestamp)
}
pub fn floor_seconds(self) -> Self {
let t = jiff::Timestamp::from(self).to_zoned(TimeZone::UTC);
let d = jiff::civil::DateTime::from(t);
@@ -46,3 +68,29 @@ impl From<Timestamp> for bitcoin::locktime::absolute::Time {
bitcoin::locktime::absolute::Time::from_consensus(*value).unwrap()
}
}
impl From<usize> for Timestamp {
fn from(value: usize) -> Self {
Self(value as u32)
}
}
impl CheckedSub<Timestamp> for Timestamp {
fn checked_sub(self, rhs: Self) -> Option<Self> {
self.0.checked_sub(rhs.0).map(Self::from)
}
}
impl Div<usize> for Timestamp {
type Output = Self;
fn div(self, rhs: usize) -> Self::Output {
Self(self.0 / rhs as u32)
}
}
impl Add for Timestamp {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0 + rhs.0)
}
}

View File

@@ -61,8 +61,8 @@ impl AddAssign<Txinindex> for Txinindex {
}
impl CheckedSub<Txinindex> for Txinindex {
fn checked_sub(self, rhs: Txinindex) -> Option<Self> {
self.0.checked_sub(rhs.0).map(Txinindex::from)
fn checked_sub(self, rhs: Self) -> Option<Self> {
self.0.checked_sub(rhs.0).map(Self::from)
}
}

View File

@@ -67,8 +67,8 @@ impl AddAssign<Txoutindex> for Txoutindex {
}
impl CheckedSub<Txoutindex> for Txoutindex {
fn checked_sub(self, rhs: Txoutindex) -> Option<Self> {
self.0.checked_sub(rhs.0).map(Txoutindex::from)
fn checked_sub(self, rhs: Self) -> Option<Self> {
self.0.checked_sub(rhs.0).map(Self::from)
}
}

View File

@@ -0,0 +1,48 @@
use std::{fmt::Debug, ops::Add};
use serde::{Deserialize, Serialize};
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Default,
Serialize,
Deserialize,
FromBytes,
Immutable,
IntoBytes,
KnownLayout,
)]
pub struct Weekindex(u16);
impl From<u16> for Weekindex {
fn from(value: u16) -> Self {
Self(value)
}
}
impl From<usize> for Weekindex {
fn from(value: usize) -> Self {
Self(value as u16)
}
}
impl From<Weekindex> for usize {
fn from(value: Weekindex) -> Self {
value.0 as usize
}
}
impl Add<usize> for Weekindex {
type Output = Self;
fn add(self, rhs: usize) -> Self::Output {
Self::from(self.0 + rhs as u16)
}
}

View File

@@ -0,0 +1,48 @@
use std::{fmt::Debug, ops::Add};
use serde::{Deserialize, Serialize};
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Default,
Serialize,
Deserialize,
FromBytes,
Immutable,
IntoBytes,
KnownLayout,
)]
pub struct Yearindex(u8);
impl From<u8> for Yearindex {
fn from(value: u8) -> Self {
Self(value)
}
}
impl From<usize> for Yearindex {
fn from(value: usize) -> Self {
Self(value as u8)
}
}
impl From<Yearindex> for usize {
fn from(value: Yearindex) -> Self {
value.0 as usize
}
}
impl Add<usize> for Yearindex {
type Output = Self;
fn add(self, rhs: usize) -> Self::Output {
Self::from(self.0 + rhs as u8)
}
}

View File

@@ -11,8 +11,8 @@ fn main() -> color_eyre::Result<()> {
dbg!(fetcher.get_date(Date::new(2025, 1, 1))?);
dbg!(fetcher.get_height(
881_000_u32.into(),
1740683986.into(),
Some(1740683000.into())
1740683986_u32.into(),
Some(1740683000_u32.into())
)?);
Ok(())

View File

@@ -108,7 +108,7 @@ impl Fetcher {
let mut final_ohlc = OHLCCents::from(previous_ohlc.close);
let start = previous_timestamp.unwrap_or(Timestamp::from(0));
let start = previous_timestamp.unwrap_or(Timestamp::new(0));
let end = timestamp;
// Otherwise it's a re-org

View File

@@ -1,12 +1,9 @@
use std::path::Path;
use brk_core::{default_bitcoin_path, dot_brk_path};
use brk_core::default_bitcoin_path;
use brk_exit::Exit;
use brk_indexer::Indexer;
use brk_parser::{
Parser,
rpc::{self},
};
use brk_parser::{Parser, rpc};
fn main() -> color_eyre::Result<()> {
color_eyre::install()?;

View File

@@ -7,7 +7,7 @@ use std::{
collections::BTreeMap,
path::{Path, PathBuf},
str::FromStr,
thread::{self},
thread,
};
use brk_core::{
@@ -31,6 +31,7 @@ pub use stores::*;
pub use vecs::*;
const SNAPSHOT_BLOCK_RANGE: usize = 1000;
const COLLISIONS_CHECKED_UP_TO: u32 = 870_000;
#[derive(Clone)]
pub struct Indexer {
@@ -138,7 +139,7 @@ impl Indexer {
idxs.height = height;
// Used to check rapidhash collisions
let check_collisions = self.check_collisions && height > Height::new(640_000);
let check_collisions = self.check_collisions && height > Height::new(COLLISIONS_CHECKED_UP_TO);
let blockhash = BlockHash::from(blockhash);
let blockhash_prefix = BlockHashPrefix::from(&blockhash);

View File

@@ -1,11 +1,14 @@
use std::{
cmp::Ordering,
fmt::Debug,
io,
ops::{Deref, DerefMut},
path::{Path, PathBuf},
};
use brk_vec::{Compressed, StoredIndex, StoredType, Version};
use brk_vec::{
AnyStorableVec, Compressed, Error, MAX_CACHE_SIZE, MAX_PAGE_SIZE, Result, StoredIndex,
StoredType, Value, Version,
};
use super::Height;
@@ -20,7 +23,16 @@ where
I: StoredIndex,
T: StoredType,
{
pub fn import(path: &Path, version: Version, compressed: Compressed) -> brk_vec::Result<Self> {
pub const SIZE_OF_T: usize = size_of::<T>();
pub const PER_PAGE: usize = MAX_PAGE_SIZE / Self::SIZE_OF_T;
pub const PAGE_SIZE: usize = Self::PER_PAGE * Self::SIZE_OF_T;
pub const CACHE_LENGTH: usize = MAX_CACHE_SIZE / Self::PAGE_SIZE;
pub fn forced_import(
path: &Path,
version: Version,
compressed: Compressed,
) -> brk_vec::Result<Self> {
let mut vec = brk_vec::StorableVec::forced_import(path, version, compressed)?;
vec.enable_large_cache();
@@ -31,6 +43,76 @@ where
})
}
#[inline]
pub fn get(&self, index: I) -> Result<Option<Value<'_, T>>> {
self.get_(index.to_usize()?)
}
fn get_(&self, index: usize) -> Result<Option<Value<'_, T>>> {
match self.vec.index_to_pushed_index(index) {
Ok(index) => {
if let Some(index) = index {
return Ok(self.vec.pushed().get(index).map(|v| Value::Ref(v)));
}
}
Err(Error::IndexTooHigh) => return Ok(None),
Err(Error::IndexTooLow) => {}
Err(error) => return Err(error),
}
let large_cache_len = self.vec.large_cache_len();
if large_cache_len != 0 {
let page_index = Self::index_to_page_index(index);
let last_index = self.vec.stored_len() - 1;
let max_page_index = Self::index_to_page_index(last_index);
let min_page_index = (max_page_index + 1) - large_cache_len;
if page_index >= min_page_index {
let values = self
.vec
.pages()
.unwrap()
.get(page_index - min_page_index)
.ok_or(Error::MmapsVecIsTooSmall)?
.get_or_init(|| self.vec.decode_page(page_index).unwrap());
return Ok(values.get(index)?.map(|v| Value::Ref(v)));
}
}
Ok(self.vec.read_(index)?.map(|v| Value::Owned(v)))
}
pub fn iter_from<F>(&mut self, index: I, f: F) -> Result<()>
where
F: FnMut((I, &T)) -> Result<()>,
{
self.vec.iter_from(index, f)
}
#[inline(always)]
fn index_to_page_index(index: usize) -> usize {
index / Self::PER_PAGE
}
#[inline]
pub fn push_if_needed(&mut self, index: I, value: T) -> Result<()> {
match self.vec.len().cmp(&index.to_usize()?) {
Ordering::Greater => {
// dbg!(len, index, &self.pathbuf);
// panic!();
Ok(())
}
Ordering::Equal => {
self.vec.push(value);
Ok(())
}
Ordering::Less => {
dbg!(index, value);
Err(Error::IndexTooHigh)
}
}
}
pub fn truncate_if_needed(&mut self, index: I, height: Height) -> brk_vec::Result<()> {
if self.height.is_none_or(|self_height| self_height != height) {
height.write(&self.path_height())?;
@@ -39,6 +121,36 @@ where
Ok(())
}
pub fn flush(&mut self, height: Height) -> io::Result<()> {
height.write(&self.path_height())?;
self.vec.flush()
}
pub fn vec(&self) -> &brk_vec::StorableVec<I, T> {
&self.vec
}
pub fn mut_vec(&mut self) -> &mut brk_vec::StorableVec<I, T> {
&mut self.vec
}
pub fn any_vec(&self) -> &dyn AnyStorableVec {
&self.vec
}
pub fn len(&self) -> usize {
self.vec.len()
}
pub fn is_empty(&self) -> bool {
self.vec.is_empty()
}
#[inline]
pub fn hasnt(&self, index: I) -> Result<bool> {
self.vec.has(index).map(|b| !b)
}
pub fn height(&self) -> brk_core::Result<Height> {
Height::try_from(self.path_height().as_path())
}
@@ -48,24 +160,19 @@ where
fn path_height_(path: &Path) -> PathBuf {
path.join("height")
}
pub fn flush(&mut self, height: Height) -> io::Result<()> {
height.write(&self.path_height())?;
self.vec.flush()
}
}
impl<I, T> Deref for StorableVec<I, T> {
type Target = brk_vec::StorableVec<I, T>;
fn deref(&self) -> &Self::Target {
&self.vec
}
}
impl<I, T> DerefMut for StorableVec<I, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.vec
}
}
// impl<I, T> Deref for StorableVec<I, T> {
// type Target = brk_vec::StorableVec<I, T>;
// fn deref(&self) -> &Self::Target {
// &self.vec
// }
// }
// impl<I, T> DerefMut for StorableVec<I, T> {
// fn deref_mut(&mut self) -> &mut Self::Target {
// &mut self.vec
// }
// }
impl<I, T> Clone for StorableVec<I, T>
where
I: StoredIndex,

View File

@@ -58,6 +58,7 @@ pub struct Vecs {
pub txindex_to_total_size: StorableVec<Txindex, usize>,
pub txindex_to_is_explicitly_rbf: StorableVec<Txindex, bool>,
pub txindex_to_txversion: StorableVec<Txindex, TxVersion>,
/// If txoutindex == Txoutindex MAX then is it's coinbase
pub txinindex_to_txoutindex: StorableVec<Txinindex, Txoutindex>,
pub txoutindex_to_addressindex: StorableVec<Txoutindex, Addressindex>,
pub txoutindex_to_value: StorableVec<Txoutindex, Sats>,
@@ -68,217 +69,217 @@ impl Vecs {
fs::create_dir_all(path)?;
Ok(Self {
addressindex_to_addresstype: StorableVec::import(
addressindex_to_addresstype: StorableVec::forced_import(
&path.join("addressindex_to_addresstype"),
Version::from(1),
compressed,
)?,
addressindex_to_addresstypeindex: StorableVec::import(
addressindex_to_addresstypeindex: StorableVec::forced_import(
&path.join("addressindex_to_addresstypeindex"),
Version::from(1),
compressed,
)?,
addressindex_to_height: StorableVec::import(
addressindex_to_height: StorableVec::forced_import(
&path.join("addressindex_to_height"),
Version::from(1),
compressed,
)?,
height_to_blockhash: StorableVec::import(
height_to_blockhash: StorableVec::forced_import(
&path.join("height_to_blockhash"),
Version::from(1),
Compressed::NO,
)?,
height_to_difficulty: StorableVec::import(
height_to_difficulty: StorableVec::forced_import(
&path.join("height_to_difficulty"),
Version::from(1),
compressed,
)?,
height_to_first_addressindex: StorableVec::import(
height_to_first_addressindex: StorableVec::forced_import(
&path.join("height_to_first_addressindex"),
Version::from(1),
compressed,
)?,
height_to_first_emptyindex: StorableVec::import(
height_to_first_emptyindex: StorableVec::forced_import(
&path.join("height_to_first_emptyindex"),
Version::from(1),
compressed,
)?,
height_to_first_multisigindex: StorableVec::import(
height_to_first_multisigindex: StorableVec::forced_import(
&path.join("height_to_first_multisigindex"),
Version::from(1),
compressed,
)?,
height_to_first_opreturnindex: StorableVec::import(
height_to_first_opreturnindex: StorableVec::forced_import(
&path.join("height_to_first_opreturnindex"),
Version::from(1),
compressed,
)?,
height_to_first_pushonlyindex: StorableVec::import(
height_to_first_pushonlyindex: StorableVec::forced_import(
&path.join("height_to_first_pushonlyindex"),
Version::from(1),
compressed,
)?,
height_to_first_txindex: StorableVec::import(
height_to_first_txindex: StorableVec::forced_import(
&path.join("height_to_first_txindex"),
Version::from(1),
compressed,
)?,
height_to_first_txinindex: StorableVec::import(
height_to_first_txinindex: StorableVec::forced_import(
&path.join("height_to_first_txinindex"),
Version::from(1),
compressed,
)?,
height_to_first_txoutindex: StorableVec::import(
height_to_first_txoutindex: StorableVec::forced_import(
&path.join("height_to_first_txoutindex"),
Version::from(1),
compressed,
)?,
height_to_first_unknownindex: StorableVec::import(
height_to_first_unknownindex: StorableVec::forced_import(
&path.join("height_to_first_unkownindex"),
Version::from(1),
compressed,
)?,
height_to_first_p2pk33index: StorableVec::import(
height_to_first_p2pk33index: StorableVec::forced_import(
&path.join("height_to_first_p2pk33index"),
Version::from(1),
compressed,
)?,
height_to_first_p2pk65index: StorableVec::import(
height_to_first_p2pk65index: StorableVec::forced_import(
&path.join("height_to_first_p2pk65index"),
Version::from(1),
compressed,
)?,
height_to_first_p2pkhindex: StorableVec::import(
height_to_first_p2pkhindex: StorableVec::forced_import(
&path.join("height_to_first_p2pkhindex"),
Version::from(1),
compressed,
)?,
height_to_first_p2shindex: StorableVec::import(
height_to_first_p2shindex: StorableVec::forced_import(
&path.join("height_to_first_p2shindex"),
Version::from(1),
compressed,
)?,
height_to_first_p2trindex: StorableVec::import(
height_to_first_p2trindex: StorableVec::forced_import(
&path.join("height_to_first_p2trindex"),
Version::from(1),
compressed,
)?,
height_to_first_p2wpkhindex: StorableVec::import(
height_to_first_p2wpkhindex: StorableVec::forced_import(
&path.join("height_to_first_p2wpkhindex"),
Version::from(1),
compressed,
)?,
height_to_first_p2wshindex: StorableVec::import(
height_to_first_p2wshindex: StorableVec::forced_import(
&path.join("height_to_first_p2wshindex"),
Version::from(1),
compressed,
)?,
height_to_size: StorableVec::import(
height_to_size: StorableVec::forced_import(
&path.join("height_to_size"),
Version::from(1),
compressed,
)?,
height_to_timestamp: StorableVec::import(
height_to_timestamp: StorableVec::forced_import(
&path.join("height_to_timestamp"),
Version::from(1),
compressed,
)?,
height_to_weight: StorableVec::import(
height_to_weight: StorableVec::forced_import(
&path.join("height_to_weight"),
Version::from(1),
compressed,
)?,
p2pk33index_to_p2pk33addressbytes: StorableVec::import(
p2pk33index_to_p2pk33addressbytes: StorableVec::forced_import(
&path.join("p2pk33index_to_p2pk33addressbytes"),
Version::from(1),
Compressed::NO,
)?,
p2pk65index_to_p2pk65addressbytes: StorableVec::import(
p2pk65index_to_p2pk65addressbytes: StorableVec::forced_import(
&path.join("p2pk65index_to_p2pk65addressbytes"),
Version::from(1),
Compressed::NO,
)?,
p2pkhindex_to_p2pkhaddressbytes: StorableVec::import(
p2pkhindex_to_p2pkhaddressbytes: StorableVec::forced_import(
&path.join("p2pkhindex_to_p2pkhaddressbytes"),
Version::from(1),
Compressed::NO,
)?,
p2shindex_to_p2shaddressbytes: StorableVec::import(
p2shindex_to_p2shaddressbytes: StorableVec::forced_import(
&path.join("p2shindex_to_p2shaddressbytes"),
Version::from(1),
Compressed::NO,
)?,
p2trindex_to_p2traddressbytes: StorableVec::import(
p2trindex_to_p2traddressbytes: StorableVec::forced_import(
&path.join("p2trindex_to_p2traddressbytes"),
Version::from(1),
Compressed::NO,
)?,
p2wpkhindex_to_p2wpkhaddressbytes: StorableVec::import(
p2wpkhindex_to_p2wpkhaddressbytes: StorableVec::forced_import(
&path.join("p2wpkhindex_to_p2wpkhaddressbytes"),
Version::from(1),
Compressed::NO,
)?,
p2wshindex_to_p2wshaddressbytes: StorableVec::import(
p2wshindex_to_p2wshaddressbytes: StorableVec::forced_import(
&path.join("p2wshindex_to_p2wshaddressbytes"),
Version::from(1),
Compressed::NO,
)?,
txindex_to_first_txinindex: StorableVec::import(
txindex_to_first_txinindex: StorableVec::forced_import(
&path.join("txindex_to_first_txinindex"),
Version::from(1),
compressed,
)?,
txindex_to_first_txoutindex: StorableVec::import(
txindex_to_first_txoutindex: StorableVec::forced_import(
&path.join("txindex_to_first_txoutindex"),
Version::from(1),
Compressed::NO,
)?,
txindex_to_height: StorableVec::import(
txindex_to_height: StorableVec::forced_import(
&path.join("txindex_to_height"),
Version::from(1),
compressed,
)?,
txindex_to_locktime: StorableVec::import(
txindex_to_locktime: StorableVec::forced_import(
&path.join("txindex_to_locktime"),
Version::from(1),
compressed,
)?,
txindex_to_txid: StorableVec::import(
txindex_to_txid: StorableVec::forced_import(
&path.join("txindex_to_txid"),
Version::from(1),
Compressed::NO,
)?,
txindex_to_base_size: StorableVec::import(
txindex_to_base_size: StorableVec::forced_import(
&path.join("txindex_to_base_size"),
Version::from(1),
compressed,
)?,
txindex_to_total_size: StorableVec::import(
txindex_to_total_size: StorableVec::forced_import(
&path.join("txindex_to_total_size"),
Version::from(1),
compressed,
)?,
txindex_to_is_explicitly_rbf: StorableVec::import(
txindex_to_is_explicitly_rbf: StorableVec::forced_import(
&path.join("txindex_to_is_explicitly_rbf"),
Version::from(1),
compressed,
)?,
txindex_to_txversion: StorableVec::import(
txindex_to_txversion: StorableVec::forced_import(
&path.join("txindex_to_txversion"),
Version::from(1),
compressed,
)?,
txinindex_to_txoutindex: StorableVec::import(
txinindex_to_txoutindex: StorableVec::forced_import(
&path.join("txinindex_to_txoutindex"),
Version::from(1),
compressed,
)?,
txoutindex_to_addressindex: StorableVec::import(
txoutindex_to_addressindex: StorableVec::forced_import(
&path.join("txoutindex_to_addressindex"),
Version::from(1),
compressed,
)?,
txoutindex_to_value: StorableVec::import(
txoutindex_to_value: StorableVec::forced_import(
&path.join("txoutindex_to_value"),
Version::from(1),
compressed,
@@ -496,49 +497,49 @@ impl Vecs {
pub fn as_any_vecs(&self) -> Vec<&dyn AnyStorableVec> {
vec![
&*self.addressindex_to_addresstype,
&*self.addressindex_to_addresstypeindex,
&*self.addressindex_to_height,
&*self.height_to_blockhash,
&*self.height_to_difficulty,
&*self.height_to_first_addressindex,
&*self.height_to_first_emptyindex,
&*self.height_to_first_multisigindex,
&*self.height_to_first_opreturnindex,
&*self.height_to_first_pushonlyindex,
&*self.height_to_first_txindex,
&*self.height_to_first_txinindex,
&*self.height_to_first_txoutindex,
&*self.height_to_first_unknownindex,
&*self.height_to_first_p2pk33index,
&*self.height_to_first_p2pk65index,
&*self.height_to_first_p2pkhindex,
&*self.height_to_first_p2shindex,
&*self.height_to_first_p2trindex,
&*self.height_to_first_p2wpkhindex,
&*self.height_to_first_p2wshindex,
&*self.height_to_size,
&*self.height_to_timestamp,
&*self.height_to_weight,
&*self.p2pk33index_to_p2pk33addressbytes,
&*self.p2pk65index_to_p2pk65addressbytes,
&*self.p2pkhindex_to_p2pkhaddressbytes,
&*self.p2shindex_to_p2shaddressbytes,
&*self.p2trindex_to_p2traddressbytes,
&*self.p2wpkhindex_to_p2wpkhaddressbytes,
&*self.p2wshindex_to_p2wshaddressbytes,
&*self.txindex_to_first_txinindex,
&*self.txindex_to_first_txoutindex,
&*self.txindex_to_height,
&*self.txindex_to_locktime,
&*self.txindex_to_txid,
&*self.txindex_to_base_size,
&*self.txindex_to_total_size,
&*self.txindex_to_is_explicitly_rbf,
&*self.txindex_to_txversion,
&*self.txinindex_to_txoutindex,
&*self.txoutindex_to_addressindex,
&*self.txoutindex_to_value,
self.addressindex_to_addresstype.any_vec(),
self.addressindex_to_addresstypeindex.any_vec(),
self.addressindex_to_height.any_vec(),
self.height_to_blockhash.any_vec(),
self.height_to_difficulty.any_vec(),
self.height_to_first_addressindex.any_vec(),
self.height_to_first_emptyindex.any_vec(),
self.height_to_first_multisigindex.any_vec(),
self.height_to_first_opreturnindex.any_vec(),
self.height_to_first_pushonlyindex.any_vec(),
self.height_to_first_txindex.any_vec(),
self.height_to_first_txinindex.any_vec(),
self.height_to_first_txoutindex.any_vec(),
self.height_to_first_unknownindex.any_vec(),
self.height_to_first_p2pk33index.any_vec(),
self.height_to_first_p2pk65index.any_vec(),
self.height_to_first_p2pkhindex.any_vec(),
self.height_to_first_p2shindex.any_vec(),
self.height_to_first_p2trindex.any_vec(),
self.height_to_first_p2wpkhindex.any_vec(),
self.height_to_first_p2wshindex.any_vec(),
self.height_to_size.any_vec(),
self.height_to_timestamp.any_vec(),
self.height_to_weight.any_vec(),
self.p2pk33index_to_p2pk33addressbytes.any_vec(),
self.p2pk65index_to_p2pk65addressbytes.any_vec(),
self.p2pkhindex_to_p2pkhaddressbytes.any_vec(),
self.p2shindex_to_p2shaddressbytes.any_vec(),
self.p2trindex_to_p2traddressbytes.any_vec(),
self.p2wpkhindex_to_p2wpkhaddressbytes.any_vec(),
self.p2wshindex_to_p2wshaddressbytes.any_vec(),
self.txindex_to_first_txinindex.any_vec(),
self.txindex_to_first_txoutindex.any_vec(),
self.txindex_to_height.any_vec(),
self.txindex_to_locktime.any_vec(),
self.txindex_to_txid.any_vec(),
self.txindex_to_base_size.any_vec(),
self.txindex_to_total_size.any_vec(),
self.txindex_to_is_explicitly_rbf.any_vec(),
self.txindex_to_txversion.any_vec(),
self.txinindex_to_txoutindex.any_vec(),
self.txoutindex_to_addressindex.any_vec(),
self.txoutindex_to_value.any_vec(),
]
}

View File

@@ -3,14 +3,7 @@
#![doc = include_str!("../examples/main.rs")]
#![doc = "```"]
use std::{
cmp::Ordering,
collections::BTreeMap,
fs::{self},
ops::ControlFlow,
path::PathBuf,
thread,
};
use std::{cmp::Ordering, collections::BTreeMap, fs, ops::ControlFlow, path::PathBuf, thread};
use bitcoin::{Block, BlockHash};
use bitcoincore_rpc::RpcApi;

View File

@@ -21,8 +21,8 @@ color-eyre = { workspace = true }
jiff = { workspace = true }
log = { workspace = true }
minreq = { workspace = true }
oxc = { version = "0.58.1", features = ["codegen", "minifier"] }
oxc = { version = "0.60.0", features = ["codegen", "minifier"] }
serde = { workspace = true }
tokio = { version = "1.44.1", features = ["full"] }
tower-http = { version = "0.6.2", features = ["compression-full"] }
zip = "2.2.3"
zip = "2.4.1"

View File

@@ -1,8 +1,4 @@
use std::{
fs::{self},
path::Path,
time::Instant,
};
use std::{fs, path::Path, time::Instant};
use axum::{
body::Body,

View File

@@ -24,12 +24,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
StorableVec::forced_import(Path::new("./vec"), Version::from(1), Compressed::YES)?;
dbg!(vec.get(0)?);
dbg!(vec.read(0)?);
dbg!(vec.read(1)?);
dbg!(vec.read(2)?);
dbg!(vec.read(20)?);
dbg!(vec.get(0)?);
dbg!(vec.get(1)?);
dbg!(vec.get(2)?);
dbg!(vec.get(20)?);
dbg!(vec.read(0)?);
dbg!(vec.get(20)?);
dbg!(vec.get(0)?);
vec.push(21);
vec.push(22);

View File

@@ -4,7 +4,6 @@
#![doc = "```"]
use std::{
cmp::Ordering,
fs::{self, File, OpenOptions},
io::{self, Read, Seek, SeekFrom, Write},
marker::PhantomData,
@@ -29,7 +28,7 @@ pub use traits::*;
const ONE_KIB: usize = 1024;
pub const MAX_PAGE_SIZE: usize = 16 * ONE_KIB;
const ONE_MIB: usize = ONE_KIB * ONE_KIB;
const MAX_CACHE_SIZE: usize = 100 * ONE_MIB;
pub const MAX_CACHE_SIZE: usize = 100 * ONE_MIB;
#[allow(private_interfaces)]
#[derive(Debug)]
@@ -83,49 +82,11 @@ where
}
#[inline]
pub fn get(&self, index: I) -> Result<Option<Value<'_, T>>> {
self.get_(Self::i_to_usize(index)?)
}
fn get_(&self, index: usize) -> Result<Option<Value<'_, T>>> {
match self.index_to_pushed_index(index) {
Ok(index) => {
if let Some(index) = index {
return Ok(self.pushed().get(index).map(|v| Value::Ref(v)));
}
}
Err(Error::IndexTooHigh) => return Ok(None),
Err(Error::IndexTooLow) => {}
Err(error) => return Err(error),
}
let large_cache_len = self.large_cache_len();
if large_cache_len != 0 {
let page_index = Self::index_to_page_index(index);
let last_index = self.stored_len() - 1;
let max_page_index = Self::index_to_page_index(last_index);
let min_page_index = (max_page_index + 1) - large_cache_len;
if page_index >= min_page_index {
let values = self
.pages()
.unwrap()
.get(page_index - min_page_index)
.ok_or(Error::MmapsVecIsTooSmall)?
.get_or_init(|| self.decode_page(page_index).unwrap());
return Ok(values.get(index)?.map(|v| Value::Ref(v)));
}
}
Ok(self.open_then_read_(index)?.map(|v| Value::Owned(v)))
}
#[inline]
pub fn read(&mut self, index: I) -> Result<Option<&T>> {
self.read_(Self::i_to_usize(index)?)
pub fn get(&mut self, index: I) -> Result<Option<&T>> {
self.get_(index.to_usize()?)
}
#[inline]
pub fn read_(&mut self, index: usize) -> Result<Option<&T>> {
pub fn get_(&mut self, index: usize) -> Result<Option<&T>> {
match self.index_to_pushed_index(index) {
Ok(index) => {
if let Some(index) = index {
@@ -147,18 +108,18 @@ where
self.page().unwrap().1.get(index)
}
pub fn read_last(&mut self) -> Result<Option<&T>> {
pub fn get_last(&mut self) -> Result<Option<&T>> {
let len = self.len();
if len == 0 {
return Ok(None);
}
self.read_(len - 1)
self.get_(len - 1)
}
pub fn open_then_read(&self, index: I) -> Result<Option<T>> {
self.open_then_read_(Self::i_to_usize(index)?)
pub fn read(&self, index: I) -> Result<Option<T>> {
self.read_(index.to_usize()?)
}
fn open_then_read_(&self, index: usize) -> Result<Option<T>> {
pub fn read_(&self, index: usize) -> Result<Option<T>> {
Ok(match self {
Self::Raw { .. } => {
let mut file = self.open_file()?;
@@ -193,7 +154,7 @@ where
let stored_len = I::from(self.stored_len());
while index < stored_len {
let v = self.read(index)?.unwrap();
let v = self.get(index)?.unwrap();
f((index, v))?;
index = index + 1;
}
@@ -212,7 +173,7 @@ where
let stored_len = I::from(self.stored_len());
while index < stored_len {
let v = self.read(index)?.unwrap().clone();
let v = self.get(index)?.unwrap().clone();
f((index, v, self))?;
index = index + 1;
}
@@ -265,7 +226,7 @@ where
Ok(values)
}
fn decode_page(&self, page_index: usize) -> Result<Values<T>> {
pub fn decode_page(&self, page_index: usize) -> Result<Values<T>> {
Self::decode_page_(
self.stored_len(),
page_index,
@@ -327,26 +288,7 @@ where
#[inline]
pub fn push(&mut self, value: T) {
self.mut_pushed().push(value)
}
#[inline]
pub fn push_if_needed(&mut self, index: I, value: T) -> Result<()> {
match self.len().cmp(&Self::i_to_usize(index)?) {
Ordering::Greater => {
// dbg!(len, index, &self.pathbuf);
// panic!();
Ok(())
}
Ordering::Equal => {
self.mut_pushed().push(value);
Ok(())
}
Ordering::Less => {
dbg!(index, value);
Err(Error::IndexTooHigh)
}
}
self.mut_base().pushed.push(value)
}
pub fn flush(&mut self) -> io::Result<()> {
@@ -464,7 +406,7 @@ where
}
pub fn truncate_if_needed(&mut self, index: I) -> Result<()> {
let index = Self::i_to_usize(index)?;
let index = index.to_usize()?;
if index >= self.stored_len() {
return Ok(());
@@ -580,7 +522,7 @@ where
}
}
fn large_cache_len(&self) -> usize {
pub fn large_cache_len(&self) -> usize {
self.pages().map_or(0, |v| v.len())
}
@@ -601,12 +543,7 @@ where
}
#[inline]
pub fn i_to_usize(index: I) -> Result<usize> {
index.try_into().map_err(|_| Error::FailedKeyTryIntoUsize)
}
#[inline]
fn index_to_pushed_index(&self, index: usize) -> Result<Option<usize>> {
pub fn index_to_pushed_index(&self, index: usize) -> Result<Option<usize>> {
let stored_len = self.stored_len();
if index >= stored_len {
@@ -662,7 +599,7 @@ where
}
#[inline]
fn pages(&self) -> Option<&Vec<OnceLock<Values<T>>>> {
pub fn pages(&self) -> Option<&Vec<OnceLock<Values<T>>>> {
self.base().pages.as_ref()
}
@@ -682,7 +619,7 @@ where
#[inline]
pub fn has(&self, index: I) -> Result<bool> {
Ok(self.has_(Self::i_to_usize(index)?))
Ok(self.has_(index.to_usize()?))
}
#[inline]
fn has_(&self, index: usize) -> bool {
@@ -690,20 +627,10 @@ where
}
#[inline]
pub fn hasnt(&self, index: I) -> Result<bool> {
self.has(index).map(|b| !b)
}
#[inline]
fn pushed(&self) -> &Vec<T> {
pub fn pushed(&self) -> &Vec<T> {
&self.base().pushed
}
#[inline]
fn mut_pushed(&mut self) -> &mut Vec<T> {
&mut self.mut_base().pushed
}
#[inline]
pub fn pushed_len(&self) -> usize {
self.pushed().len()
@@ -715,7 +642,7 @@ where
}
#[inline]
fn stored_len(&self) -> usize {
pub fn stored_len(&self) -> usize {
*self.base().stored_len
}

View File

@@ -1,9 +1,4 @@
use std::{
fs,
io::{self},
ops::Deref,
path::Path,
};
use std::{fs, io, ops::Deref, path::Path};
use crate::{Error, Result};

View File

@@ -9,7 +9,9 @@ use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
use crate::{Error, Result};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, FromBytes, IntoBytes, Immutable, KnownLayout)]
#[derive(
Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, FromBytes, IntoBytes, Immutable, KnownLayout,
)]
pub struct Version(u32);
impl Version {
@@ -54,7 +56,7 @@ impl TryFrom<&Path> for Version {
}
impl Add<Version> for Version {
type Output = Version;
type Output = Self;
fn add(self, rhs: Version) -> Self::Output {
Self(self.0 + rhs.0)
}

View File

@@ -1,5 +1,7 @@
use std::{fmt::Debug, ops::Add};
use crate::{Error, Result};
pub trait StoredIndex
where
Self: Debug
@@ -16,8 +18,10 @@ where
+ Send
+ Sync,
{
fn to_usize(self) -> Result<usize>;
}
impl<I> StoredIndex for I where
impl<I> StoredIndex for I
where
I: Debug
+ Default
+ Copy
@@ -30,6 +34,10 @@ impl<I> StoredIndex for I where
+ From<usize>
+ Add<usize, Output = Self>
+ Send
+ Sync
+ Sync,
{
#[inline(always)]
fn to_usize(self) -> Result<usize> {
self.try_into().map_err(|_| Error::FailedKeyTryIntoUsize)
}
}