1use crate::WriteOptions;
4use futures::future::{BoxFuture, FutureExt as _, Shared};
5
6pub mod paged;
7mod read;
8mod tip;
9mod write;
10
11pub use read::Read;
12pub use write::Write;
13
14#[derive(Clone)]
20struct Completion(Shared<BoxFuture<'static, Result<(), crate::Error>>>);
21
22impl Completion {
23 fn handle(&self) -> crate::Handle<()> {
25 crate::Handle::from_future(self.0.clone())
26 }
27
28 async fn wait(&self) -> Result<(), crate::Error> {
30 self.0.clone().await
31 }
32}
33
34impl From<crate::Handle<()>> for Completion {
35 fn from(handle: crate::Handle<()>) -> Self {
36 Self(handle.boxed().shared())
37 }
38}
39
40enum SyncState {
54 Clean,
56 Dirty,
58 Pending(Completion),
60}
61
62impl SyncState {
63 const fn is_clean(&self) -> bool {
65 matches!(self, Self::Clean)
66 }
67
68 async fn wait_for_pending(&mut self) -> Result<(), crate::Error> {
70 let Self::Pending(pending) = self else {
71 return Ok(());
72 };
73 pending.wait().await?;
74 *self = Self::Clean;
75 Ok(())
76 }
77
78 async fn write_at(
80 &mut self,
81 blob: &impl crate::Blob,
82 offset: u64,
83 bufs: impl Into<crate::IoBufs> + Send,
84 options: WriteOptions,
85 ) -> Result<(), crate::Error> {
86 self.wait_for_pending().await?;
87 let bufs = bufs.into();
88 if !options.contains(WriteOptions::SYNC) {
89 blob.write_at(offset, bufs, options).await?;
90 *self = Self::Dirty;
91 return Ok(());
92 }
93
94 match self {
95 Self::Dirty => {
96 blob.write_at(offset, bufs, options.without(WriteOptions::SYNC))
98 .await?;
99 blob.sync().await?;
100 *self = Self::Clean;
101 Ok(())
102 }
103 Self::Clean => blob.write_at(offset, bufs, options).await,
104 Self::Pending(_) => unreachable!("pending sync waited above"),
105 }
106 }
107
108 async fn resize(&mut self, blob: &impl crate::Blob, len: u64) -> Result<(), crate::Error> {
110 self.wait_for_pending().await?;
111 blob.resize(len).await?;
112 *self = Self::Dirty;
113 Ok(())
114 }
115
116 async fn sync(&mut self, blob: &impl crate::Blob) -> Result<(), crate::Error> {
118 self.wait_for_pending().await?;
119 if matches!(self, Self::Clean) {
120 return Ok(());
121 }
122 blob.sync().await?;
123 *self = Self::Clean;
124 Ok(())
125 }
126
127 async fn start_sync(&mut self, blob: &impl crate::Blob) -> crate::Handle<()> {
129 match self {
130 Self::Clean => crate::Handle::ready(Ok(())),
131 Self::Dirty => {
132 let pending = Completion::from(blob.start_sync().await);
134 let handle = pending.handle();
135 *self = Self::Pending(pending);
136 handle
137 }
138 Self::Pending(pending) => pending.handle(),
139 }
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146 use crate::{
147 Blob as _, Error, Handle, IoBufMut, IoBufs, IoBufsMut, ReadOptions, Runner, Storage,
148 WriteOptions, deterministic,
149 mocks::{DelayedSyncBlob, WriteFaultContext, WriteFaults, next_pending_sync},
150 };
151 use commonware_macros::test_traced;
152 use commonware_utils::{NZUsize, sync::Mutex};
153 use futures::FutureExt;
154 use std::sync::Arc;
155
156 #[derive(Default)]
157 struct RangeSyncState {
158 data: Vec<u8>,
163
164 durable: Vec<u8>,
166
167 writes: usize,
169
170 full_syncs: usize,
172
173 range_syncs: usize,
175
176 uncached_writes: usize,
178
179 uncached_range_syncs: usize,
181 }
182
183 pub struct SyncTrackingBlob {
190 state: Mutex<RangeSyncState>,
191 }
192
193 impl SyncTrackingBlob {
194 pub fn new() -> Self {
195 Self {
196 state: Mutex::new(RangeSyncState::default()),
197 }
198 }
199
200 pub fn snapshot(&self) -> (Vec<u8>, usize, usize, usize) {
201 let state = self.state.lock();
202 (
203 state.durable.clone(),
204 state.writes,
205 state.full_syncs,
206 state.range_syncs,
207 )
208 }
209
210 pub fn size(&self) -> u64 {
211 self.state.lock().data.len() as u64
212 }
213
214 pub fn uncached_snapshot(&self) -> (usize, usize) {
215 let state = self.state.lock();
216 (state.uncached_writes, state.uncached_range_syncs)
217 }
218
219 fn write(data: &mut Vec<u8>, offset: u64, buf: &[u8]) -> Result<(), Error> {
220 let start = usize::try_from(offset).map_err(|_| Error::OffsetOverflow)?;
221 let end = start.checked_add(buf.len()).ok_or(Error::OffsetOverflow)?;
222 if end > data.len() {
223 data.resize(end, 0);
224 }
225 data[start..end].copy_from_slice(buf);
226 Ok(())
227 }
228 }
229
230 impl crate::Blob for SyncTrackingBlob {
231 async fn read_at(
232 &self,
233 offset: u64,
234 len: usize,
235 options: ReadOptions,
236 ) -> Result<IoBufsMut, Error> {
237 self.read_at_buf(offset, len, IoBufMut::with_capacity(len), options)
238 .await
239 }
240
241 async fn read_at_buf(
242 &self,
243 offset: u64,
244 len: usize,
245 buf: impl Into<IoBufsMut> + Send,
246 _options: ReadOptions,
247 ) -> Result<IoBufsMut, Error> {
248 let start = usize::try_from(offset).map_err(|_| Error::OffsetOverflow)?;
249 let end = start.checked_add(len).ok_or(Error::OffsetOverflow)?;
250 let state = self.state.lock();
251 if end > state.data.len() {
252 return Err(Error::BlobInsufficientLength);
253 }
254
255 let mut out = buf.into();
256 assert!(out.capacity() >= len);
257 unsafe { out.set_len(len) };
259 out.copy_from_slice(&state.data[start..end]);
260 Ok(out)
261 }
262
263 async fn write_at(
264 &self,
265 offset: u64,
266 buf: impl Into<IoBufs> + Send,
267 options: WriteOptions,
268 ) -> Result<(), Error> {
269 let buf = buf.into().coalesce();
270 let mut state = self.state.lock();
271 Self::write(&mut state.data, offset, buf.as_ref())?;
272 state.writes += 1;
273
274 let sync = options.contains(WriteOptions::SYNC);
275 if sync {
276 Self::write(&mut state.durable, offset, buf.as_ref())?;
277 state.range_syncs += 1;
278 }
279 if options.contains(WriteOptions::DONT_CACHE) {
280 if sync {
281 state.uncached_range_syncs += 1;
282 } else {
283 state.uncached_writes += 1;
284 }
285 }
286 Ok(())
287 }
288
289 async fn resize(&self, len: u64) -> Result<(), Error> {
290 let len = usize::try_from(len).map_err(|_| Error::OffsetOverflow)?;
291 self.state.lock().data.resize(len, 0);
292 Ok(())
293 }
294
295 async fn sync(&self) -> Result<(), Error> {
296 let mut state = self.state.lock();
297 state.durable = state.data.clone();
298 state.full_syncs += 1;
299 Ok(())
300 }
301
302 async fn start_sync(&self) -> Handle<()> {
303 Handle::ready(self.sync().await)
304 }
305 }
306
307 #[test_traced]
308 fn test_read_basic() {
309 let executor = deterministic::Runner::default();
310 executor.start(|context| async move {
311 let data = b"Hello, world! This is a test.";
313 let (blob, size) = context.open("partition", b"test").await.unwrap();
314 assert_eq!(size, 0);
315 blob.write_at(0, data, WriteOptions::default())
316 .await
317 .unwrap();
318 let size = data.len() as u64;
319
320 let mut reader = Read::new(blob, size, NZUsize!(10));
322
323 let read = reader.read(5).await.unwrap().coalesce();
325 assert_eq!(read.as_ref(), b"Hello");
326
327 let read = reader.read(14).await.unwrap().coalesce();
329 assert_eq!(read.as_ref(), b", world! This ");
330
331 assert_eq!(reader.position(), 19);
333
334 let read = reader.read(7).await.unwrap().coalesce();
336 assert_eq!(read.as_ref(), b"is a te");
337
338 let result = reader.read(5).await;
340 assert!(matches!(result, Err(Error::BlobInsufficientLength)));
341 });
342 }
343
344 #[test_traced]
345 fn test_read_cross_boundary() {
346 let executor = deterministic::Runner::default();
347 executor.start(|context| async move {
348 let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
350 let (blob, size) = context.open("partition", b"test").await.unwrap();
351 assert_eq!(size, 0);
352 blob.write_at(0, data, WriteOptions::default())
353 .await
354 .unwrap();
355 let size = data.len() as u64;
356
357 let mut reader = Read::new(blob, size, NZUsize!(10));
359
360 let read = reader.read(15).await.unwrap().coalesce();
362 assert_eq!(read.as_ref(), b"ABCDEFGHIJKLMNO");
363
364 assert_eq!(reader.position(), 15);
366
367 let read = reader.read(11).await.unwrap().coalesce();
369 assert_eq!(read.as_ref(), b"PQRSTUVWXYZ");
370
371 assert_eq!(reader.position(), 26);
373 assert_eq!(reader.blob_remaining(), 0);
374 });
375 }
376
377 #[test_traced]
379 fn test_read_to_end_then_rewind_and_read_again() {
380 let executor = deterministic::Runner::default();
381 executor.start(|context| async move {
382 let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
383 let (blob, size) = context.open("partition", b"test").await.unwrap();
384 assert_eq!(size, 0);
385 blob.write_at(0, data, WriteOptions::default())
386 .await
387 .unwrap();
388 let size = data.len() as u64;
389
390 let mut reader = Read::new(blob, size, NZUsize!(20));
391
392 let read = reader.read(21).await.unwrap().coalesce();
394 assert_eq!(read.as_ref(), b"ABCDEFGHIJKLMNOPQRSTU");
395
396 assert_eq!(reader.position(), 21);
398
399 let read = reader.read(5).await.unwrap().coalesce();
401 assert_eq!(read.as_ref(), b"VWXYZ");
402
403 reader.seek_to(0).unwrap();
405 let read = reader.read(21).await.unwrap().coalesce();
406 assert_eq!(read.as_ref(), b"ABCDEFGHIJKLMNOPQRSTU");
407 });
408 }
409
410 #[test_traced]
411 fn test_read_with_known_size() {
412 let executor = deterministic::Runner::default();
413 executor.start(|context| async move {
414 let data = b"This is a test with known size limitations.";
416 let (blob, size) = context.open("partition", b"test").await.unwrap();
417 assert_eq!(size, 0);
418 blob.write_at(0, data, WriteOptions::default())
419 .await
420 .unwrap();
421 let size = data.len() as u64;
422
423 let mut reader = Read::new(blob, size, NZUsize!(10));
425
426 assert_eq!(reader.blob_remaining(), size);
428
429 let read = reader.read(5).await.unwrap().coalesce();
431 assert_eq!(read.as_ref(), b"This ");
432
433 assert_eq!(reader.blob_remaining(), size - 5);
435
436 let read = reader.read((size - 5) as usize).await.unwrap().coalesce();
438 assert_eq!(read.as_ref(), b"is a test with known size limitations.");
439
440 assert_eq!(reader.blob_remaining(), 0);
442
443 let result = reader.read(1).await;
445 assert!(matches!(result, Err(Error::BlobInsufficientLength)));
446 });
447 }
448
449 #[test_traced]
450 fn test_read_oversized_request_does_not_consume_buffered_bytes() {
451 let executor = deterministic::Runner::default();
452 executor.start(|context| async move {
453 let data = b"abcdefghij";
454 let (blob, size) = context
455 .open("partition", b"double-count-regression")
456 .await
457 .unwrap();
458 assert_eq!(size, 0);
459 blob.write_at(0, data, WriteOptions::default())
460 .await
461 .unwrap();
462
463 let mut reader = Read::new(blob, data.len() as u64, NZUsize!(8));
464
465 let first = reader.read(6).await.unwrap().coalesce();
467 assert_eq!(first.as_ref(), b"abcdef");
468 assert_eq!(reader.position(), 6);
469
470 let err = reader.read(5).await.unwrap_err();
472 assert!(matches!(err, Error::BlobInsufficientLength));
473 assert_eq!(reader.position(), 6);
474
475 let tail = reader.read(4).await.unwrap().coalesce();
477 assert_eq!(tail.as_ref(), b"ghij");
478 assert_eq!(reader.position(), 10);
479 });
480 }
481
482 #[test_traced]
483 fn test_read_large_data() {
484 let executor = deterministic::Runner::default();
485 executor.start(|context| async move {
486 let data_size = 1024 * 256; let data = vec![0x42; data_size];
489 let (blob, size) = context.open("partition", b"test").await.unwrap();
490 assert_eq!(size, 0);
491 blob.write_at(0, data.clone(), WriteOptions::default())
492 .await
493 .unwrap();
494 let size = data.len() as u64;
495
496 let mut reader = Read::new(blob, size, NZUsize!(64 * 1024));
498
499 let mut total_read = 0;
501 let chunk_size = 8 * 1024; while total_read < data_size {
504 let to_read = std::cmp::min(chunk_size, data_size - total_read);
505 let read = reader.read(to_read).await.unwrap().coalesce();
506
507 assert!(
509 read.as_ref().iter().all(|&b| b == 0x42),
510 "Data at position {total_read} is not correct"
511 );
512
513 total_read += to_read;
514 }
515
516 assert_eq!(total_read, data_size);
518
519 let result = reader.read(1).await;
521 assert!(matches!(result, Err(Error::BlobInsufficientLength)));
522 });
523 }
524
525 #[test_traced]
526 fn test_read_exact_size_reads() {
527 let executor = deterministic::Runner::default();
528 executor.start(|context| async move {
529 let buffer_size = 1024;
531 let data_size = buffer_size * 5 / 2; let data = vec![0x37; data_size];
533
534 let (blob, size) = context.open("partition", b"test").await.unwrap();
535 assert_eq!(size, 0);
536 blob.write_at(0, data.clone(), WriteOptions::default())
537 .await
538 .unwrap();
539 let size = data.len() as u64;
540
541 let mut reader = Read::new(blob, size, NZUsize!(buffer_size));
542
543 let read = reader.read(buffer_size).await.unwrap().coalesce();
545 assert!(read.as_ref().iter().all(|&b| b == 0x37));
546
547 let read = reader.read(buffer_size).await.unwrap().coalesce();
549 assert!(read.as_ref().iter().all(|&b| b == 0x37));
550
551 let half_buffer = buffer_size / 2;
553 let read = reader.read(half_buffer).await.unwrap().coalesce();
554 assert!(read.as_ref().iter().all(|&b| b == 0x37));
555
556 assert_eq!(reader.blob_remaining(), 0);
558 assert_eq!(reader.position(), size);
559 });
560 }
561
562 #[test_traced]
563 fn test_read_structure_single_vs_chunked() {
564 let executor = deterministic::Runner::default();
565 executor.start(|context| async move {
566 let data = b"ABCDEFGHIJKL";
567 let (blob, size) = context.open("partition", b"structural").await.unwrap();
568 assert_eq!(size, 0);
569 blob.write_at(0, data, WriteOptions::default())
570 .await
571 .unwrap();
572
573 let mut reader = Read::new(blob, data.len() as u64, NZUsize!(5));
574
575 let first = reader.read(3).await.unwrap();
577 assert!(first.is_single());
578 assert_eq!(first.coalesce().as_ref(), b"ABC");
579
580 let second = reader.read(7).await.unwrap();
582 assert!(!second.is_single());
583 assert_eq!(second.coalesce().as_ref(), b"DEFGHIJ");
584 });
585 }
586
587 #[test_traced]
588 fn test_read_seek_to() {
589 let executor = deterministic::Runner::default();
590 executor.start(|context| async move {
591 let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
593 let (blob, size) = context.open("partition", b"test").await.unwrap();
594 assert_eq!(size, 0);
595 blob.write_at(0, data, WriteOptions::default())
596 .await
597 .unwrap();
598 let size = data.len() as u64;
599
600 let mut reader = Read::new(blob, size, NZUsize!(10));
602
603 let read = reader.read(5).await.unwrap().coalesce();
605 assert_eq!(read.as_ref(), b"ABCDE");
606 assert_eq!(reader.position(), 5);
607
608 reader.seek_to(10).unwrap();
610 assert_eq!(reader.position(), 10);
611
612 let read = reader.read(5).await.unwrap().coalesce();
614 assert_eq!(read.as_ref(), b"KLMNO");
615
616 reader.seek_to(0).unwrap();
618 assert_eq!(reader.position(), 0);
619
620 let read = reader.read(5).await.unwrap().coalesce();
621 assert_eq!(read.as_ref(), b"ABCDE");
622
623 reader.seek_to(size).unwrap();
625 assert_eq!(reader.position(), size);
626
627 let result = reader.read(1).await;
629 assert!(matches!(result, Err(Error::BlobInsufficientLength)));
630
631 let result = reader.seek_to(size + 10);
633 assert!(matches!(result, Err(Error::BlobInsufficientLength)));
634 });
635 }
636
637 #[test_traced]
638 fn test_read_seek_with_refill() {
639 let executor = deterministic::Runner::default();
640 executor.start(|context| async move {
641 let data = vec![0x41; 1000]; let (blob, size) = context.open("partition", b"test").await.unwrap();
644 assert_eq!(size, 0);
645 blob.write_at(0, data.clone(), WriteOptions::default())
646 .await
647 .unwrap();
648 let size = data.len() as u64;
649
650 let mut reader = Read::new(blob, size, NZUsize!(10));
652
653 let _ = reader.read(5).await.unwrap().coalesce();
655
656 reader.seek_to(500).unwrap();
658
659 let read = reader.read(5).await.unwrap().coalesce();
661 assert_eq!(read.as_ref(), b"AAAAA"); assert_eq!(reader.position(), 505);
663
664 reader.seek_to(100).unwrap();
666
667 let _ = reader.read(5).await.unwrap().coalesce();
669 assert_eq!(reader.position(), 105);
670 });
671 }
672
673 #[test_traced]
674 fn test_read_seek_within_buffered_range() {
675 let executor = deterministic::Runner::default();
676 executor.start(|context| async move {
677 let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
678 let (blob, size) = context.open("partition", b"test").await.unwrap();
679 assert_eq!(size, 0);
680 blob.write_at(0, data, WriteOptions::default())
681 .await
682 .unwrap();
683
684 let mut reader = Read::new(blob, data.len() as u64, NZUsize!(10));
685
686 let read = reader.read(6).await.unwrap().coalesce();
688 assert_eq!(read.as_ref(), b"ABCDEF");
689 assert_eq!(reader.position(), 6);
690 assert_eq!(reader.buffer_remaining(), 4);
691
692 reader.seek_to(3).unwrap();
694 assert_eq!(reader.position(), 3);
695 assert_eq!(reader.buffer_remaining(), 7);
696
697 let read = reader.read(5).await.unwrap().coalesce();
698 assert_eq!(read.as_ref(), b"DEFGH");
699 assert_eq!(reader.position(), 8);
700 assert_eq!(reader.buffer_remaining(), 2);
701 });
702 }
703
704 #[test_traced]
705 fn test_read_seek_within_unread_buffer_does_not_refill() {
706 let executor = deterministic::Runner::default();
707 executor.start(|context| async move {
708 let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
709 let (blob, size) = context
710 .open("partition", b"seek_unread_no_refill")
711 .await
712 .unwrap();
713 assert_eq!(size, 0);
714 blob.write_at(0, data, WriteOptions::default())
715 .await
716 .unwrap();
717
718 let mut reader = Read::new(blob, data.len() as u64, NZUsize!(10));
719
720 let first = reader.read(6).await.unwrap();
722 assert_eq!(first.coalesce().as_ref(), b"ABCDEF");
723 assert_eq!(reader.position(), 6);
724 assert_eq!(reader.buffer_remaining(), 4);
725
726 reader.seek_to(7).unwrap();
728 assert_eq!(reader.position(), 7);
729 assert_eq!(reader.buffer_remaining(), 3);
730
731 let second = reader.read(3).await.unwrap();
733 assert_eq!(second.coalesce().as_ref(), b"HIJ");
734 assert_eq!(reader.position(), 10);
735 assert_eq!(reader.buffer_remaining(), 0);
736
737 let third = reader.read(1).await.unwrap();
739 assert_eq!(third.coalesce().as_ref(), b"K");
740 assert_eq!(reader.position(), 11);
741 assert_eq!(reader.buffer_remaining(), 9);
742 });
743 }
744
745 #[test_traced]
746 fn test_read_resize() {
747 let executor = deterministic::Runner::default();
748 executor.start(|context| async move {
749 let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
751 let (blob, size) = context.open("partition", b"test").await.unwrap();
752 assert_eq!(size, 0);
753 blob.write_at(0, data, WriteOptions::default())
754 .await
755 .unwrap();
756 let data_len = data.len() as u64;
757
758 let reader = Read::new(blob, data_len, NZUsize!(10));
760
761 let resize_len = data_len / 2;
763 reader.resize(resize_len).await.unwrap();
764
765 let (blob, size) = context.open("partition", b"test").await.unwrap();
767 assert_eq!(size, resize_len, "Blob should be resized to half size");
768
769 let mut new_reader = Read::new(blob, size, NZUsize!(10));
771
772 let read = new_reader.read(size as usize).await.unwrap().coalesce();
774 assert_eq!(
775 read.as_ref(),
776 b"ABCDEFGHIJKLM",
777 "Resized content should match"
778 );
779
780 let result = new_reader.read(1).await;
782 assert!(matches!(result, Err(Error::BlobInsufficientLength)));
783
784 new_reader.resize(data_len * 2).await.unwrap();
786
787 let (blob, new_size) = context.open("partition", b"test").await.unwrap();
789 assert_eq!(new_size, data_len * 2);
790
791 let mut new_reader = Read::new(blob, new_size, NZUsize!(10));
793 let read = new_reader.read(new_size as usize).await.unwrap().coalesce();
794 assert_eq!(&read.as_ref()[..size as usize], b"ABCDEFGHIJKLM");
795 assert_eq!(
796 &read.as_ref()[size as usize..],
797 vec![0u8; new_size as usize - size as usize]
798 );
799 });
800 }
801
802 #[test_traced]
803 fn test_read_resize_to_zero() {
804 let executor = deterministic::Runner::default();
805 executor.start(|context| async move {
806 let data = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
808 let data_len = data.len() as u64;
809 let (blob, size) = context.open("partition", b"test").await.unwrap();
810 assert_eq!(size, 0);
811 blob.write_at(0, data, WriteOptions::default())
812 .await
813 .unwrap();
814
815 let reader = Read::new(blob, data_len, NZUsize!(10));
817
818 reader.resize(0).await.unwrap();
820
821 let (blob, size) = context.open("partition", b"test").await.unwrap();
823 assert_eq!(size, 0, "Blob should be resized to zero");
824
825 let mut new_reader = Read::new(blob, size, NZUsize!(10));
827
828 let result = new_reader.read(1).await;
830 assert!(matches!(result, Err(Error::BlobInsufficientLength)));
831 });
832 }
833
834 #[test_traced]
835 fn test_write_basic() {
836 let executor = deterministic::Runner::default();
837 executor.start(|context| async move {
838 let (blob, size) = context.open("partition", b"write_basic").await.unwrap();
840 assert_eq!(size, 0);
841
842 let mut writer = Write::new(blob, size, NZUsize!(8));
843 writer = writer.write_at(0, b"hello").await.unwrap();
844 assert_eq!(writer.size(), 5);
845 writer = writer.sync().await.unwrap();
846 assert_eq!(writer.size(), 5);
847
848 drop(writer);
850 let (blob, size) = context.open("partition", b"write_basic").await.unwrap();
851 assert_eq!(size, 5);
852 let mut reader = Read::new(blob, size, NZUsize!(8));
853 let read = reader.read(5).await.unwrap().coalesce();
854 assert_eq!(read.as_ref(), b"hello");
855 });
856 }
857
858 #[test_traced]
859 fn test_write_multiple_flushes() {
860 let executor = deterministic::Runner::default();
861 executor.start(|context| async move {
862 let (blob, size) = context.open("partition", b"write_multi").await.unwrap();
864 assert_eq!(size, 0);
865
866 let mut writer = Write::new(blob, size, NZUsize!(4));
867 writer = writer.write_at(0, b"abc").await.unwrap();
868 assert_eq!(writer.size(), 3);
869 writer = writer.write_at(3, b"defg").await.unwrap();
870 assert_eq!(writer.size(), 7);
871 writer = writer.sync().await.unwrap();
872
873 drop(writer);
875 let (blob, size) = context.open("partition", b"write_multi").await.unwrap();
876 assert_eq!(size, 7);
877 let mut reader = Read::new(blob, size, NZUsize!(4));
878 let read = reader.read(7).await.unwrap().coalesce();
879 assert_eq!(read.as_ref(), b"abcdefg");
880 });
881 }
882
883 #[test_traced]
884 fn test_write_large_data() {
885 let executor = deterministic::Runner::default();
886 executor.start(|context| async move {
887 let (blob, size) = context.open("partition", b"write_large").await.unwrap();
889 assert_eq!(size, 0);
890
891 let mut writer = Write::new(blob, size, NZUsize!(4));
892 writer = writer.write_at(0, b"abc").await.unwrap();
893 assert_eq!(writer.size(), 3);
894 writer = writer
895 .write_at(3, b"defghijklmnopqrstuvwxyz")
896 .await
897 .unwrap();
898 assert_eq!(writer.size(), 26);
899 writer = writer.sync().await.unwrap();
900 assert_eq!(writer.size(), 26);
901
902 drop(writer);
904 let (blob, size) = context.open("partition", b"write_large").await.unwrap();
905 assert_eq!(size, 26);
906 let mut reader = Read::new(blob, size, NZUsize!(4));
907 let read = reader.read(26).await.unwrap().coalesce();
908 assert_eq!(read.as_ref(), b"abcdefghijklmnopqrstuvwxyz");
909 });
910 }
911
912 #[test_traced]
913 fn test_write_append_to_buffer() {
914 let executor = deterministic::Runner::default();
915 executor.start(|context| async move {
916 let (blob, size) = context.open("partition", b"append_buf").await.unwrap();
918 let mut writer = Write::new(blob, size, NZUsize!(10));
919
920 writer = writer.write_at(0, b"hello").await.unwrap();
922 assert_eq!(writer.size(), 5);
923
924 writer = writer.write_at(5, b" world").await.unwrap();
926 writer = writer.sync().await.unwrap();
927 assert_eq!(writer.size(), 11);
928
929 drop(writer);
931 let (blob, size) = context.open("partition", b"append_buf").await.unwrap();
932 assert_eq!(size, 11);
933 let mut reader = Read::new(blob, size, NZUsize!(10));
934 let read = reader.read(11).await.unwrap().coalesce();
935 assert_eq!(read.as_ref(), b"hello world");
936 });
937 }
938
939 #[test_traced]
940 fn test_write_into_middle_of_buffer() {
941 let executor = deterministic::Runner::default();
942 executor.start(|context| async move {
943 let (blob, size) = context.open("partition", b"middle_buf").await.unwrap();
945 let mut writer = Write::new(blob, size, NZUsize!(20));
946
947 writer = writer.write_at(0, b"abcdefghij").await.unwrap();
949 assert_eq!(writer.size(), 10);
950
951 writer = writer.write_at(2, b"01234").await.unwrap();
953 assert_eq!(writer.size(), 10);
954 writer = writer.sync().await.unwrap();
955
956 drop(writer);
958 let (blob, size) = context.open("partition", b"middle_buf").await.unwrap();
959 let blob = Arc::new(blob);
960 assert_eq!(size, 10);
961 let mut reader = Read::new(blob.clone(), size, NZUsize!(10));
962 let read = reader.read(10).await.unwrap().coalesce();
963 assert_eq!(read.as_ref(), b"ab01234hij");
964 drop(reader);
965 let mut writer = Write::new(blob, size, NZUsize!(20));
966
967 writer = writer.write_at(10, b"klmnopqrst").await.unwrap();
969 assert_eq!(writer.size(), 20);
970 writer = writer.write_at(9, b"wxyz").await.unwrap();
971 assert_eq!(writer.size(), 20);
972 writer = writer.sync().await.unwrap();
973
974 drop(writer);
976 let (blob, size) = context.open("partition", b"middle_buf").await.unwrap();
977 assert_eq!(size, 20);
978 let mut reader = Read::new(blob, size, NZUsize!(20));
979 let read = reader.read(20).await.unwrap().coalesce();
980 assert_eq!(read.as_ref(), b"ab01234hiwxyznopqrst");
981 });
982 }
983
984 #[test_traced]
985 fn test_write_before_buffer() {
986 let executor = deterministic::Runner::default();
987 executor.start(|context| async move {
988 let (blob, size) = context.open("partition", b"before_buf").await.unwrap();
990 let mut writer = Write::new(blob, size, NZUsize!(10));
991
992 writer = writer.write_at(10, b"0123456789").await.unwrap();
994 assert_eq!(writer.size(), 20);
995
996 writer = writer.write_at(0, b"abcde").await.unwrap();
998 assert_eq!(writer.size(), 20);
999 writer = writer.sync().await.unwrap();
1000
1001 drop(writer);
1003 let (blob, size) = context.open("partition", b"before_buf").await.unwrap();
1004 let blob = Arc::new(blob);
1005 assert_eq!(size, 20);
1006 let mut reader = Read::new(blob.clone(), size, NZUsize!(20));
1007 let read = reader.read(20).await.unwrap().coalesce();
1008 let mut expected = vec![0u8; 20];
1009 expected[0..5].copy_from_slice("abcde".as_bytes());
1010 expected[10..20].copy_from_slice("0123456789".as_bytes());
1011 assert_eq!(read.as_ref(), expected.as_slice());
1012 drop(reader);
1013 let mut writer = Write::new(blob, size, NZUsize!(10));
1014
1015 writer = writer.write_at(5, b"fghij").await.unwrap();
1017 assert_eq!(writer.size(), 20);
1018 writer = writer.sync().await.unwrap();
1019 assert_eq!(writer.size(), 20);
1020
1021 drop(writer);
1023 let (blob, size) = context.open("partition", b"before_buf").await.unwrap();
1024 assert_eq!(size, 20);
1025 let mut reader = Read::new(blob, size, NZUsize!(20));
1026 let read = reader.read(20).await.unwrap().coalesce();
1027 expected[0..10].copy_from_slice("abcdefghij".as_bytes());
1028 assert_eq!(read.as_ref(), expected.as_slice());
1029 });
1030 }
1031
1032 #[test_traced]
1033 fn test_write_resize() {
1034 let executor = deterministic::Runner::default();
1035 executor.start(|context| async move {
1036 let (blob, size) = context.open("partition", b"resize_write").await.unwrap();
1038 let mut writer = Write::new(blob, size, NZUsize!(10));
1039
1040 writer = writer.write_at(0, b"hello world").await.unwrap();
1042 assert_eq!(writer.size(), 11);
1043 writer = writer.sync().await.unwrap();
1044 assert_eq!(writer.size(), 11);
1045
1046 drop(writer);
1047 let (blob_check, size_check) =
1048 context.open("partition", b"resize_write").await.unwrap();
1049 assert_eq!(size_check, 11);
1050 let mut writer = Write::new(blob_check, size_check, NZUsize!(10));
1051
1052 writer = writer.resize(5).await.unwrap();
1054 assert_eq!(writer.size(), 5);
1055 writer = writer.sync().await.unwrap();
1056
1057 drop(writer);
1059 let (blob, size) = context.open("partition", b"resize_write").await.unwrap();
1060 let blob = Arc::new(blob);
1061 assert_eq!(size, 5);
1062 let mut reader = Read::new(blob.clone(), size, NZUsize!(5));
1063 let read = reader.read(5).await.unwrap().coalesce();
1064 assert_eq!(read.as_ref(), b"hello");
1065 drop(reader);
1066 let mut writer = Write::new(blob, size, NZUsize!(10));
1067
1068 writer = writer.write_at(0, b"X").await.unwrap();
1070 assert_eq!(writer.size(), 5);
1071 writer = writer.sync().await.unwrap();
1072
1073 drop(writer);
1075 let (blob, size) = context.open("partition", b"resize_write").await.unwrap();
1076 let blob = Arc::new(blob);
1077 assert_eq!(size, 5);
1078 let mut reader = Read::new(blob.clone(), size, NZUsize!(5));
1079 let read = reader.read(5).await.unwrap().coalesce();
1080 assert_eq!(read.as_ref(), b"Xello");
1081 drop(reader);
1082 let mut writer = Write::new(blob, size, NZUsize!(10));
1083
1084 writer = writer.resize(10).await.unwrap();
1086 assert_eq!(writer.size(), 10);
1087 writer = writer.sync().await.unwrap();
1088
1089 drop(writer);
1091 let (blob, size) = context.open("partition", b"resize_write").await.unwrap();
1092 assert_eq!(size, 10);
1093 let mut reader = Read::new(blob, size, NZUsize!(10));
1094 let read = reader.read(10).await.unwrap().coalesce();
1095 assert_eq!(&read.as_ref()[0..5], b"Xello");
1096 assert_eq!(&read.as_ref()[5..10], [0u8; 5]);
1097
1098 let (blob_zero, size) = context.open("partition", b"resize_zero").await.unwrap();
1100 let mut writer_zero = Write::new(blob_zero, size, NZUsize!(10));
1101 writer_zero = writer_zero.write_at(0, b"some data").await.unwrap();
1102 assert_eq!(writer_zero.size(), 9);
1103 writer_zero = writer_zero.sync().await.unwrap();
1104 assert_eq!(writer_zero.size(), 9);
1105 writer_zero = writer_zero.resize(0).await.unwrap();
1106 assert_eq!(writer_zero.size(), 0);
1107 writer_zero = writer_zero.sync().await.unwrap();
1108 assert_eq!(writer_zero.size(), 0);
1109
1110 drop(writer_zero);
1112 let (_, size_z) = context.open("partition", b"resize_zero").await.unwrap();
1113 assert_eq!(size_z, 0);
1114 });
1115 }
1116
1117 #[test_traced]
1118 fn test_write_resize_grow_flushes_buffered_data() {
1119 let executor = deterministic::Runner::default();
1120 executor.start(|context| async move {
1121 let (blob, size) = context.open("partition", b"resize_grow").await.unwrap();
1122 let mut writer = Write::new(blob, size, NZUsize!(10));
1123
1124 writer = writer.write_at(0, b"hello").await.unwrap();
1125 writer = writer.resize(10).await.unwrap();
1126 writer = writer.sync().await.unwrap();
1127
1128 let read = writer.read_at(0, 5).await.unwrap().coalesce();
1129 assert_eq!(read.as_ref(), b"hello");
1130 });
1131 }
1132
1133 #[test_traced]
1134 fn test_write_read_at_on_writer() {
1135 let executor = deterministic::Runner::default();
1136 executor.start(|context| async move {
1137 let (blob, size) = context.open("partition", b"read_at_writer").await.unwrap();
1139 let mut writer = Write::new(blob, size, NZUsize!(10));
1140
1141 writer = writer.write_at(0, b"buffered").await.unwrap();
1143 assert_eq!(writer.size(), 8);
1144
1145 let read_buf_vec = writer.read_at(0, 4).await.unwrap().coalesce();
1147 assert_eq!(read_buf_vec, b"buff");
1148
1149 let read_buf_vec = writer.read_at(4, 4).await.unwrap().coalesce();
1150 assert_eq!(read_buf_vec, b"ered");
1151
1152 assert!(writer.read_at(8, 1).await.is_err());
1154
1155 writer = writer.write_at(8, b" and flushed").await.unwrap();
1157 assert_eq!(writer.size(), 20);
1158 writer = writer.sync().await.unwrap();
1159 assert_eq!(writer.size(), 20);
1160
1161 let read_buf_vec_2 = writer.read_at(0, 4).await.unwrap().coalesce();
1163 assert_eq!(read_buf_vec_2, b"buff");
1164
1165 let read_buf_7_vec = writer.read_at(13, 7).await.unwrap().coalesce();
1166 assert_eq!(read_buf_7_vec, b"flushed");
1167
1168 writer = writer.write_at(20, b" more data").await.unwrap();
1170 assert_eq!(writer.size(), 30);
1171
1172 let read_buf_vec_3 = writer.read_at(20, 5).await.unwrap().coalesce();
1174 assert_eq!(read_buf_vec_3, b" more");
1175
1176 let combo_read_buf_vec = writer.read_at(16, 12).await.unwrap();
1178 assert_eq!(combo_read_buf_vec.coalesce(), b"shed more da");
1179
1180 writer = writer.sync().await.unwrap();
1182 assert_eq!(writer.size(), 30);
1183 drop(writer);
1184 let (final_blob, final_size) =
1185 context.open("partition", b"read_at_writer").await.unwrap();
1186 assert_eq!(final_size, 30);
1187 let mut final_reader = Read::new(final_blob, final_size, NZUsize!(30));
1188 let read = final_reader.read(30).await.unwrap().coalesce();
1189 assert_eq!(read.as_ref(), b"buffered and flushed more data");
1190 });
1191 }
1192
1193 #[test_traced]
1194 fn test_write_zero_length_read_past_eof_errors() {
1195 let executor = deterministic::Runner::default();
1196 executor.start(|context| async move {
1197 let (blob, size) = context.open("partition", b"zero_len_probe").await.unwrap();
1198 let mut writer = Write::new(blob, size, NZUsize!(8));
1199 writer = writer.write_at(0, b"abc").await.unwrap();
1200
1201 let empty = writer.read_at(3, 0).await.unwrap();
1202 assert!(empty.is_empty());
1203
1204 let err = writer.read_at(4, 0).await.unwrap_err();
1205 assert!(matches!(err, Error::BlobInsufficientLength));
1206 });
1207 }
1208
1209 #[test_traced]
1210 fn test_write_straddling_non_mergeable() {
1211 let executor = deterministic::Runner::default();
1212 executor.start(|context| async move {
1213 let (blob, size) = context.open("partition", b"write_straddle").await.unwrap();
1215 let mut writer = Write::new(blob, size, NZUsize!(10));
1216
1217 writer = writer.write_at(0, b"0123456789").await.unwrap();
1219 assert_eq!(writer.size(), 10);
1220
1221 writer = writer.write_at(15, b"abc").await.unwrap();
1223 assert_eq!(writer.size(), 18);
1224 writer = writer.sync().await.unwrap();
1225 assert_eq!(writer.size(), 18);
1226
1227 drop(writer);
1229 let (blob_check, size_check) =
1230 context.open("partition", b"write_straddle").await.unwrap();
1231 assert_eq!(size_check, 18);
1232 let mut reader = Read::new(blob_check, size_check, NZUsize!(20));
1233 let read = reader.read(18).await.unwrap().coalesce();
1234
1235 let mut expected = vec![0u8; 18];
1236 expected[0..10].copy_from_slice(b"0123456789");
1237 expected[15..18].copy_from_slice(b"abc");
1238 assert_eq!(read.as_ref(), expected.as_slice());
1239
1240 let (blob2, size) = context.open("partition", b"write_straddle2").await.unwrap();
1242 let mut writer2 = Write::new(blob2, size, NZUsize!(10));
1243 writer2 = writer2.write_at(0, b"0123456789").await.unwrap();
1244 assert_eq!(writer2.size(), 10);
1245
1246 writer2 = writer2.write_at(5, b"ABCDEFGHIJKL").await.unwrap();
1248 assert_eq!(writer2.size(), 17);
1249 writer2 = writer2.sync().await.unwrap();
1250 assert_eq!(writer2.size(), 17);
1251
1252 drop(writer2);
1254 let (blob_check2, size_check2) =
1255 context.open("partition", b"write_straddle2").await.unwrap();
1256 assert_eq!(size_check2, 17);
1257 let mut reader2 = Read::new(blob_check2, size_check2, NZUsize!(20));
1258 let read = reader2.read(17).await.unwrap().coalesce();
1259 assert_eq!(read.as_ref(), b"01234ABCDEFGHIJKL");
1260 });
1261 }
1262
1263 #[test_traced]
1264 fn test_write_close() {
1265 let executor = deterministic::Runner::default();
1266 executor.start(|context| async move {
1267 let (blob_orig, size) = context.open("partition", b"write_close").await.unwrap();
1269 let mut writer = Write::new(blob_orig, size, NZUsize!(8));
1270 writer = writer.write_at(0, b"pending").await.unwrap();
1271 assert_eq!(writer.size(), 7);
1272
1273 writer = writer.sync().await.unwrap();
1275
1276 drop(writer);
1278 let (blob_check, size_check) = context.open("partition", b"write_close").await.unwrap();
1279 assert_eq!(size_check, 7);
1280 let mut reader = Read::new(blob_check, size_check, NZUsize!(8));
1281 let read = reader.read(7).await.unwrap().coalesce();
1282 assert_eq!(read.as_ref(), b"pending");
1283 });
1284 }
1285
1286 #[test_traced]
1287 fn test_write_direct_due_to_size() {
1288 let executor = deterministic::Runner::default();
1289 executor.start(|context| async move {
1290 let (blob, size) = context
1292 .open("partition", b"write_direct_size")
1293 .await
1294 .unwrap();
1295 let mut writer = Write::new(blob, size, NZUsize!(5));
1296
1297 let data_large = b"0123456789";
1299 writer = writer.write_at(0, data_large).await.unwrap();
1300 assert_eq!(writer.size(), 10);
1301
1302 writer = writer.sync().await.unwrap();
1304
1305 drop(writer);
1307 let (blob_check, size_check) = context
1308 .open("partition", b"write_direct_size")
1309 .await
1310 .unwrap();
1311 let blob_check = Arc::new(blob_check);
1312 assert_eq!(size_check, 10);
1313 let mut reader = Read::new(blob_check.clone(), size_check, NZUsize!(10));
1314 let read = reader.read(10).await.unwrap().coalesce();
1315 assert_eq!(read.as_ref(), data_large.as_slice());
1316 drop(reader);
1317 let mut writer = Write::new(blob_check, size_check, NZUsize!(5));
1318
1319 writer = writer.write_at(10, b"abc").await.unwrap();
1321 assert_eq!(writer.size(), 13);
1322
1323 let read_small_buf_vec = writer.read_at(10, 3).await.unwrap().coalesce();
1325 assert_eq!(read_small_buf_vec, b"abc");
1326
1327 writer = writer.sync().await.unwrap();
1328
1329 drop(writer);
1331 let (blob_check2, size_check2) = context
1332 .open("partition", b"write_direct_size")
1333 .await
1334 .unwrap();
1335 assert_eq!(size_check2, 13);
1336 let mut reader2 = Read::new(blob_check2, size_check2, NZUsize!(13));
1337 let read = reader2.read(13).await.unwrap().coalesce();
1338 assert_eq!(&read.as_ref()[10..], b"abc".as_slice());
1339 });
1340 }
1341
1342 #[test_traced]
1343 fn test_write_overwrite_and_extend_in_buffer() {
1344 let executor = deterministic::Runner::default();
1345 executor.start(|context| async move {
1346 let (blob, size) = context
1348 .open("partition", b"overwrite_extend_buf")
1349 .await
1350 .unwrap();
1351 let mut writer = Write::new(blob, size, NZUsize!(15));
1352
1353 writer = writer.write_at(0, b"0123456789").await.unwrap();
1355 assert_eq!(writer.size(), 10);
1356
1357 writer = writer.write_at(5, b"ABCDEFGHIJ").await.unwrap();
1359 assert_eq!(writer.size(), 15);
1360
1361 let read_buf_vec = writer.read_at(0, 15).await.unwrap().coalesce();
1363 assert_eq!(read_buf_vec, b"01234ABCDEFGHIJ");
1364
1365 writer = writer.sync().await.unwrap();
1366
1367 drop(writer);
1369 let (blob_check, size_check) = context
1370 .open("partition", b"overwrite_extend_buf")
1371 .await
1372 .unwrap();
1373 assert_eq!(size_check, 15);
1374 let mut reader = Read::new(blob_check, size_check, NZUsize!(15));
1375 let read = reader.read(15).await.unwrap().coalesce();
1376 assert_eq!(read.as_ref(), b"01234ABCDEFGHIJ".as_slice());
1377 });
1378 }
1379
1380 #[test_traced]
1381 fn test_write_at_size() {
1382 let executor = deterministic::Runner::default();
1383 executor.start(|context| async move {
1384 let (blob, size) = context.open("partition", b"write_end").await.unwrap();
1386 let mut writer = Write::new(blob, size, NZUsize!(20));
1387
1388 writer = writer.write_at(0, b"0123456789").await.unwrap();
1390 assert_eq!(writer.size(), 10);
1391 writer = writer.sync().await.unwrap();
1392
1393 let end = writer.size();
1395 writer = writer.write_at(end, b"abc").await.unwrap();
1396 assert_eq!(writer.size(), 13);
1397 writer = writer.sync().await.unwrap();
1398
1399 drop(writer);
1401 let (blob_check, size_check) = context.open("partition", b"write_end").await.unwrap();
1402 assert_eq!(size_check, 13);
1403 let mut reader = Read::new(blob_check, size_check, NZUsize!(13));
1404 let read = reader.read(13).await.unwrap().coalesce();
1405 assert_eq!(read.as_ref(), b"0123456789abc");
1406 });
1407 }
1408
1409 #[test_traced]
1410 fn test_write_at_size_multiple_appends() {
1411 let executor = deterministic::Runner::default();
1412 executor.start(|context| async move {
1413 let (blob, size) = context
1415 .open("partition", b"write_multiple_appends_at_size")
1416 .await
1417 .unwrap();
1418 let mut writer = Write::new(blob, size, NZUsize!(5));
1419
1420 writer = writer.write_at(0, b"AAA").await.unwrap();
1422 assert_eq!(writer.size(), 3);
1423 writer = writer.sync().await.unwrap();
1424 assert_eq!(writer.size(), 3);
1425
1426 let end = writer.size();
1428 writer = writer.write_at(end, b"BBB").await.unwrap();
1429 assert_eq!(writer.size(), 6); writer = writer.sync().await.unwrap();
1431 assert_eq!(writer.size(), 6);
1432
1433 let end = writer.size();
1435 writer = writer.write_at(end, b"CCC").await.unwrap();
1436 assert_eq!(writer.size(), 9); writer = writer.sync().await.unwrap();
1438 assert_eq!(writer.size(), 9);
1439
1440 drop(writer);
1442 let (blob_check, size_check) = context
1443 .open("partition", b"write_multiple_appends_at_size")
1444 .await
1445 .unwrap();
1446 assert_eq!(size_check, 9);
1447 let mut reader = Read::new(blob_check, size_check, NZUsize!(9));
1448 let read = reader.read(9).await.unwrap().coalesce();
1449 assert_eq!(read.as_ref(), b"AAABBBCCC");
1450 });
1451 }
1452
1453 #[test_traced]
1454 fn test_write_non_contiguous_then_append_at_size() {
1455 let executor = deterministic::Runner::default();
1456 executor.start(|context| async move {
1457 let (blob, size) = context
1459 .open("partition", b"write_non_contiguous_then_append")
1460 .await
1461 .unwrap();
1462 let mut writer = Write::new(blob, size, NZUsize!(10));
1463
1464 writer = writer.write_at(0, b"INITIAL").await.unwrap();
1466 assert_eq!(writer.size(), 7);
1467
1468 writer = writer.write_at(20, b"NONCONTIG").await.unwrap();
1470 assert_eq!(writer.size(), 29);
1471 writer = writer.sync().await.unwrap();
1472 assert_eq!(writer.size(), 29);
1473
1474 let end = writer.size();
1476 writer = writer.write_at(end, b"APPEND").await.unwrap();
1477 assert_eq!(writer.size(), 35);
1478 writer = writer.sync().await.unwrap();
1479 assert_eq!(writer.size(), 35);
1480
1481 drop(writer);
1483 let (blob_check, size_check) = context
1484 .open("partition", b"write_non_contiguous_then_append")
1485 .await
1486 .unwrap();
1487 assert_eq!(size_check, 35);
1488 let mut reader = Read::new(blob_check, size_check, NZUsize!(35));
1489 let read = reader.read(35).await.unwrap().coalesce();
1490
1491 let mut expected = vec![0u8; 35];
1492 expected[0..7].copy_from_slice(b"INITIAL");
1493 expected[20..29].copy_from_slice(b"NONCONTIG");
1494 expected[29..35].copy_from_slice(b"APPEND");
1495 assert_eq!(read.as_ref(), expected.as_slice());
1496 });
1497 }
1498
1499 #[test_traced]
1500 fn test_write_resize_then_append_at_size() {
1501 let executor = deterministic::Runner::default();
1502 executor.start(|context| async move {
1503 let (blob, size) = context
1505 .open("partition", b"resize_then_append_at_size")
1506 .await
1507 .unwrap();
1508 let mut writer = Write::new(blob, size, NZUsize!(10));
1509
1510 writer = writer.write_at(0, b"0123456789ABCDEF").await.unwrap();
1512 assert_eq!(writer.size(), 16);
1513 writer = writer.sync().await.unwrap();
1514 assert_eq!(writer.size(), 16);
1515
1516 let resize_to = 5;
1518 writer = writer.resize(resize_to).await.unwrap();
1519 assert_eq!(writer.size(), resize_to);
1520 writer = writer.sync().await.unwrap();
1521 assert_eq!(writer.size(), resize_to);
1522
1523 let end = writer.size();
1525 writer = writer.write_at(end, b"XXXXX").await.unwrap();
1526 assert_eq!(writer.size(), 10);
1527 writer = writer.sync().await.unwrap();
1528 assert_eq!(writer.size(), 10);
1529
1530 drop(writer);
1532 let (blob_check, size_check) = context
1533 .open("partition", b"resize_then_append_at_size")
1534 .await
1535 .unwrap();
1536 assert_eq!(size_check, 10);
1537 let mut reader = Read::new(blob_check, size_check, NZUsize!(10));
1538 let read = reader.read(10).await.unwrap().coalesce();
1539 assert_eq!(read.as_ref(), b"01234XXXXX");
1540 });
1541 }
1542
1543 #[test_traced]
1545 fn test_write_start_sync_flush_failure_returns_err() {
1546 let executor = deterministic::Runner::default();
1547 executor.start(|context| async move {
1548 let faults = WriteFaults::default();
1549 let context = WriteFaultContext {
1550 inner: context,
1551 faults: faults.clone(),
1552 };
1553 let (blob, size) = context
1554 .open("partition", b"start_sync_flush_failure")
1555 .await
1556 .unwrap();
1557 let writer = Write::new(blob, size, NZUsize!(8));
1558
1559 let writer = writer.write_at(0, b"abc").await.unwrap();
1561
1562 faults.arm();
1564 assert!(writer.start_sync().await.is_err());
1565 });
1566 }
1567
1568 #[test_traced]
1571 fn test_write_try_write_at_merges_only_when_it_fits() {
1572 let executor = deterministic::Runner::default();
1573 executor.start(|context| async move {
1574 let (blob, _) = context.open("partition", b"try_write_at").await.unwrap();
1575 let mut writer = Write::new(blob, 0, NZUsize!(8));
1576
1577 assert!(writer.try_write_at(0, b"abc"));
1579 assert_eq!(writer.size(), 3);
1580
1581 assert!(!writer.try_write_at(3, b"0123456789"));
1583 assert_eq!(writer.size(), 3);
1584
1585 assert!(!writer.try_write_at(u64::MAX, b"x"));
1587 assert_eq!(writer.size(), 3);
1588
1589 assert!(writer.try_write_at(6, &[]));
1591 assert_eq!(writer.size(), 3);
1592
1593 let writer = writer.sync().await.unwrap();
1595 let read = writer.read_at(0, 3).await.unwrap().coalesce();
1596 assert_eq!(read.as_ref(), b"abc");
1597 });
1598 }
1599
1600 #[test_traced]
1603 fn test_write_needs_sync_tracks_sync_work() {
1604 let executor = deterministic::Runner::default();
1605 executor.start(|_| async move {
1606 let (blob, pending) = DelayedSyncBlob::new(SyncTrackingBlob::new());
1607 let writer = Write::new(blob, 0, NZUsize!(8));
1608
1609 assert!(writer.needs_sync());
1611 let mut writer = writer.sync().await.unwrap();
1612 assert!(!writer.needs_sync());
1613
1614 writer = writer.write_at(0, b"abc").await.unwrap();
1616 assert!(writer.needs_sync());
1617 writer = writer.sync().await.unwrap();
1618 assert!(!writer.needs_sync());
1619
1620 writer = writer.write_at(3, b"d").await.unwrap();
1622 let (writer, handle) = writer.start_sync().await.unwrap();
1623 assert!(writer.needs_sync());
1624 next_pending_sync(&pending).release.send(Ok(())).unwrap();
1625 handle.await.unwrap();
1626 assert!(writer.needs_sync());
1627 let writer = writer.wait_for_sync().await.unwrap();
1628 assert!(!writer.needs_sync());
1629
1630 let writer = writer.write_at(4, b"e").await.unwrap();
1633 let (writer, handle) = writer.start_sync().await.unwrap();
1634 next_pending_sync(&pending)
1635 .release
1636 .send(Err(Error::Closed))
1637 .unwrap();
1638 assert!(handle.await.is_err());
1639 assert!(writer.needs_sync());
1640 assert!(writer.sync().await.is_err());
1641 });
1642 }
1643
1644 #[test_traced]
1646 fn test_write_start_sync_persists_and_marks_clean() {
1647 let executor = deterministic::Runner::default();
1648 executor.start(|_| async move {
1649 let blob = SyncTrackingBlob::new();
1650 let blob = Arc::new(blob);
1651 let mut writer = Write::new(blob.clone(), 0, NZUsize!(8));
1652
1653 writer = writer.write_at(0, b"abc").await.unwrap();
1655 let (mut writer, handle) = writer.start_sync().await.unwrap();
1656 handle.await.unwrap();
1657
1658 let (durable, writes, full_syncs, range_syncs) = blob.snapshot();
1660 assert_eq!(durable.as_slice(), b"abc");
1661 assert_eq!(writes, 1);
1662 assert_eq!(full_syncs, 1);
1663 assert_eq!(range_syncs, 0);
1664
1665 writer = writer.write_at(3, b"d").await.unwrap();
1667 writer = writer.sync().await.unwrap();
1668 let (durable, writes, full_syncs, range_syncs) = blob.snapshot();
1669 assert_eq!(durable.as_slice(), b"abcd");
1670 assert_eq!(writes, 2);
1671 assert_eq!(full_syncs, 1);
1672 assert_eq!(range_syncs, 1);
1673
1674 let (_, handle) = writer.start_sync().await.unwrap();
1676 handle.await.unwrap();
1677 let (_, _, full_syncs, range_syncs) = blob.snapshot();
1678 assert_eq!(full_syncs, 1);
1679 assert_eq!(range_syncs, 1);
1680 });
1681 }
1682
1683 #[test_traced]
1685 fn test_write_sync_waits_for_outstanding_start_sync() {
1686 let executor = deterministic::Runner::default();
1687 executor.start(|_| async move {
1688 let inner = SyncTrackingBlob::new();
1689 let inner = Arc::new(inner);
1690 let (blob, pending) = DelayedSyncBlob::new(inner.clone());
1691 let writer = Write::new(blob, 0, NZUsize!(8));
1692
1693 let (writer, handle) = writer.start_sync().await.unwrap();
1695 let deferred = next_pending_sync(&pending);
1696
1697 let mut sync = Box::pin(writer.sync());
1699 assert!(
1700 sync.as_mut().now_or_never().is_none(),
1701 "sync must wait for the outstanding start_sync handle"
1702 );
1703 deferred
1704 .blocked
1705 .await
1706 .expect("sync never waited on start_sync");
1707
1708 let (_, _, full_syncs, range_syncs) = inner.snapshot();
1709 assert_eq!(full_syncs, 0);
1710 assert_eq!(range_syncs, 0);
1711
1712 deferred.release.send(Ok(())).unwrap();
1714 sync.await.unwrap();
1715 handle.await.unwrap();
1716 let (_, _, full_syncs, range_syncs) = inner.snapshot();
1717 assert_eq!(full_syncs, 1);
1718 assert_eq!(range_syncs, 0);
1719 });
1720 }
1721
1722 #[test_traced]
1724 fn test_write_sync_after_start_sync_and_small_write_waits_before_range_sync() {
1725 let executor = deterministic::Runner::default();
1726 executor.start(|_| async move {
1727 let inner = SyncTrackingBlob::new();
1728 let inner = Arc::new(inner);
1729 let (blob, pending) = DelayedSyncBlob::new(inner.clone());
1730 let writer = Write::new(blob, 0, NZUsize!(8));
1731
1732 let (mut writer, handle) = writer.start_sync().await.unwrap();
1734 let deferred = next_pending_sync(&pending);
1735
1736 writer = writer.write_at(0, b"abc").await.unwrap();
1738 let mut sync = Box::pin(writer.sync());
1739 assert!(
1740 sync.as_mut().now_or_never().is_none(),
1741 "sync must wait for the outstanding start_sync before flushing the small write"
1742 );
1743 deferred
1744 .blocked
1745 .await
1746 .expect("sync never waited on start_sync");
1747
1748 let (_, writes, full_syncs, range_syncs) = inner.snapshot();
1749 assert_eq!(writes, 0);
1750 assert_eq!(full_syncs, 0);
1751 assert_eq!(range_syncs, 0);
1752
1753 deferred.release.send(Ok(())).unwrap();
1755 sync.await.unwrap();
1756 handle.await.unwrap();
1757
1758 let (durable, writes, full_syncs, range_syncs) = inner.snapshot();
1759 assert_eq!(durable.as_slice(), b"abc");
1760 assert_eq!(writes, 1);
1761 assert_eq!(full_syncs, 1);
1762 assert_eq!(range_syncs, 1);
1763 });
1764 }
1765
1766 #[test_traced]
1768 fn test_write_at_overlap_flush_waits_for_outstanding_start_sync() {
1769 let executor = deterministic::Runner::default();
1770 executor.start(|_| async move {
1771 let inner = SyncTrackingBlob::new();
1772 let inner = Arc::new(inner);
1773 inner
1774 .write_at(0, b"xxx", WriteOptions::default())
1775 .await
1776 .unwrap();
1777
1778 let (blob, pending) = DelayedSyncBlob::new(inner.clone());
1779 let writer = Write::new(blob, inner.size(), NZUsize!(8));
1780
1781 let (mut writer, handle) = writer.start_sync().await.unwrap();
1782 let deferred = next_pending_sync(&pending);
1783
1784 writer = writer.write_at(3, b"abc").await.unwrap();
1786
1787 let mut write = Box::pin(writer.write_at(2, b"ZZ"));
1789 assert!(
1790 write.as_mut().now_or_never().is_none(),
1791 "overlapping write must wait for the outstanding start_sync before flushing"
1792 );
1793 deferred
1794 .blocked
1795 .await
1796 .expect("write never waited on start_sync");
1797
1798 let (_, writes, full_syncs, range_syncs) = inner.snapshot();
1799 assert_eq!(writes, 1);
1800 assert_eq!(full_syncs, 0);
1801 assert_eq!(range_syncs, 0);
1802
1803 deferred.release.send(Ok(())).unwrap();
1805 write.await.unwrap();
1806 handle.await.unwrap();
1807
1808 let (_, writes, full_syncs, range_syncs) = inner.snapshot();
1809 assert_eq!(writes, 3);
1810 assert_eq!(full_syncs, 1);
1811 assert_eq!(range_syncs, 0);
1812 });
1813 }
1814
1815 #[test_traced]
1817 fn test_write_resize_waits_for_outstanding_start_sync_before_resizing() {
1818 let executor = deterministic::Runner::default();
1819 executor.start(|_| async move {
1820 let inner = SyncTrackingBlob::new();
1821 let inner = Arc::new(inner);
1822 inner
1823 .write_at(0, b"abcdef", WriteOptions::default())
1824 .await
1825 .unwrap();
1826
1827 let (blob, pending) = DelayedSyncBlob::new(inner.clone());
1828 let writer = Write::new(blob, inner.size(), NZUsize!(8));
1829
1830 let (writer, handle) = writer.start_sync().await.unwrap();
1831 let deferred = next_pending_sync(&pending);
1832 let original_size = inner.size();
1833
1834 let mut resize = Box::pin(writer.resize(3));
1836 assert!(
1837 resize.as_mut().now_or_never().is_none(),
1838 "resize must wait for the outstanding start_sync handle"
1839 );
1840 deferred
1841 .blocked
1842 .await
1843 .expect("resize never waited on start_sync");
1844 assert_eq!(
1845 inner.size(),
1846 original_size,
1847 "resize must not mutate the blob before the pending sync finishes"
1848 );
1849
1850 deferred.release.send(Ok(())).unwrap();
1852 let writer = resize.await.unwrap();
1853 handle.await.unwrap();
1854 assert_eq!(writer.size(), 3);
1855 assert_eq!(inner.size(), 3);
1856 });
1857 }
1858
1859 #[test_traced]
1860 fn test_write_sync_uses_range_sync_for_buffer_only_write() {
1861 let executor = deterministic::Runner::default();
1862 executor.start(|_| async move {
1863 let blob = SyncTrackingBlob::new();
1864 let blob = Arc::new(blob);
1865 let mut writer = Write::new(blob.clone(), 0, NZUsize!(8));
1866
1867 writer = writer.sync().await.unwrap();
1869 let (durable, writes, full_syncs, range_syncs) = blob.snapshot();
1870 assert!(durable.is_empty());
1871 assert_eq!(writes, 0);
1872 assert_eq!(full_syncs, 1);
1873 assert_eq!(range_syncs, 0);
1874
1875 writer = writer.write_at(0, b"abc").await.unwrap();
1877 writer = writer.sync().await.unwrap();
1878
1879 let (durable, writes, full_syncs, range_syncs) = blob.snapshot();
1881 assert_eq!(durable.as_slice(), b"abc");
1882 assert_eq!(writes, 1);
1883 assert_eq!(full_syncs, 1);
1884 assert_eq!(range_syncs, 1);
1885
1886 writer.sync().await.unwrap();
1888 let (durable, writes, full_syncs, range_syncs) = blob.snapshot();
1889 assert_eq!(durable.as_slice(), b"abc");
1890 assert_eq!(writes, 1);
1891 assert_eq!(full_syncs, 1);
1892 assert_eq!(range_syncs, 1);
1893 });
1894 }
1895
1896 #[test_traced]
1897 fn test_write_sync_persists_pre_wrapped_blob_mutation() {
1898 let executor = deterministic::Runner::default();
1899 executor.start(|_| async move {
1900 let blob = SyncTrackingBlob::new();
1901 let blob = Arc::new(blob);
1902
1903 blob.write_at(0, b"abc", WriteOptions::default())
1905 .await
1906 .unwrap();
1907
1908 let mut writer = Write::new(blob.clone(), 3, NZUsize!(8));
1909 writer = writer.sync().await.unwrap();
1910
1911 let (durable, writes, full_syncs, range_syncs) = blob.snapshot();
1913 assert_eq!(durable.as_slice(), b"abc");
1914 assert_eq!(writes, 1);
1915 assert_eq!(full_syncs, 1);
1916 assert_eq!(range_syncs, 0);
1917
1918 writer = writer.write_at(3, b"d").await.unwrap();
1920 writer.sync().await.unwrap();
1921
1922 let (durable, writes, full_syncs, range_syncs) = blob.snapshot();
1923 assert_eq!(durable.as_slice(), b"abcd");
1924 assert_eq!(writes, 2);
1925 assert_eq!(full_syncs, 1);
1926 assert_eq!(range_syncs, 1);
1927 });
1928 }
1929
1930 #[test_traced]
1931 fn test_write_sync_persists_prior_direct_flushes_with_buffered_tip() {
1932 let executor = deterministic::Runner::default();
1933 executor.start(|_| async move {
1934 let blob = SyncTrackingBlob::new();
1935 let blob = Arc::new(blob);
1936 let mut writer = Write::new(blob.clone(), 0, NZUsize!(4));
1937
1938 writer = writer.write_at(0, b"abcdef").await.unwrap();
1940 writer = writer.write_at(6, b"g").await.unwrap();
1941 writer = writer.sync().await.unwrap();
1942
1943 let (durable, writes, full_syncs, range_syncs) = blob.snapshot();
1945 assert_eq!(durable.as_slice(), b"abcdefg");
1946 assert_eq!(writes, 2);
1947 assert_eq!(full_syncs, 1);
1948 assert_eq!(range_syncs, 0);
1949
1950 writer = writer.sync().await.unwrap();
1952 let (durable, writes, full_syncs, range_syncs) = blob.snapshot();
1953 assert_eq!(durable.as_slice(), b"abcdefg");
1954 assert_eq!(writes, 2);
1955 assert_eq!(full_syncs, 1);
1956 assert_eq!(range_syncs, 0);
1957
1958 writer = writer.write_at(7, b"h").await.unwrap();
1960 writer.sync().await.unwrap();
1961
1962 let (durable, writes, full_syncs, range_syncs) = blob.snapshot();
1963 assert_eq!(durable.as_slice(), b"abcdefgh");
1964 assert_eq!(writes, 3);
1965 assert_eq!(full_syncs, 1);
1966 assert_eq!(range_syncs, 1);
1967 });
1968 }
1969
1970 #[test_traced]
1971 fn test_write_sync_uses_full_sync_after_resize() {
1972 let executor = deterministic::Runner::default();
1973 executor.start(|_| async move {
1974 let blob = SyncTrackingBlob::new();
1975 let blob = Arc::new(blob);
1976 let mut writer = Write::new(blob.clone(), 0, NZUsize!(8));
1977 writer = writer.sync().await.unwrap();
1978
1979 writer = writer.write_at(0, b"abcdef").await.unwrap();
1981 writer = writer.sync().await.unwrap();
1982
1983 writer = writer.resize(4).await.unwrap();
1985 writer.sync().await.unwrap();
1986
1987 let (durable, writes, full_syncs, range_syncs) = blob.snapshot();
1989 assert_eq!(durable.as_slice(), b"abcd");
1990 assert_eq!(writes, 1);
1991 assert_eq!(full_syncs, 2);
1992 assert_eq!(range_syncs, 1);
1993 });
1994 }
1995}