1use std::any::Any;
18use std::ops::Bound;
19use std::sync::Arc;
20use harmos_domain::Aggregate;
22use harmos_storage::signal::Summary;
23use tokio::sync::{mpsc, oneshot};
24use super::BeneathWindow;
26use crate::aggregate;
27use crate::{state::At, state::Position, streams::Definition};
28
29pub(crate) type Served = At<Arc<dyn Any + Send + Sync>>;
36
37#[derive(Clone, Copy, Debug, PartialEq)]
40pub struct Point {
41 pub axis: u64,
42 pub value: f64,
43}
44
45#[derive(Clone, Debug, PartialEq)]
48pub struct Bucket {
49 pub field: String,
50 pub first: Point,
51 pub last: Point,
52 pub min: Point,
53 pub max: Point,
54 summary: Summary,
55}
56
57#[derive(Clone, Debug, PartialEq)]
58pub struct Aggregated {
59 pub field: String,
60 pub value: f64,
61}
62
63pub(crate) struct Opened {
64 pub(crate) source: Result<Box<dyn crate::streams::RowSource>, crate::streams::ReadError>,
65 pub(crate) permit: tokio::sync::OwnedSemaphorePermit,
66}
67
68#[derive(Clone)]
69pub(crate) struct Tier {
70 sender: mpsc::Sender<Request>,
71 readers: Arc<tokio::sync::Semaphore>,
72}
73
74pub(crate) enum Request {
77 Reader {
78 stream: Definition,
79 track: Vec<String>,
80 start: Bound<Position>,
81 end: Bound<Position>,
82 limits: crate::streams::ReadLimits,
83 permit: tokio::sync::OwnedSemaphorePermit,
84 reply: oneshot::Sender<Opened>,
85 },
86 Rows {
87 stream: Definition,
88 track: Vec<String>,
89 start: Bound<Position>,
90 end: Bound<Position>,
91 reply: oneshot::Sender<Result<Vec<Served>, BeneathWindow>>,
92 },
93 Buckets {
94 stream: Definition,
95 track: Vec<String>,
96 start: Bound<u64>,
97 end: Bound<u64>,
98 budget: usize,
99 reply: oneshot::Sender<Result<Vec<Bucket>, BeneathWindow>>,
100 },
101 Aggregate {
102 stream: Definition,
103 track: Vec<String>,
104 start: Bound<u64>,
105 end: Bound<u64>,
106 kind: Aggregate,
107 reply: oneshot::Sender<Result<Vec<Aggregated>, BeneathWindow>>,
108 },
109 Seal {
110 stream: Definition,
111 track: Vec<String>,
112 reply: oneshot::Sender<Position>,
113 },
114}
115
116impl Bucket {
121 pub fn point(field: impl Into<String>, point: Point) -> Self {
122 let mut summary = Summary::new();
123 summary.push(point.value);
124
125 Self {
126 field: field.into(),
127 first: point,
128 last: point,
129 min: point,
130 max: point,
131 summary,
132 }
133 }
134
135 pub fn merge(&self, later: &Self) -> Self {
136 assert_eq!(self.field, later.field, "a bucket merges only with a bucket of its own field");
137
138 Self {
139 field: self.field.clone(),
140 first: earliest(self.first, later.first),
141 last: latest(self.last, later.last),
142 min: lower(self.min, later.min),
143 max: higher(self.max, later.max),
144 summary: self.summary.merge(&later.summary),
145 }
146 }
147
148 pub fn count(&self) -> u64 {
149 self.summary.count()
150 }
151
152 pub fn summary(&self) -> &Summary {
153 &self.summary
154 }
155
156 pub fn aggregate(&self, kind: Aggregate) -> Option<f64> {
159 aggregate::of_summary(&self.summary, kind)
160 }
161}
162
163impl Tier {
164 pub(crate) fn channel(capacity: usize) -> (Self, mpsc::Receiver<Request>) {
165 let (sender, receiver) = mpsc::channel(capacity.max(1));
166
167 (
168 Self {
169 sender,
170 readers: Arc::new(tokio::sync::Semaphore::new(capacity.max(1))),
171 },
172 receiver,
173 )
174 }
175
176 pub(crate) fn reader_permit(&self) -> Result<tokio::sync::OwnedSemaphorePermit, crate::streams::ReadError> {
177 self.readers.clone().try_acquire_owned().map_err(|_| crate::streams::ReadError::Busy)
178 }
179
180 pub(crate) async fn reader(
181 &self, stream: Definition, track: Vec<String>, start: Bound<Position>, end: Bound<Position>, limits: crate::streams::ReadLimits,
182 permit: tokio::sync::OwnedSemaphorePermit,
183 ) -> Result<Opened, crate::streams::ReadError> {
184 let (reply, answer) = oneshot::channel();
185 self.sender
186 .send(Request::Reader {
187 stream,
188 track,
189 start,
190 end,
191 limits,
192 permit,
193 reply,
194 })
195 .await
196 .map_err(|_| crate::streams::ReadError::Closed)?;
197 answer.await.map_err(|_| crate::streams::ReadError::Closed)
198 }
199
200 pub(crate) async fn rows(
201 &self, stream: Definition, track: Vec<String>, start: Bound<Position>, end: Bound<Position>,
202 ) -> Result<Vec<Served>, BeneathWindow> {
203 let (reply, answer) = oneshot::channel();
204 self.sender.send(Request::Rows { stream, track, start, end, reply }).await.map_err(|_| BeneathWindow::Unserved)?;
205
206 answer.await.map_err(|_| BeneathWindow::Unserved)?
207 }
208
209 pub(crate) async fn buckets(
210 &self, stream: Definition, track: Vec<String>, start: Bound<u64>, end: Bound<u64>, budget: usize,
211 ) -> Result<Vec<Bucket>, BeneathWindow> {
212 let (reply, answer) = oneshot::channel();
213 self.sender.send(Request::Buckets { stream, track, start, end, budget, reply }).await.map_err(|_| BeneathWindow::Unserved)?;
214
215 answer.await.map_err(|_| BeneathWindow::Unserved)?
216 }
217
218 pub(crate) async fn aggregate(
219 &self, stream: Definition, track: Vec<String>, start: Bound<u64>, end: Bound<u64>, kind: Aggregate,
220 ) -> Result<Vec<Aggregated>, BeneathWindow> {
221 let (reply, answer) = oneshot::channel();
222 self.sender.send(Request::Aggregate { stream, track, start, end, kind, reply }).await.map_err(|_| BeneathWindow::Unserved)?;
223
224 answer.await.map_err(|_| BeneathWindow::Unserved)?
225 }
226
227 pub(crate) async fn seal(&self, stream: Definition, track: Vec<String>) -> Position {
228 let (reply, answer) = oneshot::channel();
229
230 if self.sender.send(Request::Seal { stream, track, reply }).await.is_err() {
231 return Position::ORIGIN;
232 }
233
234 answer.await.unwrap_or(Position::ORIGIN)
235 }
236}
237
238fn earliest(held: Point, next: Point) -> Point {
243 if next.axis < held.axis { next } else { held }
244}
245
246fn latest(held: Point, next: Point) -> Point {
247 if next.axis >= held.axis { next } else { held }
248}
249
250fn lower(held: Point, next: Point) -> Point {
251 if next.value < held.value { next } else { held }
252}
253
254fn higher(held: Point, next: Point) -> Point {
255 if next.value > held.value { next } else { held }
256}
257
258