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 { field: field.into(), first: point, last: point, min: point, max: point, summary }
126 }
127
128 pub fn merge(&self, later: &Self) -> Self {
129 assert_eq!(self.field, later.field, "a bucket merges only with a bucket of its own field");
130
131 Self {
132 field: self.field.clone(),
133 first: earliest(self.first, later.first),
134 last: latest(self.last, later.last),
135 min: lower(self.min, later.min),
136 max: higher(self.max, later.max),
137 summary: self.summary.merge(&later.summary),
138 }
139 }
140
141 pub fn count(&self) -> u64 {
142 self.summary.count()
143 }
144
145 pub fn summary(&self) -> &Summary {
146 &self.summary
147 }
148
149 pub fn aggregate(&self, kind: Aggregate) -> Option<f64> {
152 aggregate::of_summary(&self.summary, kind)
153 }
154}
155
156impl Tier {
157 pub(crate) fn channel(capacity: usize) -> (Self, mpsc::Receiver<Request>) {
158 let (sender, receiver) = mpsc::channel(capacity.max(1));
159
160 (Self { sender, readers: Arc::new(tokio::sync::Semaphore::new(capacity.max(1))) }, receiver)
161 }
162
163 pub(crate) fn reader_permit(&self) -> Result<tokio::sync::OwnedSemaphorePermit, crate::streams::ReadError> {
164 self.readers.clone().try_acquire_owned().map_err(|_| crate::streams::ReadError::Busy)
165 }
166
167 pub(crate) async fn reader(
168 &self, stream: Definition, track: Vec<String>, start: Bound<Position>, end: Bound<Position>, limits: crate::streams::ReadLimits,
169 permit: tokio::sync::OwnedSemaphorePermit,
170 ) -> Result<Opened, crate::streams::ReadError> {
171 let (reply, answer) = oneshot::channel();
172 self.sender
173 .send(Request::Reader { stream, track, start, end, limits, permit, reply })
174 .await
175 .map_err(|_| crate::streams::ReadError::Closed)?;
176 answer.await.map_err(|_| crate::streams::ReadError::Closed)
177 }
178
179 pub(crate) async fn rows(
180 &self, stream: Definition, track: Vec<String>, start: Bound<Position>, end: Bound<Position>,
181 ) -> Result<Vec<Served>, BeneathWindow> {
182 let (reply, answer) = oneshot::channel();
183 self.sender.send(Request::Rows { stream, track, start, end, reply }).await.map_err(|_| BeneathWindow::Unserved)?;
184
185 answer.await.map_err(|_| BeneathWindow::Unserved)?
186 }
187
188 pub(crate) async fn buckets(
189 &self, stream: Definition, track: Vec<String>, start: Bound<u64>, end: Bound<u64>, budget: usize,
190 ) -> Result<Vec<Bucket>, BeneathWindow> {
191 let (reply, answer) = oneshot::channel();
192 self.sender.send(Request::Buckets { stream, track, start, end, budget, reply }).await.map_err(|_| BeneathWindow::Unserved)?;
193
194 answer.await.map_err(|_| BeneathWindow::Unserved)?
195 }
196
197 pub(crate) async fn aggregate(
198 &self, stream: Definition, track: Vec<String>, start: Bound<u64>, end: Bound<u64>, kind: Aggregate,
199 ) -> Result<Vec<Aggregated>, BeneathWindow> {
200 let (reply, answer) = oneshot::channel();
201 self.sender.send(Request::Aggregate { stream, track, start, end, kind, reply }).await.map_err(|_| BeneathWindow::Unserved)?;
202
203 answer.await.map_err(|_| BeneathWindow::Unserved)?
204 }
205
206 pub(crate) async fn seal(&self, stream: Definition, track: Vec<String>) -> Position {
207 let (reply, answer) = oneshot::channel();
208
209 if self.sender.send(Request::Seal { stream, track, reply }).await.is_err() {
210 return Position::ORIGIN;
211 }
212
213 answer.await.unwrap_or(Position::ORIGIN)
214 }
215}
216
217fn earliest(held: Point, next: Point) -> Point {
222 if next.axis < held.axis { next } else { held }
223}
224
225fn latest(held: Point, next: Point) -> Point {
226 if next.axis >= held.axis { next } else { held }
227}
228
229fn lower(held: Point, next: Point) -> Point {
230 if next.value < held.value { next } else { held }
231}
232
233fn higher(held: Point, next: Point) -> Point {
234 if next.value > held.value { next } else { held }
235}
236
237