risingwave_stream/executor/over_window/
range_cache.rs1use std::collections::BTreeMap;
16use std::ops::{Bound, RangeInclusive};
17
18use risingwave_common::config::streaming::OverWindowCachePolicy as CachePolicy;
19use risingwave_common::row::OwnedRow;
20use risingwave_common::types::Sentinelled;
21use risingwave_common_estimate_size::EstimateSize;
22use risingwave_common_estimate_size::collections::EstimatedBTreeMap;
23use risingwave_expr::window_function::StateKey;
24use static_assertions::const_assert;
25
26pub(super) type CacheKey = Sentinelled<StateKey>;
27
28#[derive(Clone, Debug, Default)]
40pub(super) struct PartitionCache {
41 inner: EstimatedBTreeMap<CacheKey, OwnedRow>,
42}
43
44impl PartitionCache {
45 pub fn new_without_sentinels() -> Self {
47 Self {
48 inner: EstimatedBTreeMap::new(),
49 }
50 }
51
52 pub fn new() -> Self {
54 let mut cache = Self {
55 inner: EstimatedBTreeMap::new(),
56 };
57 cache.insert(CacheKey::Smallest, OwnedRow::empty());
58 cache.insert(CacheKey::Largest, OwnedRow::empty());
59 cache
60 }
61
62 pub fn inner(&self) -> &BTreeMap<CacheKey, OwnedRow> {
64 self.inner.inner()
65 }
66
67 pub fn insert(&mut self, key: CacheKey, value: OwnedRow) -> Option<OwnedRow> {
69 self.inner.insert(key, value)
70 }
71
72 pub fn remove(&mut self, key: &CacheKey) -> Option<OwnedRow> {
74 self.inner.remove(key)
75 }
76
77 pub fn len(&self) -> usize {
79 self.inner.len()
80 }
81
82 pub fn is_empty(&self) -> bool {
84 self.inner.is_empty()
85 }
86
87 pub fn first_key_value(&self) -> Option<(&CacheKey, &OwnedRow)> {
89 self.inner.first_key_value()
90 }
91
92 pub fn last_key_value(&self) -> Option<(&CacheKey, &OwnedRow)> {
94 self.inner.last_key_value()
95 }
96
97 fn retain_range(
101 &mut self,
102 range: RangeInclusive<&CacheKey>,
103 ) -> (BTreeMap<CacheKey, OwnedRow>, BTreeMap<CacheKey, OwnedRow>) {
104 let had_smallest = self.inner.inner().contains_key(&CacheKey::Smallest);
106 let had_largest = self.inner.inner().contains_key(&CacheKey::Largest);
107
108 let (left_removed, right_removed) = self.inner.retain_range(range);
109
110 if had_smallest {
112 self.inner.insert(CacheKey::Smallest, OwnedRow::empty());
113 }
114 if had_largest {
115 self.inner.insert(CacheKey::Largest, OwnedRow::empty());
116 }
117
118 let left_removed = left_removed
120 .into_iter()
121 .filter(|(k, _)| k.is_normal())
122 .collect();
123 let right_removed = right_removed
124 .into_iter()
125 .filter(|(k, _)| k.is_normal())
126 .collect();
127
128 (left_removed, right_removed)
129 }
130
131 pub fn normal_len(&self) -> usize {
133 let len = self.inner().len();
134 if len <= 1 {
135 debug_assert!(
136 self.inner()
137 .first_key_value()
138 .map(|(k, _)| k.is_normal())
139 .unwrap_or(true)
140 );
141 return len;
142 }
143 let cache_inner = self.inner();
145 let sentinels = [
146 cache_inner.first_key_value().unwrap().0.is_sentinel(),
148 cache_inner.last_key_value().unwrap().0.is_sentinel(),
149 ];
150 len - sentinels.into_iter().filter(|x| *x).count()
151 }
152
153 pub fn first_normal_key(&self) -> Option<&StateKey> {
155 self.inner()
156 .iter()
157 .find(|(k, _)| k.is_normal())
158 .map(|(k, _)| k.as_normal_expect())
159 }
160
161 pub fn last_normal_key(&self) -> Option<&StateKey> {
163 self.inner()
164 .iter()
165 .rev()
166 .find(|(k, _)| k.is_normal())
167 .map(|(k, _)| k.as_normal_expect())
168 }
169
170 pub fn left_is_sentinel(&self) -> bool {
172 self.first_key_value()
173 .map(|(k, _)| k.is_sentinel())
174 .unwrap_or(false)
175 }
176
177 pub fn right_is_sentinel(&self) -> bool {
179 self.last_key_value()
180 .map(|(k, _)| k.is_sentinel())
181 .unwrap_or(false)
182 }
183
184 pub fn shrink(
186 &mut self,
187 deduped_part_key: &OwnedRow,
188 cache_policy: CachePolicy,
189 recently_accessed_range: RangeInclusive<StateKey>,
190 ) {
191 const MAGIC_CACHE_SIZE: usize = 1024;
192 const MAGIC_JITTER_PREVENTION: usize = MAGIC_CACHE_SIZE / 8;
193
194 if self.is_empty() {
197 return;
198 }
199
200 tracing::trace!(
201 partition=?deduped_part_key,
202 cache_policy=?cache_policy,
203 recently_accessed_range=?recently_accessed_range,
204 "find the range to retain in the range cache"
205 );
206
207 let (start, end) = match cache_policy {
208 CachePolicy::Full => {
209 return;
211 }
212 CachePolicy::Recent => {
213 let (sk_start, sk_end) = recently_accessed_range.into_inner();
214 let (ck_start, ck_end) = (CacheKey::from(sk_start), CacheKey::from(sk_end));
215
216 let mut cursor = self.inner().upper_bound(Bound::Excluded(&ck_start));
218 for _ in 0..MAGIC_JITTER_PREVENTION {
219 if cursor.prev().is_none() {
220 break;
222 }
223 }
224 let start = cursor
225 .peek_prev()
226 .map(|(k, _)| k)
227 .unwrap_or_else(|| self.first_key_value().unwrap().0)
228 .clone();
229
230 let mut cursor = self.inner().lower_bound(Bound::Excluded(&ck_end));
232 for _ in 0..MAGIC_JITTER_PREVENTION {
233 if cursor.next().is_none() {
234 break;
236 }
237 }
238 let end = cursor
239 .peek_next()
240 .map(|(k, _)| k)
241 .unwrap_or_else(|| self.last_key_value().unwrap().0)
242 .clone();
243
244 (start, end)
245 }
246 CachePolicy::RecentFirstN => {
247 if self.len() <= MAGIC_CACHE_SIZE {
248 return;
250 } else {
251 let (sk_start, _sk_end) = recently_accessed_range.into_inner();
252 let ck_start = CacheKey::from(sk_start);
253
254 let mut capacity_remain = MAGIC_CACHE_SIZE; const_assert!(MAGIC_JITTER_PREVENTION < MAGIC_CACHE_SIZE);
256
257 let cursor_just_before_ck_start =
259 self.inner().upper_bound(Bound::Excluded(&ck_start));
260
261 let mut cursor = cursor_just_before_ck_start.clone();
262 for _ in 0..MAGIC_JITTER_PREVENTION {
264 if cursor.prev().is_none() {
265 break;
267 }
268 capacity_remain -= 1;
269 }
270 let start = cursor
271 .peek_prev()
272 .map(|(k, _)| k)
273 .unwrap_or_else(|| self.first_key_value().unwrap().0)
274 .clone();
275
276 let mut cursor = cursor_just_before_ck_start;
277 for _ in 0..capacity_remain {
279 if cursor.next().is_none() {
280 break;
282 }
283 }
284 let end = cursor
285 .peek_next()
286 .map(|(k, _)| k)
287 .unwrap_or_else(|| self.last_key_value().unwrap().0)
288 .clone();
289
290 (start, end)
291 }
292 }
293 CachePolicy::RecentLastN => {
294 if self.len() <= MAGIC_CACHE_SIZE {
295 return;
297 } else {
298 let (_sk_start, sk_end) = recently_accessed_range.into_inner();
299 let ck_end = CacheKey::from(sk_end);
300
301 let mut capacity_remain = MAGIC_CACHE_SIZE; const_assert!(MAGIC_JITTER_PREVENTION < MAGIC_CACHE_SIZE);
303
304 let cursor_just_after_ck_end =
306 self.inner().lower_bound(Bound::Excluded(&ck_end));
307
308 let mut cursor = cursor_just_after_ck_end.clone();
309 for _ in 0..MAGIC_JITTER_PREVENTION {
311 if cursor.next().is_none() {
312 break;
314 }
315 capacity_remain -= 1;
316 }
317 let end = cursor
318 .peek_next()
319 .map(|(k, _)| k)
320 .unwrap_or_else(|| self.last_key_value().unwrap().0)
321 .clone();
322
323 let mut cursor = cursor_just_after_ck_end;
324 for _ in 0..capacity_remain {
326 if cursor.prev().is_none() {
327 break;
329 }
330 }
331 let start = cursor
332 .peek_prev()
333 .map(|(k, _)| k)
334 .unwrap_or_else(|| self.first_key_value().unwrap().0)
335 .clone();
336
337 (start, end)
338 }
339 }
340 };
341
342 tracing::trace!(
343 partition=?deduped_part_key,
344 retain_range=?(&start..=&end),
345 "retain range in the range cache"
346 );
347
348 let (left_removed, right_removed) = self.retain_range(&start..=&end);
349 if self.is_empty() {
350 if !left_removed.is_empty() || !right_removed.is_empty() {
351 self.insert(CacheKey::Smallest, OwnedRow::empty());
352 self.insert(CacheKey::Largest, OwnedRow::empty());
353 }
354 } else {
355 if !left_removed.is_empty() {
356 self.insert(CacheKey::Smallest, OwnedRow::empty());
357 }
358 if !right_removed.is_empty() {
359 self.insert(CacheKey::Largest, OwnedRow::empty());
360 }
361 }
362 }
363}
364
365impl EstimateSize for PartitionCache {
366 fn estimated_heap_size(&self) -> usize {
367 self.inner.estimated_heap_size()
368 }
369}
370
371#[cfg(test)]
372mod tests {
373 use risingwave_common::row::OwnedRow;
374 use risingwave_common::types::{DefaultOrdered, ScalarImpl};
375 use risingwave_common::util::memcmp_encoding::encode_value;
376 use risingwave_common::util::sort_util::OrderType;
377 use risingwave_expr::window_function::StateKey;
378
379 use super::*;
380
381 fn create_test_state_key(value: i32) -> StateKey {
382 let row = OwnedRow::new(vec![Some(ScalarImpl::Int32(value))]);
383 StateKey {
384 order_key: encode_value(Some(ScalarImpl::Int32(value)), OrderType::ascending())
385 .unwrap(),
386 pk: DefaultOrdered::new(row),
387 }
388 }
389
390 fn create_test_cache_key(value: i32) -> CacheKey {
391 CacheKey::from(create_test_state_key(value))
392 }
393
394 fn create_test_row(value: i32) -> OwnedRow {
395 OwnedRow::new(vec![Some(ScalarImpl::Int32(value))])
396 }
397
398 #[test]
399 fn test_partition_cache_new() {
400 let cache = PartitionCache::new_without_sentinels();
401 assert!(cache.is_empty());
402 assert_eq!(cache.len(), 0);
403 }
404
405 #[test]
406 fn test_partition_cache_new_with_sentinels() {
407 let cache = PartitionCache::new();
408 assert!(!cache.is_empty());
409 assert_eq!(cache.len(), 2);
410
411 let first = cache.first_key_value().unwrap();
413 let last = cache.last_key_value().unwrap();
414
415 assert_eq!(*first.0, CacheKey::Smallest);
416 assert_eq!(*last.0, CacheKey::Largest);
417 }
418
419 #[test]
420 fn test_partition_cache_insert_and_remove() {
421 let mut cache = PartitionCache::new_without_sentinels();
422 let key = create_test_cache_key(1);
423 let value = create_test_row(100);
424
425 assert!(cache.insert(key.clone(), value.clone()).is_none());
427 assert_eq!(cache.len(), 1);
428 assert!(!cache.is_empty());
429
430 let removed = cache.remove(&key);
432 assert!(removed.is_some());
433 assert_eq!(removed.unwrap(), value);
434 assert!(cache.is_empty());
435 assert_eq!(cache.len(), 0);
436 }
437
438 #[test]
439 fn test_partition_cache_first_last_key_value() {
440 let mut cache = PartitionCache::new_without_sentinels();
441
442 assert!(cache.first_key_value().is_none());
444 assert!(cache.last_key_value().is_none());
445
446 cache.insert(create_test_cache_key(2), create_test_row(200));
448 cache.insert(create_test_cache_key(1), create_test_row(100));
449 cache.insert(create_test_cache_key(3), create_test_row(300));
450
451 let first = cache.first_key_value().unwrap();
452 let last = cache.last_key_value().unwrap();
453
454 assert_eq!(*first.0, create_test_cache_key(1));
456 assert_eq!(*first.1, create_test_row(100));
457
458 assert_eq!(*last.0, create_test_cache_key(3));
459 assert_eq!(*last.1, create_test_row(300));
460 }
461
462 #[test]
463 fn test_partition_cache_retain_range() {
464 let mut cache = PartitionCache::new();
465
466 for i in 1..=5 {
468 cache.insert(create_test_cache_key(i), create_test_row(i * 100));
469 }
470
471 assert_eq!(cache.len(), 7); let start = create_test_cache_key(2);
475 let end = create_test_cache_key(4);
476 let (left_removed, right_removed) = cache.retain_range(&start..=&end);
477
478 assert_eq!(left_removed.len(), 1);
480 assert_eq!(right_removed.len(), 1);
481 assert!(left_removed.contains_key(&create_test_cache_key(1)));
482 assert!(right_removed.contains_key(&create_test_cache_key(5)));
483
484 assert_eq!(cache.len(), 5);
486 for i in 2..=4 {
487 let key = create_test_cache_key(i);
488 assert!(cache.inner.iter().any(|(k, _)| *k == key));
489 }
490 }
491
492 #[test]
493 fn test_partition_cache_shrink_full_policy() {
494 let mut cache = PartitionCache::new();
495
496 for i in 1..=10 {
498 cache.insert(create_test_cache_key(i), create_test_row(i * 100));
499 }
500
501 let initial_len = cache.len();
502 let deduped_part_key = OwnedRow::empty();
503 let recently_accessed_range = create_test_state_key(3)..=create_test_state_key(7);
504
505 cache.shrink(
507 &deduped_part_key,
508 CachePolicy::Full,
509 recently_accessed_range,
510 );
511
512 assert_eq!(cache.len(), initial_len);
513 }
514
515 #[test]
516 fn test_partition_cache_shrink_recent_policy() {
517 let mut cache = PartitionCache::new();
518
519 for i in 1..=10 {
521 cache.insert(create_test_cache_key(i), create_test_row(i * 100));
522 }
523
524 let deduped_part_key = OwnedRow::empty();
525 let recently_accessed_range = create_test_state_key(4)..=create_test_state_key(6);
526
527 cache.shrink(
529 &deduped_part_key,
530 CachePolicy::Recent,
531 recently_accessed_range,
532 );
533
534 let remaining_keys: Vec<_> = cache
536 .inner
537 .iter()
538 .filter_map(|(k, _)| match k {
539 CacheKey::Normal(state_key) => Some(state_key),
540 _ => None,
541 })
542 .collect();
543
544 for i in 4..=6 {
546 let target_key = create_test_state_key(i);
547 assert!(
548 remaining_keys
549 .iter()
550 .any(|k| k.order_key == target_key.order_key)
551 );
552 }
553 }
554
555 #[test]
556 fn test_partition_cache_shrink_with_small_cache() {
557 let mut cache = PartitionCache::new();
558
559 for i in 1..=5 {
561 cache.insert(create_test_cache_key(i), create_test_row(i * 100));
562 }
563
564 let initial_len = cache.len();
565 let deduped_part_key = OwnedRow::empty();
566 let recently_accessed_range = create_test_state_key(2)..=create_test_state_key(4);
567
568 cache.shrink(
570 &deduped_part_key,
571 CachePolicy::RecentFirstN,
572 recently_accessed_range.clone(),
573 );
574 assert_eq!(cache.len(), initial_len);
575
576 cache.shrink(
577 &deduped_part_key,
578 CachePolicy::RecentLastN,
579 recently_accessed_range,
580 );
581 assert_eq!(cache.len(), initial_len);
582 }
583
584 #[test]
585 fn test_partition_cache_estimate_size() {
586 let cache = PartitionCache::new_without_sentinels();
587 let size_without_sentinels = cache.estimated_heap_size();
588
589 let mut cache = PartitionCache::new();
590 let size_with_sentinels = cache.estimated_heap_size();
591
592 assert!(size_with_sentinels >= size_without_sentinels);
594
595 cache.insert(create_test_cache_key(1), create_test_row(100));
596 let size_with_entry = cache.estimated_heap_size();
597
598 assert!(size_with_entry > size_with_sentinels);
599 }
600}