1use std::any::Any;
18use std::collections::VecDeque;
19use std::future::Future;
20use std::marker::PhantomData;
21use std::ops::Bound;
22use std::pin::Pin;
23use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
24use std::sync::{Arc, RwLock};
25use std::task::{Context, Poll};
26use tokio::sync::watch;
28use super::demand::Holding;
30use crate::{state::At, state::Position};
31
32pub(crate) type Row = Arc<dyn Any + Send + Sync>;
39
40type Step = Pin<Box<dyn Future<Output = (Parts, Turn)> + Send>>;
41
42pub(crate) struct Window {
45 ring: RwLock<Ring>,
46 pub(super) visibility: Arc<RwLock<()>>,
47 sequence: Arc<AtomicU64>,
48 doorbell: watch::Sender<u64>,
49 pump: watch::Sender<()>,
50 demand: watch::Sender<usize>,
51}
52
53struct Ring {
54 batches: Option<super::batches::State>,
55 rows: VecDeque<(u64, u64, Position, Row)>,
56 capacity: usize,
57 next: u64,
58 last: u64,
59 evicted: u64,
61 missed: u64,
63 floor: Position,
64 standing: bool,
65}
66
67#[cfg(any(feature = "plugin", feature = "plugin-guest", feature = "plugin-sidecar"))]
68pub(super) struct ListenerCandidate {
69 pub(super) cursor: u64,
70 pub(super) sequence: u64,
71 pub(super) source: usize,
72}
73
74pub(crate) struct Retained {
75 pub(crate) rows: Vec<(Position, Row)>,
76 pub(crate) floor: Position,
77 pub(crate) beneath: bool,
78}
79
80pub(crate) struct Advanced {
81 pub(crate) missed: u64,
82 pub(crate) rows: Vec<(Position, Row)>,
83 pub(crate) frontier: u64,
84}
85
86struct Parts {
87 window: Arc<Window>,
88 doorbell: watch::Receiver<u64>,
89 frontier: u64,
90 closed: Arc<AtomicBool>,
91
92 #[allow(dead_code, reason = "held for its drop, which releases the demand count")]
93 held: Holding,
94}
95
96struct Following<S> {
97 parts: Option<Parts>,
98 step: Option<Step>,
99 gap: u64,
100 pending: VecDeque<(Position, Row)>,
101 done: bool,
102 marker: PhantomData<fn() -> S>,
103}
104
105#[derive(Clone, Copy, Debug, PartialEq, Eq)]
108pub enum Item<S> {
109 Row(At<S>),
110 Gap { missed: u64 },
111}
112
113#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
114pub enum BeneathWindow {
115 #[error("no series adapter serves beneath the retained window")]
116 Unserved,
117
118 #[error("the served history begins after position {}", floor.0)]
119 Floor { floor: Position },
120
121 #[error("the series adapter could not read its own history: {0}")]
122 Unreadable(String),
123}
124
125enum Turn {
126 Advanced(Advanced),
127 Ended,
128}
129
130impl Window {
135 pub(crate) fn wired(capacity: usize, floor: Position, sequence: Arc<AtomicU64>, pump: watch::Sender<()>) -> Self {
136 let (doorbell, _) = watch::channel(0);
137 let (demand, _) = watch::channel(0);
138
139 Self {
140 visibility: Arc::new(RwLock::new(())),
141 ring: RwLock::new(Ring {
142 batches: None,
143 rows: VecDeque::with_capacity(capacity),
144 capacity,
145 next: 0,
146 last: 0,
147 evicted: 0,
148 missed: 0,
149 floor,
150 standing: false,
151 }),
152 sequence,
153 doorbell,
154 pump,
155 demand,
156 }
157 }
158
159 pub(super) fn visible_with(mut self, visibility: Arc<RwLock<()>>) -> Self {
160 self.visibility = visibility;
161 self
162 }
163
164 pub(crate) fn batching(self, definition: Option<super::BatchDefinition>) -> Self {
165 self.ring.write().expect("ring is healthy").batches = definition.map(super::batches::State::new);
166 self
167 }
168
169 pub(crate) fn batches<S>(&self, held: Holding) -> super::Batches<S> {
170 let ring = self.ring.read().expect("ring is healthy");
171 ring.batches.as_ref().expect("stream declared batching").feed.following(held)
172 }
173
174 pub(crate) fn close_batches(&self) {
175 if let Some(batches) = &mut self.ring.write().expect("ring is healthy").batches {
176 batches.close();
177 }
178 }
179
180 pub(crate) fn publish(&self, at: Position, row: Row) {
181 self.append(at, row, 0).expect("native stream cursor exhausted");
182 }
183
184 pub(super) fn append(&self, at: Position, row: Row, missed: u64) -> Result<(), super::StreamPublicationError> {
185 let _visibility = self.visibility.read().expect("stream visibility poisoned");
186 let evicted = self.append_locked(at, row, missed)?;
187 drop(_visibility);
188 drop(evicted);
189 self.knock();
190 self.pump.send_modify(|()| {});
191 Ok(())
192 }
193
194 pub(super) fn append_locked(&self, at: Position, row: Row, missed: u64) -> Result<Option<Row>, super::StreamPublicationError> {
196 let evicted;
197 {
198 let mut ring = self.ring.write().expect("the ring is never poisoned");
199 let advance = missed.checked_add(1).ok_or(super::StreamPublicationError::Sequence)?;
200 let next = ring.next.checked_add(advance).ok_or(super::StreamPublicationError::Sequence)?;
201 let previous = self
202 .sequence
203 .try_update(Ordering::Relaxed, Ordering::Relaxed, |cursor| cursor.checked_add(advance))
204 .map_err(|_| super::StreamPublicationError::Sequence)?;
205 let cursor = previous + advance;
206 if missed > 0 {
207 ring.missed = cursor - 1;
208 if let Some(batches) = &mut ring.batches {
209 batches.miss(missed);
210 }
211 }
212 evicted = if ring.rows.len() == ring.capacity {
213 let (lost, _, stamp, row) = ring.rows.pop_front().expect("full ring");
214 ring.evicted = lost;
215 ring.floor = stamp;
216 ring.standing = true;
217 Some(row)
218 } else {
219 None
220 };
221 if let Some(batches) = &mut ring.batches {
222 batches.publish(row.as_ref());
223 }
224 if let Some(publication) = row.downcast_ref::<super::ManagedPublication>() {
225 publication.assign_sequence(next);
226 }
227 ring.rows.push_back((cursor, next, at, row));
228 ring.next = next;
229 ring.last = cursor;
230 }
231 Ok(evicted)
232 }
233
234 pub(super) fn can_advance(&self, count: u64) -> bool {
237 self.sequence.load(Ordering::Relaxed).checked_add(count).is_some()
238 && self.ring.read().expect("the ring is never poisoned").next.checked_add(count).is_some()
239 }
240
241 pub(super) fn reclaim(&self, needed_bytes: usize, needed_rows: usize, taken: u64) -> Option<()> {
243 let mut ring = self.ring.write().expect("the ring is never poisoned");
244 let mut bytes = 0usize;
245 let mut rows = 0usize;
246 let mut prefix = 0usize;
247 for (cursor, _, _, row) in &ring.rows {
248 if *cursor > taken {
249 break;
250 }
251 let publication = row.downcast_ref::<super::ManagedPublication>()?;
252 prefix += 1;
253 if Arc::strong_count(row) == 1
254 && let Some(charge) = publication.reclaimable_bytes()
255 {
256 bytes = bytes.saturating_add(charge);
257 rows += 1;
258 }
259 if bytes >= needed_bytes && rows >= needed_rows {
260 break;
261 }
262 }
263 if bytes < needed_bytes || rows < needed_rows {
264 return None;
265 }
266 for _ in 0..prefix {
267 let (cursor, _, position, row) = ring.rows.pop_front().expect("validated retention prefix");
268 ring.evicted = cursor;
269 ring.floor = position;
270 ring.standing = true;
271 drop(row);
274 }
275 Some(())
276 }
277
278 pub(super) fn evicts_unread(&self, taken: u64) -> bool {
280 let ring = self.ring.read().expect("the ring is never poisoned");
281 ring.rows.len() == ring.capacity && ring.rows.front().is_some_and(|(cursor, ..)| *cursor > taken)
282 }
283
284 #[cfg(any(feature = "plugin", feature = "plugin-guest", feature = "plugin-sidecar"))]
286 pub(super) fn room(&self, taken: u64) -> usize {
287 let ring = self.ring.read().expect("the ring is never poisoned");
288 let read = ring.rows.partition_point(|(cursor, ..)| *cursor <= taken);
289 ring.capacity - (ring.rows.len() - read)
290 }
291
292 #[cfg(feature = "plugin-sidecar")]
293 pub(crate) fn miss(&self, count: u64) {
294 let _visibility = self.visibility.read().expect("stream visibility poisoned");
295 if count == 0 {
296 return;
297 }
298
299 let published;
300 {
301 let mut ring = self.ring.write().expect("the ring is never poisoned");
302 let next = ring.next.checked_add(count).expect("native stream cursor exhausted");
303 let previous = self
304 .sequence
305 .try_update(Ordering::Relaxed, Ordering::Relaxed, |cursor| cursor.checked_add(count))
306 .expect("native stream cursor exhausted");
307 let cursor = previous + count;
308 if let Some(batches) = &mut ring.batches {
309 batches.miss(count);
310 }
311 ring.missed = cursor;
312 ring.next = next;
313 ring.last = cursor;
314 published = ring.next;
315 }
316 drop(_visibility);
317 self.doorbell.send_replace(published);
318 self.pump.send_modify(|()| {});
319 }
320
321 pub(crate) fn stands_on(&self, floor: Position) {
322 let _visibility = self.visibility.read().expect("stream visibility poisoned");
323 let mut ring = self.ring.write().expect("the ring is never poisoned");
324
325 ring.floor = floor;
326 ring.standing = true;
327 }
328
329 pub(crate) fn snapshot(&self, start: Bound<Position>, end: Bound<Position>, as_of: Option<Position>) -> Retained {
330 self.snapshot_scope(start, end, as_of, true)
331 }
332
333 pub(crate) fn snapshot_scope(&self, start: Bound<Position>, end: Bound<Position>, as_of: Option<Position>, history: bool) -> Retained {
334 let _visibility = self.visibility.read().expect("stream visibility poisoned");
335 let ring = self.ring.read().expect("the ring is never poisoned");
336 let beneath = history && ring.standing && reaches_beneath(start, ring.floor);
337
338 Retained {
339 rows: ring
340 .rows
341 .iter()
342 .filter(|(_, _, stamp, _)| !beneath || *stamp > ring.floor)
343 .filter(|(_, _, stamp, _)| admitted(start, end, *stamp))
344 .filter(|(_, _, stamp, _)| as_of.is_none_or(|cutoff| *stamp <= cutoff))
345 .map(|(_, _, stamp, row)| (*stamp, Arc::clone(row)))
346 .collect(),
347 floor: ring.floor,
348 beneath,
349 }
350 }
351
352 pub(crate) fn reader<S: serde::Serialize + 'static>(
353 &self, start: Bound<Position>, end: Bound<Position>, limits: super::ReadLimits,
354 ) -> Result<Box<dyn super::RowSource>, super::ReadError> {
355 struct Frozen {
356 cut: super::ReadCut,
357 rows: std::collections::vec_deque::IntoIter<(Position, Row)>,
358 }
359 impl super::RowSource for Frozen {
360 fn cut(&self) -> super::ReadCut {
361 self.cut
362 }
363 fn next(&mut self, cancelled: &AtomicBool) -> Result<Option<crate::state::At<Row>>, super::ReadError> {
364 if cancelled.load(Ordering::Acquire) {
365 return Err(super::ReadError::Closed);
366 }
367 Ok(self.rows.next().map(|(position, value)| crate::state::At { position, value }))
368 }
369 }
370 let _visibility = self.visibility.read().expect("stream visibility poisoned");
371 let ring = self.ring.read().expect("the ring is never poisoned");
372 if ring.missed > 0 {
373 return Err(super::ReadError::IncompleteCapture);
374 }
375 if ring.standing && reaches_beneath(start, ring.floor) {
376 return Err(super::ReadError::Retained { floor: ring.floor });
377 }
378 let mut bytes = 0usize;
379 let mut rows = VecDeque::new();
380 for (scanned, (_, _, position, row)) in ring.rows.iter().enumerate() {
381 if scanned == limits.rows {
382 return Err(super::ReadError::Limit("window row scan"));
383 }
384 if !admitted(start, end, *position) {
385 continue;
386 }
387 let typed =
388 super::row_value::<S>(row.as_ref()).ok_or_else(|| super::ReadError::Unreadable("window row type mismatch".into()))?;
389 bytes = bytes
390 .checked_add(super::reader::encoded_size(typed, limits.row_bytes)?)
391 .and_then(|bytes| bytes.checked_add(std::mem::size_of::<(Position, Row)>()))
392 .filter(|bytes| *bytes <= limits.pinned_bytes)
393 .ok_or(super::ReadError::Limit("pinned bytes"))?;
394 rows.push_back((*position, Arc::clone(row)));
395 }
396 Ok(Box::new(Frozen { cut: super::ReadCut::Window { delivered: crate::storage::Cursor(ring.last) }, rows: rows.into_iter() }))
397 }
398
399 pub(crate) fn since(&self, frontier: u64) -> Advanced {
400 let _visibility = self.visibility.read().expect("stream visibility poisoned");
401 let ring = self.ring.read().expect("the ring is never poisoned");
402 let rows: Vec<_> =
403 ring.rows.iter().filter(|(_, sequence, ..)| *sequence > frontier).map(|(_, _, stamp, row)| (*stamp, Arc::clone(row))).collect();
404 let missed = ring.next.saturating_sub(frontier).saturating_sub(rows.len() as u64);
405 Advanced { missed, rows, frontier: ring.next.max(frontier) }
406 }
407
408 pub(super) fn latest_locked(&self) -> u64 {
409 self.ring.read().expect("the ring is never poisoned").last
410 }
411
412 pub(super) fn recorded_after_locked(&self, resume: u64, reaches: u64) -> (Vec<(u64, Position, Row)>, bool) {
413 let ring = self.ring.read().expect("the ring is never poisoned");
414 let rows = ring
415 .rows
416 .iter()
417 .filter(|(cursor, ..)| *cursor > resume && *cursor <= reaches)
418 .map(|(cursor, _, stamp, row)| (*cursor, *stamp, Arc::clone(row)))
419 .collect();
420 (rows, ring.evicted > resume || ring.missed > resume)
424 }
425
426 #[cfg(any(feature = "plugin", feature = "plugin-guest", feature = "plugin-sidecar"))]
427 pub(super) fn listener_candidates(&self, after: u64, through: u64, source: usize, limit: usize, selected: &mut Vec<ListenerCandidate>) {
428 let ring = self.ring.read().expect("the ring is never poisoned");
429 let mut lower = 0;
430 let mut upper = ring.rows.len();
431 while lower < upper {
432 let mid = lower + (upper - lower) / 2;
433 if ring.rows[mid].0 <= after {
434 lower = mid + 1;
435 } else {
436 upper = mid;
437 }
438 }
439 for (cursor, sequence, ..) in ring.rows.iter().skip(lower).take(limit) {
440 if *cursor > through || selected.len() == limit && *cursor >= selected.last().unwrap().cursor {
441 break;
442 }
443 let index = selected.partition_point(|candidate| candidate.cursor < *cursor);
444 if selected.len() == limit {
445 selected.pop();
446 }
447 selected.insert(index, ListenerCandidate { cursor: *cursor, sequence: *sequence, source });
448 }
449 }
450
451 #[cfg(any(feature = "plugin", feature = "plugin-guest", feature = "plugin-sidecar"))]
452 pub(super) fn listener_row(&self, cursor: u64) -> Option<Row> {
453 let ring = self.ring.read().expect("the ring is never poisoned");
454 let mut lower = 0;
455 let mut upper = ring.rows.len();
456 while lower < upper {
457 let mid = lower + (upper - lower) / 2;
458 if ring.rows[mid].0 < cursor {
459 lower = mid + 1;
460 } else {
461 upper = mid;
462 }
463 }
464 ring.rows.get(lower).filter(|row| row.0 == cursor).map(|row| Arc::clone(&row.3))
465 }
466
467 #[cfg(any(feature = "plugin", feature = "plugin-guest", feature = "plugin-sidecar"))]
468 pub(super) fn logical_frontier(&self) -> u64 {
469 self.ring.read().expect("the ring is never poisoned").next
470 }
471
472 pub(super) fn wake_delivery(&self) {
473 self.pump.send_modify(|()| {});
474 }
475
476 pub(crate) fn knock(&self) {
477 self.doorbell.send_modify(|_| {});
478 }
479
480 pub(crate) fn interest(&self) -> watch::Receiver<usize> {
481 self.demand.subscribe()
482 }
483
484 pub(crate) fn engaged(&self) {
485 self.demand.send_modify(|count| *count += 1);
486 }
487
488 pub(crate) fn released(&self) {
489 self.demand.send_modify(|count| *count -= 1);
490 }
491}
492
493impl std::fmt::Debug for Window {
494 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
495 formatter.debug_struct("Window").finish_non_exhaustive()
496 }
497}
498
499impl<S> Unpin for Following<S> {}
500
501impl<S: Clone + 'static> futures_core::Stream for Following<S> {
502 type Item = Item<S>;
503
504 fn poll_next(self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Option<Self::Item>> {
505 let following = self.get_mut();
506
507 loop {
508 if following.gap > 0 {
509 let missed = std::mem::take(&mut following.gap);
510 return Poll::Ready(Some(Item::Gap { missed }));
511 }
512 if let Some((position, row)) = following.pending.pop_front() {
513 let value = super::row_value::<S>(row.as_ref()).expect("a window holds only its own stream's rows").clone();
514 return Poll::Ready(Some(Item::Row(At { value, position })));
515 }
516 if following.done {
517 return Poll::Ready(None);
518 }
519
520 let mut step = match following.step.take() {
521 Some(step) => step,
522 None => match following.parts.take() {
523 Some(parts) => Box::pin(turn(parts)),
524 None => {
525 following.done = true;
526 return Poll::Ready(None);
527 }
528 },
529 };
530
531 match step.as_mut().poll(context) {
532 Poll::Pending => {
533 following.step = Some(step);
534 return Poll::Pending;
535 }
536 Poll::Ready((parts, Turn::Advanced(advanced))) => {
537 following.parts = Some(parts);
538 following.gap = advanced.missed;
539 following.pending = advanced.rows.into();
540 }
541 Poll::Ready((parts, Turn::Ended)) => {
542 following.parts = Some(parts);
543 following.done = true;
544 }
545 }
546 }
547 }
548}
549
550pub(crate) fn following<S: Clone + 'static>(
553 window: Arc<Window>, closed: Arc<AtomicBool>, held: Holding,
554) -> impl futures_core::Stream<Item = Item<S>> + Send + Unpin {
555 let doorbell = window.doorbell.subscribe();
556 let frontier = {
557 let _visibility = window.visibility.read().expect("stream visibility poisoned");
558 window.ring.read().expect("the ring is never poisoned").next
559 };
560
561 Following {
562 parts: Some(Parts { window, doorbell, frontier, closed, held }),
563 step: None,
564 gap: 0,
565 pending: VecDeque::new(),
566 done: false,
567 marker: PhantomData,
568 }
569}
570
571fn reaches_beneath(start: Bound<Position>, floor: Position) -> bool {
574 match start {
575 Bound::Included(at) => at <= floor,
576 Bound::Excluded(at) => at < floor,
577 Bound::Unbounded => true,
578 }
579}
580
581fn admitted(start: Bound<Position>, end: Bound<Position>, at: Position) -> bool {
582 let above = match start {
583 Bound::Included(from) => at >= from,
584 Bound::Excluded(from) => at > from,
585 Bound::Unbounded => true,
586 };
587 let below = match end {
588 Bound::Included(to) => at <= to,
589 Bound::Excluded(to) => at < to,
590 Bound::Unbounded => true,
591 };
592
593 above && below
594}
595
596async fn turn(mut parts: Parts) -> (Parts, Turn) {
597 loop {
598 let was_closed = parts.closed.load(Ordering::Acquire);
599 let advanced = parts.window.since(parts.frontier);
600 parts.frontier = advanced.frontier;
601
602 if advanced.missed > 0 || !advanced.rows.is_empty() {
603 return (parts, Turn::Advanced(advanced));
604 }
605 if was_closed || parts.doorbell.changed().await.is_err() {
606 return (parts, Turn::Ended);
607 }
608 }
609}
610
611