mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-10 02:28:13 -07:00
120 lines
3.0 KiB
Rust
120 lines
3.0 KiB
Rust
use std::{
|
|
fs::{self, OpenOptions},
|
|
io::{self, Seek, SeekFrom, Write},
|
|
path::{Path, PathBuf},
|
|
};
|
|
|
|
use brk_core::Result;
|
|
use rayon::prelude::*;
|
|
use zerocopy::{IntoBytes, TryFromBytes};
|
|
|
|
use super::{CompressedPageMetadata, UnsafeSlice};
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct CompressedPagesMetadata {
|
|
vec: Vec<CompressedPageMetadata>,
|
|
change_at: Option<usize>,
|
|
path: PathBuf,
|
|
}
|
|
|
|
impl CompressedPagesMetadata {
|
|
const PAGE_SIZE: usize = size_of::<CompressedPageMetadata>();
|
|
|
|
pub fn read(path: &Path) -> Result<CompressedPagesMetadata> {
|
|
let path = path.join("pages_meta");
|
|
|
|
let slf = Self {
|
|
vec: fs::read(&path)
|
|
.unwrap_or_default()
|
|
.chunks(Self::PAGE_SIZE)
|
|
.map(|bytes| {
|
|
if bytes.len() != Self::PAGE_SIZE {
|
|
panic!()
|
|
}
|
|
CompressedPageMetadata::try_read_from_bytes(bytes).unwrap()
|
|
})
|
|
.collect::<Vec<_>>(),
|
|
path: path.to_owned(),
|
|
change_at: None,
|
|
};
|
|
|
|
Ok(slf)
|
|
}
|
|
|
|
pub fn write(&mut self) -> io::Result<()> {
|
|
if self.change_at.is_none() {
|
|
return Ok(());
|
|
}
|
|
|
|
let change_at = self.change_at.take().unwrap();
|
|
|
|
let len = (self.vec.len() - change_at) * Self::PAGE_SIZE;
|
|
|
|
let mut bytes: Vec<u8> = vec![0; len];
|
|
|
|
let unsafe_bytes = UnsafeSlice::new(&mut bytes);
|
|
|
|
self.vec[change_at..]
|
|
.par_iter()
|
|
.enumerate()
|
|
.for_each(|(i, v)| unsafe_bytes.copy_slice(i * Self::PAGE_SIZE, v.as_bytes()));
|
|
|
|
let mut file = OpenOptions::new()
|
|
.read(true)
|
|
.create(true)
|
|
.truncate(false)
|
|
.append(true)
|
|
.open(&self.path)?;
|
|
|
|
file.set_len((change_at * Self::PAGE_SIZE) as u64)?;
|
|
file.seek(SeekFrom::End(0))?;
|
|
|
|
file.write_all(&bytes)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn len(&self) -> usize {
|
|
self.vec.len()
|
|
}
|
|
|
|
pub fn is_empty(&self) -> bool {
|
|
self.len() == 0
|
|
}
|
|
|
|
pub fn get(&self, page_index: usize) -> Option<&CompressedPageMetadata> {
|
|
self.vec.get(page_index)
|
|
}
|
|
|
|
pub fn last(&self) -> Option<&CompressedPageMetadata> {
|
|
self.vec.last()
|
|
}
|
|
|
|
pub fn pop(&mut self) -> Option<CompressedPageMetadata> {
|
|
self.vec.pop()
|
|
}
|
|
|
|
pub fn push(&mut self, page_index: usize, page: CompressedPageMetadata) {
|
|
if page_index != self.vec.len() {
|
|
panic!();
|
|
}
|
|
|
|
self.set_changed_at(page_index);
|
|
|
|
self.vec.push(page);
|
|
}
|
|
|
|
fn set_changed_at(&mut self, page_index: usize) {
|
|
if self.change_at.is_none_or(|pi| pi > page_index) {
|
|
self.change_at.replace(page_index);
|
|
}
|
|
}
|
|
|
|
pub fn truncate(&mut self, page_index: usize) -> Option<CompressedPageMetadata> {
|
|
let page = self.get(page_index).cloned();
|
|
self.vec.truncate(page_index);
|
|
self.set_changed_at(page_index);
|
|
page
|
|
}
|
|
}
|