mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-14 12:38:13 -07:00
indexer: rm canopy+sanakirja + init rollback; svec: added truncate
This commit is contained in:
@@ -1,50 +0,0 @@
|
||||
use std::{
|
||||
ops::{Deref, DerefMut},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use canopydb::{Database as CanopyDatabase, DbOptions, Error, WriteTransaction};
|
||||
|
||||
use super::Environment;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Database {
|
||||
db: CanopyDatabase,
|
||||
// pub wtx: WriteTransaction,
|
||||
}
|
||||
impl Deref for Database {
|
||||
type Target = CanopyDatabase;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.db
|
||||
}
|
||||
}
|
||||
impl DerefMut for Database {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.db
|
||||
}
|
||||
}
|
||||
|
||||
impl Database {
|
||||
pub fn new(environment: &Environment, name: &str) -> color_eyre::Result<Self> {
|
||||
let mut options = DbOptions::default();
|
||||
options.use_wal = false;
|
||||
options.checkpoint_interval = Duration::from_secs(u64::MAX);
|
||||
options.checkpoint_target_size = usize::MAX;
|
||||
options.throttle_memory_limit = usize::MAX;
|
||||
options.stall_memory_limit = usize::MAX;
|
||||
options.write_txn_memory_limit = usize::MAX;
|
||||
|
||||
let db = environment.get_or_create_database_with(name, options)?;
|
||||
|
||||
Ok(Self {
|
||||
// wtx: db.begin_write()?,
|
||||
db,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn flush(&mut self) -> Result<(), Error> {
|
||||
// drop(blockhash_prefix_to_height_tree);
|
||||
// blockhash_prefix_to_height_tx_opt.take().map(|tx| tx.commit());
|
||||
self.checkpoint()
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
use std::path::Path;
|
||||
|
||||
use canopydb::{EnvOptions, Environment as CanopyEnvironment};
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
|
||||
#[derive(Debug, Deref, DerefMut)]
|
||||
pub struct Environment(CanopyEnvironment);
|
||||
|
||||
impl Environment {
|
||||
pub fn new(path: &Path) -> color_eyre::Result<Self> {
|
||||
let mut options = EnvOptions::new(path);
|
||||
// options.use_mmap = true;
|
||||
options.disable_fsync = true;
|
||||
options.wal_new_file_on_checkpoint = false;
|
||||
options.wal_background_sync_interval = None;
|
||||
options.wal_write_batch_memory_limit = usize::MAX;
|
||||
|
||||
Ok(Self(CanopyEnvironment::with_options(options)?))
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
mod database;
|
||||
mod environment;
|
||||
// mod transaction;
|
||||
mod tree;
|
||||
|
||||
pub use database::*;
|
||||
pub use environment::*;
|
||||
// pub use transaction::*;
|
||||
pub use tree::*;
|
||||
@@ -1,19 +0,0 @@
|
||||
use canopydb::{Tree as CanopyTree, TreeOptions, WriteTransaction};
|
||||
|
||||
use super::{Database, Tree};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Transaction<'a, K, V> {
|
||||
tx: WriteTransaction,
|
||||
tree: Tree<'a, K, V>,
|
||||
}
|
||||
|
||||
impl<'a, K, V> Transaction<'a, K, V> {
|
||||
pub fn new(db: &Database) -> color_eyre::Result<Self> {
|
||||
let tx = db.begin_write()?;
|
||||
|
||||
let tree = Tree::new(&tx)?;
|
||||
|
||||
Ok(Self { tx, tree })
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
use std::{
|
||||
fmt::Debug,
|
||||
marker::PhantomData,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
|
||||
use canopydb::{Tree as CanopyTree, TreeOptions, WriteTransaction};
|
||||
use color_eyre::eyre::eyre;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Tree<'a, K, V> {
|
||||
tree: CanopyTree<'a>,
|
||||
k: PhantomData<K>,
|
||||
v: PhantomData<V>,
|
||||
}
|
||||
impl<'a, K, V> Deref for Tree<'a, K, V> {
|
||||
type Target = CanopyTree<'a>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.tree
|
||||
}
|
||||
}
|
||||
impl<'a, K, V> DerefMut for Tree<'a, K, V> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.tree
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> Tree<'a, K, V>
|
||||
where
|
||||
K: Debug + Sized,
|
||||
V: Debug + Sized + Clone + Copy,
|
||||
{
|
||||
const SIZE_OF_K: usize = size_of::<K>();
|
||||
const SIZE_OF_V: usize = size_of::<V>();
|
||||
|
||||
pub fn new(tx: &'a WriteTransaction) -> color_eyre::Result<Self> {
|
||||
let mut options = TreeOptions::new();
|
||||
options.compress_overflow_values = None;
|
||||
options.fixed_key_len = size_of::<K>() as i8;
|
||||
options.fixed_value_len = size_of::<V>() as i8;
|
||||
|
||||
Ok(Self {
|
||||
tree: tx.get_or_create_tree_with(b"tree", options)?,
|
||||
k: PhantomData,
|
||||
v: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get(&self, key: &K) -> color_eyre::Result<Option<V>> {
|
||||
let slice = self.tree.get(Self::key_as_slice(key))?;
|
||||
|
||||
if slice.is_none() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let slice = slice.unwrap();
|
||||
|
||||
let (prefix, shorts, suffix) = unsafe { slice.align_to::<V>() };
|
||||
|
||||
if !prefix.is_empty() || shorts.len() != 1 || !suffix.is_empty() {
|
||||
dbg!(&key, &prefix, &shorts, &suffix);
|
||||
return Err(eyre!("align_to issue"));
|
||||
}
|
||||
|
||||
Ok(Some(shorts[0]))
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, key: &K, value: &V) -> Result<(), canopydb::Error> {
|
||||
self.tree
|
||||
.insert(Self::key_as_slice(key), Self::value_as_slice(value))
|
||||
}
|
||||
|
||||
fn key_as_slice(key: &K) -> &[u8] {
|
||||
let data: *const K = key;
|
||||
let data: *const u8 = data as *const u8;
|
||||
unsafe { std::slice::from_raw_parts(data, Self::SIZE_OF_K) }
|
||||
}
|
||||
|
||||
fn value_as_slice(value: &V) -> &[u8] {
|
||||
let data: *const V = value;
|
||||
let data: *const u8 = data as *const u8;
|
||||
unsafe { std::slice::from_raw_parts(data, Self::SIZE_OF_V) }
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
use std::{
|
||||
fs, io,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use snkrj::UnitDatabase;
|
||||
|
||||
use super::{Height, Version};
|
||||
|
||||
pub struct StoreMeta {
|
||||
pathbuf: PathBuf,
|
||||
version: Version,
|
||||
height: Option<Height>,
|
||||
pub len: usize,
|
||||
}
|
||||
|
||||
impl StoreMeta {
|
||||
pub fn checked_open(path: &Path, version: Version) -> Result<Self, snkrj::Error> {
|
||||
fs::create_dir_all(path)?;
|
||||
|
||||
let is_same_version =
|
||||
Version::try_from(Self::path_version_(path).as_path()).is_ok_and(|prev_version| version == prev_version);
|
||||
|
||||
if !is_same_version {
|
||||
fs::remove_dir_all(path)?;
|
||||
fs::create_dir(path)?;
|
||||
}
|
||||
|
||||
let this = Self {
|
||||
pathbuf: path.to_owned(),
|
||||
version,
|
||||
height: Height::try_from(Self::path_height_(path).as_path()).ok(),
|
||||
len: UnitDatabase::read_length_(path),
|
||||
};
|
||||
|
||||
this.version.write(&this.path_version())?;
|
||||
|
||||
Ok(this)
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn len(&self) -> usize {
|
||||
self.len
|
||||
}
|
||||
|
||||
pub fn export(mut self, height: Height) -> Result<(), io::Error> {
|
||||
self.height = Some(height);
|
||||
height.write(&self.path_height())?;
|
||||
UnitDatabase::write_length_(&self.pathbuf, self.len)
|
||||
}
|
||||
|
||||
pub fn path_parts(&self) -> PathBuf {
|
||||
Self::path_parts_(&self.pathbuf)
|
||||
}
|
||||
fn path_parts_(path: &Path) -> PathBuf {
|
||||
path.join("parts")
|
||||
}
|
||||
|
||||
fn path_version(&self) -> PathBuf {
|
||||
Self::path_version_(&self.pathbuf)
|
||||
}
|
||||
fn path_version_(path: &Path) -> PathBuf {
|
||||
path.join("version")
|
||||
}
|
||||
|
||||
pub fn height(&self) -> Option<&Height> {
|
||||
self.height.as_ref()
|
||||
}
|
||||
pub fn needs(&self, height: Height) -> bool {
|
||||
self.height.is_none_or(|self_height| height > self_height)
|
||||
}
|
||||
pub fn has(&self, height: Height) -> bool {
|
||||
!self.needs(height)
|
||||
}
|
||||
fn path_height(&self) -> PathBuf {
|
||||
Self::path_height_(&self.pathbuf)
|
||||
}
|
||||
fn path_height_(path: &Path) -> PathBuf {
|
||||
path.join("height")
|
||||
}
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
use std::{path::Path, thread};
|
||||
|
||||
use crate::{
|
||||
structs::Version, AddressbytesPrefix, Addressindex, BlockHashPrefix, Height, TxidPrefix, Txindex, Txoutindex,
|
||||
};
|
||||
|
||||
mod meta;
|
||||
mod multi;
|
||||
mod unique;
|
||||
|
||||
use meta::*;
|
||||
use unique::*;
|
||||
|
||||
pub struct Stores {
|
||||
pub addressbytes_prefix_to_addressindex: StoreUnique<AddressbytesPrefix, Addressindex>,
|
||||
pub blockhash_prefix_to_height: StoreUnique<BlockHashPrefix, Height>,
|
||||
pub txid_prefix_to_txindex: StoreUnique<TxidPrefix, Txindex>,
|
||||
}
|
||||
|
||||
impl Stores {
|
||||
pub fn open(path: &Path) -> color_eyre::Result<Self> {
|
||||
Ok(Self {
|
||||
addressbytes_prefix_to_addressindex: StoreUnique::open(
|
||||
&path.join("addressbytes_prefix_to_addressindex"),
|
||||
Version::from(1),
|
||||
)?,
|
||||
blockhash_prefix_to_height: StoreUnique::open(&path.join("blockhash_prefix_to_height"), Version::from(1))?,
|
||||
txid_prefix_to_txindex: StoreUnique::open(&path.join("txid_prefix_to_txindex"), Version::from(1))?,
|
||||
})
|
||||
}
|
||||
|
||||
// pub fn rollback_from(
|
||||
// &mut self,
|
||||
// _wtx: &mut WriteTransaction,
|
||||
// _height: Height,
|
||||
// _exit: &Exit,
|
||||
// ) -> color_eyre::Result<()> {
|
||||
// panic!();
|
||||
// let mut txindex = None;
|
||||
|
||||
// wtx.range(self.height_to_blockhash.data(), Slice::from(height)..)
|
||||
// .try_for_each(|slice| -> color_eyre::Result<()> {
|
||||
// let (height_slice, slice_blockhash) = slice?;
|
||||
// let blockhash = BlockHash::from_slice(&slice_blockhash)?;
|
||||
|
||||
// wtx.remove(self.height_to_blockhash.data(), height_slice);
|
||||
|
||||
// wtx.remove(self.blockhash_prefix_to_height.data(), blockhash.prefix());
|
||||
|
||||
// if txindex.is_none() {
|
||||
// txindex.replace(
|
||||
// wtx.get(self.height_to_first_txindex.data(), height_slice)?
|
||||
// .context("for height to have first txindex")?,
|
||||
// );
|
||||
// }
|
||||
// wtx.remove(self.height_to_first_txindex.data(), height_slice);
|
||||
// wtx.remove(self.height_to_last_txindex.data(), height_slice);
|
||||
|
||||
// Ok(())
|
||||
// })?;
|
||||
|
||||
// let txindex = txindex.context("txindex to not be none by now")?;
|
||||
|
||||
// wtx.range(self.txindex_to_txid.data(), Slice::from(txindex)..)
|
||||
// .try_for_each(|slice| -> color_eyre::Result<()> {
|
||||
// let (slice_txindex, slice_txid) = slice?;
|
||||
// let txindex = Txindex::from(slice_txindex);
|
||||
// let txid = Txid::from_slice(&slice_txid)?;
|
||||
|
||||
// wtx.remove(self.txindex_to_txid.data(), Slice::from(txindex));
|
||||
// wtx.remove(self.txindex_to_height.data(), Slice::from(txindex));
|
||||
// wtx.remove(self.txid_prefix_to_txindex.data(), txid.prefix());
|
||||
|
||||
// Ok(())
|
||||
// })?;
|
||||
|
||||
// let txoutindex = Txoutindex::from(txindex);
|
||||
|
||||
// let mut addressindexes = BTreeSet::new();
|
||||
|
||||
// wtx.range(self.txoutindex_to_amount.data(), Slice::from(txoutindex)..)
|
||||
// .try_for_each(|slice| -> color_eyre::Result<()> {
|
||||
// let (txoutindex_slice, _) = slice?;
|
||||
|
||||
// wtx.remove(self.txoutindex_to_amount.data(), txoutindex_slice);
|
||||
|
||||
// if let Some(addressindex_slice) =
|
||||
// wtx.get(self.txoutindex_to_addressindex.data(), txoutindex_slice)?
|
||||
// {
|
||||
// wtx.remove(self.txoutindex_to_addressindex.data(), txoutindex_slice);
|
||||
|
||||
// let addressindex = Addressindex::from(addressindex_slice);
|
||||
// addressindexes.insert(addressindex);
|
||||
|
||||
// let txoutindex = Txoutindex::from(txoutindex_slice);
|
||||
// let addresstxoutindex = Addresstxoutindex::from((addressindex, txoutindex));
|
||||
|
||||
// wtx.remove(
|
||||
// self.addressindex_to_txoutindexes.data(),
|
||||
// Slice::from(addresstxoutindex),
|
||||
// );
|
||||
// }
|
||||
|
||||
// Ok(())
|
||||
// })?;
|
||||
|
||||
// addressindexes
|
||||
// .into_iter()
|
||||
// .filter(|addressindex| {
|
||||
// let is_empty = wtx
|
||||
// .prefix(
|
||||
// self.addressindex_to_txoutindexes.data(),
|
||||
// Slice::from(*addressindex),
|
||||
// )
|
||||
// .next()
|
||||
// .is_none();
|
||||
// is_empty
|
||||
// })
|
||||
// .try_for_each(|addressindex| -> color_eyre::Result<()> {
|
||||
// let addressindex_slice = Slice::from(addressindex);
|
||||
|
||||
// let addressbytes = Addressbytes::from(
|
||||
// wtx.get(
|
||||
// self.addressindex_to_addressbytes.data(),
|
||||
// &addressindex_slice,
|
||||
// )?
|
||||
// .context("addressindex_to_address to have value")?,
|
||||
// );
|
||||
// wtx.remove(
|
||||
// self.addressbytes_prefix_to_addressindex.data(),
|
||||
// addressbytes.prefix(),
|
||||
// );
|
||||
// wtx.remove(
|
||||
// self.addressindex_to_addressbytes.data(),
|
||||
// &addressindex_slice,
|
||||
// );
|
||||
// wtx.remove(self.addressindex_to_addresstype.data(), &addressindex_slice);
|
||||
|
||||
// Ok(())
|
||||
// })?;
|
||||
//
|
||||
|
||||
// todo!("clear addresstxoutindexes_out")
|
||||
// todo!("clear addresstxoutindexes_in")
|
||||
// todo!("clear zero_txoutindexes")
|
||||
// todo!("clear txindexvout_to_txoutindex")
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
pub fn min_height(&self) -> Option<Height> {
|
||||
[
|
||||
self.addressbytes_prefix_to_addressindex.height(),
|
||||
self.blockhash_prefix_to_height.height(),
|
||||
self.txid_prefix_to_txindex.height(),
|
||||
]
|
||||
.into_iter()
|
||||
.min()
|
||||
.flatten()
|
||||
.cloned()
|
||||
}
|
||||
|
||||
pub fn export(self, height: Height) -> Result<(), snkrj::Error> {
|
||||
thread::scope(|scope| {
|
||||
vec![
|
||||
scope.spawn(|| self.addressbytes_prefix_to_addressindex.export(height)),
|
||||
scope.spawn(|| self.blockhash_prefix_to_height.export(height)),
|
||||
scope.spawn(|| self.txid_prefix_to_txindex.export(height)),
|
||||
]
|
||||
.into_iter()
|
||||
.try_for_each(|handle| -> Result<(), snkrj::Error> { handle.join().unwrap() })
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
use std::{array, path::Path, sync::OnceLock};
|
||||
|
||||
use rayon::prelude::*;
|
||||
use snkrj::{DatabaseKey, DatabaseMulti, DatabaseValue};
|
||||
|
||||
use super::{Height, StoreMeta, Version};
|
||||
|
||||
pub struct StoreMulti<K, V>
|
||||
where
|
||||
K: DatabaseKey,
|
||||
V: DatabaseValue,
|
||||
{
|
||||
meta: StoreMeta,
|
||||
pub parts: [OnceLock<Box<DatabaseMulti<K, V>>>; 256],
|
||||
}
|
||||
|
||||
impl<K, V> StoreMulti<K, V>
|
||||
where
|
||||
K: DatabaseKey,
|
||||
V: DatabaseValue,
|
||||
{
|
||||
pub fn open(path: &Path, version: Version) -> Result<Self, snkrj::Error> {
|
||||
let meta = StoreMeta::checked_open(path, version)?;
|
||||
|
||||
Ok(Self {
|
||||
meta,
|
||||
parts: array::from_fn(|_| OnceLock::new()),
|
||||
})
|
||||
}
|
||||
|
||||
// pub fn len(&self) -> usize {
|
||||
// self.meta.len()
|
||||
// }
|
||||
|
||||
fn get_or_init_store(&self, key: &K) -> &DatabaseMulti<K, V> {
|
||||
self.get_or_init_store_(key.as_ne_byte() as usize)
|
||||
}
|
||||
|
||||
fn get_or_init_store_(&self, storeindex: usize) -> &DatabaseMulti<K, V> {
|
||||
self.parts[storeindex]
|
||||
.get_or_init(|| Box::new(DatabaseMulti::open(self.meta.path_parts().join(storeindex.to_string())).unwrap()))
|
||||
}
|
||||
|
||||
fn get_or_init_mut_store(&mut self, key: &K) -> &mut DatabaseMulti<K, V> {
|
||||
self.get_or_init_store(key);
|
||||
|
||||
self.parts
|
||||
.get_mut(key.as_ne_byte() as usize)
|
||||
.unwrap()
|
||||
.get_mut()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn open_all(&self) {
|
||||
(0..=(u8::MAX) as usize).for_each(|storeindex| {
|
||||
self.get_or_init_store_(storeindex);
|
||||
});
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn get(&self, key: &K) -> Result<Option<&V>, snkrj::Error> {
|
||||
self.get_or_init_store(key).get(key)
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, key: K, value: V) -> Option<V> {
|
||||
self.meta.len += 1;
|
||||
self.get_or_init_mut_store(&key).insert(key, value)
|
||||
}
|
||||
|
||||
pub fn insert_if_needed(&mut self, key: K, value: V, height: Height) {
|
||||
if self.meta.needs(height) {
|
||||
self.insert(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn export(self, height: Height) -> Result<(), snkrj::Error> {
|
||||
if self.has(height) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.meta.export(height)?;
|
||||
|
||||
self.parts.into_par_iter().try_for_each(|s| {
|
||||
if let Some(db) = s.into_inner() {
|
||||
db.export()
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn height(&self) -> Option<&Height> {
|
||||
self.meta.height()
|
||||
}
|
||||
#[allow(unused)]
|
||||
pub fn needs(&self, height: Height) -> bool {
|
||||
self.meta.needs(height)
|
||||
}
|
||||
pub fn has(&self, height: Height) -> bool {
|
||||
self.meta.has(height)
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
use std::{array, path::Path, sync::OnceLock};
|
||||
|
||||
use rayon::prelude::*;
|
||||
use snkrj::{DatabaseKey, DatabaseUnique, DatabaseValue};
|
||||
|
||||
use super::{Height, StoreMeta, Version};
|
||||
|
||||
pub struct StoreUnique<K, V>
|
||||
where
|
||||
K: DatabaseKey,
|
||||
V: DatabaseValue,
|
||||
{
|
||||
meta: StoreMeta,
|
||||
pub parts: [OnceLock<Box<DatabaseUnique<K, V>>>; 256],
|
||||
}
|
||||
|
||||
impl<K, V> StoreUnique<K, V>
|
||||
where
|
||||
K: DatabaseKey,
|
||||
V: DatabaseValue,
|
||||
{
|
||||
pub fn open(path: &Path, version: Version) -> Result<Self, snkrj::Error> {
|
||||
let meta = StoreMeta::checked_open(path, version)?;
|
||||
|
||||
Ok(Self {
|
||||
meta,
|
||||
parts: array::from_fn(|_| OnceLock::new()),
|
||||
})
|
||||
}
|
||||
|
||||
// pub fn len(&self) -> usize {
|
||||
// self.meta.len()
|
||||
// }
|
||||
|
||||
fn get_or_init_store(&self, key: &K) -> &DatabaseUnique<K, V> {
|
||||
self.get_or_init_store_(key.as_ne_byte() as usize)
|
||||
}
|
||||
|
||||
fn get_or_init_store_(&self, storeindex: usize) -> &DatabaseUnique<K, V> {
|
||||
self.parts[storeindex].get_or_init(|| {
|
||||
Box::new(DatabaseUnique::open(self.meta.path_parts().join(storeindex.to_string())).unwrap())
|
||||
})
|
||||
}
|
||||
|
||||
fn get_or_init_mut_store(&mut self, key: &K) -> &mut DatabaseUnique<K, V> {
|
||||
self.get_or_init_store(key);
|
||||
|
||||
self.parts
|
||||
.get_mut(key.as_ne_byte() as usize)
|
||||
.unwrap()
|
||||
.get_mut()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn open_all(&self) {
|
||||
(0..=(u8::MAX) as usize).for_each(|storeindex| {
|
||||
self.get_or_init_store_(storeindex);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn get(&self, key: &K) -> Result<Option<&V>, snkrj::Error> {
|
||||
self.get_or_init_store(key).get(key)
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, key: K, value: V) -> Option<V> {
|
||||
self.meta.len += 1;
|
||||
self.get_or_init_mut_store(&key).insert(key, value)
|
||||
}
|
||||
|
||||
pub fn insert_if_needed(&mut self, key: K, value: V, height: Height) {
|
||||
if self.meta.needs(height) {
|
||||
self.insert(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn export(self, height: Height) -> Result<(), snkrj::Error> {
|
||||
if self.has(height) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.meta.export(height)?;
|
||||
|
||||
self.parts.into_par_iter().try_for_each(|s| {
|
||||
if let Some(db) = s.into_inner() {
|
||||
db.export()
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn height(&self) -> Option<&Height> {
|
||||
self.meta.height()
|
||||
}
|
||||
pub fn needs(&self, height: Height) -> bool {
|
||||
self.meta.needs(height)
|
||||
}
|
||||
pub fn has(&self, height: Height) -> bool {
|
||||
self.meta.has(height)
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,11 @@ where
|
||||
self.vec.flush()
|
||||
}
|
||||
|
||||
pub fn truncate_if_needed(&mut self, index: I, height: Height) -> storable_vec::Result<Option<T>> {
|
||||
height.write(&self.path_height())?;
|
||||
self.vec.truncate_if_needed(index)
|
||||
}
|
||||
|
||||
pub fn height(&self) -> storable_vec::Result<Height> {
|
||||
Height::try_from(self.path_height().as_path())
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::{fs, io, path::Path};
|
||||
use std::{collections::BTreeMap, fs, io, path::Path};
|
||||
|
||||
use exit::Exit;
|
||||
use rayon::prelude::*;
|
||||
@@ -181,117 +181,114 @@ impl<const MODE: u8> StorableVecs<MODE> {
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn rollback_from(&mut self, _height: Height, _exit: &Exit) -> color_eyre::Result<()> {
|
||||
panic!();
|
||||
// let mut txindex = None;
|
||||
pub fn rollback_from(&mut self, height: Height, exit: &Exit) -> storable_vec::Result<()> {
|
||||
let prev_height = height.decremented();
|
||||
|
||||
// wtx.range(self.height_to_blockhash.data(), Slice::from(height)..)
|
||||
// .try_for_each(|slice| -> color_eyre::Result<()> {
|
||||
// let (height_slice, slice_blockhash) = slice?;
|
||||
// let blockhash = BlockHash::from_slice(&slice_blockhash)?;
|
||||
let mut truncated_indexes: BTreeMap<String, Option<usize>> = BTreeMap::new();
|
||||
|
||||
// wtx.remove(self.height_to_blockhash.data(), height_slice);
|
||||
let addressindex = self
|
||||
.height_to_first_addressindex
|
||||
.truncate_if_needed(height, prev_height)?;
|
||||
let txindex = self.height_to_first_txindex.truncate_if_needed(height, prev_height)?;
|
||||
let txinindex = self.height_to_first_txinindex.truncate_if_needed(height, prev_height)?;
|
||||
let txoutindex = self
|
||||
.height_to_first_txoutindex
|
||||
.truncate_if_needed(height, prev_height)?;
|
||||
let p2pk33index = self
|
||||
.height_to_first_p2pk33index
|
||||
.truncate_if_needed(height, prev_height)?;
|
||||
let p2pk65index = self
|
||||
.height_to_first_p2pk65index
|
||||
.truncate_if_needed(height, prev_height)?;
|
||||
let p2pkhindex = self
|
||||
.height_to_first_p2pkhindex
|
||||
.truncate_if_needed(height, prev_height)?;
|
||||
let p2shindex = self.height_to_first_p2shindex.truncate_if_needed(height, prev_height)?;
|
||||
let p2trindex = self.height_to_first_p2trindex.truncate_if_needed(height, prev_height)?;
|
||||
let p2wpkhindex = self
|
||||
.height_to_first_p2wpkhindex
|
||||
.truncate_if_needed(height, prev_height)?;
|
||||
let p2wshindex = self
|
||||
.height_to_first_p2wshindex
|
||||
.truncate_if_needed(height, prev_height)?;
|
||||
|
||||
// wtx.remove(self.blockhash_prefix_to_height.data(), blockhash.prefix());
|
||||
self.height_to_blockhash.truncate_if_needed(height, prev_height)?;
|
||||
self.height_to_difficulty.truncate_if_needed(height, prev_height)?;
|
||||
self.height_to_first_emptyindex
|
||||
.truncate_if_needed(height, prev_height)?;
|
||||
self.height_to_first_multisigindex
|
||||
.truncate_if_needed(height, prev_height)?;
|
||||
self.height_to_first_opreturnindex
|
||||
.truncate_if_needed(height, prev_height)?;
|
||||
self.height_to_first_pushonlyindex
|
||||
.truncate_if_needed(height, prev_height)?;
|
||||
self.height_to_first_unknownindex
|
||||
.truncate_if_needed(height, prev_height)?;
|
||||
self.height_to_size.truncate_if_needed(height, prev_height)?;
|
||||
self.height_to_timestamp.truncate_if_needed(height, prev_height)?;
|
||||
self.height_to_weight.truncate_if_needed(height, prev_height)?;
|
||||
|
||||
// if txindex.is_none() {
|
||||
// txindex.replace(
|
||||
// wtx.get(self.height_to_first_txindex.data(), height_slice)?
|
||||
// .context("for height to have first txindex")?,
|
||||
// );
|
||||
// }
|
||||
// wtx.remove(self.height_to_first_txindex.data(), height_slice);
|
||||
// wtx.remove(self.height_to_last_txindex.data(), height_slice);
|
||||
if let Some(addressindex) = addressindex {
|
||||
self.addressindex_to_addresstype
|
||||
.truncate_if_needed(addressindex, prev_height)?;
|
||||
self.addressindex_to_addresstypeindex
|
||||
.truncate_if_needed(addressindex, prev_height)?;
|
||||
self.addressindex_to_height
|
||||
.truncate_if_needed(addressindex, prev_height)?;
|
||||
}
|
||||
|
||||
// Ok(())
|
||||
// })?;
|
||||
if let Some(p2pk33index) = p2pk33index {
|
||||
self.p2pk33index_to_p2pk33addressbytes
|
||||
.truncate_if_needed(p2pk33index, prev_height)?;
|
||||
}
|
||||
if let Some(p2pk65index) = p2pk65index {
|
||||
self.p2pk65index_to_p2pk65addressbytes
|
||||
.truncate_if_needed(p2pk65index, prev_height)?;
|
||||
}
|
||||
if let Some(p2pkhindex) = p2pkhindex {
|
||||
self.p2pkhindex_to_p2pkhaddressbytes
|
||||
.truncate_if_needed(p2pkhindex, prev_height)?;
|
||||
}
|
||||
if let Some(p2shindex) = p2shindex {
|
||||
self.p2shindex_to_p2shaddressbytes
|
||||
.truncate_if_needed(p2shindex, prev_height)?;
|
||||
}
|
||||
if let Some(p2trindex) = p2trindex {
|
||||
self.p2trindex_to_p2traddressbytes
|
||||
.truncate_if_needed(p2trindex, prev_height)?;
|
||||
}
|
||||
if let Some(p2wpkhindex) = p2wpkhindex {
|
||||
self.p2wpkhindex_to_p2wpkhaddressbytes
|
||||
.truncate_if_needed(p2wpkhindex, prev_height)?;
|
||||
}
|
||||
if let Some(p2wshindex) = p2wshindex {
|
||||
self.p2wshindex_to_p2wshaddressbytes
|
||||
.truncate_if_needed(p2wshindex, prev_height);
|
||||
}
|
||||
|
||||
// let txindex = txindex.context("txindex to not be none by now")?;
|
||||
if let Some(txindex) = txindex {
|
||||
self.txindex_to_first_txinindex
|
||||
.truncate_if_needed(txindex, prev_height)?;
|
||||
self.txindex_to_first_txoutindex
|
||||
.truncate_if_needed(txindex, prev_height)?;
|
||||
self.txindex_to_height.truncate_if_needed(txindex, prev_height)?;
|
||||
self.txindex_to_locktime.truncate_if_needed(txindex, prev_height)?;
|
||||
self.txindex_to_txid.truncate_if_needed(txindex, prev_height)?;
|
||||
self.txindex_to_txversion.truncate_if_needed(txindex, prev_height)?;
|
||||
}
|
||||
|
||||
// wtx.range(self.txindex_to_txid.data(), Slice::from(txindex)..)
|
||||
// .try_for_each(|slice| -> color_eyre::Result<()> {
|
||||
// let (slice_txindex, slice_txid) = slice?;
|
||||
// let txindex = Txindex::from(slice_txindex);
|
||||
// let txid = Txid::from_slice(&slice_txid)?;
|
||||
if let Some(txinindex) = txinindex {
|
||||
self.txinindex_to_txoutindex
|
||||
.truncate_if_needed(txinindex, prev_height)?;
|
||||
}
|
||||
|
||||
// wtx.remove(self.txindex_to_txid.data(), Slice::from(txindex));
|
||||
// wtx.remove(self.txindex_to_height.data(), Slice::from(txindex));
|
||||
// wtx.remove(self.txid_prefix_to_txindex.data(), txid.prefix());
|
||||
if let Some(txoutindex) = txoutindex {
|
||||
self.txoutindex_to_addressindex
|
||||
.truncate_if_needed(txoutindex, prev_height)?;
|
||||
self.txoutindex_to_value.truncate_if_needed(txoutindex, prev_height)?;
|
||||
}
|
||||
|
||||
// Ok(())
|
||||
// })?;
|
||||
|
||||
// let txoutindex = Txoutindex::from(txindex);
|
||||
|
||||
// let mut addressindexes = BTreeSet::new();
|
||||
|
||||
// wtx.range(self.txoutindex_to_amount.data(), Slice::from(txoutindex)..)
|
||||
// .try_for_each(|slice| -> color_eyre::Result<()> {
|
||||
// let (txoutindex_slice, _) = slice?;
|
||||
|
||||
// wtx.remove(self.txoutindex_to_amount.data(), txoutindex_slice);
|
||||
|
||||
// if let Some(addressindex_slice) =
|
||||
// wtx.get(self.txoutindex_to_addressindex.data(), txoutindex_slice)?
|
||||
// {
|
||||
// wtx.remove(self.txoutindex_to_addressindex.data(), txoutindex_slice);
|
||||
|
||||
// let addressindex = Addressindex::from(addressindex_slice);
|
||||
// addressindexes.insert(addressindex);
|
||||
|
||||
// let txoutindex = Txoutindex::from(txoutindex_slice);
|
||||
// let addresstxoutindex = Addresstxoutindex::from((addressindex, txoutindex));
|
||||
|
||||
// wtx.remove(
|
||||
// self.addressindex_to_txoutindexes.data(),
|
||||
// Slice::from(addresstxoutindex),
|
||||
// );
|
||||
// }
|
||||
|
||||
// Ok(())
|
||||
// })?;
|
||||
|
||||
// addressindexes
|
||||
// .into_iter()
|
||||
// .filter(|addressindex| {
|
||||
// let is_empty = wtx
|
||||
// .prefix(
|
||||
// self.addressindex_to_txoutindexes.data(),
|
||||
// Slice::from(*addressindex),
|
||||
// )
|
||||
// .next()
|
||||
// .is_none();
|
||||
// is_empty
|
||||
// })
|
||||
// .try_for_each(|addressindex| -> color_eyre::Result<()> {
|
||||
// let addressindex_slice = Slice::from(addressindex);
|
||||
|
||||
// let addressbytes = Addressbytes::from(
|
||||
// wtx.get(
|
||||
// self.addressindex_to_addressbytes.data(),
|
||||
// &addressindex_slice,
|
||||
// )?
|
||||
// .context("addressindex_to_address to have value")?,
|
||||
// );
|
||||
// wtx.remove(
|
||||
// self.addressbytes_prefix_to_addressindex.data(),
|
||||
// addressbytes.prefix(),
|
||||
// );
|
||||
// wtx.remove(
|
||||
// self.addressindex_to_addressbytes.data(),
|
||||
// &addressindex_slice,
|
||||
// );
|
||||
// wtx.remove(self.addressindex_to_addresstype.data(), &addressindex_slice);
|
||||
|
||||
// Ok(())
|
||||
// })?;
|
||||
//
|
||||
|
||||
// todo!("clear addresstxoutindexes_out")
|
||||
// todo!("clear addresstxoutindexes_in")
|
||||
// todo!("clear zero_txoutindexes")
|
||||
|
||||
// Ok(())
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn flush(&mut self, height: Height) -> io::Result<()> {
|
||||
|
||||
@@ -33,6 +33,10 @@ impl Height {
|
||||
pub fn write(&self, path: &Path) -> Result<(), io::Error> {
|
||||
fs::write(path, self.as_bytes())
|
||||
}
|
||||
|
||||
pub fn decremented(&self) -> Self {
|
||||
Self(self.0.checked_sub(1).unwrap_or_default())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<u64> for Height {
|
||||
|
||||
Reference in New Issue
Block a user