1use delivery_blob::compression::{ChunkedArchiveError, DataBuffer};
6use fuchsia_sync::Mutex;
7use mapping::{
8 DeliveryCommand, DeliveryHandler, PENDING_DELIVERY_COMMANDS_CAPACITY, PageRequest,
9 RawDeliveryCommand,
10};
11use std::ops::Range;
12use std::sync::Arc;
13use storage_ptr_slice::MutPtrByteSlice;
14use vmo_fifo::SyncSender;
15
16pub struct Verifier {
18 sender: Mutex<Option<SyncSender<RawDeliveryCommand>>>,
19}
20
21impl Verifier {
22 pub fn new(delivery_queue: zx::Vmo) -> Self {
23 let sender = if delivery_queue.get_size().unwrap_or(0) > 0 {
24 SyncSender::<RawDeliveryCommand>::new(
28 delivery_queue,
29 zx::system_get_page_size() as usize,
30 PENDING_DELIVERY_COMMANDS_CAPACITY,
31 )
32 .ok()
33 } else {
34 None
35 };
36 Self { sender: Mutex::new(sender) }
37 }
38}
39
40impl DeliveryHandler for Verifier {
41 type Request = Buffer;
42
43 fn get_page_request(self: &Arc<Self>, key: u64, original_range: Range<u64>) -> Buffer {
45 Buffer {
46 verifier: Arc::clone(self),
47 key,
48 read_range: original_range,
49 read_alignment: 0,
50 committed_len: 0,
51 delivered_len: 0,
52 data: Vec::new(),
53 }
54 }
55
56 fn register_blob(
58 &self,
59 key: u64,
60 merkle_leaves: &[[u8; 32]],
61 read_alignment: usize,
62 ) -> Result<(), anyhow::Error> {
63 let mut sender_guard = self.sender.lock();
64 if let Some(sender) = sender_guard.as_mut() {
65 let leaf_bytes: &[u8] = merkle_leaves.as_flattened();
66 let mut payload = sender.reserve_payload(leaf_bytes.len())?;
67 payload.data().copy_from_slice(leaf_bytes);
68 let cmd = DeliveryCommand::RegisterBlob {
69 key,
70 offset: payload.offset(),
71 length: leaf_bytes.len() as u32,
72 read_alignment: read_alignment as u32,
73 };
74 payload.commit(cmd.into())?;
75 }
76 Ok(())
77 }
78}
79
80pub struct Buffer {
83 verifier: Arc<Verifier>,
84 key: u64,
85 read_range: Range<u64>,
86 read_alignment: usize,
89 committed_len: usize,
91 delivered_len: usize,
93 data: Vec<u8>,
94}
95
96impl Buffer {
97 fn deliver_chunk(&mut self, size: usize) -> Result<(), ChunkedArchiveError> {
98 let chunk_data = &self.data[self.delivered_len..self.delivered_len + size];
100 let offset = self.read_range.start + self.delivered_len as u64;
101
102 let mut sender_guard = self.verifier.sender.lock();
103 if let Some(sender) = sender_guard.as_mut() {
104 let page_size = zx::system_get_page_size() as usize;
105 let aligned_size = size.next_multiple_of(page_size);
106 let mut payload = sender.reserve_payload(aligned_size).map_err(|e| {
107 log::error!(e:?; "Verifier::deliver_chunk: reserve_payload failed");
108 ChunkedArchiveError::IntegrityError
109 })?;
110
111 let payload_data = payload.data();
112 payload_data.subslice_mut(0..size).copy_from_slice(chunk_data);
113 payload_data.subslice_mut(size..aligned_size).fill(0);
114 let cmd = DeliveryCommand::Data {
115 key: self.key,
116 target_offset: offset,
117 length: aligned_size as u32,
118 offset: payload.offset(),
119 };
120 payload.commit(cmd.into()).map_err(|_| ChunkedArchiveError::IntegrityError)?;
121 }
122
123 self.delivered_len += size;
124 Ok(())
125 }
126}
127
128impl DataBuffer for Buffer {
129 fn range(&self) -> Range<u64> {
130 self.read_range.clone()
131 }
132
133 fn mut_ptr_slice(&mut self) -> MutPtrByteSlice<'_> {
139 assert!(!self.data.is_empty(), "prepare must be called before accessing mut_ptr_slice");
140 MutPtrByteSlice::from(&mut self.data[self.committed_len..])
141 }
142
143 fn commit(&mut self, size: usize) -> Result<(), ChunkedArchiveError> {
144 const VERIFICATION_FLUSH_THRESHOLD: usize = 96 * 1024;
145
146 self.committed_len += size;
147
148 if self.committed_len < self.data.len() {
149 let flush_threshold =
153 (VERIFICATION_FLUSH_THRESHOLD / self.read_alignment).max(1) * self.read_alignment;
154 if self.committed_len - self.delivered_len >= flush_threshold {
155 let to_deliver = ((self.committed_len - self.delivered_len) / self.read_alignment)
156 * self.read_alignment;
157 self.deliver_chunk(to_deliver)?;
158 }
159 } else if self.delivered_len < self.committed_len {
160 self.deliver_chunk(self.committed_len - self.delivered_len)?;
162 }
163
164 Ok(())
165 }
166}
167
168impl PageRequest for Buffer {
169 fn prepare(
170 &mut self,
171 read_range: Range<u64>,
172 read_alignment: usize,
173 ) -> Result<(), ChunkedArchiveError> {
174 assert!(self.data.is_empty(), "prepare must only be called once");
175 assert!(read_alignment > 0, "read_alignment must be non-zero");
176 self.read_range = read_range;
177 self.read_alignment = read_alignment;
178 let len = (self.read_range.end - self.read_range.start) as usize;
179 self.data = vec![0u8; len];
180 Ok(())
181 }
182}
183
184#[cfg(test)]
185mod tests {
186 use super::*;
187 use mapping::{DELIVERY_DATA_COMMAND, TARGET_READ_AHEAD_SIZE};
188 use test_case::test_case;
189
190 #[fuchsia::test]
191 fn test_verifier_buffer_incremental_commit() {
192 let delivery_queue = zx::Vmo::create(65536).unwrap();
193 let mut receiver = vmo_fifo::Receiver::<RawDeliveryCommand>::new(
194 delivery_queue.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
195 PENDING_DELIVERY_COMMANDS_CAPACITY,
196 )
197 .unwrap();
198
199 let verifier = Arc::new(Verifier::new(delivery_queue));
200 let key = 42u64;
201
202 let mut request = verifier.get_page_request(key, 0..8192);
203 request.prepare(0..8192, TARGET_READ_AHEAD_SIZE as usize).expect("prepare");
204
205 let page1_data = vec![0xAAu8; 4096];
207 request.mut_ptr_slice().subslice_mut(0..4096).copy_from_slice(&page1_data);
208 request.commit(4096).expect("commit page 1");
209
210 assert_eq!(request.mut_ptr_slice().len(), 4096);
212 assert!(receiver.is_empty());
214
215 let page2_data = vec![0xBBu8; 4096];
217 request.mut_ptr_slice().subslice_mut(0..4096).copy_from_slice(&page2_data);
218 request.commit(4096).expect("commit page 2");
219
220 assert_eq!(request.mut_ptr_slice().len(), 0);
222
223 let msg = receiver.peek().expect("msg");
225 assert_eq!(msg.opcode, DELIVERY_DATA_COMMAND);
226 assert_eq!(msg.key, key);
227 assert_eq!(msg.length, 8192);
228 assert_eq!(msg.target_offset, 0);
229 let mut buf = vec![0u8; 8192];
230 msg.payload_slice(msg.offset, msg.length).copy_to_slice(&mut buf);
231 assert_eq!(&buf[..4096], &page1_data[..]);
232 assert_eq!(&buf[4096..], &page2_data[..]);
233 msg.pop().expect("pop msg");
234 }
235
236 #[fuchsia::test]
237 fn test_verifier_buffer_page_aligned_commits() {
238 let delivery_queue = zx::Vmo::create(65536).unwrap();
239 let mut receiver = vmo_fifo::Receiver::<RawDeliveryCommand>::new(
240 delivery_queue.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
241 PENDING_DELIVERY_COMMANDS_CAPACITY,
242 )
243 .unwrap();
244
245 let verifier = Arc::new(Verifier::new(delivery_queue));
246 let key = 43u64;
247
248 let mut request = verifier.get_page_request(key, 0..5000);
249 request.prepare(0..5000, TARGET_READ_AHEAD_SIZE as usize).expect("prepare");
250
251 let data = vec![0xCCu8; 5000];
252
253 request.mut_ptr_slice().subslice_mut(0..4096).copy_from_slice(&data[..4096]);
255 request.commit(4096).expect("commit 4096 bytes");
256 assert!(receiver.is_empty());
257
258 request.mut_ptr_slice().subslice_mut(0..904).copy_from_slice(&data[4096..5000]);
260 request.commit(904).expect("commit 904 bytes");
261
262 let msg = receiver.peek().expect("msg");
264 assert_eq!(msg.target_offset, 0);
265 assert_eq!(msg.length, 8192);
266 let mut buf = vec![0u8; 8192];
267 msg.payload_slice(msg.offset, msg.length).copy_to_slice(&mut buf);
268 assert_eq!(&buf[..5000], &data[..]);
269 assert_eq!(&buf[5000..], &[0u8; 3192]);
270 msg.pop().expect("pop msg");
271 }
272
273 #[test_case(32 * 1024, 128 * 1024; "zstd_32k_read_128k")]
274 #[test_case(48 * 1024, 96 * 1024; "zstd_48k_read_96k")]
275 #[test_case(152 * 1024, 152 * 1024; "zstd_152k_read_152k")]
276 #[fuchsia::test]
277 fn test_verifier_buffer_delivery_data_size_chunking(
278 zstd_chunk_size: usize,
279 read_alignment: usize,
280 ) {
281 let total_size = read_alignment * 2;
282 let delivery_queue = zx::Vmo::create(total_size as u64 + 65536).unwrap();
283 let mut receiver = vmo_fifo::Receiver::<RawDeliveryCommand>::new(
284 delivery_queue.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
285 PENDING_DELIVERY_COMMANDS_CAPACITY,
286 )
287 .unwrap();
288
289 let verifier = Arc::new(Verifier::new(delivery_queue));
290 let key = 44u64;
291
292 let mut request = verifier.get_page_request(key, 0..total_size as u64);
293 request.prepare(0..total_size as u64, read_alignment).expect("prepare");
294
295 let chunk = vec![0x55u8; zstd_chunk_size];
296 let chunks_per_read = read_alignment / zstd_chunk_size;
297
298 for _ in 0..(chunks_per_read - 1) {
300 request.mut_ptr_slice().subslice_mut(0..zstd_chunk_size).copy_from_slice(&chunk);
301 request.commit(zstd_chunk_size).expect("commit");
302 }
303 assert!(receiver.is_empty());
304
305 request.mut_ptr_slice().subslice_mut(0..zstd_chunk_size).copy_from_slice(&chunk);
307 request.commit(zstd_chunk_size).expect("commit");
308
309 let msg1 = receiver.peek().expect("msg1");
311 assert_eq!(msg1.target_offset, 0);
312 assert_eq!(msg1.length, read_alignment as u32);
313 msg1.pop().expect("pop msg1");
314
315 for _ in 0..chunks_per_read {
317 request.mut_ptr_slice().subslice_mut(0..zstd_chunk_size).copy_from_slice(&chunk);
318 request.commit(zstd_chunk_size).expect("commit");
319 }
320
321 let msg2 = receiver.peek().expect("msg2");
323 assert_eq!(msg2.target_offset, read_alignment as u64);
324 assert_eq!(msg2.length, read_alignment as u32);
325 msg2.pop().expect("pop msg2");
326 }
327
328 #[fuchsia::test]
329 #[should_panic(expected = "prepare must only be called once")]
330 fn test_verifier_buffer_prepare_multiple_times_panics() {
331 let delivery_queue = zx::Vmo::create(4096).unwrap();
332 let verifier = Arc::new(Verifier::new(delivery_queue));
333
334 let key = 46u64;
335 let mut request = verifier.get_page_request(key, 0..8192);
336 request.prepare(0..4096, TARGET_READ_AHEAD_SIZE as usize).expect("first prepare");
337 let _ = request.prepare(0..8192, TARGET_READ_AHEAD_SIZE as usize);
338 }
339
340 #[fuchsia::test]
341 fn test_verifier_buffer_supplies_pages_via_delivery_receiver() {
342 let pager = Arc::new(zx::Pager::create(zx::PagerOptions::empty()).unwrap());
343 let port = zx::Port::create();
344 let key = 44u64;
345 let paged_vmo = pager.create_vmo(zx::VmoOptions::empty(), &port, key, 8192).unwrap();
346
347 let delivery_queue = zx::Vmo::create(65536).unwrap();
348 let vmo_provider = Arc::new(blob_pager_and_verifier::TestVmoProvider::new(
349 pager.clone(),
350 delivery_queue.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
351 ));
352 vmo_provider
353 .register_vmo(key, paged_vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap());
354 let receiver = vmo_fifo::Receiver::<RawDeliveryCommand>::new(
355 delivery_queue.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
356 PENDING_DELIVERY_COMMANDS_CAPACITY,
357 )
358 .unwrap();
359 let _processor = blob_pager_and_verifier::DeliveryQueueProcessor::spawn(
360 receiver,
361 vmo_provider,
362 delivery_queue.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
363 )
364 .unwrap();
365
366 let verifier = Arc::new(Verifier::new(delivery_queue));
367 let mut request = verifier.get_page_request(key, 0..8192);
368 request.prepare(0..8192, TARGET_READ_AHEAD_SIZE as usize).expect("prepare");
369
370 let page1_data = vec![0xAAu8; 4096];
371 request.mut_ptr_slice().subslice_mut(0..4096).copy_from_slice(&page1_data);
372 request.commit(4096).expect("commit page 1");
373
374 let page2_data = vec![0xBBu8; 4096];
375 request.mut_ptr_slice().subslice_mut(0..4096).copy_from_slice(&page2_data);
376 request.commit(4096).expect("commit page 2");
377
378 let mut read_buf = vec![0u8; 8192];
379 paged_vmo.read(&mut read_buf, 0).expect("read paged_vmo");
380 assert_eq!(&read_buf[..4096], &page1_data[..]);
381 assert_eq!(&read_buf[4096..8192], &page2_data[..]);
382 }
383
384 #[fuchsia::test]
385 fn test_verifier_register_blob() {
386 let delivery_queue = zx::Vmo::create(65536).unwrap();
387 let mut receiver = vmo_fifo::Receiver::<RawDeliveryCommand>::new(
388 delivery_queue.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
389 PENDING_DELIVERY_COMMANDS_CAPACITY,
390 )
391 .unwrap();
392
393 let verifier = Arc::new(Verifier::new(delivery_queue));
394 let key = 42u64;
395 let leaves = [[0xABu8; 32], [0xCDu8; 32]];
396
397 verifier.register_blob(key, &leaves, 96 * 1024).expect("register_blob failed");
398
399 let msg = receiver.peek().expect("peek msg");
400 assert_eq!(msg.opcode, mapping::DELIVERY_REGISTER_BLOB_COMMAND);
401 assert_eq!(msg.key, key);
402 assert_eq!(msg.length, 64);
403 assert_eq!(msg.read_alignment, 96 * 1024);
404 let mut buf = vec![0u8; 64];
405 msg.payload_slice(msg.offset, msg.length).copy_to_slice(&mut buf);
406 assert_eq!(&buf[..32], &[0xABu8; 32]);
407 assert_eq!(&buf[32..], &[0xCDu8; 32]);
408 msg.pop().expect("pop msg failed");
409 }
410
411 #[fuchsia::test]
412 fn test_verifier_buffer_96k_overlap() {
413 let total_size = 128 * 1024;
414 let chunk_size = 32 * 1024;
415 let delivery_queue = zx::Vmo::create(total_size as u64 * 2 + 65536).unwrap();
416 let mut receiver = vmo_fifo::Receiver::<RawDeliveryCommand>::new(
417 delivery_queue.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
418 PENDING_DELIVERY_COMMANDS_CAPACITY,
419 )
420 .unwrap();
421
422 let verifier = Arc::new(Verifier::new(delivery_queue));
423 let key = 45u64;
424
425 let mut request = verifier.get_page_request(key, 0..total_size as u64);
426 request.prepare(0..total_size as u64, chunk_size).expect("prepare");
427
428 let chunk = vec![0x55u8; chunk_size];
429
430 for _ in 0..2 {
432 request.mut_ptr_slice().subslice_mut(0..chunk_size).copy_from_slice(&chunk);
433 request.commit(chunk_size).expect("commit");
434 }
435 assert!(receiver.is_empty());
436
437 request.mut_ptr_slice().subslice_mut(0..chunk_size).copy_from_slice(&chunk);
440 request.commit(chunk_size).expect("commit");
441
442 let msg1 = receiver.peek().expect("msg1");
443 assert_eq!(msg1.target_offset, 0);
444 assert_eq!(msg1.length, 96 * 1024);
445 msg1.pop().expect("pop msg1");
446
447 request.mut_ptr_slice().subslice_mut(0..chunk_size).copy_from_slice(&chunk);
449 request.commit(chunk_size).expect("commit");
450
451 let msg2 = receiver.peek().expect("msg2");
452 assert_eq!(msg2.target_offset, 96 * 1024);
453 assert_eq!(msg2.length, 32 * 1024);
454 msg2.pop().expect("pop msg2");
455 }
456}