mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-05-03 18:59:10 -07:00
200 lines
4.8 KiB
Rust
200 lines
4.8 KiB
Rust
use std::sync::Arc;
|
|
|
|
use brk_core::{Error, Result, Version};
|
|
use parking_lot::RwLock;
|
|
use zerocopy::{FromBytes, IntoBytes};
|
|
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
|
|
|
use crate::{File, Stamp};
|
|
|
|
use super::Format;
|
|
|
|
const HEADER_VERSION: Version = Version::ONE;
|
|
pub const HEADER_OFFSET: usize = size_of::<HeaderInner>();
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct Header {
|
|
inner: Arc<RwLock<HeaderInner>>,
|
|
modified: bool,
|
|
}
|
|
|
|
impl Header {
|
|
pub fn create_and_write(
|
|
file: &File,
|
|
region_index: usize,
|
|
vec_version: Version,
|
|
format: Format,
|
|
) -> Result<Self> {
|
|
let inner = HeaderInner::create_and_write(file, region_index, vec_version, format)?;
|
|
Ok(Self {
|
|
inner: Arc::new(RwLock::new(inner)),
|
|
modified: false,
|
|
})
|
|
}
|
|
|
|
pub fn import_and_verify(
|
|
file: &File,
|
|
region_index: usize,
|
|
region_len: u64,
|
|
vec_version: Version,
|
|
format: Format,
|
|
) -> Result<Self> {
|
|
let inner =
|
|
HeaderInner::import_and_verify(file, region_index, region_len, vec_version, format)?;
|
|
Ok(Self {
|
|
inner: Arc::new(RwLock::new(inner)),
|
|
modified: false,
|
|
})
|
|
}
|
|
|
|
pub fn update_stamp(&mut self, stamp: Stamp) {
|
|
self.modified = true;
|
|
self.inner.write().stamp = stamp;
|
|
}
|
|
|
|
pub fn update_computed_version(&mut self, computed_version: Version) {
|
|
self.modified = true;
|
|
self.inner.write().computed_version = computed_version;
|
|
}
|
|
|
|
pub fn modified(&self) -> bool {
|
|
self.modified
|
|
}
|
|
|
|
pub fn vec_version(&self) -> Version {
|
|
self.inner.read().vec_version
|
|
}
|
|
|
|
pub fn computed_version(&self) -> Version {
|
|
self.inner.read().computed_version
|
|
}
|
|
|
|
pub fn stamp(&self) -> Stamp {
|
|
self.inner.read().stamp
|
|
}
|
|
|
|
pub fn write(&mut self, file: &File, region_index: usize) -> Result<()> {
|
|
self.inner.read().write(file, region_index)?;
|
|
self.modified = false;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Debug, Clone, FromBytes, IntoBytes, Immutable, KnownLayout)]
|
|
struct HeaderInner {
|
|
pub header_version: Version,
|
|
pub vec_version: Version,
|
|
pub computed_version: Version,
|
|
pub stamp: Stamp,
|
|
pub compressed: ZeroCopyBool,
|
|
}
|
|
|
|
impl HeaderInner {
|
|
pub fn create_and_write(
|
|
file: &File,
|
|
region_index: usize,
|
|
vec_version: Version,
|
|
format: Format,
|
|
) -> Result<Self> {
|
|
let header = Self {
|
|
header_version: HEADER_VERSION,
|
|
vec_version,
|
|
computed_version: Version::default(),
|
|
stamp: Stamp::default(),
|
|
compressed: ZeroCopyBool::from(format),
|
|
};
|
|
header.write(file, region_index)?;
|
|
Ok(header)
|
|
}
|
|
|
|
pub fn write(&self, file: &File, region_index: usize) -> Result<()> {
|
|
file.write_all_to_region_at(region_index.into(), self.as_bytes(), 0)
|
|
}
|
|
|
|
pub fn import_and_verify(
|
|
file: &File,
|
|
region_index: usize,
|
|
region_len: u64,
|
|
vec_version: Version,
|
|
format: Format,
|
|
) -> Result<Self> {
|
|
let len = region_len;
|
|
|
|
if len < HEADER_OFFSET as u64 {
|
|
return Err(Error::WrongLength);
|
|
}
|
|
|
|
let reader = file.create_region_reader(region_index.into())?;
|
|
let slice = reader.read(0, HEADER_OFFSET as u64);
|
|
let header = HeaderInner::read_from_bytes(slice)?;
|
|
|
|
if header.header_version != HEADER_VERSION {
|
|
return Err(Error::DifferentVersion {
|
|
found: header.header_version,
|
|
expected: HEADER_VERSION,
|
|
});
|
|
}
|
|
if header.vec_version != vec_version {
|
|
return Err(Error::DifferentVersion {
|
|
found: header.vec_version,
|
|
expected: vec_version,
|
|
});
|
|
}
|
|
if header.compressed.is_broken() {
|
|
return Err(Error::WrongEndian);
|
|
}
|
|
if (header.compressed.is_true() && format.is_raw())
|
|
|| (header.compressed.is_false() && format.is_compressed())
|
|
{
|
|
return Err(Error::DifferentCompressionMode);
|
|
}
|
|
|
|
Ok(header)
|
|
}
|
|
}
|
|
|
|
#[derive(
|
|
Debug,
|
|
Clone,
|
|
Copy,
|
|
Default,
|
|
PartialEq,
|
|
Eq,
|
|
PartialOrd,
|
|
Ord,
|
|
FromBytes,
|
|
IntoBytes,
|
|
Immutable,
|
|
KnownLayout,
|
|
)]
|
|
#[repr(C)]
|
|
pub struct ZeroCopyBool(u64);
|
|
|
|
impl ZeroCopyBool {
|
|
pub const TRUE: Self = Self(1);
|
|
pub const FALSE: Self = Self(0);
|
|
|
|
pub fn is_true(&self) -> bool {
|
|
*self == Self::TRUE
|
|
}
|
|
|
|
pub fn is_false(&self) -> bool {
|
|
*self == Self::FALSE
|
|
}
|
|
|
|
pub fn is_broken(&self) -> bool {
|
|
*self > Self::TRUE
|
|
}
|
|
}
|
|
|
|
impl From<Format> for ZeroCopyBool {
|
|
fn from(value: Format) -> Self {
|
|
if value.is_raw() {
|
|
Self::FALSE
|
|
} else {
|
|
Self::TRUE
|
|
}
|
|
}
|
|
}
|