use bao_tree::{
io::{fsm::BaoContentItem, sync::WriteAt},
BaoTree,
};
use bytes::Bytes;
use crate::{
util::{compute_outboard, copy_limited_slice, SparseMemFile},
IROH_BLOCK_SIZE,
};
#[derive(Debug, Default)]
pub struct MutableMemStorage {
pub data: SparseMemFile,
pub outboard: SparseMemFile,
pub sizes: SizeInfo,
}
#[derive(Debug, Default)]
pub struct SizeInfo {
pub offset: u64,
pub size: u64,
}
impl SizeInfo {
pub(crate) fn complete(size: u64) -> Self {
let mask = (1 << IROH_BLOCK_SIZE.chunk_log()) - 1;
let last_chunk_offset = size & mask;
Self {
offset: last_chunk_offset,
size,
}
}
fn write(&mut self, offset: u64, size: u64) {
if offset >= self.offset {
self.offset = offset;
self.size = size;
}
}
pub fn current_size(&self) -> u64 {
self.size
}
}
impl MutableMemStorage {
pub fn complete(
bytes: Bytes,
cb: impl Fn(u64) + Send + Sync + 'static,
) -> (Self, iroh_base::hash::Hash) {
let (hash, outboard) = compute_outboard(&bytes[..], bytes.len() as u64, move |offset| {
cb(offset);
Ok(())
})
.unwrap();
let outboard = outboard.unwrap_or_default();
let res = Self {
data: bytes.to_vec().into(),
outboard: outboard.into(),
sizes: SizeInfo::complete(bytes.len() as u64),
};
(res, hash)
}
pub(super) fn current_size(&self) -> u64 {
self.sizes.current_size()
}
pub(super) fn read_data_at(&self, offset: u64, len: usize) -> Bytes {
copy_limited_slice(&self.data, offset, len)
}
pub(super) fn data_len(&self) -> u64 {
self.data.len() as u64
}
pub(super) fn read_outboard_at(&self, offset: u64, len: usize) -> Bytes {
copy_limited_slice(&self.outboard, offset, len)
}
pub(super) fn outboard_len(&self) -> u64 {
self.outboard.len() as u64
}
pub(super) fn write_batch(
&mut self,
size: u64,
batch: &[BaoContentItem],
) -> std::io::Result<()> {
let tree = BaoTree::new(size, IROH_BLOCK_SIZE);
for item in batch {
match item {
BaoContentItem::Parent(parent) => {
if let Some(offset) = tree.pre_order_offset(parent.node) {
let o0 = offset
.checked_mul(64)
.expect("u64 overflow multiplying to hash pair offset");
let o1 = o0.checked_add(32).expect("u64 overflow");
let outboard = &mut self.outboard;
outboard.write_all_at(o0, parent.pair.0.as_bytes().as_slice())?;
outboard.write_all_at(o1, parent.pair.1.as_bytes().as_slice())?;
}
}
BaoContentItem::Leaf(leaf) => {
self.sizes.write(leaf.offset, size);
self.data.write_all_at(leaf.offset, leaf.data.as_ref())?;
}
}
}
Ok(())
}
}