1use super::{Error, cursor::Cursor, metrics::Metrics};
4use crate::{
5 Context,
6 journal::contiguous::{Contiguous as _, variable},
7};
8use commonware_codec::CodecShared;
9use commonware_macros::boxed;
10use commonware_runtime::{
11 buffer::paged::CacheRef,
12 telemetry::metrics::{Gauge, GaugeExt as _},
13};
14use commonware_utils::channel::watch;
15use std::{
16 borrow::Borrow,
17 num::{NonZeroU64, NonZeroUsize},
18 ops::Range,
19 sync::{
20 Arc,
21 atomic::{AtomicU64, Ordering},
22 },
23};
24use tracing::debug;
25
26#[derive(Clone)]
28pub struct Config<C> {
29 pub partition: String,
31
32 pub items_per_section: NonZeroU64,
37
38 pub compression: Option<u8>,
46
47 pub codec_config: C,
49
50 pub page_cache: CacheRef,
52
53 pub write_buffer: NonZeroUsize,
55
56 pub replay_buffer: NonZeroUsize,
58}
59
60type Snapshot<E, V> = Arc<variable::Reader<'static, E, V>>;
62
63pub struct Queue<E: Context, V: CodecShared> {
99 journal: variable::Journal<E, V>,
101
102 tip: Gauge,
104
105 published: Range<u64>,
107
108 snapshots: watch::Sender<Snapshot<E, V>>,
110
111 floor: Arc<AtomicU64>,
113}
114
115impl<E: Context, V: CodecShared> Queue<E, V> {
116 #[boxed]
126 pub async fn init(context: E, cfg: Config<V::Cfg>) -> Result<(Self, Reader<E, V>), Error> {
127 let metrics = Metrics::init(&context);
129
130 let journal = variable::Journal::init(
132 context.child("journal"),
133 variable::Config {
134 partition: cfg.partition,
135 items_per_section: cfg.items_per_section,
136 compression: cfg.compression,
137 codec_config: cfg.codec_config,
138 page_cache: cfg.page_cache,
139 write_buffer: cfg.write_buffer,
140 replay_buffer: cfg.replay_buffer,
141 },
142 )
143 .await?;
144
145 let bounds = journal.bounds();
148 debug!(floor = bounds.start, size = bounds.end, "queue initialized");
149 let _ = metrics.tip.try_set(bounds.end);
150 let cursor = Cursor::new(bounds.start, metrics.next, metrics.floor);
151
152 let (journal, snapshot) = journal.snapshot().await?;
155 let snapshot = Arc::new(snapshot);
156 let (sender, receiver) = watch::channel(snapshot.clone());
157 let floor = Arc::new(AtomicU64::new(bounds.start));
158 let queue = Self {
159 journal,
160 tip: metrics.tip,
161 published: bounds,
162 snapshots: sender,
163 floor: floor.clone(),
164 };
165 let reader = Reader {
166 snapshot,
167 snapshots: receiver,
168 cursor,
169 floor,
170 };
171 Ok((queue, reader))
172 }
173
174 pub async fn enqueue(self, item: &V) -> Result<(Self, u64), Error> {
181 let (queue, pos) = self.append(item).await?;
182 let queue = queue.commit().await?;
183 debug!(position = pos, "enqueued item");
184 Ok((queue, pos))
185 }
186
187 pub async fn enqueue_bulk(
194 mut self,
195 items: impl IntoIterator<Item = impl Borrow<V>>,
196 ) -> Result<(Self, Range<u64>), Error> {
197 let start = self.journal.size();
199 for item in items {
200 (self, _) = self.append(item.borrow()).await?;
201 }
202
203 let end = self.journal.size();
205 if end > start {
206 self = self.commit().await?;
207 }
208 debug!(start, end, "enqueued bulk");
209 Ok((self, start..end))
210 }
211
212 pub async fn append(mut self, item: &V) -> Result<(Self, u64), Error> {
219 let pos;
220 (self.journal, pos) = self.journal.append(item).await?;
221 let _ = self.tip.try_set(pos + 1);
222 debug!(position = pos, "appended item");
223 Ok((self, pos))
224 }
225
226 pub async fn commit(mut self) -> Result<Self, Error> {
231 self.journal = self.journal.commit().await?;
232 self.publish().await
233 }
234
235 pub async fn sync(mut self) -> Result<Self, Error> {
240 self.journal = self.journal.sync().await?;
242
243 let floor = self.floor.load(Ordering::Relaxed);
245 (self.journal, _) = self.journal.prune(floor).await?;
246
247 self.publish().await
249 }
250
251 pub fn size(&self) -> u64 {
253 self.journal.size()
254 }
255
256 async fn publish(mut self) -> Result<Self, Error> {
258 let bounds = self.journal.bounds();
259 if bounds == self.published {
260 return Ok(self);
261 }
262
263 let snapshot;
265 (self.journal, snapshot) = self.journal.snapshot().await?;
266 self.published = bounds;
267 self.snapshots.send_replace(Arc::new(snapshot));
268 Ok(self)
269 }
270
271 #[boxed]
273 pub async fn destroy(self) -> Result<(), Error> {
274 self.journal.destroy().await?;
275 Ok(())
276 }
277}
278
279impl<E: Context, V: CodecShared> std::fmt::Debug for Queue<E, V> {
280 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
281 f.debug_struct("Queue")
282 .field("size", &self.size())
283 .finish_non_exhaustive()
284 }
285}
286
287pub struct Reader<E: Context, V: CodecShared> {
291 snapshot: Snapshot<E, V>,
293
294 snapshots: watch::Receiver<Snapshot<E, V>>,
296
297 cursor: Cursor,
299
300 floor: Arc<AtomicU64>,
302}
303
304impl<E: Context, V: CodecShared> Reader<E, V> {
305 pub async fn recv(&mut self) -> Result<Option<(u64, V)>, Error> {
316 loop {
318 if let Some(item) = self.try_recv().await? {
319 return Ok(Some(item));
320 }
321
322 if self.snapshots.changed().await.is_err() {
325 return Ok(None);
326 }
327 self.snapshot = self.snapshots.borrow_and_update().clone();
328 }
329 }
330
331 pub async fn try_recv(&mut self) -> Result<Option<(u64, V)>, Error> {
339 if self.snapshots.has_changed().unwrap_or(true) {
342 self.snapshot = self.snapshots.borrow_and_update().clone();
343 }
344 self.cursor.dequeue(&*self.snapshot).await
345 }
346
347 pub fn is_acked(&self, position: u64) -> bool {
349 self.cursor.is_acked(position)
350 }
351
352 pub fn ack(&mut self, position: u64) -> Result<(), Error> {
360 self.cursor.ack(position, self.published())?;
361 self.floor.store(self.cursor.ack_floor(), Ordering::Relaxed);
362 Ok(())
363 }
364
365 pub fn ack_up_to(&mut self, up_to: u64) -> Result<(), Error> {
372 self.cursor.ack_up_to(up_to, self.published())?;
373 self.floor.store(self.cursor.ack_floor(), Ordering::Relaxed);
374 Ok(())
375 }
376
377 pub const fn ack_floor(&self) -> u64 {
381 self.cursor.ack_floor()
382 }
383
384 pub const fn read_position(&self) -> u64 {
388 self.cursor.read_position()
389 }
390
391 pub fn is_empty(&self) -> bool {
393 self.cursor.is_empty(self.published())
394 }
395
396 pub fn reset(&mut self) {
399 self.cursor.reset();
400 }
401
402 fn published(&self) -> u64 {
404 self.snapshots.borrow().bounds().end
405 }
406
407 #[cfg(test)]
409 fn pending(&self) -> u64 {
410 self.published().saturating_sub(self.cursor.read_position())
411 }
412}
413
414#[cfg(test)]
415mod tests {
416 use super::*;
417 use commonware_codec::RangeCfg;
418 use commonware_macros::{select, test_traced};
419 use commonware_runtime::{
420 Metrics as _, Runner, Spawner, Supervisor as _,
421 buffer::paged::CacheRef,
422 deterministic,
423 mocks::{DelayedSyncContext, PendingSyncs},
424 };
425 use commonware_utils::{NZU16, NZU64, NZUsize};
426 use std::num::NonZeroU16;
427
428 const PAGE_SIZE: NonZeroU16 = NZU16!(1024);
429 const PAGE_CACHE_SIZE: NonZeroUsize = NZUsize!(10);
430
431 fn test_config(partition: &str) -> Config<(RangeCfg<usize>, ())> {
432 Config {
433 partition: partition.into(),
434 items_per_section: NZU64!(10),
435 compression: None,
436 codec_config: ((0..).into(), ()),
437 page_cache: CacheRef::new(PAGE_SIZE, PAGE_CACHE_SIZE),
438 write_buffer: NZUsize!(4096),
439 replay_buffer: NZUsize!(4096),
440 }
441 }
442
443 async fn init<E: Context>(
444 context: E,
445 cfg: Config<(RangeCfg<usize>, ())>,
446 ) -> Result<(Queue<E, Vec<u8>>, Reader<E, Vec<u8>>), Error> {
447 Queue::init(context, cfg).await
448 }
449
450 fn acked_above_count<E: Context, V: CodecShared>(reader: &Reader<E, V>) -> usize {
451 reader.cursor.acked_above_count()
452 }
453
454 #[test_traced]
455 fn test_basic_enqueue_dequeue() {
456 let executor = deterministic::Runner::default();
457 executor.start(|context| async move {
458 let cfg = test_config("test_basic");
459 let (mut queue, mut reader) = Queue::<_, Vec<u8>>::init(context.child("storage"), cfg)
460 .await
461 .unwrap();
462
463 assert!(reader.is_empty());
465 assert_eq!(reader.pending(), 0);
466 assert_eq!(queue.size(), 0);
467
468 let pos0;
470 (queue, pos0) = queue.enqueue(&b"item0".to_vec()).await.unwrap();
471 let pos1;
472 (queue, pos1) = queue.enqueue(&b"item1".to_vec()).await.unwrap();
473 let pos2;
474 (queue, pos2) = queue.enqueue(&b"item2".to_vec()).await.unwrap();
475
476 assert_eq!(pos0, 0);
477 assert_eq!(pos1, 1);
478 assert_eq!(pos2, 2);
479 assert_eq!(queue.size(), 3);
480 assert_eq!(reader.pending(), 3);
481 assert!(!reader.is_empty());
482
483 let (p, item) = reader.try_recv().await.unwrap().unwrap();
485 assert_eq!(p, 0);
486 assert_eq!(item, b"item0");
487 assert_eq!(reader.pending(), 2);
488
489 let (p, item) = reader.try_recv().await.unwrap().unwrap();
490 assert_eq!(p, 1);
491 assert_eq!(item, b"item1");
492 assert_eq!(reader.pending(), 1);
493
494 let (p, item) = reader.try_recv().await.unwrap().unwrap();
495 assert_eq!(p, 2);
496 assert_eq!(item, b"item2");
497 assert_eq!(reader.pending(), 0);
498
499 assert!(!reader.is_empty());
501 assert!(reader.try_recv().await.unwrap().is_none());
502 });
503 }
504
505 #[test_traced]
506 fn test_append_commit_batch() {
507 let executor = deterministic::Runner::default();
508 executor.start(|context| async move {
509 let cfg = test_config("test_batch");
510 let (mut queue, mut reader) = Queue::<_, Vec<u8>>::init(context.child("storage"), cfg)
511 .await
512 .unwrap();
513
514 for i in 0..5u8 {
516 (queue, _) = queue.append(&vec![i]).await.unwrap();
517 }
518 let mut queue = queue.commit().await.unwrap();
519 assert_eq!(queue.size(), 5);
520
521 for i in 0..5 {
523 let (pos, item) = reader.try_recv().await.unwrap().unwrap();
524 assert_eq!(pos, i);
525 assert_eq!(item, vec![i as u8]);
526 }
527
528 for i in 5..8u8 {
530 (queue, _) = queue.append(&vec![i]).await.unwrap();
531 }
532 let queue = queue.commit().await.unwrap();
533 let (queue, _) = queue.enqueue(&vec![8]).await.unwrap();
534 assert_eq!(queue.size(), 9);
535
536 reader.ack_up_to(9).unwrap();
537 assert!(reader.is_empty());
538 });
539 }
540
541 #[test_traced]
542 fn test_append_commit_persistence() {
543 let executor = deterministic::Runner::default();
544 executor.start(|context| async move {
545 let cfg = test_config("test_batch_persist");
546
547 {
548 let (mut queue, _reader) =
549 Queue::<_, Vec<u8>>::init(context.child("first"), cfg.clone())
550 .await
551 .unwrap();
552 for i in 0..4u8 {
553 (queue, _) = queue.append(&vec![i]).await.unwrap();
554 }
555 let queue = queue.commit().await.unwrap();
556 queue.sync().await.unwrap();
557 }
558
559 {
560 let (queue, mut reader) = Queue::<_, Vec<u8>>::init(context.child("second"), cfg)
561 .await
562 .unwrap();
563 assert_eq!(queue.size(), 4);
564 for i in 0..4 {
565 let (pos, item) = reader.try_recv().await.unwrap().unwrap();
566 assert_eq!(pos, i);
567 assert_eq!(item, vec![i as u8]);
568 }
569 }
570 });
571 }
572
573 #[test_traced]
574 fn test_commit_after_sync_recovers_without_second_sync() {
575 let executor = deterministic::Runner::default();
576 executor.start(|context| async move {
577 let cfg = test_config("test_commit_after_sync_recovery");
578
579 {
580 let (mut queue, _reader) =
581 Queue::<_, Vec<u8>>::init(context.child("first"), cfg.clone())
582 .await
583 .unwrap();
584
585 (queue, _) = queue.append(&b"synced".to_vec()).await.unwrap();
587 queue = queue.commit().await.unwrap();
588 queue = queue.sync().await.unwrap();
589
590 (queue, _) = queue.append(&b"committed-a".to_vec()).await.unwrap();
592 (queue, _) = queue.append(&b"committed-b".to_vec()).await.unwrap();
593 queue.commit().await.unwrap();
594 }
595
596 let (queue, mut reader) = Queue::<_, Vec<u8>>::init(context.child("second"), cfg)
597 .await
598 .unwrap();
599 assert_eq!(queue.size(), 3);
600 for (expected_pos, expected_item) in [
601 (0, b"synced".to_vec()),
602 (1, b"committed-a".to_vec()),
603 (2, b"committed-b".to_vec()),
604 ] {
605 let (pos, item) = reader.try_recv().await.unwrap().unwrap();
606 assert_eq!(pos, expected_pos);
607 assert_eq!(item, expected_item);
608 }
609
610 queue.destroy().await.unwrap();
611 });
612 }
613
614 #[test_traced]
615 fn test_sequential_ack() {
616 let executor = deterministic::Runner::default();
617 executor.start(|context| async move {
618 let cfg = test_config("test_seq_ack");
619 let (mut queue, mut reader) = Queue::<_, Vec<u8>>::init(context.child("storage"), cfg)
620 .await
621 .unwrap();
622
623 for i in 0..5u8 {
625 (queue, _) = queue.enqueue(&vec![i]).await.unwrap();
626 }
627
628 for i in 0..5 {
630 let (pos, _) = reader.try_recv().await.unwrap().unwrap();
631 assert_eq!(pos, i);
632 reader.ack(pos).unwrap();
633 assert_eq!(reader.ack_floor(), i + 1);
634 }
635
636 assert!(reader.is_empty());
638 assert_eq!(reader.ack_floor(), 5);
639 });
640 }
641
642 #[test_traced]
643 fn test_out_of_order_ack() {
644 let executor = deterministic::Runner::default();
645 executor.start(|context| async move {
646 let cfg = test_config("test_ooo_ack");
647 let (mut queue, mut reader) = Queue::<_, Vec<u8>>::init(context.child("storage"), cfg)
648 .await
649 .unwrap();
650
651 for i in 0..5u8 {
653 (queue, _) = queue.enqueue(&vec![i]).await.unwrap();
654 }
655
656 for _ in 0..5 {
658 reader.try_recv().await.unwrap();
659 }
660
661 reader.ack(2).unwrap();
663 assert_eq!(reader.ack_floor(), 0); assert!(reader.is_acked(2));
665
666 reader.ack(4).unwrap();
667 assert_eq!(reader.ack_floor(), 0);
668 assert!(reader.is_acked(4));
669
670 reader.ack(1).unwrap();
671 assert_eq!(reader.ack_floor(), 0);
672
673 reader.ack(3).unwrap();
674 assert_eq!(reader.ack_floor(), 0);
675
676 reader.ack(0).unwrap();
678 assert_eq!(reader.ack_floor(), 5);
679 assert!(reader.is_empty());
680 });
681 }
682
683 #[test_traced]
684 fn test_ack_up_to() {
685 let executor = deterministic::Runner::default();
686 executor.start(|context| async move {
687 let cfg = test_config("test_ack_up_to");
688 let (mut queue, mut reader) = Queue::<_, Vec<u8>>::init(context.child("storage"), cfg)
689 .await
690 .unwrap();
691
692 for i in 0..10u8 {
694 (queue, _) = queue.enqueue(&vec![i]).await.unwrap();
695 }
696
697 reader.ack_up_to(5).unwrap();
699 assert_eq!(reader.ack_floor(), 5);
700
701 for i in 0..5 {
703 assert!(reader.is_acked(i));
704 }
705 for i in 5..10 {
707 assert!(!reader.is_acked(i));
708 }
709
710 let (p, _) = reader.try_recv().await.unwrap().unwrap();
712 assert_eq!(p, 5);
713 });
714 }
715
716 #[test_traced]
717 fn test_ack_up_to_with_existing_acks() {
718 let executor = deterministic::Runner::default();
719 executor.start(|context| async move {
720 let cfg = test_config("test_ack_up_to_existing");
721 let (mut queue, mut reader) = Queue::<_, Vec<u8>>::init(context.child("storage"), cfg)
722 .await
723 .unwrap();
724
725 for i in 0..10u8 {
727 (queue, _) = queue.enqueue(&vec![i]).await.unwrap();
728 }
729
730 reader.ack(7).unwrap();
732 reader.ack(8).unwrap();
733 assert_eq!(acked_above_count(&reader), 2);
734
735 reader.ack_up_to(5).unwrap();
737 assert_eq!(reader.ack_floor(), 5);
738 assert_eq!(acked_above_count(&reader), 2);
739
740 reader.ack_up_to(9).unwrap();
742 assert_eq!(reader.ack_floor(), 9);
743 assert_eq!(acked_above_count(&reader), 0);
744 });
745 }
746
747 #[test_traced]
748 fn test_ack_up_to_coalesces_with_acked_above() {
749 let executor = deterministic::Runner::default();
750 executor.start(|context| async move {
751 let cfg = test_config("test_ack_up_to_coalesce");
752 let (mut queue, mut reader) = Queue::<_, Vec<u8>>::init(context.child("storage"), cfg)
753 .await
754 .unwrap();
755
756 for i in 0..10u8 {
758 (queue, _) = queue.enqueue(&vec![i]).await.unwrap();
759 }
760
761 reader.ack(5).unwrap();
763 reader.ack(6).unwrap();
764 reader.ack(7).unwrap();
765 assert_eq!(reader.ack_floor(), 0);
766
767 reader.ack_up_to(5).unwrap();
769 assert_eq!(reader.ack_floor(), 8); });
771 }
772
773 #[test_traced]
774 fn test_ack_up_to_errors() {
775 let executor = deterministic::Runner::default();
776 executor.start(|context| async move {
777 let cfg = test_config("test_ack_up_to_errors");
778 let (mut queue, mut reader) = Queue::<_, Vec<u8>>::init(context.child("storage"), cfg)
779 .await
780 .unwrap();
781
782 (queue, _) = queue.enqueue(&b"item0".to_vec()).await.unwrap();
783 let (_queue, _) = queue.enqueue(&b"item1".to_vec()).await.unwrap();
784
785 let err = reader.ack_up_to(5).unwrap_err();
787 assert!(matches!(err, Error::PositionOutOfRange(5, 2)));
788
789 reader.ack_up_to(2).unwrap();
791 assert_eq!(reader.ack_floor(), 2);
792
793 reader.ack_up_to(1).unwrap();
795 assert_eq!(reader.ack_floor(), 2);
796 });
797 }
798
799 #[test_traced]
800 fn test_dequeue_skips_acked() {
801 let executor = deterministic::Runner::default();
802 executor.start(|context| async move {
803 let cfg = test_config("test_skip_acked");
804 let (mut queue, mut reader) = Queue::<_, Vec<u8>>::init(context.child("storage"), cfg)
805 .await
806 .unwrap();
807
808 for i in 0..5u8 {
810 (queue, _) = queue.enqueue(&vec![i]).await.unwrap();
811 }
812
813 reader.ack(1).unwrap();
815 reader.ack(3).unwrap();
816
817 let (p, item) = reader.try_recv().await.unwrap().unwrap();
819 assert_eq!(p, 0);
820 assert_eq!(item, vec![0]);
821
822 let (p, item) = reader.try_recv().await.unwrap().unwrap();
823 assert_eq!(p, 2); assert_eq!(item, vec![2]);
825
826 let (p, item) = reader.try_recv().await.unwrap().unwrap();
827 assert_eq!(p, 4); assert_eq!(item, vec![4]);
829
830 assert!(reader.try_recv().await.unwrap().is_none());
831 });
832 }
833
834 #[test_traced]
835 fn test_ack_errors() {
836 let executor = deterministic::Runner::default();
837 executor.start(|context| async move {
838 let cfg = test_config("test_ack_errors");
839 let (mut queue, mut reader) = Queue::<_, Vec<u8>>::init(context.child("storage"), cfg)
840 .await
841 .unwrap();
842
843 (queue, _) = queue.enqueue(&b"item0".to_vec()).await.unwrap();
844 let (_queue, _) = queue.enqueue(&b"item1".to_vec()).await.unwrap();
845
846 let err = reader.ack(5).unwrap_err();
848 assert!(matches!(err, Error::PositionOutOfRange(5, 2)));
849
850 reader.ack(1).unwrap();
852 assert!(reader.is_acked(1));
853
854 reader.ack(1).unwrap();
856 });
857 }
858
859 #[test_traced]
860 fn test_prune() {
861 let executor = deterministic::Runner::default();
862 executor.start(|context| async move {
863 let cfg = test_config("test_prune");
864 let (mut queue, mut reader) = Queue::<_, Vec<u8>>::init(context.child("storage"), cfg)
865 .await
866 .unwrap();
867
868 for i in 0..25u8 {
870 (queue, _) = queue.enqueue(&vec![i]).await.unwrap();
871 }
872 let _queue = queue.sync().await.unwrap();
873
874 for i in 0..15 {
876 reader.try_recv().await.unwrap();
877 reader.ack(i).unwrap();
878 }
879 assert_eq!(reader.ack_floor(), 15);
880
881 let (p, item) = reader.try_recv().await.unwrap().unwrap();
883 assert_eq!(p, 15);
884 assert_eq!(item, vec![15]);
885 });
886 }
887
888 #[test_traced]
889 fn test_ack_across_sections() {
890 let executor = deterministic::Runner::default();
891 executor.start(|context| async move {
892 let cfg = test_config("test_multi_prune");
893 let (mut queue, mut reader) = Queue::<_, Vec<u8>>::init(context.child("storage"), cfg)
894 .await
895 .unwrap();
896
897 for i in 0..50u8 {
899 (queue, _) = queue.enqueue(&vec![i]).await.unwrap();
900 }
901 let _queue = queue.sync().await.unwrap();
902
903 for i in 0..15 {
905 reader.try_recv().await.unwrap();
906 reader.ack(i).unwrap();
907 }
908 assert_eq!(reader.ack_floor(), 15);
909
910 let (p, item) = reader.try_recv().await.unwrap().unwrap();
912 assert_eq!(p, 15);
913 assert_eq!(item, vec![15]);
914
915 reader.ack(15).unwrap();
917 for i in 16..30 {
918 reader.try_recv().await.unwrap();
919 reader.ack(i).unwrap();
920 }
921 assert_eq!(reader.ack_floor(), 30);
922
923 let (p, item) = reader.try_recv().await.unwrap().unwrap();
925 assert_eq!(p, 30);
926 assert_eq!(item, vec![30]);
927
928 reader.ack(30).unwrap();
930 for i in 31..50 {
931 reader.try_recv().await.unwrap();
932 reader.ack(i).unwrap();
933 }
934 assert_eq!(reader.ack_floor(), 50);
935
936 assert!(reader.is_empty());
938 assert!(reader.try_recv().await.unwrap().is_none());
939 });
940 }
941
942 #[test_traced]
943 fn test_crash_recovery_replays_from_pruning_boundary() {
944 let executor = deterministic::Runner::default();
946 executor.start(|context| async move {
947 let cfg = test_config("test_recovery_replay");
948
949 {
951 let (mut queue, mut reader) =
952 Queue::<_, Vec<u8>>::init(context.child("first"), cfg.clone())
953 .await
954 .unwrap();
955
956 for i in 0..5u8 {
957 (queue, _) = queue.enqueue(&vec![i]).await.unwrap();
958 }
959
960 reader.ack(0).unwrap();
962 reader.ack(1).unwrap();
963 reader.ack(2).unwrap();
964 assert_eq!(reader.ack_floor(), 3);
965
966 queue.sync().await.unwrap();
967 }
968
969 {
971 let (_queue, mut reader) =
972 Queue::<_, Vec<u8>>::init(context.child("second"), cfg.clone())
973 .await
974 .unwrap();
975
976 assert_eq!(reader.ack_floor(), 0);
978
979 for i in 0..5 {
981 let (p, _) = reader.try_recv().await.unwrap().unwrap();
982 assert_eq!(p, i);
983 }
984 }
985 });
986 }
987
988 #[test_traced]
989 fn test_crash_recovery_with_pruning() {
990 let executor = deterministic::Runner::default();
992 executor.start(|context| async move {
993 let cfg = test_config("test_recovery_pruned");
994
995 let expected_pruning_boundary = {
997 let (mut queue, mut reader) =
998 Queue::<_, Vec<u8>>::init(context.child("first"), cfg.clone())
999 .await
1000 .unwrap();
1001
1002 for i in 0..25u8 {
1004 (queue, _) = queue.enqueue(&vec![i]).await.unwrap();
1005 }
1006
1007 for i in 0..15 {
1009 reader.ack(i).unwrap();
1010 }
1011 assert_eq!(reader.ack_floor(), 15);
1012
1013 queue = queue.sync().await.unwrap();
1015
1016 let pruning_boundary = queue.journal.bounds().start;
1018 assert!(pruning_boundary > 0, "expected some pruning to occur");
1019
1020 pruning_boundary
1021 };
1022
1023 {
1025 let (queue, mut reader) =
1026 Queue::<_, Vec<u8>>::init(context.child("second"), cfg.clone())
1027 .await
1028 .unwrap();
1029
1030 let pruning_boundary = queue.journal.bounds().start;
1032 assert_eq!(reader.ack_floor(), pruning_boundary);
1033 assert_eq!(pruning_boundary, expected_pruning_boundary);
1034
1035 for i in pruning_boundary..25 {
1037 let (p, item) = reader.try_recv().await.unwrap().unwrap();
1038 assert_eq!(p, i);
1039 assert_eq!(item, vec![i as u8]);
1040 }
1041
1042 assert!(reader.try_recv().await.unwrap().is_none());
1043 }
1044 });
1045 }
1046
1047 #[test_traced]
1048 fn test_reset() {
1049 let executor = deterministic::Runner::default();
1050 executor.start(|context| async move {
1051 let cfg = test_config("test_reset");
1052 let (mut queue, mut reader) = Queue::<_, Vec<u8>>::init(context.child("storage"), cfg)
1053 .await
1054 .unwrap();
1055
1056 for i in 0..5u8 {
1058 (queue, _) = queue.enqueue(&vec![i]).await.unwrap();
1059 }
1060
1061 reader.try_recv().await.unwrap();
1063 reader.try_recv().await.unwrap();
1064 reader.try_recv().await.unwrap();
1065 assert_eq!(reader.read_position(), 3);
1066
1067 reader.reset();
1069 assert_eq!(reader.read_position(), 0);
1070
1071 let (p, item) = reader.try_recv().await.unwrap().unwrap();
1073 assert_eq!(p, 0);
1074 assert_eq!(item, vec![0]);
1075 });
1076 }
1077
1078 #[test_traced]
1079 fn test_reset_with_ack() {
1080 let executor = deterministic::Runner::default();
1081 executor.start(|context| async move {
1082 let cfg = test_config("test_reset_ack");
1083 let (mut queue, mut reader) = Queue::<_, Vec<u8>>::init(context.child("storage"), cfg)
1084 .await
1085 .unwrap();
1086
1087 for i in 0..10u8 {
1089 (queue, _) = queue.enqueue(&vec![i]).await.unwrap();
1090 }
1091
1092 for i in 0..5 {
1094 reader.try_recv().await.unwrap();
1095 reader.ack(i).unwrap();
1096 }
1097 assert_eq!(reader.ack_floor(), 5);
1098 assert_eq!(reader.read_position(), 5);
1099
1100 reader.try_recv().await.unwrap();
1102 reader.try_recv().await.unwrap();
1103 assert_eq!(reader.read_position(), 7);
1104
1105 reader.reset();
1107 assert_eq!(reader.read_position(), 5);
1108
1109 let (p, item) = reader.try_recv().await.unwrap().unwrap();
1111 assert_eq!(p, 5);
1112 assert_eq!(item, vec![5]);
1113 });
1114 }
1115
1116 #[test_traced]
1117 fn test_empty_queue_operations() {
1118 let executor = deterministic::Runner::default();
1119 executor.start(|context| async move {
1120 let cfg = test_config("test_empty");
1121 let (queue, mut reader) = Queue::<_, Vec<u8>>::init(context.child("storage"), cfg)
1122 .await
1123 .unwrap();
1124
1125 assert!(reader.is_empty());
1127 assert!(reader.try_recv().await.unwrap().is_none());
1128 let _queue = queue.sync().await.unwrap();
1129 reader.reset();
1130 });
1131 }
1132
1133 #[test_traced]
1134 fn test_persistence() {
1135 let executor = deterministic::Runner::default();
1136 executor.start(|context| async move {
1137 let cfg = test_config("test_persist");
1138
1139 {
1141 let (mut queue, _reader) =
1142 Queue::<_, Vec<u8>>::init(context.child("first"), cfg.clone())
1143 .await
1144 .unwrap();
1145
1146 (queue, _) = queue.enqueue(&b"item0".to_vec()).await.unwrap();
1147 (queue, _) = queue.enqueue(&b"item1".to_vec()).await.unwrap();
1148 queue.sync().await.unwrap();
1149 }
1150
1151 {
1153 let (queue, mut reader) =
1154 Queue::<_, Vec<u8>>::init(context.child("second"), cfg.clone())
1155 .await
1156 .unwrap();
1157
1158 assert_eq!(queue.size(), 2);
1159
1160 let (_, item) = reader.try_recv().await.unwrap().unwrap();
1161 assert_eq!(item, b"item0");
1162
1163 let (_, item) = reader.try_recv().await.unwrap().unwrap();
1164 assert_eq!(item, b"item1");
1165 }
1166 });
1167 }
1168
1169 #[test_traced]
1170 fn test_large_queue_with_sparse_acks() {
1171 let executor = deterministic::Runner::default();
1172 executor.start(|context| async move {
1173 let cfg = test_config("test_sparse");
1174 let (mut queue, mut reader) = Queue::<_, Vec<u8>>::init(context.child("storage"), cfg)
1175 .await
1176 .unwrap();
1177
1178 for i in 0..100u8 {
1180 (queue, _) = queue.enqueue(&vec![i]).await.unwrap();
1181 }
1182
1183 for i in (0..100).step_by(3) {
1185 reader.ack(i).unwrap();
1186 }
1187
1188 let mut received = Vec::new();
1190 while let Some((pos, _)) = reader.try_recv().await.unwrap() {
1191 received.push(pos);
1192 }
1193
1194 let expected: Vec<u64> = (0..100).filter(|x| x % 3 != 0).collect();
1196 assert_eq!(received, expected);
1197 });
1198 }
1199
1200 #[test_traced]
1201 fn test_acked_above_coalescing() {
1202 let executor = deterministic::Runner::default();
1203 executor.start(|context| async move {
1204 let cfg = test_config("test_coalesce");
1205 let (mut queue, mut reader) = Queue::<_, Vec<u8>>::init(context.child("storage"), cfg)
1206 .await
1207 .unwrap();
1208
1209 for i in 0..10u8 {
1211 (queue, _) = queue.enqueue(&vec![i]).await.unwrap();
1212 }
1213
1214 for i in 1..9 {
1216 reader.ack(i).unwrap();
1217 }
1218
1219 assert_eq!(reader.ack_floor(), 0);
1221 assert!(acked_above_count(&reader) > 0);
1222
1223 reader.ack(0).unwrap();
1225 assert_eq!(reader.ack_floor(), 9);
1226 assert_eq!(acked_above_count(&reader), 0);
1227 });
1228 }
1229
1230 #[test_traced]
1231 fn test_ack_up_to_past_read_pos() {
1232 let executor = deterministic::Runner::default();
1233 executor.start(|context| async move {
1234 let cfg = test_config("test_ack_up_to_past_read_pos");
1235 let (mut queue, mut reader) = Queue::<_, Vec<u8>>::init(context.child("storage"), cfg)
1236 .await
1237 .unwrap();
1238
1239 for i in 0..10u8 {
1240 (queue, _) = queue.enqueue(&vec![i]).await.unwrap();
1241 }
1242
1243 for _ in 0..3 {
1245 reader.try_recv().await.unwrap();
1246 }
1247 assert_eq!(reader.read_position(), 3);
1248
1249 reader.ack_up_to(7).unwrap();
1251 assert_eq!(reader.ack_floor(), 7);
1252
1253 let (pos, item) = reader.try_recv().await.unwrap().unwrap();
1255 assert_eq!(pos, 7);
1256 assert_eq!(item, vec![7]);
1257 });
1258 }
1259
1260 #[test_traced]
1261 fn test_metrics() {
1262 let executor = deterministic::Runner::default();
1263 executor.start(|context| async move {
1264 let cfg = test_config("test-metrics");
1265 let ctx = context.child("test_metrics");
1266 let (mut queue, mut reader) = Queue::<_, Vec<u8>>::init(ctx, cfg).await.unwrap();
1267
1268 let encoded = context.encode();
1269 assert!(
1270 encoded.contains("test_metrics_tip 0"),
1271 "expected tip 0: {encoded}"
1272 );
1273 assert!(
1274 encoded.contains("test_metrics_floor 0"),
1275 "expected floor 0: {encoded}"
1276 );
1277 assert!(
1278 encoded.contains("test_metrics_next 0"),
1279 "expected next 0: {encoded}"
1280 );
1281
1282 (queue, _) = queue.append(&vec![0]).await.unwrap();
1284 let encoded = context.encode();
1285 assert!(
1286 encoded.contains("test_metrics_tip 1"),
1287 "expected tip 1: {encoded}"
1288 );
1289 let mut queue = queue.commit().await.unwrap();
1290
1291 for i in 1..10u8 {
1293 (queue, _) = queue.enqueue(&vec![i]).await.unwrap();
1294 }
1295 let encoded = context.encode();
1296 assert!(
1297 encoded.contains("test_metrics_tip 10"),
1298 "expected tip 10: {encoded}"
1299 );
1300
1301 reader.try_recv().await.unwrap();
1303 reader.try_recv().await.unwrap();
1304 let encoded = context.encode();
1305 assert!(
1306 encoded.contains("test_metrics_next 2"),
1307 "expected next 2: {encoded}"
1308 );
1309
1310 reader.ack(0).unwrap();
1312 reader.ack(1).unwrap();
1313 let encoded = context.encode();
1314 assert!(
1315 encoded.contains("test_metrics_floor 2"),
1316 "expected floor 2: {encoded}"
1317 );
1318
1319 reader.ack(4).unwrap();
1321 reader.ack(6).unwrap();
1322 let encoded = context.encode();
1323 assert!(
1324 encoded.contains("test_metrics_floor 2"),
1325 "expected floor still 2: {encoded}"
1326 );
1327
1328 reader.ack(2).unwrap();
1330 reader.ack(3).unwrap();
1331 let encoded = context.encode();
1332 assert!(
1333 encoded.contains("test_metrics_floor 5"),
1334 "expected floor 5: {encoded}"
1335 );
1336
1337 reader.ack_up_to(8).unwrap();
1339 let encoded = context.encode();
1340 assert!(
1341 encoded.contains("test_metrics_floor 8"),
1342 "expected floor 8: {encoded}"
1343 );
1344
1345 reader.ack(8).unwrap();
1347 reader.ack(9).unwrap();
1348 let encoded = context.encode();
1349 assert!(
1350 encoded.contains("test_metrics_floor 10"),
1351 "expected floor 10: {encoded}"
1352 );
1353
1354 reader.reset();
1356 let encoded = context.encode();
1357 assert!(
1358 encoded.contains("test_metrics_next 10"),
1359 "expected next 10: {encoded}"
1360 );
1361 });
1362 }
1363
1364 #[test_traced]
1365 fn test_metrics_next_updates_on_fast_forward() {
1366 let executor = deterministic::Runner::default();
1367 executor.start(|context| async move {
1368 let cfg = test_config("test-ff");
1369 let ctx = context.child("test_ff");
1370 let (mut queue, mut reader) = Queue::<_, Vec<u8>>::init(ctx, cfg).await.unwrap();
1371
1372 for i in 0..3u8 {
1374 (queue, _) = queue.enqueue(&vec![i]).await.unwrap();
1375 }
1376 let (pos, _) = reader.try_recv().await.unwrap().unwrap();
1377 reader.ack(pos).unwrap();
1378
1379 let encoded = context.encode();
1380 assert!(
1381 encoded.contains("test_ff_next 1"),
1382 "expected next 1: {encoded}"
1383 );
1384
1385 reader.ack(2).unwrap();
1387 reader.ack(1).unwrap();
1388 assert_eq!(reader.ack_floor(), 3);
1389
1390 let encoded = context.encode();
1392 assert!(
1393 encoded.contains("test_ff_next 1"),
1394 "expected next still 1: {encoded}"
1395 );
1396
1397 assert!(reader.try_recv().await.unwrap().is_none());
1399 let encoded = context.encode();
1400 assert!(
1401 encoded.contains("test_ff_next 3"),
1402 "expected next 3 after fast-forward: {encoded}"
1403 );
1404 });
1405 }
1406
1407 #[test_traced]
1409 fn test_reader_basic() {
1410 let executor = deterministic::Runner::default();
1411 executor.start(|context| async move {
1412 let cfg = test_config("test_reader_basic");
1414 let (queue, mut reader) = init(context, cfg).await.unwrap();
1415
1416 let (_queue, pos) = queue.enqueue(&b"hello".to_vec()).await.unwrap();
1418 assert_eq!(pos, 0);
1419
1420 let (recv_pos, item) = reader.recv().await.unwrap().unwrap();
1422 assert_eq!(recv_pos, 0);
1423 assert_eq!(item, b"hello".to_vec());
1424
1425 reader.ack(recv_pos).unwrap();
1427 assert!(reader.is_empty());
1428 });
1429 }
1430
1431 #[test_traced]
1433 fn test_reader_append_commit() {
1434 let executor = deterministic::Runner::default();
1435 executor.start(|context| async move {
1436 let cfg = test_config("test_reader_append_commit");
1438 let (mut queue, mut reader) = init(context, cfg).await.unwrap();
1439
1440 for i in 0..5u8 {
1442 let pos;
1443 (queue, pos) = queue.append(&vec![i]).await.unwrap();
1444 assert_eq!(pos, i as u64);
1445 }
1446
1447 assert!(reader.try_recv().await.unwrap().is_none());
1449 assert!(matches!(
1450 reader.ack(0),
1451 Err(Error::PositionOutOfRange(0, 0))
1452 ));
1453 assert!(reader.is_empty());
1454
1455 let _queue = queue.commit().await.unwrap();
1457
1458 for i in 0..5 {
1460 let (pos, item) = reader.recv().await.unwrap().unwrap();
1461 assert_eq!(pos, i);
1462 assert_eq!(item, vec![i as u8]);
1463 reader.ack(pos).unwrap();
1464 }
1465 assert!(reader.is_empty());
1466 });
1467 }
1468
1469 #[test_traced]
1471 fn test_reader_enqueue_bulk() {
1472 let executor = deterministic::Runner::default();
1473 executor.start(|context| async move {
1474 let cfg = test_config("test_reader_bulk");
1476 let (queue, mut reader) = init(context, cfg).await.unwrap();
1477
1478 let items: Vec<_> = (0..5u8).map(|i| vec![i]).collect();
1480 let (_queue, range) = queue.enqueue_bulk(&items).await.unwrap();
1481 assert_eq!(range, 0..5);
1482
1483 for i in 0..5 {
1485 let (pos, item) = reader.recv().await.unwrap().unwrap();
1486 assert_eq!(pos, i);
1487 assert_eq!(item, vec![i as u8]);
1488 reader.ack(pos).unwrap();
1489 }
1490 assert!(reader.is_empty());
1491 });
1492 }
1493
1494 #[test_traced]
1496 fn test_reader_concurrent() {
1497 let executor = deterministic::Runner::default();
1498 executor.start(|context| async move {
1499 let cfg = test_config("test_reader_concurrent");
1501 let (queue, mut reader) = init(context.child("storage"), cfg).await.unwrap();
1502
1503 let queue_handle = context.child("queue").spawn(|_ctx| async move {
1505 let mut queue = queue;
1506 for i in 0..10u8 {
1507 (queue, _) = queue.enqueue(&vec![i]).await.unwrap();
1508 }
1509 queue
1510 });
1511
1512 let mut received = Vec::new();
1514 for _ in 0..10 {
1515 let (pos, item) = reader.recv().await.unwrap().unwrap();
1516 received.push((pos, item.clone()));
1517 reader.ack(pos).unwrap();
1518 }
1519
1520 for (i, (pos, item)) in received.iter().enumerate() {
1522 assert_eq!(*pos, i as u64);
1523 assert_eq!(*item, vec![i as u8]);
1524 }
1525
1526 let _ = queue_handle.await.unwrap();
1527 });
1528 }
1529
1530 #[test_traced]
1532 fn test_reader_select() {
1533 let executor = deterministic::Runner::default();
1534 executor.start(|context| async move {
1535 let cfg = test_config("test_reader_select");
1537 let (queue, mut reader) = init(context.child("storage"), cfg).await.unwrap();
1538
1539 let (_queue, _) = queue.enqueue(&b"test".to_vec()).await.unwrap();
1541
1542 let result = select! {
1544 item = reader.recv() => item,
1545 _ = futures::future::pending::<()>() => unreachable!(),
1546 };
1547
1548 let (pos, item) = result.unwrap().unwrap();
1549 assert_eq!(pos, 0);
1550 assert_eq!(item, b"test".to_vec());
1551
1552 reader.ack(pos).unwrap();
1553 });
1554 }
1555
1556 #[test_traced]
1559 fn test_reader_queue_dropped() {
1560 let executor = deterministic::Runner::default();
1561 executor.start(|context| async move {
1562 let cfg = test_config("test_reader_queue_dropped");
1564 let (queue, mut reader) = init(context.child("storage"), cfg).await.unwrap();
1565
1566 let (queue, _) = queue.enqueue(&b"item1".to_vec()).await.unwrap();
1568 let (queue, _) = queue.enqueue(&b"item2".to_vec()).await.unwrap();
1569 drop(queue);
1570
1571 let (pos1, _) = reader.recv().await.unwrap().unwrap();
1573 reader.ack(pos1).unwrap();
1574
1575 let (pos2, _) = reader.recv().await.unwrap().unwrap();
1576 reader.ack(pos2).unwrap();
1577
1578 let result = reader.recv().await.unwrap();
1580 assert!(result.is_none());
1581 });
1582 }
1583
1584 #[test_traced]
1586 fn test_reader_try_recv() {
1587 let executor = deterministic::Runner::default();
1588 executor.start(|context| async move {
1589 let cfg = test_config("test_reader_try_recv");
1591 let (queue, mut reader) = init(context, cfg).await.unwrap();
1592
1593 let result = reader.try_recv().await.unwrap();
1595 assert!(result.is_none());
1596
1597 let (_queue, _) = queue.enqueue(&b"item".to_vec()).await.unwrap();
1599 let (pos, item) = reader.try_recv().await.unwrap().unwrap();
1600 assert_eq!(pos, 0);
1601 assert_eq!(item, b"item".to_vec());
1602
1603 reader.ack(pos).unwrap();
1604 });
1605 }
1606
1607 #[test_traced]
1609 fn test_reader_try_recv_after_queue_dropped() {
1610 let executor = deterministic::Runner::default();
1611 executor.start(|context| async move {
1612 let cfg = test_config("test_reader_try_recv_dropped");
1614 let (queue, mut reader) = init(context, cfg).await.unwrap();
1615 let (queue, _) = queue.enqueue_bulk((0..3u8).map(|i| vec![i])).await.unwrap();
1616 drop(queue);
1617
1618 for i in 0..3 {
1620 let (pos, item) = reader.try_recv().await.unwrap().unwrap();
1621 assert_eq!(pos, i);
1622 assert_eq!(item, vec![i as u8]);
1623 }
1624 assert!(reader.try_recv().await.unwrap().is_none());
1625 });
1626 }
1627
1628 #[test_traced]
1631 fn test_reader_ends_after_interrupted_mutation() {
1632 let executor = deterministic::Runner::default();
1633 executor.start(|context| async move {
1634 let pending = PendingSyncs::default();
1636 let context = DelayedSyncContext {
1637 inner: context,
1638 pending: pending.clone(),
1639 };
1640 let cfg = test_config("test_reader_interrupted");
1641 let (queue, mut reader) = init(context.child("storage"), cfg).await.unwrap();
1642
1643 pending.unblock();
1645 let (queue, _) = queue.enqueue(&b"first".to_vec()).await.unwrap();
1646
1647 pending.arm();
1649 let second = b"second".to_vec();
1650 let mut enqueue = Box::pin(queue.enqueue(&second));
1651 assert!(futures::poll!(enqueue.as_mut()).is_pending());
1652 drop(enqueue);
1653
1654 let (pos, item) = reader.recv().await.unwrap().unwrap();
1656 assert_eq!(pos, 0);
1657 assert_eq!(item, b"first".to_vec());
1658 assert!(reader.recv().await.unwrap().is_none());
1659 });
1660 }
1661
1662 #[test_traced]
1664 fn test_reader_sync_publishes() {
1665 let executor = deterministic::Runner::default();
1666 executor.start(|context| async move {
1667 let cfg = test_config("test_reader_sync_publishes");
1668 let (queue, mut reader) = init(context, cfg).await.unwrap();
1669
1670 let (queue, _) = queue.append(&vec![7]).await.unwrap();
1672 assert!(reader.try_recv().await.unwrap().is_none());
1673 let _queue = queue.sync().await.unwrap();
1674
1675 let (pos, item) = reader.try_recv().await.unwrap().unwrap();
1677 assert_eq!(pos, 0);
1678 assert_eq!(item, vec![7]);
1679 });
1680 }
1681
1682 #[test_traced]
1684 fn test_reader_ack_up_to_prunes() {
1685 let executor = deterministic::Runner::default();
1686 executor.start(|context| async move {
1687 let cfg = test_config("test_reader_ack_up_to");
1689 let (queue, mut reader) = init(context.child("first"), cfg.clone()).await.unwrap();
1690 let (queue, _) = queue
1691 .enqueue_bulk((0..25u8).map(|i| vec![i]))
1692 .await
1693 .unwrap();
1694 reader.ack_up_to(15).unwrap();
1695 assert_eq!(reader.ack_floor(), 15);
1696
1697 let queue = queue.sync().await.unwrap();
1699 drop(queue);
1700 drop(reader);
1701
1702 let (_queue, reader) = init(context.child("second"), cfg).await.unwrap();
1704 assert_eq!(reader.ack_floor(), 10);
1705 });
1706 }
1707
1708 #[test_traced]
1711 fn test_reader_sync_prunes_below_ack_floor() {
1712 let executor = deterministic::Runner::default();
1713 executor.start(|context| async move {
1714 let cfg = test_config("test_reader_sync_prunes");
1716 let (queue, mut reader) = init(context.child("first"), cfg.clone()).await.unwrap();
1717 let (queue, _) = queue
1718 .enqueue_bulk((0..25u8).map(|i| vec![i]))
1719 .await
1720 .unwrap();
1721
1722 for i in 0..15 {
1725 let (pos, _) = reader.recv().await.unwrap().unwrap();
1726 assert_eq!(pos, i);
1727 reader.ack(pos).unwrap();
1728 }
1729 assert_eq!(reader.ack_floor(), 15);
1730 let queue = queue.sync().await.unwrap();
1731 assert_eq!(queue.size(), 25);
1732
1733 let (pos, _) = reader.recv().await.unwrap().unwrap();
1735 assert_eq!(pos, 15);
1736 assert_eq!(reader.snapshot.bounds().start, 10);
1737 for i in 16..25 {
1738 let (pos, item) = reader.recv().await.unwrap().unwrap();
1739 assert_eq!(pos, i);
1740 assert_eq!(item, vec![i as u8]);
1741 }
1742 assert!(reader.try_recv().await.unwrap().is_none());
1743 drop(queue);
1744 drop(reader);
1745
1746 let (_queue, mut reader) = init(context.child("second"), cfg).await.unwrap();
1748 assert_eq!(reader.ack_floor(), 10);
1749 let (pos, item) = reader.recv().await.unwrap().unwrap();
1750 assert_eq!(pos, 10);
1751 assert_eq!(item, vec![10]);
1752 });
1753 }
1754}