1use std::{
2 collections::{HashMap, VecDeque},
3 hint,
4 marker::PhantomData,
5 sync::{
6 Arc, Condvar, Mutex, MutexGuard,
7 atomic::{AtomicBool, AtomicU8, AtomicU64, AtomicUsize, Ordering, fence},
8 mpsc,
9 },
10 thread,
11 time::Duration,
12};
13
14use arc_swap::{ArcSwap, ArcSwapOption};
15use ractor::{Actor, ActorProcessingErr, ActorRef};
16use tokio::sync::Notify;
17
18use crate::{
19 StreamError, StreamResult,
20 actor::block_on_ractor_runtime,
21 stream::{BoxStream, NotUsed, Source, current_stream_cancelled},
22};
23
24const SLOT_WAIT_BACKSTOP: Duration = Duration::from_millis(10);
25const SUBSCRIPTION_DRAIN_BATCH: usize = 256;
26const STATE_OPEN: u8 = 0;
27const STATE_CLOSING: u8 = 1;
28const STATE_CLOSED: u8 = 2;
29const UNSEEDED_CURSOR: u64 = u64::MAX;
30const NO_DROP_FROM: u64 = u64::MAX;
31const NO_TERMINAL_FROM: u64 = u64::MAX;
32
33type Ack = mpsc::Sender<StreamResult<()>>;
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub enum SubscriptionOverflow {
38 Backpressure,
41 DropNew,
45 Fail,
48}
49
50pub struct Subscription<T: Send + Sync + 'static> {
72 inner: Arc<SubscriptionInner<T>>,
73}
74
75struct SubscriptionInner<T: Send + Sync + 'static> {
76 actor: ActorRef<SubscriptionMessage<T>>,
77 shared: Arc<SubscriptionShared<T>>,
78 next_subscriber_id: Arc<AtomicU64>,
79}
80
81struct SubscriptionShared<T: Send + Sync + 'static> {
82 mirror: Arc<ArcSwap<T>>,
83 published: Arc<ArcSwap<PublishedValue<T>>>,
84 subscribers: Arc<ArcSwap<SubscriptionSlotTable<T>>>,
85 ring: SubscriptionRing<T>,
86 overflow: SubscriptionOverflow,
87 lifecycle: AtomicU8,
88 active_writers: AtomicUsize,
89 next_sequence: AtomicU64,
90 published_sequence: AtomicU64,
91 parked_slots: Arc<AtomicUsize>,
92}
93
94struct PublishedValue<T: Send + Sync + 'static> {
95 sequence: u64,
96 value: Arc<T>,
97}
98
99struct SubscriptionSlotTable<T: Send + Sync + 'static> {
100 slots: Vec<Arc<SubscriptionSlot<T>>>,
101}
102
103struct SubscriptionRing<T: Send + Sync + 'static> {
104 logical_capacity: u64,
105 physical_capacity: usize,
106 slots: Vec<SubscriptionRingSlot<T>>,
107 space_lock: Mutex<()>,
108 space_available: Condvar,
109 space_waiters: AtomicUsize,
110}
111
112struct SubscriptionRingSlot<T: Send + Sync + 'static> {
113 sequence: AtomicU64,
114 value: ArcSwapOption<T>,
115}
116
117impl<T: Send + Sync + 'static> Clone for Subscription<T> {
118 fn clone(&self) -> Self {
119 Self {
120 inner: Arc::clone(&self.inner),
121 }
122 }
123}
124
125impl<T: Send + Sync + 'static> Subscription<T> {
126 pub fn new(initial: T, capacity: usize, overflow: SubscriptionOverflow) -> StreamResult<Self> {
130 assert!(
131 capacity > 0,
132 "subscription capacity must be greater than zero"
133 );
134 let value = Arc::new(initial);
135 let shared = Arc::new(SubscriptionShared {
136 mirror: Arc::new(ArcSwap::from(Arc::clone(&value))),
137 published: Arc::new(ArcSwap::from_pointee(PublishedValue {
138 sequence: 0,
139 value: Arc::clone(&value),
140 })),
141 subscribers: Arc::new(ArcSwap::from_pointee(SubscriptionSlotTable {
142 slots: Vec::new(),
143 })),
144 ring: SubscriptionRing::new(capacity),
145 overflow,
146 lifecycle: AtomicU8::new(STATE_OPEN),
147 active_writers: AtomicUsize::new(0),
148 next_sequence: AtomicU64::new(0),
149 published_sequence: AtomicU64::new(0),
150 parked_slots: Arc::new(AtomicUsize::new(0)),
151 });
152 let state = SubscriptionActorState {
153 shared: Arc::clone(&shared),
154 subscribers: HashMap::new(),
155 closed: false,
156 };
157 let (actor, _handle) =
158 block_on_ractor_runtime(Actor::spawn(None, SubscriptionActor::<T>::default(), state))?
159 .map_err(|error| {
160 StreamError::Failed(format!("subscription actor failed to spawn: {error}"))
161 })?;
162 Ok(Self {
163 inner: Arc::new(SubscriptionInner {
164 actor,
165 shared,
166 next_subscriber_id: Arc::new(AtomicU64::new(1)),
167 }),
168 })
169 }
170
171 #[must_use]
173 pub fn get(&self) -> Arc<T> {
174 self.inner.shared.mirror.load_full()
175 }
176
177 #[must_use]
183 pub fn get_cloned(&self) -> T
184 where
185 T: Clone,
186 {
187 self.inner.shared.mirror.load().as_ref().clone()
188 }
189
190 pub fn set(&self, value: T) -> StreamResult<()> {
192 self.publish_set(Arc::new(value))
193 }
194
195 pub fn set_eventually(&self, value: T) -> StreamResult<()> {
200 self.publish_set(Arc::new(value))
201 }
202
203 pub fn update<F>(&self, update: F) -> StreamResult<()>
207 where
208 F: FnMut(&T) -> T + Send + 'static,
209 {
210 self.publish_update(update)
211 }
212
213 pub fn update_eventually<F>(&self, update: F) -> StreamResult<()>
217 where
218 F: FnMut(&T) -> T + Send + 'static,
219 {
220 self.publish_update(update)
221 }
222
223 pub fn close(&self) -> StreamResult<()> {
225 self.send_close(None)
226 }
227
228 pub fn close_with(&self, final_value: T) -> StreamResult<()> {
230 self.send_close(Some(final_value))
231 }
232
233 fn publish_set(&self, value: Arc<T>) -> StreamResult<()> {
234 let _permit = self.inner.shared.begin_write()?;
235 let sequence = self.inner.shared.claim_sequence();
236 self.inner.shared.wait_publish_turn(sequence);
237 self.inner.shared.wait_for_ring_capacity(sequence);
238 let overflow = self.inner.shared.apply_overflow_policy(sequence);
239 self.inner.shared.finish_publish(sequence, value);
240 overflow
241 }
242
243 fn publish_update<F>(&self, mut update: F) -> StreamResult<()>
244 where
245 F: FnMut(&T) -> T + Send + 'static,
246 {
247 let _permit = self.inner.shared.begin_write()?;
248 let sequence = self.inner.shared.claim_sequence();
249 self.inner.shared.wait_publish_turn(sequence);
250 self.inner.shared.wait_for_ring_capacity(sequence);
251 let value = loop {
252 let current = self.inner.shared.mirror.load();
253 let next = Arc::new(update(current.as_ref()));
254 let previous = self
255 .inner
256 .shared
257 .mirror
258 .compare_and_swap(&*current, Arc::clone(&next));
259 if std::ptr::eq(current.as_ref(), previous.as_ref()) {
260 break next;
261 }
262 };
263 let overflow = self.inner.shared.apply_overflow_policy(sequence);
264 self.inner.shared.ring.store(sequence, Arc::clone(&value));
265 self.inner
266 .shared
267 .finish_publish_after_mirror(sequence, value);
268 overflow
269 }
270
271 fn send_close(&self, final_value: Option<T>) -> StreamResult<()> {
272 let (reply, receiver) = mpsc::channel();
273 self.inner
274 .actor
275 .send_message(SubscriptionMessage::Close { final_value, reply })
276 .map_err(|error| StreamError::ActorAskSendFailed {
277 reason: error.to_string(),
278 })?;
279 receiver.recv().unwrap_or(Err(StreamError::ActorTerminated))
280 }
281
282 fn register_slot(&self, slot: Arc<SubscriptionSlot<T>>, id: u64) -> StreamResult<()> {
283 let (reply, receiver) = mpsc::channel();
284 self.inner
285 .actor
286 .send_message(SubscriptionMessage::Subscribe { id, slot, reply })
287 .map_err(|error| StreamError::ActorAskSendFailed {
288 reason: error.to_string(),
289 })?;
290 receiver.recv().unwrap_or(Err(StreamError::ActorTerminated))
291 }
292}
293
294impl<T: Clone + Send + Sync + 'static> Subscription<T> {
295 #[must_use]
301 pub fn changes(&self) -> Source<T> {
302 let actor = self.inner.actor.clone();
303 let subscription = self.clone();
304 let shared = Arc::clone(&self.inner.shared);
305 let next_subscriber_id = Arc::clone(&self.inner.next_subscriber_id);
306 Source::from_materialized_factory(move |_materializer| {
307 let id = next_subscriber_id.fetch_add(1, Ordering::Relaxed);
308 let slot = SubscriptionSlot::new(id, actor.clone(), Arc::clone(&shared.parked_slots));
309 subscription.register_slot(Arc::clone(&slot), id)?;
310 let stream: BoxStream<T> = Box::new(SubscriptionChangesStream {
311 shared: Arc::clone(&shared),
312 slot,
313 pending: VecDeque::new(),
314 terminated: false,
315 });
316 Ok((stream, NotUsed))
317 })
318 }
319
320 #[doc(hidden)]
321 pub fn __benchmark_changes(&self) -> StreamResult<SubscriptionBenchmarkStream<T>> {
322 let id = self
323 .inner
324 .next_subscriber_id
325 .fetch_add(1, Ordering::Relaxed);
326 let slot = SubscriptionSlot::new(
327 id,
328 self.inner.actor.clone(),
329 Arc::clone(&self.inner.shared.parked_slots),
330 );
331 self.register_slot(Arc::clone(&slot), id)?;
332 Ok(SubscriptionBenchmarkStream {
333 shared: Arc::clone(&self.inner.shared),
334 slot,
335 pending: VecDeque::new(),
336 terminated: false,
337 })
338 }
339}
340
341impl<T: Send + Sync + 'static> SubscriptionShared<T> {
342 fn begin_write(&self) -> StreamResult<WritePermit<'_>> {
343 if self.lifecycle.load(Ordering::Acquire) != STATE_OPEN {
344 return Err(closed_error());
345 }
346 self.active_writers.fetch_add(1, Ordering::AcqRel);
347 if self.lifecycle.load(Ordering::Acquire) == STATE_OPEN {
348 Ok(WritePermit {
349 active_writers: &self.active_writers,
350 })
351 } else {
352 self.active_writers.fetch_sub(1, Ordering::AcqRel);
353 Err(closed_error())
354 }
355 }
356
357 fn claim_sequence(&self) -> u64 {
358 self.next_sequence.fetch_add(1, Ordering::AcqRel) + 1
359 }
360
361 fn wait_publish_turn(&self, sequence: u64) {
362 let mut spins = 0_u32;
363 while self.published_sequence.load(Ordering::Acquire) + 1 != sequence {
364 spins = spins.wrapping_add(1);
365 if spins < 64 {
366 hint::spin_loop();
367 } else {
368 thread::yield_now();
369 }
370 }
371 }
372
373 fn wait_for_ring_capacity(&self, sequence: u64) {
374 if self.overflow != SubscriptionOverflow::Backpressure {
375 return;
376 }
377 let mut guard = self
378 .ring
379 .space_lock
380 .lock()
381 .unwrap_or_else(|poison| poison.into_inner());
382 while self.sequence_would_overflow(sequence) {
383 self.ring.space_waiters.fetch_add(1, Ordering::AcqRel);
384 if !self.sequence_would_overflow(sequence) {
385 self.ring.space_waiters.fetch_sub(1, Ordering::AcqRel);
386 break;
387 }
388 guard = self
389 .ring
390 .space_available
391 .wait_timeout(guard, SLOT_WAIT_BACKSTOP)
392 .unwrap_or_else(|poison| poison.into_inner())
393 .0;
394 self.ring.space_waiters.fetch_sub(1, Ordering::AcqRel);
395 }
396 }
397
398 fn sequence_would_overflow(&self, sequence: u64) -> bool {
399 let Some(cursor) = self.min_active_cursor() else {
400 return false;
401 };
402 sequence >= cursor.saturating_add(self.ring.logical_capacity)
403 }
404
405 fn min_active_cursor(&self) -> Option<u64> {
406 let table = self.subscribers.load();
407 table
408 .slots
409 .iter()
410 .filter_map(|slot| slot.backpressure_cursor())
411 .min()
412 }
413
414 fn apply_overflow_policy(&self, sequence: u64) -> StreamResult<()> {
415 match self.overflow {
416 SubscriptionOverflow::Backpressure => Ok(()),
417 SubscriptionOverflow::DropNew => {
418 let table = self.subscribers.load();
419 for slot in &table.slots {
420 if slot.is_full_for(sequence, self.ring.logical_capacity) {
421 slot.drop_new(sequence, self.ring.logical_capacity);
422 }
423 }
424 Ok(())
425 }
426 SubscriptionOverflow::Fail => {
427 let table = self.subscribers.load();
428 let mut overflowed = false;
429 let error = overflow_error(self.ring.logical_capacity);
430 for slot in &table.slots {
431 if slot.is_full_for(sequence, self.ring.logical_capacity) {
432 overflowed = true;
433 slot.fail_after(sequence, error.clone());
434 }
435 }
436 if overflowed { Err(error) } else { Ok(()) }
437 }
438 }
439 }
440
441 fn finish_publish(&self, sequence: u64, value: Arc<T>) {
442 self.ring.store(sequence, Arc::clone(&value));
443 self.mirror.store(Arc::clone(&value));
444 self.finish_publish_after_mirror(sequence, value);
445 }
446
447 fn finish_publish_after_mirror(&self, sequence: u64, value: Arc<T>) {
448 self.published.store(Arc::new(PublishedValue {
449 sequence,
450 value: Arc::clone(&value),
451 }));
452 self.published_sequence.store(sequence, Ordering::Release);
453 if self.parked_slots.load(Ordering::Acquire) != 0 {
454 let table = self.subscribers.load();
455 for slot in &table.slots {
456 slot.wake_for_sequence(sequence);
457 }
458 }
459 }
460
461 fn wait_for_writers_to_drain(&self) {
462 while self.active_writers.load(Ordering::Acquire) != 0 {
463 thread::yield_now();
464 }
465 }
466}
467
468impl<T: Send + Sync + 'static> SubscriptionRing<T> {
469 fn new(logical_capacity: usize) -> Self {
470 let physical_capacity = logical_capacity.max(1_024).next_power_of_two();
471 let mut slots = Vec::with_capacity(physical_capacity);
472 for _ in 0..physical_capacity {
473 slots.push(SubscriptionRingSlot {
474 sequence: AtomicU64::new(0),
475 value: ArcSwapOption::empty(),
476 });
477 }
478 Self {
479 logical_capacity: logical_capacity as u64,
480 physical_capacity,
481 slots,
482 space_lock: Mutex::new(()),
483 space_available: Condvar::new(),
484 space_waiters: AtomicUsize::new(0),
485 }
486 }
487
488 fn store(&self, sequence: u64, value: Arc<T>) {
489 let slot = &self.slots[self.index(sequence)];
490 slot.value.store(Some(value));
491 slot.sequence.store(sequence, Ordering::Release);
492 }
493
494 fn load(&self, sequence: u64) -> Option<Arc<T>> {
495 let slot = &self.slots[self.index(sequence)];
496 if slot.sequence.load(Ordering::Acquire) == sequence {
497 slot.value.load_full()
498 } else {
499 None
500 }
501 }
502
503 fn has(&self, sequence: u64) -> bool {
504 let slot = &self.slots[self.index(sequence)];
505 slot.sequence.load(Ordering::Acquire) == sequence
506 }
507
508 fn oldest_available(&self, published_sequence: u64) -> u64 {
509 published_sequence
510 .saturating_sub(self.physical_capacity as u64)
511 .saturating_add(1)
512 .max(1)
513 }
514
515 fn notify_space(&self) {
516 if self.space_waiters.load(Ordering::Acquire) == 0 {
517 return;
518 }
519 let _guard = self
520 .space_lock
521 .lock()
522 .unwrap_or_else(|poison| poison.into_inner());
523 self.space_available.notify_all();
524 }
525
526 fn index(&self, sequence: u64) -> usize {
527 sequence as usize & (self.physical_capacity - 1)
528 }
529}
530
531struct WritePermit<'a> {
532 active_writers: &'a AtomicUsize,
533}
534
535impl Drop for WritePermit<'_> {
536 fn drop(&mut self) {
537 self.active_writers.fetch_sub(1, Ordering::AcqRel);
538 }
539}
540
541impl<T: Send + Sync + 'static> Drop for SubscriptionInner<T> {
542 fn drop(&mut self) {
543 self.actor.stop(None);
544 }
545}
546
547enum SubscriptionMessage<T: Send + Sync + 'static> {
548 Close {
549 final_value: Option<T>,
550 reply: Ack,
551 },
552 Subscribe {
553 id: u64,
554 slot: Arc<SubscriptionSlot<T>>,
555 reply: Ack,
556 },
557 Unsubscribe {
558 id: u64,
559 },
560}
561
562struct SubscriptionActor<T> {
563 _marker: PhantomData<fn() -> T>,
564}
565
566impl<T> Default for SubscriptionActor<T> {
567 fn default() -> Self {
568 Self {
569 _marker: PhantomData,
570 }
571 }
572}
573
574struct SubscriptionActorState<T: Send + Sync + 'static> {
575 shared: Arc<SubscriptionShared<T>>,
576 subscribers: HashMap<u64, Arc<SubscriptionSlot<T>>>,
577 closed: bool,
578}
579
580impl<T: Send + Sync + 'static> Actor for SubscriptionActor<T> {
581 type Msg = SubscriptionMessage<T>;
582 type State = SubscriptionActorState<T>;
583 type Arguments = SubscriptionActorState<T>;
584
585 async fn pre_start(
586 &self,
587 _myself: ActorRef<Self::Msg>,
588 args: Self::Arguments,
589 ) -> Result<Self::State, ActorProcessingErr> {
590 Ok(args)
591 }
592
593 async fn handle(
594 &self,
595 _myself: ActorRef<Self::Msg>,
596 message: Self::Msg,
597 state: &mut Self::State,
598 ) -> Result<(), ActorProcessingErr> {
599 match message {
600 SubscriptionMessage::Close { final_value, reply } => {
601 close_subscription(state, final_value);
602 let _ = reply.send(Ok(()));
603 }
604 SubscriptionMessage::Subscribe { id, slot, reply } => {
605 if state.closed || state.shared.lifecycle.load(Ordering::Acquire) == STATE_CLOSED {
606 let published = state.shared.published.load_full();
607 slot.complete_post_close(Arc::clone(&published.value));
608 } else {
609 state.subscribers.insert(id, Arc::clone(&slot));
610 publish_subscription_slot_table(state);
611 let published = state.shared.published.load_full();
612 slot.seed(
613 published.sequence.saturating_add(1),
614 Arc::clone(&published.value),
615 );
616 }
617 let _ = reply.send(Ok(()));
618 }
619 SubscriptionMessage::Unsubscribe { id } => {
620 state.subscribers.remove(&id);
621 publish_subscription_slot_table(state);
622 state.shared.ring.notify_space();
623 }
624 }
625 Ok(())
626 }
627
628 async fn post_stop(
629 &self,
630 _myself: ActorRef<Self::Msg>,
631 state: &mut Self::State,
632 ) -> Result<(), ActorProcessingErr> {
633 if !state.closed {
634 for slot in state.subscribers.values() {
635 slot.fail_now(StreamError::ActorTerminated);
636 }
637 state.subscribers.clear();
638 publish_subscription_slot_table(state);
639 state.shared.ring.notify_space();
640 }
641 Ok(())
642 }
643}
644
645fn close_subscription<T: Send + Sync + 'static>(
646 state: &mut SubscriptionActorState<T>,
647 final_value: Option<T>,
648) {
649 if state.closed {
650 return;
651 }
652 match state.shared.lifecycle.compare_exchange(
653 STATE_OPEN,
654 STATE_CLOSING,
655 Ordering::AcqRel,
656 Ordering::Acquire,
657 ) {
658 Ok(_) => {}
659 Err(STATE_CLOSED) => {
660 state.closed = true;
661 return;
662 }
663 Err(_) => {}
664 }
665 state.shared.wait_for_writers_to_drain();
666
667 let sequence = state.shared.claim_sequence();
668 state.shared.wait_publish_turn(sequence);
669 let value = final_value
670 .map(Arc::new)
671 .unwrap_or_else(|| state.shared.mirror.load_full());
672 state.shared.mirror.store(Arc::clone(&value));
673 state.shared.published.store(Arc::new(PublishedValue {
674 sequence,
675 value: Arc::clone(&value),
676 }));
677 state
678 .shared
679 .published_sequence
680 .store(sequence, Ordering::Release);
681 state
682 .shared
683 .lifecycle
684 .store(STATE_CLOSED, Ordering::Release);
685
686 for slot in state.subscribers.values() {
687 slot.complete_with_final(sequence, Arc::clone(&value));
688 }
689 state.subscribers.clear();
690 publish_subscription_slot_table(state);
691 state.shared.ring.notify_space();
692 state.closed = true;
693}
694
695fn publish_subscription_slot_table<T: Send + Sync + 'static>(state: &SubscriptionActorState<T>) {
696 let slots = state.subscribers.values().cloned().collect::<Vec<_>>();
697 state
698 .shared
699 .subscribers
700 .store(Arc::new(SubscriptionSlotTable { slots }));
701}
702
703fn closed_error() -> StreamError {
704 StreamError::Failed("subscription is closed".into())
705}
706
707fn overflow_error(capacity: u64) -> StreamError {
708 StreamError::Failed(format!(
709 "subscription buffer overflow (max capacity was: {capacity})"
710 ))
711}
712
713fn atomic_fetch_min(target: &AtomicU64, value: u64) {
714 let mut current = target.load(Ordering::Acquire);
715 while value < current {
716 match target.compare_exchange(current, value, Ordering::AcqRel, Ordering::Acquire) {
717 Ok(_) => return,
718 Err(observed) => current = observed,
719 }
720 }
721}
722
723fn atomic_fetch_max(target: &AtomicU64, value: u64) {
724 let mut current = target.load(Ordering::Acquire);
725 while value > current {
726 match target.compare_exchange(current, value, Ordering::AcqRel, Ordering::Acquire) {
727 Ok(_) => return,
728 Err(observed) => current = observed,
729 }
730 }
731}
732
733struct SubscriptionSlot<T: Send + Sync + 'static> {
734 id: u64,
735 actor: ActorRef<SubscriptionMessage<T>>,
736 parked_count: Arc<AtomicUsize>,
737 cursor: AtomicU64,
738 active: AtomicBool,
739 parked: AtomicBool,
740 drop_from: AtomicU64,
741 drop_through: AtomicU64,
742 terminal_from: AtomicU64,
743 state: Mutex<SubscriptionSlotState<T>>,
744 available: Condvar,
745 async_available: Notify,
746}
747
748struct SubscriptionSlotState<T: Send + Sync + 'static> {
749 seed: Option<Arc<T>>,
750 terminal: Option<SubscriptionSlotTerminal<T>>,
751}
752
753#[derive(Clone)]
754enum SubscriptionSlotTerminal<T: Send + Sync + 'static> {
755 Complete {
756 final_sequence: u64,
757 final_value: Option<Arc<T>>,
758 },
759 Error {
760 after_sequence: u64,
761 error: StreamError,
762 },
763}
764
765impl<T: Send + Sync + 'static> SubscriptionSlot<T> {
766 fn new(
767 id: u64,
768 actor: ActorRef<SubscriptionMessage<T>>,
769 parked_count: Arc<AtomicUsize>,
770 ) -> Arc<Self> {
771 Arc::new(Self {
772 id,
773 actor,
774 parked_count,
775 cursor: AtomicU64::new(UNSEEDED_CURSOR),
776 active: AtomicBool::new(true),
777 parked: AtomicBool::new(false),
778 drop_from: AtomicU64::new(NO_DROP_FROM),
779 drop_through: AtomicU64::new(0),
780 terminal_from: AtomicU64::new(NO_TERMINAL_FROM),
781 state: Mutex::new(SubscriptionSlotState {
782 seed: None,
783 terminal: None,
784 }),
785 available: Condvar::new(),
786 async_available: Notify::new(),
787 })
788 }
789
790 fn lock(&self) -> MutexGuard<'_, SubscriptionSlotState<T>> {
791 self.state
792 .lock()
793 .unwrap_or_else(|poison| poison.into_inner())
794 }
795
796 fn seed(&self, next_sequence: u64, value: Arc<T>) {
797 self.cursor.store(next_sequence, Ordering::Release);
798 let mut state = self.lock();
799 state.seed = Some(value);
800 drop(state);
801 self.wake();
802 }
803
804 fn complete_post_close(&self, value: Arc<T>) {
805 self.cursor.store(0, Ordering::Release);
806 let mut state = self.lock();
807 state.seed = Some(value);
808 state.terminal = Some(SubscriptionSlotTerminal::Complete {
809 final_sequence: 0,
810 final_value: None,
811 });
812 drop(state);
813 self.terminal_from.store(0, Ordering::Release);
814 self.active.store(false, Ordering::Release);
815 self.wake();
816 }
817
818 fn complete_with_final(&self, final_sequence: u64, value: Arc<T>) {
819 let mut state = self.lock();
820 if state.terminal.is_none() {
821 state.terminal = Some(SubscriptionSlotTerminal::Complete {
822 final_sequence,
823 final_value: Some(value),
824 });
825 }
826 drop(state);
827 self.terminal_from
828 .fetch_min(final_sequence, Ordering::AcqRel);
829 self.wake();
830 }
831
832 fn fail_after(&self, after_sequence: u64, error: StreamError) {
833 let mut state = self.lock();
834 if state.terminal.is_none() {
835 state.terminal = Some(SubscriptionSlotTerminal::Error {
836 after_sequence,
837 error,
838 });
839 }
840 drop(state);
841 self.terminal_from
842 .fetch_min(after_sequence, Ordering::AcqRel);
843 self.active.store(false, Ordering::Release);
844 self.wake();
845 }
846
847 fn fail_now(&self, error: StreamError) {
848 let cursor = self.cursor.load(Ordering::Acquire);
849 let after_sequence = if cursor == UNSEEDED_CURSOR { 0 } else { cursor };
850 self.fail_after(after_sequence, error);
851 }
852
853 fn is_full_for(&self, sequence: u64, capacity: u64) -> bool {
854 if !self.active.load(Ordering::Acquire) {
855 return false;
856 }
857 let cursor = self.cursor.load(Ordering::Acquire);
858 cursor != UNSEEDED_CURSOR && sequence >= cursor.saturating_add(capacity)
859 }
860
861 fn backpressure_cursor(&self) -> Option<u64> {
862 if !self.active.load(Ordering::Acquire) {
863 return None;
864 }
865 let cursor = self.cursor.load(Ordering::Acquire);
866 (cursor != UNSEEDED_CURSOR).then_some(cursor)
867 }
868
869 fn drop_new(&self, sequence: u64, capacity: u64) {
870 let cursor = self.cursor.load(Ordering::Acquire);
871 if cursor == UNSEEDED_CURSOR {
872 return;
873 }
874 let from = cursor.saturating_add(capacity);
875 if sequence >= from {
876 atomic_fetch_min(&self.drop_from, from);
877 atomic_fetch_max(&self.drop_through, sequence);
878 self.wake();
879 }
880 }
881
882 fn skip_dropped(&self, cursor: u64) -> Option<u64> {
883 let from = self.drop_from.load(Ordering::Acquire);
884 let through = self.drop_through.load(Ordering::Acquire);
885 if from != NO_DROP_FROM && cursor >= from && cursor <= through {
886 self.drop_from.store(NO_DROP_FROM, Ordering::Release);
887 self.drop_through.store(0, Ordering::Release);
888 Some(through.saturating_add(1))
889 } else {
890 None
891 }
892 }
893
894 fn has_dropped(&self, cursor: u64) -> bool {
895 let from = self.drop_from.load(Ordering::Acquire);
896 let through = self.drop_through.load(Ordering::Acquire);
897 from != NO_DROP_FROM && cursor >= from && cursor <= through
898 }
899
900 fn terminal_blocks(&self, cursor: u64) -> bool {
901 cursor >= self.terminal_from.load(Ordering::Acquire)
902 }
903
904 fn wake(&self) {
905 if self.parked.swap(false, Ordering::AcqRel) {
906 self.parked_count.fetch_sub(1, Ordering::AcqRel);
907 self.available.notify_all();
908 self.async_available.notify_waiters();
909 }
910 }
911
912 fn park(&self) {
913 if !self.parked.swap(true, Ordering::AcqRel) {
914 self.parked_count.fetch_add(1, Ordering::AcqRel);
915 }
916 }
917
918 fn unpark(&self) {
919 if self.parked.swap(false, Ordering::AcqRel) {
920 self.parked_count.fetch_sub(1, Ordering::AcqRel);
921 }
922 }
923
924 fn wake_for_sequence(&self, sequence: u64) {
925 if self.cursor.load(Ordering::Acquire) == sequence {
926 self.wake();
927 }
928 }
929
930 fn unsubscribe(&self) {
931 self.active.store(false, Ordering::Release);
932 let _ = self
933 .actor
934 .send_message(SubscriptionMessage::Unsubscribe { id: self.id });
935 }
936}
937
938struct SubscriptionChangesStream<T: Clone + Send + Sync + 'static> {
939 shared: Arc<SubscriptionShared<T>>,
940 slot: Arc<SubscriptionSlot<T>>,
941 pending: VecDeque<Arc<T>>,
942 terminated: bool,
943}
944
945#[doc(hidden)]
946pub struct SubscriptionBenchmarkStream<T: Clone + Send + Sync + 'static> {
947 shared: Arc<SubscriptionShared<T>>,
948 slot: Arc<SubscriptionSlot<T>>,
949 pending: VecDeque<Arc<T>>,
950 terminated: bool,
951}
952
953impl<T: Clone + Send + Sync + 'static> Iterator for SubscriptionChangesStream<T> {
954 type Item = StreamResult<T>;
955
956 fn next(&mut self) -> Option<Self::Item> {
957 if self.terminated {
958 return None;
959 }
960
961 loop {
962 if let Some(value) = self.pending.pop_front() {
963 return Some(Ok(value.as_ref().clone()));
964 }
965
966 if let Some(item) = self.poll_seed_or_terminal() {
967 return item;
968 }
969
970 let cursor = self.slot.cursor.load(Ordering::Acquire);
971 if cursor == UNSEEDED_CURSOR {
972 self.wait_for_wake();
973 continue;
974 }
975
976 if let Some(next_cursor) = self.slot.skip_dropped(cursor) {
977 self.slot.cursor.store(next_cursor, Ordering::Release);
978 self.shared.ring.notify_space();
979 continue;
980 }
981
982 if let Some(value) = self.drain_available(cursor) {
983 return Some(Ok(value.as_ref().clone()));
984 }
985
986 let published = self.shared.published_sequence.load(Ordering::Acquire);
987 if cursor <= published {
988 let oldest = self.shared.ring.oldest_available(published);
989 if cursor < oldest {
990 match self.shared.overflow {
991 SubscriptionOverflow::DropNew => {
992 self.slot.cursor.store(oldest, Ordering::Release);
993 self.shared.ring.notify_space();
994 continue;
995 }
996 SubscriptionOverflow::Backpressure | SubscriptionOverflow::Fail => {
997 self.terminated = true;
998 return Some(Err(overflow_error(self.shared.ring.logical_capacity)));
999 }
1000 }
1001 }
1002 }
1003
1004 if current_stream_cancelled()
1005 .as_ref()
1006 .is_some_and(|cancelled| cancelled.load(Ordering::SeqCst))
1007 {
1008 self.terminated = true;
1009 return Some(Err(StreamError::Cancelled));
1010 }
1011
1012 self.wait_for_wake();
1013 }
1014 }
1015}
1016
1017impl<T: Clone + Send + Sync + 'static> SubscriptionChangesStream<T> {
1018 fn drain_available(&mut self, start_cursor: u64) -> Option<Arc<T>> {
1019 let mut cursor = start_cursor;
1020 let first = self.shared.ring.load(cursor)?;
1021 cursor = cursor.saturating_add(1);
1022 let mut drained = 1_usize;
1023
1024 while drained < SUBSCRIPTION_DRAIN_BATCH {
1025 if self.slot.has_dropped(cursor) || self.slot.terminal_blocks(cursor) {
1026 break;
1027 }
1028 let Some(value) = self.shared.ring.load(cursor) else {
1029 break;
1030 };
1031 self.pending.push_back(value);
1032 cursor = cursor.saturating_add(1);
1033 drained += 1;
1034 }
1035
1036 self.slot.cursor.store(cursor, Ordering::Release);
1037 self.shared.ring.notify_space();
1038 Some(first)
1039 }
1040
1041 fn poll_seed_or_terminal(&mut self) -> Option<Option<StreamResult<T>>> {
1042 let mut state = self.slot.lock();
1043 if let Some(seed) = state.seed.take() {
1044 return Some(Some(Ok(seed.as_ref().clone())));
1045 }
1046
1047 let cursor = self.slot.cursor.load(Ordering::Acquire);
1048 if let Some(terminal) = &mut state.terminal {
1049 match terminal {
1050 SubscriptionSlotTerminal::Complete {
1051 final_sequence,
1052 final_value,
1053 } => {
1054 if cursor >= *final_sequence {
1055 if let Some(value) = final_value.take() {
1056 return Some(Some(Ok(value.as_ref().clone())));
1057 }
1058 self.terminated = true;
1059 return Some(None);
1060 }
1061 }
1062 SubscriptionSlotTerminal::Error {
1063 after_sequence,
1064 error,
1065 } => {
1066 if cursor >= *after_sequence {
1067 self.terminated = true;
1068 return Some(Some(Err(error.clone())));
1069 }
1070 }
1071 }
1072 }
1073 None
1074 }
1075
1076 fn wait_for_wake(&self) {
1077 let state = self.slot.lock();
1078 self.slot.park();
1079 fence(Ordering::SeqCst);
1080 let cursor = self.slot.cursor.load(Ordering::Acquire);
1081 if state.seed.is_some()
1082 || state.terminal.is_some()
1083 || self.slot.has_dropped(cursor)
1084 || (cursor != UNSEEDED_CURSOR && self.shared.ring.has(cursor))
1085 {
1086 self.slot.unpark();
1087 return;
1088 }
1089 let _guard = self
1090 .slot
1091 .available
1092 .wait_timeout(state, SLOT_WAIT_BACKSTOP)
1093 .unwrap_or_else(|poison| poison.into_inner())
1094 .0;
1095 self.slot.unpark();
1096 }
1097}
1098
1099impl<T: Clone + Send + Sync + 'static> Drop for SubscriptionChangesStream<T> {
1100 fn drop(&mut self) {
1101 self.slot.unsubscribe();
1102 self.shared.ring.notify_space();
1103 }
1104}
1105
1106impl<T: Clone + Send + Sync + 'static> SubscriptionBenchmarkStream<T> {
1107 #[doc(hidden)]
1108 pub async fn next(&mut self) -> Option<StreamResult<T>> {
1109 if self.terminated {
1110 return None;
1111 }
1112
1113 loop {
1114 if let Some(value) = self.pending.pop_front() {
1115 return Some(Ok(value.as_ref().clone()));
1116 }
1117
1118 if let Some(item) = self.poll_seed_or_terminal() {
1119 return item;
1120 }
1121
1122 let cursor = self.slot.cursor.load(Ordering::Acquire);
1123 if cursor == UNSEEDED_CURSOR {
1124 self.wait_for_wake().await;
1125 continue;
1126 }
1127
1128 if let Some(next_cursor) = self.slot.skip_dropped(cursor) {
1129 self.slot.cursor.store(next_cursor, Ordering::Release);
1130 self.shared.ring.notify_space();
1131 continue;
1132 }
1133
1134 if let Some(value) = self.drain_available(cursor) {
1135 return Some(Ok(value.as_ref().clone()));
1136 }
1137
1138 let published = self.shared.published_sequence.load(Ordering::Acquire);
1139 if cursor <= published {
1140 let oldest = self.shared.ring.oldest_available(published);
1141 if cursor < oldest {
1142 match self.shared.overflow {
1143 SubscriptionOverflow::DropNew => {
1144 self.slot.cursor.store(oldest, Ordering::Release);
1145 self.shared.ring.notify_space();
1146 continue;
1147 }
1148 SubscriptionOverflow::Backpressure | SubscriptionOverflow::Fail => {
1149 self.terminated = true;
1150 return Some(Err(overflow_error(self.shared.ring.logical_capacity)));
1151 }
1152 }
1153 }
1154 }
1155
1156 self.wait_for_wake().await;
1157 }
1158 }
1159
1160 #[doc(hidden)]
1161 pub async fn count_changes(&mut self, target: u64) -> StreamResult<u64> {
1162 let mut count = 0_u64;
1163 while count < target {
1164 if self.terminated {
1165 return Err(StreamError::Failed(
1166 "subscription stream ended before requested count".into(),
1167 ));
1168 }
1169
1170 if !self.pending.is_empty() {
1171 let drained = self.pending.len().min((target - count) as usize);
1172 self.pending.drain(..drained);
1173 count += drained as u64;
1174 continue;
1175 }
1176
1177 if let Some(item) = self.poll_seed_or_terminal() {
1178 match item {
1179 Some(Ok(_)) => {
1180 count += 1;
1181 continue;
1182 }
1183 Some(Err(error)) => return Err(error),
1184 None => {
1185 return Err(StreamError::Failed(
1186 "subscription stream completed before requested count".into(),
1187 ));
1188 }
1189 }
1190 }
1191
1192 let cursor = self.slot.cursor.load(Ordering::Acquire);
1193 if cursor == UNSEEDED_CURSOR {
1194 self.wait_for_wake().await;
1195 continue;
1196 }
1197
1198 if let Some(next_cursor) = self.slot.skip_dropped(cursor) {
1199 self.slot.cursor.store(next_cursor, Ordering::Release);
1200 self.shared.ring.notify_space();
1201 continue;
1202 }
1203
1204 if let Some(drained) = self.drain_available_count(cursor, (target - count) as usize) {
1205 count += drained as u64;
1206 continue;
1207 }
1208
1209 let published = self.shared.published_sequence.load(Ordering::Acquire);
1210 if cursor <= published {
1211 let oldest = self.shared.ring.oldest_available(published);
1212 if cursor < oldest {
1213 return Err(overflow_error(self.shared.ring.logical_capacity));
1214 }
1215 }
1216
1217 self.wait_for_wake().await;
1218 }
1219 Ok(count)
1220 }
1221
1222 fn drain_available(&mut self, start_cursor: u64) -> Option<Arc<T>> {
1223 let mut cursor = start_cursor;
1224 let first = self.shared.ring.load(cursor)?;
1225 cursor = cursor.saturating_add(1);
1226 let mut drained = 1_usize;
1227
1228 while drained < SUBSCRIPTION_DRAIN_BATCH {
1229 if self.slot.has_dropped(cursor) || self.slot.terminal_blocks(cursor) {
1230 break;
1231 }
1232 let Some(value) = self.shared.ring.load(cursor) else {
1233 break;
1234 };
1235 self.pending.push_back(value);
1236 cursor = cursor.saturating_add(1);
1237 drained += 1;
1238 }
1239
1240 self.slot.cursor.store(cursor, Ordering::Release);
1241 self.shared.ring.notify_space();
1242 Some(first)
1243 }
1244
1245 fn drain_available_count(&mut self, start_cursor: u64, limit: usize) -> Option<usize> {
1246 if self.slot.has_dropped(start_cursor) || self.slot.terminal_blocks(start_cursor) {
1247 return None;
1248 }
1249 let published = self.shared.published_sequence.load(Ordering::Acquire);
1250 if start_cursor > published {
1251 return None;
1252 }
1253 let oldest = self.shared.ring.oldest_available(published);
1254 if start_cursor < oldest {
1255 return None;
1256 }
1257 let available = published.saturating_sub(start_cursor).saturating_add(1) as usize;
1258 let limit = limit.min(SUBSCRIPTION_DRAIN_BATCH);
1259 let drained = available.min(limit);
1260 if drained == 0 {
1261 return None;
1262 }
1263
1264 self.slot.cursor.store(
1265 start_cursor.saturating_add(drained as u64),
1266 Ordering::Release,
1267 );
1268 self.shared.ring.notify_space();
1269 Some(drained)
1270 }
1271
1272 fn poll_seed_or_terminal(&mut self) -> Option<Option<StreamResult<T>>> {
1273 let mut state = self.slot.lock();
1274 if let Some(seed) = state.seed.take() {
1275 return Some(Some(Ok(seed.as_ref().clone())));
1276 }
1277
1278 let cursor = self.slot.cursor.load(Ordering::Acquire);
1279 if let Some(terminal) = &mut state.terminal {
1280 match terminal {
1281 SubscriptionSlotTerminal::Complete {
1282 final_sequence,
1283 final_value,
1284 } => {
1285 if cursor >= *final_sequence {
1286 if let Some(value) = final_value.take() {
1287 return Some(Some(Ok(value.as_ref().clone())));
1288 }
1289 self.terminated = true;
1290 return Some(None);
1291 }
1292 }
1293 SubscriptionSlotTerminal::Error {
1294 after_sequence,
1295 error,
1296 } => {
1297 if cursor >= *after_sequence {
1298 self.terminated = true;
1299 return Some(Some(Err(error.clone())));
1300 }
1301 }
1302 }
1303 }
1304 None
1305 }
1306
1307 async fn wait_for_wake(&self) {
1308 let notified = self.slot.async_available.notified();
1309 tokio::pin!(notified);
1310 notified.as_mut().enable();
1311
1312 {
1313 let state = self.slot.lock();
1314 self.slot.park();
1315 fence(Ordering::SeqCst);
1316 let cursor = self.slot.cursor.load(Ordering::Acquire);
1317 if state.seed.is_some()
1318 || state.terminal.is_some()
1319 || self.slot.has_dropped(cursor)
1320 || (cursor != UNSEEDED_CURSOR && self.shared.ring.has(cursor))
1321 {
1322 self.slot.unpark();
1323 return;
1324 }
1325 }
1326
1327 notified.await;
1328 self.slot.unpark();
1329 }
1330}
1331
1332impl<T: Clone + Send + Sync + 'static> Drop for SubscriptionBenchmarkStream<T> {
1333 fn drop(&mut self) {}
1334}
1335
1336#[cfg(test)]
1337mod tests {
1338 use super::*;
1339 use crate::{Sink, stream::Materializer};
1340 use std::{
1341 sync::{
1342 Arc,
1343 atomic::{AtomicBool, AtomicUsize},
1344 },
1345 thread,
1346 time::{Duration, Instant},
1347 };
1348
1349 fn wait<T>(completion: crate::StreamCompletion<T>) -> T {
1350 completion.wait().unwrap()
1351 }
1352
1353 fn wait_until<F>(timeout: Duration, mut condition: F) -> bool
1354 where
1355 F: FnMut() -> bool,
1356 {
1357 let deadline = Instant::now() + timeout;
1358 while Instant::now() < deadline {
1359 if condition() {
1360 return true;
1361 }
1362 thread::yield_now();
1363 }
1364 condition()
1365 }
1366
1367 #[test]
1368 fn get_snapshot_and_acked_set_read_your_writes() {
1369 let subscription = Subscription::new(1_u64, 8, SubscriptionOverflow::Backpressure).unwrap();
1370 assert_eq!(*subscription.get(), 1);
1371 assert_eq!(subscription.get_cloned(), 1);
1372 subscription.set(2).unwrap();
1373 assert_eq!(*subscription.get(), 2);
1374 assert_eq!(subscription.get_cloned(), 2);
1375 subscription.update(|value| *value + 1).unwrap();
1376 assert_eq!(*subscription.get(), 3);
1377 assert_eq!(subscription.get_cloned(), 3);
1378 }
1379
1380 #[test]
1381 fn lossless_backpressure_subscribers_see_all_changes() {
1382 const SUBSCRIBERS: usize = 4;
1383 const WRITES: u64 = 128;
1384 let subscription =
1385 Subscription::new(0_u64, 256, SubscriptionOverflow::Backpressure).unwrap();
1386 let completions = (0..SUBSCRIBERS)
1387 .map(|_| subscription.changes().run_with(Sink::collect()).unwrap())
1388 .collect::<Vec<_>>();
1389
1390 for value in 1..=WRITES {
1391 subscription.set(value).unwrap();
1392 }
1393 subscription.close_with(WRITES + 1).unwrap();
1394
1395 for completion in completions {
1396 let values = wait(completion);
1397 let expected = (0..=WRITES + 1).collect::<Vec<_>>();
1398 assert_eq!(values, expected);
1399 }
1400 }
1401
1402 #[test]
1403 fn backpressure_parks_producer_ack_until_capacity_returns() {
1404 let subscription = Subscription::new(0_u64, 1, SubscriptionOverflow::Backpressure).unwrap();
1405 let seen = Arc::new(Mutex::new(Vec::new()));
1406 let gate = Arc::new(AtomicBool::new(false));
1407 let sink_seen = Arc::clone(&seen);
1408 let sink_gate = Arc::clone(&gate);
1409 let completion = subscription
1410 .changes()
1411 .run_with(Sink::foreach(move |item| {
1412 sink_seen.lock().unwrap().push(item);
1413 while !sink_gate.load(Ordering::SeqCst) {
1414 thread::yield_now();
1415 }
1416 }))
1417 .unwrap();
1418
1419 assert!(wait_until(Duration::from_secs(1), || {
1420 seen.lock().unwrap().as_slice() == [0]
1421 }));
1422 subscription.set(1).unwrap();
1423
1424 let producer_subscription = subscription.clone();
1425 let completed = Arc::new(AtomicBool::new(false));
1426 let producer_completed = Arc::clone(&completed);
1427 let producer = thread::spawn(move || {
1428 producer_subscription.set(2).unwrap();
1429 producer_completed.store(true, Ordering::SeqCst);
1430 });
1431
1432 assert!(!wait_until(Duration::from_millis(25), || completed
1433 .load(Ordering::SeqCst)));
1434 assert_eq!(*subscription.get(), 1);
1435 gate.store(true, Ordering::SeqCst);
1436 assert!(wait_until(Duration::from_secs(1), || completed.load(Ordering::SeqCst)));
1437 producer.join().unwrap();
1438 assert_eq!(*subscription.get(), 2);
1439 subscription.close_with(3).unwrap();
1440 wait(completion);
1441 assert_eq!(seen.lock().unwrap().as_slice(), [0, 1, 2, 3]);
1442 }
1443
1444 #[test]
1445 fn drop_new_policy_drops_only_full_subscribers() {
1446 let subscription = Subscription::new(0_u64, 1, SubscriptionOverflow::DropNew).unwrap();
1447 let seen = Arc::new(Mutex::new(Vec::new()));
1448 let gate = Arc::new(AtomicBool::new(false));
1449 let sink_seen = Arc::clone(&seen);
1450 let sink_gate = Arc::clone(&gate);
1451 let completion = subscription
1452 .changes()
1453 .run_with(Sink::foreach(move |item| {
1454 sink_seen.lock().unwrap().push(item);
1455 while !sink_gate.load(Ordering::SeqCst) {
1456 thread::yield_now();
1457 }
1458 }))
1459 .unwrap();
1460 assert!(wait_until(Duration::from_secs(1), || {
1461 seen.lock().unwrap().as_slice() == [0]
1462 }));
1463 subscription.set(1).unwrap();
1464 subscription.set(2).unwrap();
1465 subscription.close_with(3).unwrap();
1466 gate.store(true, Ordering::SeqCst);
1467 wait(completion);
1468 assert_eq!(seen.lock().unwrap().as_slice(), [0, 1, 3]);
1469 assert_eq!(*subscription.get(), 3);
1470 }
1471
1472 #[test]
1473 fn fail_policy_fails_full_subscriber_and_reports_overflow() {
1474 let subscription = Subscription::new(0_u64, 1, SubscriptionOverflow::Fail).unwrap();
1475 let seen = Arc::new(Mutex::new(Vec::new()));
1476 let gate = Arc::new(AtomicBool::new(false));
1477 let sink_seen = Arc::clone(&seen);
1478 let sink_gate = Arc::clone(&gate);
1479 let completion = subscription
1480 .changes()
1481 .run_with(Sink::foreach(move |item| {
1482 sink_seen.lock().unwrap().push(item);
1483 while !sink_gate.load(Ordering::SeqCst) {
1484 thread::yield_now();
1485 }
1486 }))
1487 .unwrap();
1488 assert!(wait_until(Duration::from_secs(1), || {
1489 seen.lock().unwrap().as_slice() == [0]
1490 }));
1491 subscription.set(1).unwrap();
1492 assert!(matches!(
1493 subscription.set(2),
1494 Err(StreamError::Failed(message)) if message.contains("subscription buffer overflow")
1495 ));
1496 gate.store(true, Ordering::SeqCst);
1497 assert!(matches!(
1498 completion.wait(),
1499 Err(StreamError::Failed(message)) if message.contains("subscription buffer overflow")
1500 ));
1501 assert_eq!(seen.lock().unwrap().as_slice(), [0, 1]);
1502 assert_eq!(*subscription.get(), 2);
1503 }
1504
1505 #[test]
1506 fn terminal_ordering_and_post_close_subscribe() {
1507 let subscription = Subscription::new(0_u64, 8, SubscriptionOverflow::Backpressure).unwrap();
1508 let completion = subscription.changes().run_with(Sink::collect()).unwrap();
1509 subscription.set(1).unwrap();
1510 subscription.close_with(9).unwrap();
1511 assert_eq!(wait(completion), vec![0, 1, 9]);
1512
1513 let post_close = subscription.changes().run_collect().unwrap();
1514 assert_eq!(post_close, vec![9]);
1515 }
1516
1517 #[test]
1518 fn dropping_feed_source_cancels_and_unsubscribes() {
1519 let subscription = Subscription::new(0_u64, 1, SubscriptionOverflow::Backpressure).unwrap();
1520 let pulled = Arc::new(AtomicUsize::new(0));
1521 let sink_pulled = Arc::clone(&pulled);
1522 let completion = subscription
1523 .changes()
1524 .run_with(Sink::foreach(move |_| {
1525 sink_pulled.fetch_add(1, Ordering::SeqCst);
1526 }))
1527 .unwrap();
1528 assert!(wait_until(Duration::from_secs(1), || {
1529 pulled.load(Ordering::SeqCst) == 1
1530 }));
1531 drop(completion);
1532 assert!(wait_until(Duration::from_secs(1), || subscription
1533 .set(1)
1534 .is_ok()));
1535 }
1536
1537 #[test]
1538 fn actor_death_fails_feed() {
1539 let subscription = Subscription::new(0_u64, 8, SubscriptionOverflow::Backpressure).unwrap();
1540 let materializer = Materializer::new();
1541 let completion = subscription
1542 .changes()
1543 .drop(1)
1544 .run_with_materializer(Sink::head(), &materializer)
1545 .unwrap();
1546 drop(subscription);
1547 match completion.wait() {
1548 Err(StreamError::ActorTerminated) => {}
1549 other => panic!("expected actor termination, got {other:?}"),
1550 }
1551 }
1552}