1use crate::client::SubscriptionGuard;
5use crate::errors::OxiaError;
6use crate::key;
7use crate::types::{GetResult, Notification};
8use futures::Stream;
9use std::fmt;
10use std::pin::Pin;
11use std::task::{Context, Poll};
12use tokio::sync::mpsc;
13
14pub(crate) type ShardStream<T> = Pin<Box<dyn Stream<Item = Result<T, OxiaError>> + Send>>;
16
17pub(crate) trait MergeItem {
19 fn merge_key(&self) -> &str;
20}
21
22impl MergeItem for String {
23 fn merge_key(&self) -> &str {
24 self
25 }
26}
27
28impl MergeItem for GetResult {
29 fn merge_key(&self) -> &str {
30 &self.key
31 }
32}
33
34pub(crate) struct Merged<T> {
40 streams: Vec<ShardStream<T>>,
41 peeked: Vec<Option<T>>,
42 done: Vec<bool>,
43 finished: bool,
44}
45
46pub(crate) fn merged<T>(streams: Vec<ShardStream<T>>) -> Merged<T> {
47 let count = streams.len();
48 Merged {
49 streams,
50 peeked: (0..count).map(|_| None).collect(),
51 done: vec![false; count],
52 finished: false,
53 }
54}
55
56impl<T: MergeItem + Unpin> Stream for Merged<T> {
57 type Item = Result<T, OxiaError>;
58
59 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
60 let this = self.get_mut();
61 if this.finished {
62 return Poll::Ready(None);
63 }
64 let mut pending = false;
68 for i in 0..this.streams.len() {
69 while this.peeked[i].is_none() && !this.done[i] {
70 match this.streams[i].as_mut().poll_next(cx) {
71 Poll::Ready(Some(Ok(item))) => this.peeked[i] = Some(item),
72 Poll::Ready(Some(Err(err))) => {
73 this.finished = true;
74 return Poll::Ready(Some(Err(err)));
75 }
76 Poll::Ready(None) => this.done[i] = true,
77 Poll::Pending => {
78 pending = true;
79 break;
80 }
81 }
82 }
83 }
84 if pending {
85 return Poll::Pending;
86 }
87 let mut min_idx: Option<usize> = None;
88 for i in 0..this.peeked.len() {
89 if let (Some(candidate), Some(m)) = (&this.peeked[i], min_idx) {
90 let current = this.peeked[m].as_ref().expect("min slot is filled");
91 if key::compare(candidate.merge_key(), current.merge_key()).is_lt() {
92 min_idx = Some(i);
93 }
94 } else if this.peeked[i].is_some() && min_idx.is_none() {
95 min_idx = Some(i);
96 }
97 }
98 match min_idx {
99 Some(i) => Poll::Ready(Some(Ok(this.peeked[i].take().expect("slot is filled")))),
100 None => {
101 this.finished = true;
102 Poll::Ready(None)
103 }
104 }
105 }
106}
107
108pub struct ListStream {
118 inner: Merged<String>,
119}
120
121impl ListStream {
122 pub(crate) fn new(inner: Merged<String>) -> Self {
123 ListStream { inner }
124 }
125}
126
127impl Stream for ListStream {
128 type Item = Result<String, OxiaError>;
129
130 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
131 Pin::new(&mut self.inner).poll_next(cx)
132 }
133}
134
135impl fmt::Debug for ListStream {
136 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137 f.debug_struct("ListStream").finish_non_exhaustive()
138 }
139}
140
141pub struct RangeScanStream {
152 inner: Merged<GetResult>,
153}
154
155impl RangeScanStream {
156 pub(crate) fn new(inner: Merged<GetResult>) -> Self {
157 RangeScanStream { inner }
158 }
159}
160
161impl Stream for RangeScanStream {
162 type Item = Result<GetResult, OxiaError>;
163
164 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
165 Pin::new(&mut self.inner).poll_next(cx)
166 }
167}
168
169impl fmt::Debug for RangeScanStream {
170 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171 f.debug_struct("RangeScanStream").finish_non_exhaustive()
172 }
173}
174
175pub struct Notifications {
185 rx: mpsc::Receiver<Notification>,
186 _guard: SubscriptionGuard,
188}
189
190impl Notifications {
191 pub(crate) fn new(rx: mpsc::Receiver<Notification>, guard: SubscriptionGuard) -> Self {
192 Notifications { rx, _guard: guard }
193 }
194
195 pub async fn recv(&mut self) -> Option<Notification> {
200 self.rx.recv().await
201 }
202}
203
204impl fmt::Debug for Notifications {
205 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206 f.debug_struct("Notifications").finish_non_exhaustive()
207 }
208}
209
210impl Stream for Notifications {
211 type Item = Notification;
212
213 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
214 self.rx.poll_recv(cx)
215 }
216}
217
218pub struct SequenceUpdates {
227 rx: mpsc::Receiver<String>,
228 _guard: SubscriptionGuard,
230}
231
232impl SequenceUpdates {
233 pub(crate) fn new(rx: mpsc::Receiver<String>, guard: SubscriptionGuard) -> Self {
234 SequenceUpdates { rx, _guard: guard }
235 }
236
237 pub async fn recv(&mut self) -> Option<String> {
242 self.rx.recv().await
243 }
244}
245
246impl fmt::Debug for SequenceUpdates {
247 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248 f.debug_struct("SequenceUpdates").finish_non_exhaustive()
249 }
250}
251
252impl Stream for SequenceUpdates {
253 type Item = String;
254
255 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
256 self.rx.poll_recv(cx)
257 }
258}
259
260#[cfg(test)]
261mod tests {
262 use super::*;
263 use futures::StreamExt;
264
265 fn shard(items: Vec<Result<String, OxiaError>>) -> ShardStream<String> {
266 Box::pin(futures::stream::iter(items))
267 }
268
269 fn keys(items: &[&str]) -> ShardStream<String> {
270 shard(items.iter().map(|s| Ok(s.to_string())).collect())
271 }
272
273 #[tokio::test]
274 async fn merges_in_key_order() {
275 let merged = merged(vec![
276 keys(&["a", "d", "e"]),
277 keys(&["b", "c", "f"]),
278 keys(&[]),
279 ]);
280 let out: Vec<String> = merged.map(|r| r.unwrap()).collect().await;
281 assert_eq!(out, vec!["a", "b", "c", "d", "e", "f"]);
282 }
283
284 #[tokio::test]
285 async fn merges_with_slash_order() {
286 let merged = merged(vec![keys(&["/x"]), keys(&["a"])]);
288 let out: Vec<String> = merged.map(|r| r.unwrap()).collect().await;
289 assert_eq!(out, vec!["a", "/x"]);
290 }
291
292 #[tokio::test]
293 async fn error_terminates_stream() {
294 let merged = merged(vec![
295 shard(vec![Ok("a".to_string()), Err(OxiaError::Timeout)]),
296 keys(&["b", "c"]),
297 ]);
298 let out: Vec<Result<String, OxiaError>> = merged.collect().await;
299 assert!(matches!(out[0], Ok(ref k) if k == "a"));
300 assert!(out.iter().any(|r| r.is_err()));
301 let err_pos = out.iter().position(|r| r.is_err()).unwrap();
303 assert_eq!(err_pos, out.len() - 1);
304 }
305
306 #[tokio::test]
307 async fn empty_merge_ends() {
308 let merged = merged::<String>(vec![]);
309 let out: Vec<_> = merged.collect().await;
310 assert!(out.is_empty());
311 }
312}