1use std::num::NonZeroUsize;
20use std::sync::Arc;
21use std::sync::atomic::{AtomicU64, Ordering};
22
23use super::backend::{ReadLimits, ScanPage};
27use super::capacity::{Attempt, Refusal};
28use super::config::SCAN_ROWS;
29use super::manager::{Domain, Inner, State, encoded_size};
30pub use super::selection::Entry;
31use super::selection::Queued;
32use super::snapshot::Snapshot;
33use super::{StorageCursor, StorageManager};
34use crate::{Error, Result};
35
36static NEXT_FOLLOWER: AtomicU64 = AtomicU64::new(1);
39
40pub struct Follower<T: Entry> {
47 context: crate::execution::Context,
48 inner: Arc<Inner>,
49 id: u64,
50 selection: T::Selection,
51 history: Option<Snapshot>,
52 after: u64,
53 saved: StorageCursor,
54 accepted: StorageCursor,
55}
56
57pub struct FollowPage<T> {
58 entries: Vec<T>,
59}
60
61pub(super) struct Following {
62 pub(super) after: u64,
63 failure: Option<Failure>,
64}
65
66#[derive(Clone, Copy)]
69enum Failure {
70 Gap { requested: u64, available: u64 },
71 Closed,
72}
73
74impl<C> StorageManager<C> {
79 #[tracing::instrument(name = "storage.follow.follow", level = "debug", skip_all)]
80 pub async fn follow<T: Entry>(&self, after: Option<&StorageCursor>, selection: T::Selection) -> Result<Follower<T>> {
81 if let Some(after) = after {
82 self.inner.primary.history().check(&after.history)?;
83 }
84 let requested = after.map_or(0, |after| after.sequence);
85 let after = requested.max(T::start(&selection));
86 let id = NEXT_FOLLOWER.fetch_add(1, Ordering::Relaxed);
87
88 let (saved, accepted) = {
90 let mut state = self.inner.state.lock().unwrap();
91 super::capacity::admitting(&state, false)?;
92 let saved = state.status.saved.clone();
93 let accepted = state.status.accepted.clone();
94 if requested > accepted.sequence {
95 return Err(Error::InvalidInput {
96 field: "storage follow",
97 reason: "start exceeds accepted boundary",
98 });
99 }
100 state.followers.insert(
101 id,
102 Following {
103 after: saved.sequence.max(after),
104 failure: None,
105 },
106 );
107 (saved, accepted)
108 };
109 let mut follower = Follower {
110 context: crate::execution::Context::current(),
111 inner: Arc::clone(&self.inner),
112 id,
113 selection,
114 history: None,
115 after,
116 saved,
117 accepted,
118 };
119 if after < follower.saved.sequence {
120 follower.history = Some(self.snapshot(&follower.saved).await?);
121 }
122 Ok(follower)
123 }
124}
125
126impl<C> StorageManager<C> {
127 #[tracing::instrument(name = "storage.follow.page", level = "debug", skip_all)]
128 pub async fn page<T: Entry>(&self, selection: &T::Selection, after: u64, limits: ReadLimits) -> Result<FollowPage<T>> {
129 let rows = limits.rows.min(SCAN_ROWS);
130 let bytes = limits.bytes.min(self.inner.settings.scan_bytes());
131
132 let snapshot = self.snapshot(&self.cursor_saved()).await?;
133 let (entries, _) = snapshot.scan::<T>(selection, ScanPage { after, rows, bytes }).await?;
134 Ok(FollowPage { entries })
135 }
136}
137
138impl<T: Entry> Follower<T> {
139 pub fn saved_boundary(&self) -> &StorageCursor {
140 &self.saved
141 }
142
143 pub fn accepted_boundary(&self) -> &StorageCursor {
144 &self.accepted
145 }
146
147 pub async fn next(&mut self) -> Result<FollowPage<T>> {
148 let context = self.context.clone();
149 let span = context.sync(|| tracing::trace_span!("storage.reader.page"));
150 let future = async {
151 loop {
152 if let Some(page) = self.next_history().await? {
153 return Ok(page);
154 }
155 if let Some(page) = self.next_live().await? {
156 return Ok(page);
157 }
158 }
159 };
160 context.scope(tracing::Instrument::instrument(future, span)).await
161 }
162
163 #[tracing::instrument(name = "storage.follow.next_history", level = "debug", skip_all)]
165 async fn next_history(&mut self) -> Result<Option<FollowPage<T>>> {
166 let Some(snapshot) = &self.history else {
167 return Ok(None);
168 };
169 let bytes = self.inner.settings.scan_bytes();
170
171 let page = ScanPage {
172 after: self.after,
173 rows: SCAN_ROWS,
174 bytes,
175 };
176 let (entries, _) = snapshot.scan::<T>(&self.selection, page).await?;
177 let Some(last) = entries.last() else {
178 self.history = None;
179 self.after = self.after.max(self.saved.sequence);
180 return Ok(None);
181 };
182 self.after = last.position().sequence;
183 Ok(Some(FollowPage { entries }))
184 }
185
186 #[tracing::instrument(name = "storage.follow.next_live", level = "debug", skip_all)]
188 async fn next_live(&mut self) -> Result<Option<FollowPage<T>>> {
189 let id = self.id;
190 let selection = &self.selection;
191 self.inner
192 .wait(None, |state| match find::<T>(state, id, selection) {
193 Ok(true) => Attempt::Ready(()),
194 Ok(false) => Attempt::Wait,
195 Err(error) => Attempt::Refuse(Refusal::Failed(error)),
196 })
197 .await
198 .map_err(Refusal::into_error)?;
199
200 let bytes = self.inner.settings.scan_bytes();
202
203 let (entries, _) = {
204 let mut state = self.inner.state.lock().unwrap();
205 copy::<T>(&mut state, self.id, &self.selection, bytes)?
206 };
207 let Some(last) = entries.last() else {
208 return Ok(None);
209 };
210 self.after = last.position().sequence;
211 Ok(Some(FollowPage { entries }))
212 }
213}
214
215impl<T: Entry> Drop for Follower<T> {
216 fn drop(&mut self) {
217 let mut state = self.inner.state.lock().unwrap();
218 state.followers.remove(&self.id);
219 state.retire_data();
220 state.collect();
221 drop(state);
222 self.inner.notify();
223 }
224}
225
226impl<T> FollowPage<T> {
227 pub fn entries(&self) -> &[T] {
228 &self.entries
229 }
230}
231
232impl Following {
233 fn retains(&self) -> bool {
234 self.failure.is_none()
235 }
236
237 fn check(&self) -> Result<()> {
238 match self.failure {
239 Some(Failure::Gap { requested, available }) => Err(Error::Gap { requested, available }),
240 Some(Failure::Closed) => Err(Error::Closing { domain: "storage" }),
241 None => Ok(()),
242 }
243 }
244}
245
246impl State {
247 pub(super) fn close_followers(&mut self) {
248 for following in self.followers.values_mut() {
249 following.failure.get_or_insert(Failure::Closed);
250 }
251 self.retire_data();
252 }
253
254 pub(super) fn retire_data(&mut self) {
255 let through =
256 self.followers.values().filter(|following| following.retains()).map(|following| following.after).min().unwrap_or(u64::MAX);
257 self.queue.retire_data(self.data_flushed, through);
258 }
259
260 pub(super) fn lag_followers(&mut self) -> bool {
261 let Some(through) = self
262 .queue
263 .iter()
264 .filter(|entry| entry.operation.domain() == Domain::Data && entry.index <= self.data_flushed)
265 .map(|entry| entry.operation.sequence())
266 .max()
267 else {
268 return false;
269 };
270 let mut changed = false;
271 for following in self.followers.values_mut() {
272 if following.retains() && following.after < through {
273 following.failure = Some(Failure::Gap {
274 requested: following.after.saturating_add(1),
275 available: through.saturating_add(1),
276 });
277 changed = true;
278 }
279 }
280 if changed {
281 self.retire_data();
282 self.collect();
283 }
284 changed
285 }
286}
287
288fn find<T: Entry>(state: &mut State, id: u64, selection: &T::Selection) -> Result<bool> {
295 super::capacity::admitting(state, false)?;
296 let following = state.followers.get(&id).ok_or(Error::Closing { domain: "storage follow" })?;
297 following.check()?;
298 let mut cursor = following.after;
299 let mut found = false;
300 for pending in state.queue.iter().filter(|entry| entry.operation.domain() == Domain::Data) {
301 if pending.operation.sequence() <= cursor {
302 continue;
303 }
304 let entries = T::pending(Queued::new(&pending.operation));
305 let start = entries.partition_point(|entry| entry.position().sequence <= cursor);
306 if entries[start..].iter().any(|entry| entry.matches(selection)) {
307 found = true;
308 break;
309 }
310 cursor = pending.operation.sequence();
311 }
312 let following = state.followers.get_mut(&id).expect("registered follower");
313 if cursor > following.after {
314 following.after = cursor;
315 state.retire_data();
316 state.collect();
317 }
318 Ok(found)
319}
320
321fn copy<T: Entry>(state: &mut State, id: u64, selection: &T::Selection, bytes: NonZeroUsize) -> Result<(Vec<T>, usize)> {
323 let following = state.followers.get(&id).ok_or(Error::Closing { domain: "storage follow" })?;
324 following.check()?;
325 let mut cursor = following.after;
326 let mut entries = Vec::new();
327 let mut encoded = 0usize;
328 'queue: for pending in state.queue.iter().filter(|entry| entry.operation.domain() == Domain::Data) {
329 if pending.operation.sequence() <= cursor {
330 continue;
331 }
332 let values = T::pending(Queued::new(&pending.operation));
333 let start = values.partition_point(|entry| entry.position().sequence <= cursor);
334 for entry in &values[start..] {
335 if entries.len() >= SCAN_ROWS.get() {
336 break 'queue;
337 }
338 if entry.matches(selection) {
339 let size = encoded_size(entry)?;
340 if !entries.is_empty() && encoded.saturating_add(size) > bytes.get() {
341 break 'queue;
342 }
343 encoded = encoded.saturating_add(size);
344 entries.push(entry.clone());
345 }
346 cursor = entry.position().sequence;
347 }
348 cursor = cursor.max(pending.operation.sequence());
349 }
350 let following = state.followers.get_mut(&id).expect("registered follower");
351 following.after = following.after.max(cursor);
352 state.retire_data();
353 state.collect();
354 Ok((entries, encoded))
355}
356
357