reifydb_core/window/engine/
mod.rs1pub mod config;
14pub mod multi_rolling;
15pub mod rolling;
16pub mod rolling_incremental;
17pub mod tumbling;
18pub mod tumbling_carry;
19
20use std::ops::Bound;
21
22use reifydb_codec::key::{
23 encode_u64,
24 encoded::{EncodedKey, EncodedKeyRange, IntoEncodedKey},
25};
26use reifydb_value::value::row_number::RowNumber;
27use serde::{Deserialize, Serialize};
28
29use crate::{key::flow_node_internal_state::FlowNodeInternalStateKey, window::span::WindowSpan};
30
31pub enum AccumulatorEvent<C> {
33 Add(C),
34 Remove(C),
35}
36
37#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
40pub enum LatePolicy {
41 #[default]
43 Drop,
44 Process,
47}
48
49#[derive(Clone, Copy, Debug, PartialEq, Eq)]
51pub enum EmitKind {
52 Insert,
53 Update,
54 Remove,
55}
56
57pub struct WindowResult<G, Coord, Output> {
59 pub row_number: RowNumber,
60 pub group: G,
61 pub span: WindowSpan<Coord>,
62 pub value: Output,
63 pub prior: Option<Output>,
68 pub kind: EmitKind,
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize)]
74#[serde(bound(serialize = "K: Serialize", deserialize = "K: serde::de::DeserializeOwned"))]
75pub struct GroupMeta<K> {
76 pub high_water: Option<K>,
77}
78
79impl<K> Default for GroupMeta<K> {
80 fn default() -> Self {
81 Self {
82 high_water: None,
83 }
84 }
85}
86
87#[derive(Clone, Hash, PartialEq, Eq)]
90pub struct MetaKey(pub EncodedKey);
91
92impl IntoEncodedKey for &MetaKey {
93 fn into_encoded_key(self) -> EncodedKey {
94 let inner = self.0.as_ref();
95 let mut bytes = Vec::with_capacity(1 + inner.len());
96 bytes.push(FlowNodeInternalStateKey::WINDOW_META_TAG);
97 bytes.extend_from_slice(inner);
98 EncodedKey::new(bytes)
99 }
100}
101
102pub fn meta_key_for<G>(group: &G) -> MetaKey
103where
104 for<'a> &'a G: IntoEncodedKey,
105{
106 MetaKey(group.into_encoded_key())
107}
108
109pub fn expiry_key<G>(expiry: u64, group: &G, suffix: &[u8]) -> EncodedKey
110where
111 for<'a> &'a G: IntoEncodedKey,
112{
113 let group = group.into_encoded_key();
114 let group = group.as_ref();
115 let mut bytes = Vec::with_capacity(1 + 8 + group.len() + suffix.len());
116 bytes.push(FlowNodeInternalStateKey::WINDOW_EXPIRY_TAG);
117 bytes.extend_from_slice(&encode_u64(expiry));
118 bytes.extend_from_slice(group);
119 bytes.extend_from_slice(suffix);
120 EncodedKey::new(bytes)
121}
122
123pub fn expiry_due_range(threshold: u64) -> EncodedKeyRange {
124 let mut start = Vec::with_capacity(1 + 8);
125 start.push(FlowNodeInternalStateKey::WINDOW_EXPIRY_TAG);
126 start.extend_from_slice(&encode_u64(threshold));
127 let end = vec![FlowNodeInternalStateKey::WINDOW_EXPIRY_TAG + 1];
128 EncodedKeyRange::new(Bound::Included(EncodedKey::new(start)), Bound::Excluded(EncodedKey::new(end)))
129}
130
131#[cfg(test)]
132pub(crate) mod test_support {
133 use std::{collections::HashMap, ops::Bound};
134
135 use postcard::{from_bytes, to_allocvec};
136 use reifydb_codec::key::encoded::{EncodedKey, EncodedKeyRange};
137 use reifydb_value::{Result, value::row_number::RowNumber};
138 use serde::{Deserialize, Serialize, de::DeserializeOwned};
139
140 use crate::{
141 key::flow_node_internal_state::FlowNodeInternalStateKey,
142 window::{accumulator::WindowAccumulator, store::WindowStore},
143 };
144
145 #[derive(Default)]
146 pub(crate) struct MockStore {
147 data: HashMap<Vec<u8>, Vec<u8>>,
148 internal: HashMap<Vec<u8>, Vec<u8>>,
149 rows: HashMap<Vec<u8>, u64>,
150 next_row: u64,
151 }
152
153 impl MockStore {
154 pub(crate) fn index_entry_count(&mut self) -> usize {
155 self.internal
156 .keys()
157 .filter(|k| k.first() == Some(&FlowNodeInternalStateKey::WINDOW_EXPIRY_TAG))
158 .count()
159 }
160 }
161
162 impl WindowStore for MockStore {
163 fn state_get<V: DeserializeOwned>(&mut self, key: &EncodedKey) -> Result<Option<V>> {
164 Ok(self.data.get(key.as_bytes()).map(|b| from_bytes(b).expect("decode")))
165 }
166 fn state_get_many_visit<V: DeserializeOwned>(
167 &mut self,
168 keys: &[EncodedKey],
169 visit: &mut dyn FnMut(EncodedKey, V) -> Result<()>,
170 ) -> Result<()> {
171 for key in keys {
172 if let Some(b) = self.data.get(key.as_bytes()) {
173 visit(key.clone(), from_bytes(b).expect("decode"))?;
174 }
175 }
176 Ok(())
177 }
178 fn state_set<V: Serialize>(&mut self, key: &EncodedKey, value: &V) -> Result<()> {
179 self.data.insert(key.as_bytes().to_vec(), to_allocvec(value).expect("encode"));
180 Ok(())
181 }
182 fn state_remove(&mut self, key: &EncodedKey) -> Result<()> {
183 self.data.remove(key.as_bytes());
184 Ok(())
185 }
186 fn state_drop(&mut self, key: &EncodedKey) -> Result<()> {
187 self.data.remove(key.as_bytes());
188 Ok(())
189 }
190 fn internal_get<V: DeserializeOwned>(&mut self, key: &EncodedKey) -> Result<Option<V>> {
191 Ok(self.internal.get(key.as_bytes()).map(|b| from_bytes(b).expect("decode")))
192 }
193 fn internal_get_many_visit<V: DeserializeOwned>(
194 &mut self,
195 keys: &[EncodedKey],
196 visit: &mut dyn FnMut(EncodedKey, V) -> Result<()>,
197 ) -> Result<()> {
198 for key in keys {
199 if let Some(b) = self.internal.get(key.as_bytes()) {
200 visit(key.clone(), from_bytes(b).expect("decode"))?;
201 }
202 }
203 Ok(())
204 }
205 fn internal_set<V: Serialize>(&mut self, key: &EncodedKey, value: &V) -> Result<()> {
206 self.internal.insert(key.as_bytes().to_vec(), to_allocvec(value).expect("encode"));
207 Ok(())
208 }
209 fn internal_remove(&mut self, key: &EncodedKey) -> Result<()> {
210 self.internal.remove(key.as_bytes());
211 Ok(())
212 }
213 fn internal_drop(&mut self, key: &EncodedKey) -> Result<()> {
214 self.internal.remove(key.as_bytes());
215 Ok(())
216 }
217 fn internal_range_visit<V: DeserializeOwned>(
218 &mut self,
219 range: EncodedKeyRange,
220 visit: &mut dyn FnMut(EncodedKey, V) -> Result<()>,
221 ) -> Result<()> {
222 let after_start = |k: &[u8]| match &range.start {
223 Bound::Included(s) => k >= s.as_bytes(),
224 Bound::Excluded(s) => k > s.as_bytes(),
225 Bound::Unbounded => true,
226 };
227 let before_end = |k: &[u8]| match &range.end {
228 Bound::Included(e) => k <= e.as_bytes(),
229 Bound::Excluded(e) => k < e.as_bytes(),
230 Bound::Unbounded => true,
231 };
232 let mut matched: Vec<(Vec<u8>, Vec<u8>)> = self
233 .internal
234 .iter()
235 .filter(|(k, _)| after_start(k) && before_end(k))
236 .map(|(k, v)| (k.clone(), v.clone()))
237 .collect();
238 matched.sort_by(|a, b| a.0.cmp(&b.0));
239 for (k, b) in matched {
240 visit(EncodedKey::new(k), from_bytes(&b).expect("decode"))?;
241 }
242 Ok(())
243 }
244 fn get_or_create_row_number(&mut self, key: &EncodedKey) -> Result<(RowNumber, bool)> {
245 if let Some(rn) = self.rows.get(key.as_bytes()) {
246 return Ok((RowNumber(*rn), false));
247 }
248 self.next_row += 1;
249 self.rows.insert(key.as_bytes().to_vec(), self.next_row);
250 Ok((RowNumber(self.next_row), true))
251 }
252 fn get_or_create_row_numbers(&mut self, keys: &[EncodedKey]) -> Result<Vec<(RowNumber, bool)>> {
253 keys.iter().map(|k| self.get_or_create_row_number(k)).collect()
254 }
255 fn allocate_row_numbers(&mut self, count: u64) -> Result<RowNumber> {
256 let start = self.next_row + 1;
257 self.next_row += count;
258 Ok(RowNumber(start))
259 }
260 fn clock_now_nanos(&self) -> u64 {
261 0
262 }
263 }
264
265 #[derive(Clone, Debug, Default, Serialize, Deserialize)]
266 pub(crate) struct SumAccumulator {
267 pub sum: i64,
268 pub count: u64,
269 }
270
271 impl WindowAccumulator for SumAccumulator {
272 type Contribution = i64;
273 type Output = i64;
274
275 fn add(&mut self, contribution: &i64) {
276 self.sum += *contribution;
277 self.count += 1;
278 }
279 fn remove(&mut self, contribution: &i64) {
280 self.sum -= *contribution;
281 self.count = self.count.saturating_sub(1);
282 }
283 fn finalize(&self) -> Option<i64> {
284 if self.count == 0 {
285 None
286 } else {
287 Some(self.sum)
288 }
289 }
290 fn is_empty(&self) -> bool {
291 self.count == 0
292 }
293 }
294
295 #[derive(Clone, Debug, Default, Serialize, Deserialize)]
296 pub(crate) struct StampedSum {
297 pub sum: i64,
298 pub count: u64,
299 pub stamp: Option<u64>,
300 }
301
302 impl WindowAccumulator for StampedSum {
303 type Contribution = (i64, u64);
304 type Output = i64;
305
306 fn add(&mut self, contribution: &(i64, u64)) {
307 self.sum += contribution.0;
308 self.count += 1;
309 self.stamp = Some(self.stamp.map_or(contribution.1, |s| s.max(contribution.1)));
310 }
311 fn remove(&mut self, contribution: &(i64, u64)) {
312 self.sum -= contribution.0;
313 self.count = self.count.saturating_sub(1);
314 }
315 fn finalize(&self) -> Option<i64> {
316 if self.count == 0 {
317 None
318 } else {
319 Some(self.sum)
320 }
321 }
322 fn is_empty(&self) -> bool {
323 self.count == 0
324 }
325 fn stamp(&self) -> Option<u64> {
326 self.stamp
327 }
328 }
329}