Skip to main content

re_query/
cache_stats.rs

1use std::collections::BTreeMap;
2
3use re_byte_size::SizeBytes as _;
4
5use crate::{QueryCache, QueryCacheKey};
6
7// ---
8
9/// Stats for all primary caches.
10///
11/// Fetch them via [`QueryCache::stats`].
12#[derive(Default, Debug, Clone)]
13pub struct QueryCachesStats {
14    pub latest_at: BTreeMap<QueryCacheKey, QueryCacheStats>,
15    pub range: BTreeMap<QueryCacheKey, QueryCacheStats>,
16}
17
18impl QueryCachesStats {
19    #[inline]
20    pub fn total_size_bytes(&self) -> u64 {
21        re_tracing::profile_function!();
22
23        let Self { latest_at, range } = self;
24
25        let latest_at_size_bytes: u64 = latest_at
26            .values()
27            .map(|stats| stats.total_actual_size_bytes)
28            .sum();
29        let range_size_bytes: u64 = range
30            .values()
31            .map(|stats| stats.total_actual_size_bytes)
32            .sum();
33
34        latest_at_size_bytes + range_size_bytes
35    }
36}
37
38/// Stats for a single `crate::RangeCache`.
39#[derive(Default, Debug, Clone)]
40pub struct QueryCacheStats {
41    /// How many chunks in the cache?
42    pub total_chunks: u64,
43
44    /// What would be the size of this cache in the worst case, i.e. if all chunks had
45    /// been fully copied?
46    pub total_effective_size_bytes: u64,
47
48    /// What is the actual size of this cache after deduplication?
49    pub total_actual_size_bytes: u64,
50}
51
52impl QueryCache {
53    /// Computes the stats for all primary caches.
54    pub fn stats(&self) -> QueryCachesStats {
55        re_tracing::profile_function!();
56
57        let latest_at = {
58            let latest_at = self.latest_at_per_cache_key.read().clone();
59            // Implicitly releasing top-level cache mappings -- concurrent queries can run once again.
60
61            latest_at
62                .iter()
63                .map(|(key, cache)| {
64                    let cache = cache.read();
65                    (
66                        key.clone(),
67                        QueryCacheStats {
68                            total_chunks: cache.per_query_time.len() as _,
69                            total_effective_size_bytes: cache
70                                .per_query_time
71                                .values()
72                                .map(|cached| cached.unit.total_size_bytes())
73                                .sum(),
74                            total_actual_size_bytes: cache.per_query_time.total_size_bytes(),
75                        },
76                    )
77                })
78                .collect()
79        };
80
81        let range = {
82            let range = self.range_per_cache_key.read().clone();
83            // Implicitly releasing top-level cache mappings -- concurrent queries can run once again.
84
85            range
86                .iter()
87                .map(|(key, cache)| {
88                    let cache = cache.read();
89
90                    (
91                        key.clone(),
92                        QueryCacheStats {
93                            total_chunks: cache.chunks.len() as _,
94                            total_effective_size_bytes: cache
95                                .chunks
96                                .values()
97                                .map(|cached| cached.chunk.total_size_bytes())
98                                .sum(),
99                            total_actual_size_bytes: cache.chunks.total_size_bytes(),
100                        },
101                    )
102                })
103                .collect()
104        };
105
106        QueryCachesStats { latest_at, range }
107    }
108}