1pub mod config;
14pub mod multi_rolling;
15pub mod rolling;
16pub mod rolling_incremental;
17pub mod tumbling;
18pub mod tumbling_carry;
19
20use std::{
21 collections::{BTreeMap, BTreeSet},
22 ops::Bound,
23};
24
25use reifydb_codec::key::{
26 encode_u64,
27 encoded::{EncodedKey, EncodedKeyRange, IntoEncodedKey},
28};
29use reifydb_value::{Result, value::row_number::RowNumber};
30use serde::{Deserialize, Serialize, de::DeserializeOwned};
31
32use crate::{
33 key::flow_node_internal_state::FlowNodeInternalStateKey,
34 window::{
35 accumulator::WindowAccumulator,
36 span::{Slot, WindowSpan},
37 state::StateCache,
38 store::WindowStore,
39 },
40};
41
42pub enum AccumulatorEvent<C> {
44 Add(C),
45 Remove(C),
46}
47
48pub fn seal_horizon(watermark: u64, seal_after: u64) -> u64 {
54 watermark.saturating_sub(seal_after)
55}
56
57pub fn is_sealed(anchor: u64, horizon: u64) -> bool {
58 anchor < horizon
59}
60
61#[derive(Clone, Copy, Debug, PartialEq, Eq)]
63pub enum EmitKind {
64 Insert,
65 Update,
66 Remove,
67}
68
69pub struct WindowResult<G, Coord, Output> {
71 pub row_number: RowNumber,
72 pub group: G,
73 pub span: WindowSpan<Coord>,
74 pub value: Output,
75 pub prior: Option<Output>,
80 pub kind: EmitKind,
81}
82
83#[derive(Debug, Clone, Serialize, Deserialize)]
86#[serde(bound(serialize = "K: Serialize", deserialize = "K: serde::de::DeserializeOwned"))]
87pub struct GroupMeta<K> {
88 pub high_water: Option<K>,
89}
90
91impl<K> Default for GroupMeta<K> {
92 fn default() -> Self {
93 Self {
94 high_water: None,
95 }
96 }
97}
98
99pub(crate) trait MetaHighWater {
106 fn high_water_order(&self) -> Option<u64>;
107}
108
109impl<C: Slot> MetaHighWater for GroupMeta<C> {
110 fn high_water_order(&self) -> Option<u64> {
111 self.high_water.as_ref().map(|hw| hw.order_key())
112 }
113}
114
115pub(crate) fn meta_range() -> EncodedKeyRange {
117 EncodedKeyRange::new(
118 Bound::Included(EncodedKey::new(vec![FlowNodeInternalStateKey::WINDOW_META_TAG])),
119 Bound::Excluded(EncodedKey::new(vec![FlowNodeInternalStateKey::WINDOW_META_TAG + 1])),
120 )
121}
122
123pub(crate) fn sweep_stale_meta<S, M>(
138 store: &mut S,
139 meta: &mut StateCache<MetaKey, M>,
140 threshold: u64,
141 low_water: &mut Option<u64>,
142) -> Result<usize>
143where
144 S: WindowStore,
145 M: MetaHighWater + Clone + Serialize + DeserializeOwned,
146{
147 if low_water.is_some_and(|lw| lw >= threshold) {
148 return Ok(0);
149 }
150 meta.flush(store)?;
151 let mut stale: Vec<MetaKey> = Vec::new();
152 let mut min_surviving: Option<u64> = None;
153 store.internal_range_visit::<M>(meta_range(), None, &mut |key, value| {
154 if let Some(hw) = value.high_water_order() {
155 if hw < threshold {
156 stale.push(MetaKey(EncodedKey::new(key.as_bytes()[1..].to_vec())));
157 } else {
158 min_surviving = Some(min_surviving.map_or(hw, |m| m.min(hw)));
159 }
160 }
161 Ok(())
162 })?;
163 *low_water = min_surviving;
164 let count = stale.len();
165 for key in &stale {
166 meta.remove(store, key)?;
167 }
168 meta.flush(store)?;
169 Ok(count)
170}
171
172#[derive(Clone, Hash, PartialEq, Eq)]
175pub struct MetaKey(pub EncodedKey);
176
177#[derive(Clone, Copy, Hash, PartialEq, Eq)]
178pub struct RunningKey(pub RowNumber);
179
180impl IntoEncodedKey for &RunningKey {
181 fn into_encoded_key(self) -> EncodedKey {
182 let inner = (&self.0).into_encoded_key();
183 let inner = inner.as_ref();
184 let mut bytes = Vec::with_capacity(1 + inner.len());
185 bytes.push(FlowNodeInternalStateKey::WINDOW_RUNNING_TAG);
186 bytes.extend_from_slice(inner);
187 EncodedKey::new(bytes)
188 }
189}
190
191#[derive(Clone, Copy, Hash, PartialEq, Eq)]
192pub struct WindowStateKey(pub RowNumber);
193
194impl IntoEncodedKey for &WindowStateKey {
195 fn into_encoded_key(self) -> EncodedKey {
196 let inner = (&self.0).into_encoded_key();
197 let inner = inner.as_ref();
198 let mut bytes = Vec::with_capacity(1 + inner.len());
199 bytes.push(FlowNodeInternalStateKey::WINDOW_ROW_STATE_TAG);
200 bytes.extend_from_slice(inner);
201 EncodedKey::new(bytes)
202 }
203}
204
205#[derive(Clone, Copy, Hash, PartialEq, Eq)]
206pub struct EmitKey(pub RowNumber);
207
208impl IntoEncodedKey for &EmitKey {
209 fn into_encoded_key(self) -> EncodedKey {
210 let inner = (&self.0).into_encoded_key();
211 let inner = inner.as_ref();
212 let mut bytes = Vec::with_capacity(1 + inner.len());
213 bytes.push(FlowNodeInternalStateKey::WINDOW_EMIT_TAG);
214 bytes.extend_from_slice(inner);
215 EncodedKey::new(bytes)
216 }
217}
218
219impl IntoEncodedKey for &MetaKey {
220 fn into_encoded_key(self) -> EncodedKey {
221 let inner = self.0.as_ref();
222 let mut bytes = Vec::with_capacity(1 + inner.len());
223 bytes.push(FlowNodeInternalStateKey::WINDOW_META_TAG);
224 bytes.extend_from_slice(inner);
225 EncodedKey::new(bytes)
226 }
227}
228
229pub fn meta_key_for<G>(group: &G) -> MetaKey
230where
231 for<'a> &'a G: IntoEncodedKey,
232{
233 MetaKey(group.into_encoded_key())
234}
235
236pub fn expiry_key<G>(expiry: u64, group: &G, suffix: &[u8]) -> EncodedKey
237where
238 for<'a> &'a G: IntoEncodedKey,
239{
240 let group = group.into_encoded_key();
241 let group = group.as_ref();
242 let mut bytes = Vec::with_capacity(1 + 8 + group.len() + suffix.len());
243 bytes.push(FlowNodeInternalStateKey::WINDOW_EXPIRY_TAG);
244 bytes.extend_from_slice(&encode_u64(expiry));
245 bytes.extend_from_slice(group);
246 bytes.extend_from_slice(suffix);
247 EncodedKey::new(bytes)
248}
249
250pub fn coord_entry_key(row_number: RowNumber, coord: u64) -> EncodedKey {
251 let mut bytes = Vec::with_capacity(17);
252 bytes.push(FlowNodeInternalStateKey::WINDOW_COORD_TAG);
253 bytes.extend_from_slice(&row_number.0.to_be_bytes());
254 bytes.extend_from_slice(&coord.to_be_bytes());
255 EncodedKey::new(bytes)
256}
257
258pub fn coord_row_range(row_number: RowNumber) -> EncodedKeyRange {
259 let mut start = Vec::with_capacity(9);
260 start.push(FlowNodeInternalStateKey::WINDOW_COORD_TAG);
261 start.extend_from_slice(&row_number.0.to_be_bytes());
262 let mut end = Vec::with_capacity(9);
263 end.push(FlowNodeInternalStateKey::WINDOW_COORD_TAG);
264 end.extend_from_slice(&(row_number.0 + 1).to_be_bytes());
265 EncodedKeyRange::new(Bound::Included(EncodedKey::new(start)), Bound::Excluded(EncodedKey::new(end)))
266}
267
268pub fn coord_due_range(row_number: RowNumber, cutoff: u64) -> EncodedKeyRange {
269 let mut start = Vec::with_capacity(9);
270 start.push(FlowNodeInternalStateKey::WINDOW_COORD_TAG);
271 start.extend_from_slice(&row_number.0.to_be_bytes());
272 let end = match cutoff.checked_add(1) {
273 Some(exclusive) => {
274 let mut end = Vec::with_capacity(17);
275 end.push(FlowNodeInternalStateKey::WINDOW_COORD_TAG);
276 end.extend_from_slice(&row_number.0.to_be_bytes());
277 end.extend_from_slice(&exclusive.to_be_bytes());
278 end
279 }
280 None => {
281 let mut end = Vec::with_capacity(9);
282 end.push(FlowNodeInternalStateKey::WINDOW_COORD_TAG);
283 end.extend_from_slice(&(row_number.0 + 1).to_be_bytes());
284 end
285 }
286 };
287 EncodedKeyRange::new(Bound::Included(EncodedKey::new(start)), Bound::Excluded(EncodedKey::new(end)))
288}
289
290pub fn coord_between_range(row_number: RowNumber, after: u64, upto: u64) -> EncodedKeyRange {
291 let start = coord_entry_key(row_number, after);
292 let end = match upto.checked_add(1) {
293 Some(exclusive) => {
294 let mut end = Vec::with_capacity(17);
295 end.push(FlowNodeInternalStateKey::WINDOW_COORD_TAG);
296 end.extend_from_slice(&row_number.0.to_be_bytes());
297 end.extend_from_slice(&exclusive.to_be_bytes());
298 end
299 }
300 None => {
301 let mut end = Vec::with_capacity(9);
302 end.push(FlowNodeInternalStateKey::WINDOW_COORD_TAG);
303 end.extend_from_slice(&(row_number.0 + 1).to_be_bytes());
304 end
305 }
306 };
307 EncodedKeyRange::new(Bound::Excluded(start), Bound::Excluded(EncodedKey::new(end)))
308}
309
310pub fn expiry_due_range(threshold: u64) -> EncodedKeyRange {
311 let mut start = Vec::with_capacity(1 + 8);
312 start.push(FlowNodeInternalStateKey::WINDOW_EXPIRY_TAG);
313 start.extend_from_slice(&encode_u64(threshold));
314 let end = vec![FlowNodeInternalStateKey::WINDOW_EXPIRY_TAG + 1];
315 EncodedKeyRange::new(Bound::Included(EncodedKey::new(start)), Bound::Excluded(EncodedKey::new(end)))
316}
317
318pub(crate) fn entry_key_coord(key: &EncodedKey) -> Option<u64> {
319 let bytes = key.as_bytes();
320 if bytes.len() == 17 {
321 let mut coord = [0u8; 8];
322 coord.copy_from_slice(&bytes[9..17]);
323 Some(u64::from_be_bytes(coord))
324 } else {
325 None
326 }
327}
328
329pub(crate) fn load_buffer<S, C, A>(store: &mut S, row_number: RowNumber) -> Result<(BTreeMap<C, A>, Vec<u64>)>
330where
331 S: WindowStore,
332 C: Slot,
333 A: WindowAccumulator,
334{
335 let mut buffer = BTreeMap::new();
336 let mut loaded: Vec<u64> = Vec::new();
337 store.internal_range_visit::<A>(coord_row_range(row_number), None, &mut |key, accumulator| {
338 if let Some(order) = entry_key_coord(&key) {
339 buffer.insert(C::from_order_key(order), accumulator);
340 loaded.push(order);
341 }
342 Ok(())
343 })?;
344 Ok((buffer, loaded))
345}
346
347pub(crate) fn persist_buffer<S, C, A>(
348 store: &mut S,
349 row_number: RowNumber,
350 buffer: &BTreeMap<C, A>,
351 loaded_coords: &[u64],
352 dirty: &BTreeSet<u64>,
353) -> Result<()>
354where
355 S: WindowStore,
356 C: Slot,
357 A: WindowAccumulator,
358{
359 let live: BTreeSet<u64> = buffer.keys().map(|c| c.order_key()).collect();
360 let loaded: BTreeSet<u64> = loaded_coords.iter().copied().collect();
361 for old in loaded_coords {
362 if !live.contains(old) {
363 store.internal_drop(&coord_entry_key(row_number, *old))?;
364 }
365 }
366 for (coord, accumulator) in buffer {
367 let order = coord.order_key();
368 if dirty.contains(&order) || !loaded.contains(&order) {
369 store.internal_set(&coord_entry_key(row_number, order), accumulator)?;
370 }
371 }
372 Ok(())
373}
374
375pub(crate) fn drop_all_coords<S, A>(store: &mut S, row_number: RowNumber) -> Result<()>
376where
377 S: WindowStore,
378 A: WindowAccumulator,
379{
380 let mut keys: Vec<EncodedKey> = Vec::new();
381 store.internal_range_visit::<A>(coord_row_range(row_number), None, &mut |key, _accumulator| {
382 keys.push(key);
383 Ok(())
384 })?;
385 for key in keys {
386 store.internal_drop(&key)?;
387 }
388 Ok(())
389}
390
391#[cfg(test)]
392pub(crate) mod test_support {
393 use std::{collections::HashMap, ops::Bound};
394
395 use postcard::{from_bytes, to_allocvec};
396 use reifydb_codec::key::encoded::{EncodedKey, EncodedKeyRange};
397 use reifydb_value::{Result, value::row_number::RowNumber};
398 use serde::{Deserialize, Serialize, de::DeserializeOwned};
399
400 use crate::{
401 key::flow_node_internal_state::FlowNodeInternalStateKey,
402 window::{accumulator::WindowAccumulator, store::WindowStore},
403 };
404
405 #[derive(Default)]
406 pub(crate) struct MockStore {
407 data: HashMap<Vec<u8>, Vec<u8>>,
408 internal: HashMap<Vec<u8>, Vec<u8>>,
409 rows: HashMap<Vec<u8>, u64>,
410 next_row: u64,
411 }
412
413 impl MockStore {
414 pub(crate) fn index_entry_count(&mut self) -> usize {
415 self.internal
416 .keys()
417 .filter(|k| k.first() == Some(&FlowNodeInternalStateKey::WINDOW_EXPIRY_TAG))
418 .count()
419 }
420
421 pub(crate) fn coord_entry_count(&mut self) -> usize {
422 self.internal
423 .keys()
424 .filter(|k| k.first() == Some(&FlowNodeInternalStateKey::WINDOW_COORD_TAG))
425 .count()
426 }
427
428 pub(crate) fn running_entry_count(&mut self) -> usize {
429 self.internal
430 .keys()
431 .filter(|k| k.first() == Some(&FlowNodeInternalStateKey::WINDOW_RUNNING_TAG))
432 .count()
433 }
434
435 pub(crate) fn meta_entry_count(&mut self) -> usize {
436 self.internal
437 .keys()
438 .filter(|k| k.first() == Some(&FlowNodeInternalStateKey::WINDOW_META_TAG))
439 .count()
440 }
441
442 pub(crate) fn mapping_entry_count(&mut self) -> usize {
443 self.internal
444 .keys()
445 .filter(|k| k.first() == Some(&FlowNodeInternalStateKey::ROW_NUMBER_MAPPING_TAG))
446 .count()
447 }
448
449 pub(crate) fn seed_mapping_key(&mut self, suffix: u8) {
450 self.internal.insert(vec![FlowNodeInternalStateKey::ROW_NUMBER_MAPPING_TAG, suffix], vec![0u8]);
451 }
452
453 pub(crate) fn contains_row_mapping(&self, key: &EncodedKey) -> bool {
454 self.rows.contains_key(key.as_bytes())
455 }
456 }
457
458 impl WindowStore for MockStore {
459 fn state_get<V: DeserializeOwned>(&mut self, key: &EncodedKey) -> Result<Option<V>> {
460 Ok(self.data.get(key.as_bytes()).map(|b| from_bytes(b).expect("decode")))
461 }
462 fn state_get_many_visit<V: DeserializeOwned>(
463 &mut self,
464 keys: &[EncodedKey],
465 visit: &mut dyn FnMut(EncodedKey, V) -> Result<()>,
466 ) -> Result<()> {
467 for key in keys {
468 if let Some(b) = self.data.get(key.as_bytes()) {
469 visit(key.clone(), from_bytes(b).expect("decode"))?;
470 }
471 }
472 Ok(())
473 }
474 fn state_set<V: Serialize>(&mut self, key: &EncodedKey, value: &V) -> Result<()> {
475 self.data.insert(key.as_bytes().to_vec(), to_allocvec(value).expect("encode"));
476 Ok(())
477 }
478 fn state_remove(&mut self, key: &EncodedKey) -> Result<()> {
479 self.data.remove(key.as_bytes());
480 Ok(())
481 }
482 fn state_drop(&mut self, key: &EncodedKey) -> Result<()> {
483 self.data.remove(key.as_bytes());
484 Ok(())
485 }
486 fn internal_get<V: DeserializeOwned>(&mut self, key: &EncodedKey) -> Result<Option<V>> {
487 Ok(self.internal.get(key.as_bytes()).map(|b| from_bytes(b).expect("decode")))
488 }
489 fn internal_get_many_visit<V: DeserializeOwned>(
490 &mut self,
491 keys: &[EncodedKey],
492 visit: &mut dyn FnMut(EncodedKey, V) -> Result<()>,
493 ) -> Result<()> {
494 for key in keys {
495 if let Some(b) = self.internal.get(key.as_bytes()) {
496 visit(key.clone(), from_bytes(b).expect("decode"))?;
497 }
498 }
499 Ok(())
500 }
501 fn internal_set<V: Serialize>(&mut self, key: &EncodedKey, value: &V) -> Result<()> {
502 self.internal.insert(key.as_bytes().to_vec(), to_allocvec(value).expect("encode"));
503 Ok(())
504 }
505 fn internal_remove(&mut self, key: &EncodedKey) -> Result<()> {
506 self.internal.remove(key.as_bytes());
507 Ok(())
508 }
509 fn internal_drop(&mut self, key: &EncodedKey) -> Result<()> {
510 self.internal.remove(key.as_bytes());
511 Ok(())
512 }
513 fn internal_range_visit<V: DeserializeOwned>(
514 &mut self,
515 range: EncodedKeyRange,
516 limit: Option<usize>,
517 visit: &mut dyn FnMut(EncodedKey, V) -> Result<()>,
518 ) -> Result<()> {
519 let after_start = |k: &[u8]| match &range.start {
520 Bound::Included(s) => k >= s.as_bytes(),
521 Bound::Excluded(s) => k > s.as_bytes(),
522 Bound::Unbounded => true,
523 };
524 let before_end = |k: &[u8]| match &range.end {
525 Bound::Included(e) => k <= e.as_bytes(),
526 Bound::Excluded(e) => k < e.as_bytes(),
527 Bound::Unbounded => true,
528 };
529 let mut matched: Vec<(Vec<u8>, Vec<u8>)> = self
530 .internal
531 .iter()
532 .filter(|(k, _)| after_start(k) && before_end(k))
533 .map(|(k, v)| (k.clone(), v.clone()))
534 .collect();
535 matched.sort_by(|a, b| a.0.cmp(&b.0));
536 if let Some(limit) = limit {
537 matched.truncate(limit);
538 }
539 for (k, b) in matched {
540 visit(EncodedKey::new(k), from_bytes(&b).expect("decode"))?;
541 }
542 Ok(())
543 }
544 fn get_or_create_row_number(&mut self, key: &EncodedKey) -> Result<(RowNumber, bool)> {
545 if let Some(rn) = self.rows.get(key.as_bytes()) {
546 return Ok((RowNumber(*rn), false));
547 }
548 self.next_row += 1;
549 self.rows.insert(key.as_bytes().to_vec(), self.next_row);
550 Ok((RowNumber(self.next_row), true))
551 }
552 fn get_or_create_row_numbers(&mut self, keys: &[EncodedKey]) -> Result<Vec<(RowNumber, bool)>> {
553 keys.iter().map(|k| self.get_or_create_row_number(k)).collect()
554 }
555 fn drop_row_number(&mut self, key: &EncodedKey) -> Result<()> {
556 self.rows.remove(key.as_bytes());
557 Ok(())
558 }
559 fn allocate_row_numbers(&mut self, count: u64) -> Result<RowNumber> {
560 let start = self.next_row + 1;
561 self.next_row += count;
562 Ok(RowNumber(start))
563 }
564 fn clock_now_nanos(&self) -> u64 {
565 0
566 }
567 }
568
569 #[derive(Clone, Debug, Default, Serialize, Deserialize)]
570 pub(crate) struct SumAccumulator {
571 pub sum: i64,
572 pub count: u64,
573 }
574
575 impl WindowAccumulator for SumAccumulator {
576 type Contribution = i64;
577 type Output = i64;
578
579 fn add(&mut self, contribution: &i64) {
580 self.sum += *contribution;
581 self.count += 1;
582 }
583 fn remove(&mut self, contribution: &i64) {
584 self.sum -= *contribution;
585 self.count = self.count.saturating_sub(1);
586 }
587 fn finalize(&self) -> Option<i64> {
588 if self.count == 0 {
589 None
590 } else {
591 Some(self.sum)
592 }
593 }
594 fn is_empty(&self) -> bool {
595 self.count == 0
596 }
597 fn merge(&mut self, other: &Self) {
598 self.sum += other.sum;
599 self.count += other.count;
600 }
601 fn unmerge(&mut self, other: &Self) {
602 self.sum -= other.sum;
603 self.count = self.count.saturating_sub(other.count);
604 }
605 }
606
607 #[derive(Clone, Debug, Default, Serialize, Deserialize)]
608 pub(crate) struct StampedSum {
609 pub sum: i64,
610 pub count: u64,
611 pub stamp: Option<u64>,
612 }
613
614 impl WindowAccumulator for StampedSum {
615 type Contribution = (i64, u64);
616 type Output = i64;
617
618 fn add(&mut self, contribution: &(i64, u64)) {
619 self.sum += contribution.0;
620 self.count += 1;
621 self.stamp = Some(self.stamp.map_or(contribution.1, |s| s.max(contribution.1)));
622 }
623 fn remove(&mut self, contribution: &(i64, u64)) {
624 self.sum -= contribution.0;
625 self.count = self.count.saturating_sub(1);
626 }
627 fn finalize(&self) -> Option<i64> {
628 if self.count == 0 {
629 None
630 } else {
631 Some(self.sum)
632 }
633 }
634 fn is_empty(&self) -> bool {
635 self.count == 0
636 }
637 fn stamp(&self) -> Option<u64> {
638 self.stamp
639 }
640 }
641}