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