commonware_utils/channel/
tracked.rs1use super::mpsc::{
50 self,
51 error::{SendError, TryRecvError, TrySendError},
52};
53use crate::{Widen, sync::Mutex};
54use futures::Stream;
55use std::{
56 collections::{HashMap, VecDeque},
57 hash::Hash,
58 pin::Pin,
59 sync::Arc,
60 task::{Context, Poll},
61};
62
63#[derive(Clone)]
66pub struct Guard<B: Eq + Hash> {
67 inner: Arc<Inner<B>>,
68}
69
70struct Inner<B: Eq + Hash> {
72 sequence: u64,
73 tracker: Arc<Mutex<State<B>>>,
74
75 batch: Option<B>,
76}
77
78impl<B: Eq + Hash> Drop for Inner<B> {
79 fn drop(&mut self) {
80 let mut state = self.tracker.lock();
82
83 let index = usize::try_from(self.sequence - state.watermark - 1)
85 .expect("pending index must fit in usize");
86 state.pending[index] = true;
87
88 while state.pending.pop_front_if(|delivered| *delivered).is_some() {
90 state.watermark += 1;
91 }
92
93 if let Some(batch) = &self.batch {
98 let count = state.batches.get_mut(batch).expect("batch must be tracked");
99 if *count > 1 {
100 *count -= 1;
101 } else {
102 state.batches.remove(batch);
103 }
104 }
105 }
106}
107
108pub struct Message<T, B: Eq + Hash> {
110 pub data: T,
112 pub guard: Guard<B>,
116}
117
118struct State<B> {
120 watermark: u64,
122 batches: HashMap<B, usize>,
124 pending: VecDeque<bool>,
128}
129
130impl<B> Default for State<B> {
131 fn default() -> Self {
132 Self {
133 watermark: 0,
134 batches: HashMap::new(),
135 pending: VecDeque::new(),
136 }
137 }
138}
139
140#[derive(Clone)]
147struct Tracker<B: Eq + Hash + Clone> {
148 state: Arc<Mutex<State<B>>>,
149}
150
151impl<B: Eq + Hash + Clone> Tracker<B> {
152 fn new() -> Self {
153 Self {
154 state: Arc::new(Mutex::new(State::default())),
155 }
156 }
157
158 fn guard(&self, batch: Option<B>) -> Guard<B> {
159 let mut state = self.state.lock();
161
162 let issued: u64 = Widen::widen(state.pending.len());
164 let sequence = state.watermark + 1 + issued;
165 state.pending.push_back(false);
166
167 if let Some(batch) = &batch {
169 *state.batches.entry(batch.clone()).or_insert(0) += 1;
170 }
171
172 Guard {
173 inner: Arc::new(Inner {
174 sequence,
175 tracker: self.state.clone(),
176
177 batch,
178 }),
179 }
180 }
181}
182
183#[derive(Clone)]
185pub struct Sender<T, B: Eq + Hash + Clone> {
186 inner: mpsc::Sender<Message<T, B>>,
187 tracker: Tracker<B>,
188}
189
190impl<T, B: Eq + Hash + Clone> Sender<T, B> {
191 pub async fn send(&self, batch: Option<B>, data: T) -> Result<u64, SendError<Message<T, B>>> {
193 let guard = self.tracker.guard(batch);
195 let watermark = guard.inner.sequence;
196
197 let msg = Message { data, guard };
199 self.inner.send(msg).await?;
200
201 Ok(watermark)
202 }
203
204 pub fn try_send(&self, batch: Option<B>, data: T) -> Result<u64, TrySendError<Message<T, B>>> {
206 let guard = self.tracker.guard(batch);
208 let watermark = guard.inner.sequence;
209
210 let msg = Message { data, guard };
212 self.inner.try_send(msg)?;
213
214 Ok(watermark)
215 }
216
217 pub fn watermark(&self) -> u64 {
219 self.tracker.state.lock().watermark
220 }
221
222 pub fn pending(&self, batch: B) -> usize {
224 self.tracker
225 .state
226 .lock()
227 .batches
228 .get(&batch)
229 .copied()
230 .unwrap_or(0)
231 }
232}
233
234pub struct Receiver<T, B: Eq + Hash> {
236 inner: mpsc::Receiver<Message<T, B>>,
237}
238
239impl<T, B: Eq + Hash> Receiver<T, B> {
240 pub async fn recv(&mut self) -> Option<Message<T, B>> {
242 self.inner.recv().await
243 }
244
245 pub fn try_recv(&mut self) -> Result<Message<T, B>, TryRecvError> {
247 self.inner.try_recv()
248 }
249}
250
251impl<T, B: Eq + Hash> Stream for Receiver<T, B> {
252 type Item = Message<T, B>;
253
254 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
255 self.inner.poll_recv(cx)
256 }
257}
258
259pub fn bounded<T, B: Eq + Hash + Clone>(buffer: usize) -> (Sender<T, B>, Receiver<T, B>) {
261 let (tx, rx) = mpsc::channel(buffer);
262 let sender = Sender {
263 inner: tx,
264 tracker: Tracker::new(),
265 };
266 let receiver = Receiver { inner: rx };
267 (sender, receiver)
268}
269
270#[cfg(test)]
271mod tests {
272 use super::*;
273 use futures::executor::block_on;
274
275 struct CallbackBatch {
277 id: u64,
278 on_drop: Box<dyn Fn() + Send + Sync>,
279 }
280
281 impl PartialEq for CallbackBatch {
282 fn eq(&self, other: &Self) -> bool {
283 self.id == other.id
284 }
285 }
286
287 impl Eq for CallbackBatch {}
288
289 impl Hash for CallbackBatch {
290 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
291 self.id.hash(state);
292 }
293 }
294
295 impl Drop for CallbackBatch {
296 fn drop(&mut self) {
297 (self.on_drop)();
298 }
299 }
300
301 #[test]
302 fn test_batch_destructor_can_read_watermark() {
303 let (observed, observations) = std::sync::mpsc::channel();
306 let worker = std::thread::spawn(move || {
307 block_on(async move {
308 let (sender, mut receiver) = bounded::<(), Arc<CallbackBatch>>(1);
309 let observer = sender.clone();
310 let batch = Arc::new(CallbackBatch {
311 id: 1,
312 on_drop: Box::new(move || observed.send(observer.watermark()).unwrap()),
313 });
314 sender.send(Some(batch), ()).await.unwrap();
315
316 drop(receiver.recv().await.unwrap());
318 });
319 });
320 let watermark = observations
321 .recv_timeout(std::time::Duration::from_secs(5))
322 .expect("batch destructor must read the watermark");
323 assert_eq!(watermark, 1);
324 worker.join().unwrap();
325 }
326
327 #[test]
328 fn test_basic() {
329 block_on(async move {
330 let (sender, mut receiver) = bounded::<i32, u64>(10);
331
332 let watermark = sender.send(None, 42).await.unwrap();
334 assert_eq!(watermark, 1);
335 assert_eq!(sender.watermark(), 0);
336
337 let msg = receiver.recv().await.unwrap();
339 assert_eq!(msg.data, 42);
340 assert_eq!(sender.watermark(), 0);
341
342 drop(msg.guard);
344 assert_eq!(sender.watermark(), 1);
345 });
346 }
347
348 #[test]
349 fn test_out_of_order_delivery() {
350 block_on(async move {
351 let (sender, mut receiver) = bounded::<i32, u64>(4);
352 for value in 1..=4 {
353 sender.send(Some(1), value).await.unwrap();
354 }
355 let first = receiver.recv().await.unwrap();
356 let second = receiver.recv().await.unwrap();
357 let third = receiver.recv().await.unwrap();
358 let fourth = receiver.recv().await.unwrap();
359
360 drop(second);
363 drop(fourth);
364 assert_eq!(sender.watermark(), 0);
365 assert_eq!(sender.pending(1), 2);
366
367 let fifth = sender.send(Some(2), 5).await.unwrap();
370 assert_eq!(fifth, 5);
371 assert_eq!(sender.pending(2), 1);
372
373 drop(first);
375 assert_eq!(sender.watermark(), 2);
376 assert_eq!(sender.pending(1), 1);
377
378 drop(third);
380 assert_eq!(sender.watermark(), 4);
381 assert_eq!(sender.pending(1), 0);
382
383 let sixth = sender.send(Some(2), 6).await.unwrap();
385 assert_eq!(sixth, 6);
386 assert_eq!(sender.pending(2), 2);
387
388 drop(receiver.recv().await.unwrap());
390 drop(receiver.recv().await.unwrap());
391 assert_eq!(sender.watermark(), 6);
392 assert_eq!(sender.pending(2), 0);
393 });
394 }
395
396 #[test]
397 fn test_batch_tracking() {
398 block_on(async move {
399 let (sender, mut receiver) = bounded::<String, u64>(10);
400
401 let watermark1 = sender.send(Some(100), "msg1".into()).await.unwrap();
403 let watermark2 = sender.send(Some(100), "msg2".into()).await.unwrap();
404 let watermark3 = sender.send(Some(200), "msg3".into()).await.unwrap();
405
406 assert_eq!(watermark1, 1);
407 assert_eq!(watermark2, 2);
408 assert_eq!(watermark3, 3);
409 assert_eq!(sender.pending(100), 2);
410 assert_eq!(sender.pending(200), 1);
411 assert_eq!(sender.pending(300), 0);
412
413 let msg1 = receiver.recv().await.unwrap();
415 assert_eq!(msg1.data, "msg1");
416 drop(msg1.guard);
417
418 assert_eq!(sender.pending(100), 1);
419 assert_eq!(sender.pending(200), 1);
420
421 let msg2 = receiver.recv().await.unwrap();
423 let msg3 = receiver.recv().await.unwrap();
424 drop(msg2.guard);
425 drop(msg3.guard);
426
427 assert_eq!(sender.pending(100), 0);
428 assert_eq!(sender.pending(200), 0);
429 });
430 }
431
432 #[test]
433 fn test_cloned_guards() {
434 block_on(async move {
435 let (sender, mut receiver) = bounded::<&str, u64>(10);
436
437 let watermark = sender.send(Some(1), "test").await.unwrap();
438 assert_eq!(watermark, 1);
439
440 let msg = receiver.recv().await.unwrap();
442 assert_eq!(msg.data, "test");
443
444 let msg_guard_clone1: Guard<u64> = msg.guard.clone();
446 let msg_guard_clone2: Guard<u64> = msg.guard.clone();
447
448 assert_eq!(sender.pending(1), 1);
449 assert_eq!(sender.watermark(), 0);
450
451 drop(msg.guard);
453 drop(msg_guard_clone1);
454 assert_eq!(sender.pending(1), 1);
455 assert_eq!(sender.watermark(), 0);
456
457 drop(msg_guard_clone2);
459 assert_eq!(sender.pending(1), 0);
460 assert_eq!(sender.watermark(), 1);
461 });
462 }
463
464 #[test]
465 fn test_try_send() {
466 block_on(async move {
467 let (sender, mut receiver) = bounded::<i32, u64>(2);
468
469 let watermark1 = sender.try_send(Some(10), 1).unwrap();
471 let watermark2 = sender.try_send(Some(10), 2).unwrap();
472
473 assert_eq!(sender.pending(10), 2);
474 assert_eq!(watermark1, 1);
475 assert_eq!(watermark2, 2);
476
477 let msg1 = receiver.recv().await.unwrap();
479 assert_eq!(msg1.data, 1);
480 drop(msg1.guard);
481
482 assert_eq!(sender.pending(10), 1);
483
484 let msg2 = receiver.recv().await.unwrap();
485 drop(msg2.guard);
486
487 assert_eq!(sender.pending(10), 0);
488 });
489 }
490
491 #[test]
492 fn test_channel_closure() {
493 block_on(async move {
494 let (sender, receiver) = bounded::<i32, u64>(10);
495
496 let _guard = sender.send(None, 1).await.unwrap();
497
498 drop(receiver);
500
501 assert!(sender.send(None, 2).await.is_err());
503 });
504 }
505}