iroh_blobs/store/
mutable_mem_storage.rs1use bao_tree::{
2 io::{fsm::BaoContentItem, sync::WriteAt},
3 BaoTree,
4};
5use bytes::Bytes;
6
7use crate::{
8 util::{compute_outboard, copy_limited_slice, SparseMemFile},
9 IROH_BLOCK_SIZE,
10};
11
12#[derive(Debug, Default)]
18pub struct MutableMemStorage {
19 pub data: SparseMemFile,
21 pub outboard: SparseMemFile,
23 pub sizes: SizeInfo,
25}
26
27#[derive(Debug, Default)]
32pub struct SizeInfo {
33 pub offset: u64,
34 pub size: u64,
35}
36
37impl SizeInfo {
38 pub(crate) fn complete(size: u64) -> Self {
40 let mask = (1 << IROH_BLOCK_SIZE.chunk_log()) - 1;
41 let last_chunk_offset = size & mask;
43 Self {
44 offset: last_chunk_offset,
45 size,
46 }
47 }
48
49 fn write(&mut self, offset: u64, size: u64) {
51 if offset >= self.offset {
53 self.offset = offset;
54 self.size = size;
55 }
56 }
57
58 pub fn current_size(&self) -> u64 {
60 self.size
61 }
62}
63
64impl MutableMemStorage {
65 pub fn complete(bytes: Bytes, cb: impl Fn(u64) + Send + Sync + 'static) -> (Self, crate::Hash) {
67 let (hash, outboard) = compute_outboard(&bytes[..], bytes.len() as u64, move |offset| {
68 cb(offset);
69 Ok(())
70 })
71 .unwrap();
72 let outboard = outboard.unwrap_or_default();
73 let res = Self {
74 data: bytes.to_vec().into(),
75 outboard: outboard.into(),
76 sizes: SizeInfo::complete(bytes.len() as u64),
77 };
78 (res, hash)
79 }
80
81 pub(super) fn current_size(&self) -> u64 {
82 self.sizes.current_size()
83 }
84
85 pub(super) fn read_data_at(&self, offset: u64, len: usize) -> Bytes {
86 copy_limited_slice(&self.data, offset, len)
87 }
88
89 pub(super) fn data_len(&self) -> u64 {
90 self.data.len() as u64
91 }
92
93 pub(super) fn read_outboard_at(&self, offset: u64, len: usize) -> Bytes {
94 copy_limited_slice(&self.outboard, offset, len)
95 }
96
97 pub(super) fn outboard_len(&self) -> u64 {
98 self.outboard.len() as u64
99 }
100
101 pub(super) fn write_batch(
102 &mut self,
103 size: u64,
104 batch: &[BaoContentItem],
105 ) -> std::io::Result<()> {
106 let tree = BaoTree::new(size, IROH_BLOCK_SIZE);
107 for item in batch {
108 match item {
109 BaoContentItem::Parent(parent) => {
110 if let Some(offset) = tree.pre_order_offset(parent.node) {
111 let o0 = offset
112 .checked_mul(64)
113 .expect("u64 overflow multiplying to hash pair offset");
114 let o1 = o0.checked_add(32).expect("u64 overflow");
115 let outboard = &mut self.outboard;
116 outboard.write_all_at(o0, parent.pair.0.as_bytes().as_slice())?;
117 outboard.write_all_at(o1, parent.pair.1.as_bytes().as_slice())?;
118 }
119 }
120 BaoContentItem::Leaf(leaf) => {
121 self.sizes.write(leaf.offset, size);
122 self.data.write_all_at(leaf.offset, leaf.data.as_ref())?;
123 }
124 }
125 }
126 Ok(())
127 }
128}