bindex: snapshot

This commit is contained in:
nym21
2025-01-23 11:11:39 +01:00
parent 1296a2e9ec
commit d629ae8fbb
64 changed files with 334 additions and 3844 deletions
Generated
+64 -3660
View File
File diff suppressed because it is too large Load Diff
+40 -36
View File
@@ -1,39 +1,43 @@
[package]
name = "kibo_money"
version = "0.6.0"
edition = "2021"
# [package]
# name = "kibo_money"
# version = "0.6.0"
# edition = "2021"
[workspace]
members = ["bindex", "biter", "iterable", "snkrj", "storable_vec"]
resolver = "2"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
allocative = "0.3.4"
axum = "0.7.9"
bincode = { git = "https://github.com/bincode-org/bincode.git", features = [
"serde",
] }
bitcoin_hashes = { version = "0.15.0" }
biter = { path = "./src/crates/biter" }
chrono = { version = "0.4.39", features = ["serde"] }
clap = { version = "4.5.26", features = ["derive"] }
color-eyre = "0.6.3"
ctrlc = { version = "3.4.5", features = ["termination"] }
derive_deref = "1.1.1"
env_logger = "0.11.6"
inferno = "0.12.1"
itertools = "0.13.0"
log = { version = "0.4.25", features = ["std", "serde"] }
ordered-float = "4.6.0"
rayon = "1.10.0"
regex = "1.11.1"
reqwest = { version = "0.12.12", features = ["blocking", "json"] }
rlimit = "0.10.2"
snkrj = { path = "./src/crates/snkrj" }
serde = { version = "1.0.217", features = ["derive"] }
serde_json = "1.0.135"
struct_iterable = { path = "./src/crates/iterable" }
swc = "9.0.2"
swc_common = "5.0.0"
tokio = { version = "1.43.0", features = ["full"] }
toml = "0.8.19"
tower-http = { version = "0.6.2", features = ["compression-full"] }
zstd = "0.13.2"
# [dependencies]
# allocative = "0.3.4"
# axum = "0.7.9"
# bincode = { git = "https://github.com/bincode-org/bincode.git", features = [
# "serde",
# ] }
# bitcoin_hashes = { version = "0.15.0" }
# biter = { path = "./src/crates/biter" }
# chrono = { version = "0.4.39", features = ["serde"] }
# clap = { version = "4.5.26", features = ["derive"] }
# color-eyre = "0.6.3"
# ctrlc = { version = "3.4.5", features = ["termination"] }
# derive_deref = "1.1.1"
# env_logger = "0.11.6"
# inferno = "0.12.1"
# itertools = "0.13.0"
# log = { version = "0.4.25", features = ["std", "serde"] }
# ordered-float = "4.6.0"
# rayon = "1.10.0"
# regex = "1.11.1"
# reqwest = { version = "0.12.12", features = ["blocking", "json"] }
# rlimit = "0.10.2"
# snkrj = { path = "./src/crates/snkrj" }
# serde = { version = "1.0.217", features = ["derive"] }
# serde_json = "1.0.135"
# struct_iterable = { path = "./src/crates/iterable" }
# swc = "9.0.2"
# swc_common = "5.0.0"
# tokio = { version = "1.43.0", features = ["full"] }
# toml = "0.8.19"
# tower-http = { version = "0.6.2", features = ["compression-full"] }
# zstd = "0.13.2"
View File
@@ -29,7 +29,8 @@ enum TxInOrAddressindextoutindex<'a> {
}
const UNSAFE_BLOCKS: u32 = 100;
const SNAPSHOT_BLOCK_RANGE: usize = 4_200; // MUST 210_000 % THIS == 0
const DAILY_BLOCK_TARGET: usize = 144;
const SNAPSHOT_BLOCK_RANGE: usize = DAILY_BLOCK_TARGET * 10;
fn main() -> color_eyre::Result<()> {
color_eyre::install()?;
@@ -38,7 +39,7 @@ fn main() -> color_eyre::Result<()> {
let check_collisions = true;
let data_dir = Path::new("../../../../bitcoin");
let data_dir = Path::new("../../bitcoin");
let cookie = Path::new(data_dir).join(".cookie");
let rpc = Client::new("http://localhost:8332", Auth::CookieFile(cookie))?;
@@ -62,59 +63,63 @@ fn main() -> color_eyre::Result<()> {
let mut txindex = vecs
.height_to_first_txindex
.get(height)?
.cloned()
.map(|v| *v)
.unwrap_or(Txindex::default());
let mut txoutindex = vecs
.height_to_first_txoutindex
.get(height)?
.cloned()
.map(|v| *v)
.unwrap_or(Txoutindex::default());
let mut addressindex = vecs
.height_to_first_addressindex
.get(height)?
.cloned()
.map(|v| *v)
.unwrap_or(Addressindex::default());
let export = |stores: Stores, vecs: &mut Vecs, height: Height| -> color_eyre::Result<()> {
exit.block();
println!("Exporting...");
// Memory: 2.87
// Real Memory: 16.23
// Private Memory: 10.8
if height > Height::from(400_000_u32) {
pause();
}
vecs.reset_cache();
println!("Resetted cache");
// Memory: 2.87
// Real Memory: 13.24
// Private Memory: 10.8
if height > Height::from(400_000_u32) {
pause();
}
// Memory: 3.76 GB
// Real Memory: 22.47 GB
// Private Memory: 12.44 GB
// if height > Height::from(400_000_u32) {
// pause();
// }
// vecs.reset_cache();
// At: 403200
// Memory: 3.78 GB
// Real Memory: 12.65 GB
// Private Memory: 11.39 GB
// if height > Height::from(400_000_u32) {
// pause();
// }
vecs.flush(height)?;
println!("Vecs flushed");
// Memory: 3.36
// Real Memory: 13.55
// Private Memory: 10.66
// At: 403200
// Memory: 3.79 GB
// Real Memory: 12.37 GB
// Private Memory: 10.95 GB
// Gone up wtf
if height > Height::from(400_000_u32) {
pause();
}
// if height > Height::from(400_000_u32) {
// pause();
// }
stores.export(height);
println!("Export done");
if height > Height::from(400_000_u32) {
pause();
}
// At: 403200
// Memory: 2.23 GB
// Real Memory: 1.05 GB
// Private Memory: 0.109 GB
// if height > Height::from(400_000_u32) {
// pause();
// }
exit.unblock();
Ok(())
};
let mut stores_opt = Some(stores);
biter::new(data_dir, Some(height.into()), None, rpc)
biter::new(data_dir, Some(height.into()), Some(400_000), rpc)
.iter()
.try_for_each(|(_height, block, blockhash)| -> color_eyre::Result<()> {
println!("Processing block {_height}...");
@@ -126,7 +131,8 @@ fn main() -> color_eyre::Result<()> {
let mut stores = stores_opt.take().context("option should have wtx")?;
if let Some(saved_blockhash) = vecs.height_to_blockhash.get(height)? {
if &blockhash != saved_blockhash {
// if &blockhash != saved_blockhash {
if &blockhash != saved_blockhash.as_ref() {
todo!("Rollback not implemented");
// parts.rollback_from(&mut wtx, height, &exit)?;
}
@@ -162,7 +168,7 @@ fn main() -> color_eyre::Result<()> {
tx.output
.iter()
.enumerate()
.map(move |(vout, txout)| (Txindex::from(index), vout as u32, txout))
.map(move |(vout, txout)| (Txindex::from(index), vout as u32, txout, tx))
}).collect::<Vec<_>>();
let tx_len = block.txdata.len();
@@ -272,7 +278,7 @@ fn main() -> color_eyre::Result<()> {
outputs.into_par_iter().enumerate()
.map(
#[allow(clippy::type_complexity)]
|(block_txoutindex, (block_txindex, vout, txout))| -> color_eyre::Result<(Txoutindex,
|(block_txoutindex, (block_txindex, vout, txout, tx))| -> color_eyre::Result<(Txoutindex,
(&TxOut, Txindexvout, Addresstype, color_eyre::Result<Addressbytes>, Option<Addressindex>))> {
let txindex_local = txindex + block_txindex;
let txindexvout = Txindexvout::from((txindex_local, vout));
@@ -294,25 +300,28 @@ fn main() -> color_eyre::Result<()> {
// Checking if not in the future
.and_then(|addressindex_local| (addressindex_local < addressindex)
.then_some(addressindex_local))
});
}); // OK
if let Some(Some(addressindex)) = check_collisions.then_some(addressindex_opt) {
if let Some(Some(addressindex_local)) = check_collisions.then_some(addressindex_opt) {
let addressbytes = addressbytes_res.as_ref().unwrap();
let prev_addresstype = *vecs.addressindex_to_addresstype.get(
addressindex,
addressindex_local,
)?.context("Expect to have address type")?;
let addresstypeindex = *vecs.addressindex_to_addresstypeindex.get(
addressindex,
addressindex_local,
)?.context("Expect to have address type index")?;
// Good first time
// Wrong after rerun
let prev_addressbytes_opt= vecs.get_addressbytes(prev_addresstype, addresstypeindex)?;
let prev_addressbytes = prev_addressbytes_opt.as_ref().context("Expect to have addressbytes")?;
if (vecs.addressindex_to_addresstype.hasnt(addressindex) && addresstype != prev_addresstype) || (stores.addressbytes_prefix_to_addressindex.needs(height) && prev_addressbytes != addressbytes) {
dbg!(addresstype, prev_addresstype, prev_addressbytes, addressbytes, addressindex, addresstypeindex, txout, AddressbytesPrefix::from((addressbytes, addresstype)), AddressbytesPrefix::from((prev_addressbytes, prev_addresstype)));
if (vecs.addressindex_to_addresstype.hasnt(addressindex_local) && addresstype != prev_addresstype) || (stores.addressbytes_prefix_to_addressindex.needs(height) && prev_addressbytes != addressbytes) {
let txid = tx.compute_txid();
dbg!(_height, txid, vout, block_txindex, addresstype, prev_addresstype, prev_addressbytes, addressbytes, addressindex, addressindex_local, addresstypeindex, txout, AddressbytesPrefix::from((addressbytes, addresstype)), AddressbytesPrefix::from((prev_addressbytes, prev_addresstype)));
panic!()
}
}
@@ -373,7 +382,7 @@ fn main() -> color_eyre::Result<()> {
let mut addressindex_local = addressindex;
let mut addressbytes_prefix= None;
let mut addressbytes_prefix = None;
if let Some(addressindex) = addressindex_opt.or_else(|| addressbytes_res.as_ref().ok().and_then(|addressbytes| {
// Check if address was first seen before in this iterator
@@ -397,6 +406,22 @@ fn main() -> color_eyre::Result<()> {
if let Ok(addressbytes) = addressbytes_res {
let addressbytes_prefix = addressbytes_prefix.unwrap();
// if addressindex_local == Addressindex::from(257905_u32) || addressbytes_prefix == AddressbytesPrefix::from(
// [
// 116_u8,
// 86,
// 96,
// 52,
// 2,
// 87,
// 151,
// 177,
// ],
// ) {
// dbg!(addressindex_local, addressbytes, addressbytes_prefix, addresstypeindex);
// panic!();
// }
already_added_addressbytes_prefix.insert(addressbytes_prefix.clone(), addressindex_local);
stores.addressbytes_prefix_to_addressindex.insert_if_needed(
@@ -491,6 +516,10 @@ fn main() -> color_eyre::Result<()> {
dbg!(txindex_local, txid, len);
})?;
// #[allow(clippy::redundant_locals)]
// let prev_txid = prev_txid;
let prev_txid = prev_txid.as_ref();
// If another Txid needs to be added to the list
// We need to check that it's also a coinbase tx otherwise par_iter inputs needs to be updated
let only_known_dup_txids = [
@@ -539,17 +568,13 @@ fn main() -> color_eyre::Result<()> {
Ok(())
})?;
dbg!(i.elapsed());
pause();
let stores = stores_opt.take().context("option should have wtx")?;
export(stores, &mut vecs, height)?;
pause();
dbg!(i.elapsed());
pause();
Ok(())
}
@@ -2,7 +2,7 @@ use jiff::tz::TimeZone;
use super::Timestamp;
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Date(jiff::civil::Date);
impl From<&Timestamp> for Date {
@@ -28,6 +28,11 @@ impl From<(&Addressbytes, Addresstype)> for AddressbytesPrefix {
))
}
}
impl From<[u8; 8]> for AddressbytesPrefix {
fn from(value: [u8; 8]) -> Self {
Self(value)
}
}
#[derive(Debug, Deref, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct BlockHashPrefix([u8; 8]);
@@ -16,7 +16,7 @@ pub struct StorableVec<I, T> {
impl<I, T> StorableVec<I, T>
where
I: Into<usize>,
T: Sized + Debug,
T: Sized + Debug + Clone,
{
pub fn import(path: &Path, version: Version) -> io::Result<Self> {
fs::create_dir_all(path)?;
@@ -70,10 +70,6 @@ where
path.join("height")
}
fn reset_cache(&mut self) {
self.vec.reset_cache();
}
// pub fn needs(&self, height: Height) -> bool {
// self.height() // store height in struct
// }
@@ -93,23 +89,18 @@ impl<I, T> DerefMut for StorableVec<I, T> {
pub trait AnyBindexVec {
fn height(&self) -> color_eyre::Result<Height>;
fn reset_cache(&mut self);
fn flush(&mut self, height: Height) -> io::Result<()>;
}
impl<I, T> AnyBindexVec for StorableVec<I, T>
where
I: Into<usize>,
T: Sized + Debug,
T: Sized + Debug + Clone,
{
fn height(&self) -> color_eyre::Result<Height> {
self.height()
}
fn reset_cache(&mut self) {
self.reset_cache();
}
fn flush(&mut self, height: Height) -> io::Result<()> {
self.flush(height)
}
@@ -168,38 +168,38 @@ impl Vecs {
Addresstype::P2PK65 => self
.p2pk65index_to_p2pk65addressbytes
.get(addresstypeindex)?
.cloned()
.map(Addressbytes::from),
// .map(|v| Addressbytes::from(v.clone())),
.map(|v| Addressbytes::from(v.into_inner())),
Addresstype::P2PK33 => self
.p2pk33index_to_p2pk33addressbytes
.get(addresstypeindex)?
.cloned()
.map(Addressbytes::from),
// .map(|v| Addressbytes::from(v.clone())),
.map(|v| Addressbytes::from(v.into_inner())),
Addresstype::P2PKH => self
.p2pkhindex_to_p2pkhaddressbytes
.get(addresstypeindex)?
.cloned()
.map(Addressbytes::from),
// .map(|v| Addressbytes::from(v.clone())),
.map(|v| Addressbytes::from(v.into_inner())),
Addresstype::P2SH => self
.p2shindex_to_p2shaddressbytes
.get(addresstypeindex)?
.cloned()
.map(Addressbytes::from),
// .map(|v| Addressbytes::from(v.clone())),
.map(|v| Addressbytes::from(v.into_inner())),
Addresstype::P2WPKH => self
.p2wpkhindex_to_p2wpkhaddressbytes
.get(addresstypeindex)?
.cloned()
.map(Addressbytes::from),
// .map(|v| Addressbytes::from(v.clone())),
.map(|v| Addressbytes::from(v.into_inner())),
Addresstype::P2WSH => self
.p2wshindex_to_p2wshaddressbytes
.get(addresstypeindex)?
.cloned()
.map(Addressbytes::from),
// .map(|v| Addressbytes::from(v.clone())),
.map(|v| Addressbytes::from(v.into_inner())),
Addresstype::P2TR => self
.p2trindex_to_p2traddressbytes
.get(addresstypeindex)?
.cloned()
.map(Addressbytes::from),
// .map(|v| Addressbytes::from(v.clone())),
.map(|v| Addressbytes::from(v.into_inner())),
_ => unreachable!(),
})
}
@@ -324,12 +324,6 @@ impl Vecs {
.try_for_each(|vec| vec.flush(height))
}
pub fn reset_cache(&mut self) {
self.as_mut_slice().par_iter_mut().for_each(|vec| {
vec.reset_cache();
})
}
pub fn min_height(&self) -> color_eyre::Result<Option<Height>> {
Ok(self
.as_slice()
View File
@@ -58,26 +58,24 @@ enum BlockState {
///
/// use bitcoincore_rpc::{Auth, Client};
///
/// fn main() {
/// let i = std::time::Instant::now();
/// let i = std::time::Instant::now();
///
/// let data_dir = Path::new("../../bitcoin");
/// let url = "http://localhost:8332";
/// let cookie = Path::new(data_dir).join(".cookie");
/// let auth = Auth::CookieFile(cookie);
/// let rpc = Client::new(url, auth).unwrap();
/// let data_dir = Path::new("../../bitcoin");
/// let url = "http://localhost:8332";
/// let cookie = Path::new(data_dir).join(".cookie");
/// let auth = Auth::CookieFile(cookie);
/// let rpc = Client::new(url, auth).unwrap();
///
/// let start = Some(850_000);
/// let end = None;
/// let start = Some(850_000);
/// let end = None;
///
/// biter::new(data_dir, start, end, rpc)
/// .iter()
/// .for_each(|(height, _block, hash)| {
/// println!("{height}: {hash}");
/// });
/// biter::new(data_dir, start, end, rpc)
/// .iter()
/// .for_each(|(height, _block, hash)| {
/// println!("{height}: {hash}");
/// });
///
/// dbg!(i.elapsed());
/// }
/// dbg!(i.elapsed());
/// ```
///
pub fn new(
@@ -285,7 +283,7 @@ pub fn new(
.unwrap();
}
if end.map_or(false, |end| height == end) {
if end == Some(height) {
return ControlFlow::Break(());
}
View File
@@ -2,11 +2,11 @@ use std::{
cmp::Ordering,
fmt::{self, Debug},
fs::{File, OpenOptions},
io::{self, Write},
io::{self, Read, Seek, SeekFrom, Write},
marker::PhantomData,
mem,
ops::Range,
path::Path,
ops::{Deref, Range},
path::{Path, PathBuf},
sync::OnceLock,
};
@@ -25,6 +25,8 @@ use memmap2::{Mmap, MmapOptions};
///
#[derive(Debug)]
pub struct StorableVec<I, T> {
pathbuf: PathBuf,
// file_for_reads: File,
file: File,
cache: Vec<OnceLock<Box<Mmap>>>, // Boxed to reduce the size of the lock (24 > 16)
disk_len: usize,
@@ -36,28 +38,69 @@ pub struct StorableVec<I, T> {
}
/// In bytes
const MAX_PAGE_SIZE: usize = 4096;
const ONE_MB: usize = 1024 * 1024;
const MAX_CACHE_SIZE: usize = 50 * ONE_MB;
const MAX_PAGE_SIZE: usize = 4 * 4096;
const ONE_MB: usize = 1000 * 1024;
const MAX_CACHE_SIZE: usize = 100 * ONE_MB;
#[derive(Debug, Clone)]
pub enum Value<'a, T> {
Ref(&'a T),
Owned(T),
}
impl<T> Value<'_, T>
where
T: Sized + Debug + Clone,
{
pub fn into_inner(self) -> T {
match self {
Self::Ref(t) => t.to_owned(),
Self::Owned(t) => t,
}
}
}
impl<T> Deref for Value<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
match self {
Self::Ref(t) => t,
Self::Owned(t) => t,
}
}
}
impl<T> AsRef<T> for Value<'_, T>
where
T: Sized + Debug + Clone,
{
fn as_ref(&self) -> &T {
match self {
Self::Ref(t) => t,
Self::Owned(t) => t,
}
}
}
impl<I, T> StorableVec<I, T>
where
I: Into<usize>,
T: Sized + Debug,
T: Sized + Debug + Clone,
{
pub const SIZE: usize = size_of::<T>();
pub const PER_PAGE: usize = MAX_PAGE_SIZE / Self::SIZE;
pub const SIZE_OF_T: usize = size_of::<T>();
pub const PER_PAGE: usize = MAX_PAGE_SIZE / Self::SIZE_OF_T;
/// In bytes
pub const PAGE_SIZE: usize = Self::PER_PAGE * Self::SIZE;
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 import(path: &Path) -> Result<Self, io::Error> {
let file = Self::open_file(path)?;
let mut this = Self {
pathbuf: path.to_owned(),
disk_len: Self::byte_index_to_index(file.metadata()?.len() as usize),
file,
// file_for_reads: Self::open_file(path)?,
cache: vec![],
pushed: vec![],
// updated: BTreeMap::new(),
@@ -66,15 +109,21 @@ where
phantom: PhantomData,
};
this.cache.resize_with(Self::CACHE_LENGTH, Default::default);
this.cache.shrink_to_fit();
this.reset_cache();
Ok(this)
}
pub fn reset_cache(&mut self) {
let len = (self.disk_len as f64 / Self::PER_PAGE as f64).ceil() as usize;
self.cache.clear();
self.cache.resize_with(len, Default::default);
fn reset_cache(&mut self) {
// let len = (self.disk_len as f64 / Self::PER_PAGE as f64).ceil() as usize;
// self.cache.clear();
// self.cache.resize_with(len, Default::default);
self.cache.iter_mut().for_each(|lock| {
lock.take();
});
}
fn open_file(path: &Path) -> Result<File, io::Error> {
@@ -87,24 +136,19 @@ where
}
#[inline]
fn index_to_mmap_index(index: usize) -> usize {
Self::index_to_byte_index(index) / Self::PAGE_SIZE
}
#[inline]
fn index_to_range(index: usize) -> Range<usize> {
fn index_to_byte_range(index: usize) -> Range<usize> {
let index = Self::index_to_byte_index(index) % Self::PAGE_SIZE;
index..(index + Self::SIZE)
index..(index + Self::SIZE_OF_T)
}
#[inline]
fn index_to_byte_index(index: usize) -> usize {
index * Self::SIZE
index * Self::SIZE_OF_T
}
#[inline]
fn byte_index_to_index(byte_index: usize) -> usize {
byte_index / Self::SIZE
byte_index / Self::SIZE_OF_T
}
fn index_to_pushed_index(&self, index: usize) -> Result<Option<usize>> {
@@ -122,14 +166,14 @@ where
#[allow(unused)]
#[inline]
pub fn get(&self, index: I) -> Result<Option<&T>> {
pub fn get(&self, index: I) -> Result<Option<Value<'_, T>>> {
self.get_(index.into())
}
pub fn get_(&self, index: usize) -> Result<Option<&T>> {
pub 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));
return Ok(self.pushed.get(index).map(|v| Value::Ref(v)));
}
}
Err(Error::IndexTooHigh) => return Ok(None),
@@ -142,35 +186,56 @@ where
// }
// }
let mmap_index = Self::index_to_mmap_index(index);
let byte_index = Self::index_to_byte_index(index);
let page_index = index / Self::PER_PAGE;
let last_index = self.disk_len - 1;
let max_page_index = last_index / Self::PER_PAGE;
let min_page_index = (max_page_index + 1)
.checked_sub(Self::CACHE_LENGTH)
.unwrap_or_default();
let mmap = &**self
.cache
.get(mmap_index)
.ok_or(Error::MmapsVecIsTooSmall)?
.get_or_init(|| {
Box::new(unsafe {
MmapOptions::new()
.len(MAX_PAGE_SIZE)
.offset((mmap_index * Self::PAGE_SIZE) as u64)
.map(&self.file)
.unwrap()
})
});
if page_index >= min_page_index {
let mmap = &**self
.cache
.get(page_index - min_page_index)
.ok_or(Error::MmapsVecIsTooSmall)?
.get_or_init(|| {
Box::new(unsafe {
MmapOptions::new()
.len(Self::PAGE_SIZE)
.offset((page_index * Self::PAGE_SIZE) as u64)
.map(&self.file)
.unwrap()
})
});
let range = Self::index_to_range(index);
let src = &mmap[range];
let range = Self::index_to_byte_range(index);
Ok(Some(T::unsafe_try_from_slice(src)?))
let slice = &mmap[range];
Ok(Some(Value::Ref(T::unsafe_try_from_slice(slice)?)))
} else {
// let mut file = &self.file_for_reads;
let mut file = Self::open_file(&self.pathbuf).unwrap();
file.seek(SeekFrom::Start(byte_index as u64)).unwrap();
let mut buf = vec![0; Self::SIZE_OF_T];
file.read_exact(&mut buf).unwrap();
let value = T::unsafe_try_from_slice(&buf[..])?;
Ok(Some(Value::Owned(value.to_owned())))
}
}
#[allow(unused)]
pub fn first(&self) -> Result<Option<&T>> {
pub fn first(&self) -> Result<Option<Value<'_, T>>> {
self.get_(0)
}
#[allow(unused)]
pub fn last(&self) -> Result<Option<&T>> {
pub fn last(&self) -> Result<Option<Value<'_, T>>> {
let len = self.len();
if len == 0 {
return Ok(None);
@@ -261,6 +326,7 @@ where
pub fn flush(&mut self) -> io::Result<()> {
self.disk_len += self.pushed.len();
self.reset_cache();
let mut bytes: Vec<u8> = vec![];
@@ -269,21 +335,28 @@ where
.into_iter()
.for_each(|v| bytes.extend_from_slice(v.unsafe_as_slice()));
self.file.write_all(&bytes)
// self.file.seek(SeekFrom::End(0))?;
self.file.write_all(&bytes)?;
// self.file_for_mmaps.write_all(&bytes)?;
// self.file_for_mmaps.sync_all()?;
// self.file_for_reads.sync_all()?;
// self.file_for_reads = Self::open_file(&self.pathbuf)?;
Ok(())
}
}
pub trait AnyStorableVec {
fn len(&self) -> usize;
fn is_empty(&self) -> bool;
fn reset_cache(&mut self);
fn flush(&mut self) -> io::Result<()>;
}
impl<I, T> AnyStorableVec for StorableVec<I, T>
where
I: Into<usize>,
T: Sized + Debug,
T: Sized + Debug + Clone,
{
fn len(&self) -> usize {
self.len()
@@ -293,10 +366,6 @@ where
self.is_empty()
}
fn reset_cache(&mut self) {
self.reset_cache();
}
fn flush(&mut self) -> io::Result<()> {
self.flush()
}