1use std::{
5 collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque},
6 mem,
7 ops::Add,
8 sync::Arc,
9};
10
11use reifydb_codec::{key::encoded::EncodedKey, row::bytes::EncodedBytes};
12pub use reifydb_macro::HeapSize;
13use reifydb_value::{
14 byte_size::ByteSize,
15 count::Count,
16 util::hash::Hash128,
17 value::{
18 Value,
19 date::Date,
20 datetime::DateTime,
21 duration::Duration,
22 identity::IdentityId,
23 ordered_f32::OrderedF32,
24 ordered_f64::OrderedF64,
25 percentile::{Centroid, Percentiles},
26 row_number::RowNumber,
27 time::Time,
28 uuid::{Uuid4, Uuid7},
29 },
30};
31
32pub trait HeapSize {
33 fn heap_size(&self) -> usize;
34}
35
36#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
37pub struct StateMemory {
38 pub entries: Count,
39 pub bytes: ByteSize,
40}
41
42impl StateMemory {
43 pub const ZERO: Self = Self {
44 entries: Count::ZERO,
45 bytes: ByteSize::ZERO,
46 };
47
48 pub fn new(entries: Count, bytes: ByteSize) -> Self {
49 Self {
50 entries,
51 bytes,
52 }
53 }
54}
55
56impl Add for StateMemory {
57 type Output = Self;
58
59 fn add(self, rhs: Self) -> Self {
60 Self {
61 entries: self.entries + rhs.entries,
62 bytes: self.bytes + rhs.bytes,
63 }
64 }
65}
66
67#[derive(Clone, Copy, Debug, PartialEq, Eq)]
68pub struct StateCompleteness {
69 pub values_complete: bool,
70 pub membership_complete: bool,
71 pub absences_served: Count,
72 pub false_positives: Count,
73 pub revocations: Count,
74}
75
76impl StateCompleteness {
77 pub const MERGE_IDENTITY: Self = Self {
78 values_complete: true,
79 membership_complete: true,
80 absences_served: Count::ZERO,
81 false_positives: Count::ZERO,
82 revocations: Count::ZERO,
83 };
84
85 pub fn merge(self, rhs: Self) -> Self {
86 Self {
87 values_complete: self.values_complete && rhs.values_complete,
88 membership_complete: self.membership_complete && rhs.membership_complete,
89 absences_served: self.absences_served + rhs.absences_served,
90 false_positives: self.false_positives + rhs.false_positives,
91 revocations: self.revocations + rhs.revocations,
92 }
93 }
94}
95
96#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
97pub struct OperatorSample {
98 pub memory: Option<StateMemory>,
99 pub row_number_cache: Option<StateMemory>,
100}
101
102impl OperatorSample {
103 pub fn with_memory(memory: StateMemory) -> Self {
104 Self {
105 memory: Some(memory),
106 ..Self::default()
107 }
108 }
109
110 pub fn with_row_number_cache(mut self, memory: StateMemory) -> Self {
111 self.row_number_cache = Some(memory);
112 self
113 }
114}
115
116macro_rules! zero_heap {
117 ($($ty:ty),* $(,)?) => {
118 $(impl HeapSize for $ty {
119 fn heap_size(&self) -> usize {
120 0
121 }
122 })*
123 };
124}
125
126zero_heap!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64, bool, char, ());
127zero_heap!(
128 OrderedF32, OrderedF64, Date, DateTime, Time, Duration, IdentityId, Uuid4, Uuid7, RowNumber, Hash128, Centroid
129);
130
131const BIGNUM_APPROX_HEAP: usize = 32;
132const BTREE_NODE_FILL_DIVISOR: usize = 2;
133
134impl HeapSize for Percentiles {
135 fn heap_size(&self) -> usize {
136 mem::size_of_val(self.centroids())
137 }
138}
139
140impl HeapSize for String {
141 fn heap_size(&self) -> usize {
142 self.capacity()
143 }
144}
145
146impl HeapSize for EncodedBytes {
147 fn heap_size(&self) -> usize {
148 self.as_slice().len()
149 }
150}
151
152impl HeapSize for EncodedKey {
153 fn heap_size(&self) -> usize {
154 match self {
155 EncodedKey::Inline {
156 ..
157 } => 0,
158 EncodedKey::Shared(bytes) => bytes.len() + 2 * mem::size_of::<usize>(),
159 }
160 }
161}
162
163impl<T: HeapSize> HeapSize for Option<T> {
164 fn heap_size(&self) -> usize {
165 self.as_ref().map_or(0, HeapSize::heap_size)
166 }
167}
168
169impl<T: HeapSize> HeapSize for Vec<T> {
170 fn heap_size(&self) -> usize {
171 self.capacity() * mem::size_of::<T>() + self.iter().map(HeapSize::heap_size).sum::<usize>()
172 }
173}
174
175impl<T: HeapSize, const N: usize> HeapSize for [T; N] {
176 fn heap_size(&self) -> usize {
177 self.iter().map(HeapSize::heap_size).sum::<usize>()
178 }
179}
180
181impl<T: HeapSize> HeapSize for VecDeque<T> {
182 fn heap_size(&self) -> usize {
183 self.capacity() * mem::size_of::<T>() + self.iter().map(HeapSize::heap_size).sum::<usize>()
184 }
185}
186
187impl<T: HeapSize> HeapSize for Box<T> {
188 fn heap_size(&self) -> usize {
189 mem::size_of::<T>() + (**self).heap_size()
190 }
191}
192
193impl<T: HeapSize> HeapSize for Arc<T> {
194 fn heap_size(&self) -> usize {
195 mem::size_of::<usize>() * 2 + mem::size_of::<T>() + (**self).heap_size()
196 }
197}
198
199impl HeapSize for Arc<str> {
200 fn heap_size(&self) -> usize {
201 mem::size_of::<usize>() * 2 + self.len()
202 }
203}
204
205impl<T: HeapSize> HeapSize for Arc<[T]> {
206 fn heap_size(&self) -> usize {
207 mem::size_of::<usize>() * 2
208 + self.len() * mem::size_of::<T>()
209 + self.iter().map(HeapSize::heap_size).sum::<usize>()
210 }
211}
212
213impl<T: HeapSize> HeapSize for Box<[T]> {
214 fn heap_size(&self) -> usize {
215 self.len() * mem::size_of::<T>() + self.iter().map(HeapSize::heap_size).sum::<usize>()
216 }
217}
218
219impl HeapSize for Box<str> {
220 fn heap_size(&self) -> usize {
221 self.len()
222 }
223}
224
225impl<K: HeapSize, V: HeapSize> HeapSize for BTreeMap<K, V> {
226 fn heap_size(&self) -> usize {
227 self.len() * BTREE_NODE_FILL_DIVISOR * (mem::size_of::<K>() + mem::size_of::<V>())
228 + self.iter().map(|(k, v)| k.heap_size() + v.heap_size()).sum::<usize>()
229 }
230}
231
232impl<T: HeapSize> HeapSize for BTreeSet<T> {
233 fn heap_size(&self) -> usize {
234 self.len() * BTREE_NODE_FILL_DIVISOR * mem::size_of::<T>()
235 + self.iter().map(HeapSize::heap_size).sum::<usize>()
236 }
237}
238
239impl<K: HeapSize, V: HeapSize, S> HeapSize for HashMap<K, V, S> {
240 fn heap_size(&self) -> usize {
241 self.capacity() * (mem::size_of::<K>() + mem::size_of::<V>() + 1)
242 + self.iter().map(|(k, v)| k.heap_size() + v.heap_size()).sum::<usize>()
243 }
244}
245
246impl<T: HeapSize, S> HeapSize for HashSet<T, S> {
247 fn heap_size(&self) -> usize {
248 self.capacity() * (mem::size_of::<T>() + 1) + self.iter().map(HeapSize::heap_size).sum::<usize>()
249 }
250}
251
252impl<A: HeapSize, B: HeapSize> HeapSize for (A, B) {
253 fn heap_size(&self) -> usize {
254 self.0.heap_size() + self.1.heap_size()
255 }
256}
257
258impl<A: HeapSize, B: HeapSize, C: HeapSize> HeapSize for (A, B, C) {
259 fn heap_size(&self) -> usize {
260 self.0.heap_size() + self.1.heap_size() + self.2.heap_size()
261 }
262}
263
264impl HeapSize for Value {
265 fn heap_size(&self) -> usize {
266 match self {
267 Value::Utf8(text) => text.capacity(),
268 Value::Blob(blob) => blob.as_bytes().len(),
269 Value::Int(_) | Value::Uint(_) | Value::Decimal(_) => BIGNUM_APPROX_HEAP,
270 Value::Any(inner) => mem::size_of::<Value>() + inner.heap_size(),
271 Value::List(items) | Value::Tuple(items) => items.heap_size(),
272 Value::Record(fields) => {
273 fields.capacity() * mem::size_of::<(String, Value)>()
274 + fields.iter()
275 .map(|(name, value)| name.capacity() + value.heap_size())
276 .sum::<usize>()
277 }
278 _ => 0,
279 }
280 }
281}
282
283#[cfg(test)]
284mod tests {
285 use super::HeapSize;
286
287 #[derive(HeapSize)]
288 struct DerivedSample {
289 name: String,
290 values: Vec<u64>,
291 count: u64,
292 }
293
294 #[test]
295 fn derived_heap_size_sums_all_fields() {
296 let sample = DerivedSample {
299 name: String::with_capacity(32),
300 values: Vec::with_capacity(4),
301 count: 7,
302 };
303 assert_eq!(sample.count, 7);
304 assert_eq!(sample.heap_size(), 32 + 4 * 8);
305 }
306}