1use std::fmt::{Display, Formatter};
2use std::sync::Arc;
3
4use super::utils::{copy_to_builder, pick_merge_destination};
5use crate::storage::buffer_cache::CacheStats;
6use crate::storage::file::{FilterKind, FilterStats, TouchedWindowCount};
7use crate::trace::cursor::{DelegatingCursor, PushCursor};
8use crate::trace::ord::file::val_batch::FileValBuilder;
9use crate::trace::ord::vec::val_batch::VecValBuilder;
10use crate::trace::{BatchLocation, GroupFilter, MergeCursor};
11use crate::{
12 DBData, DBWeight, NumEntries, Timestamp,
13 dynamic::{
14 DataTrait, DynDataTyped, DynPair, DynVec, DynWeightedPairs, Erase, Factory, WeightTrait,
15 },
16 storage::file::reader::Error as ReaderError,
17 trace::{
18 Batch, BatchFactories, BatchReader, BatchReaderFactories, Builder, FileValBatch,
19 FileValBatchFactories, Filter, VecValBatch, VecValBatchFactories, WeightedItem,
20 ord::merge_batcher::MergeBatcher,
21 },
22};
23use derive_more::Debug;
24use feldera_storage::{FileReader, StoragePath};
25use rand::Rng;
26use rkyv::{Archive, Archived, Deserialize, Fallible, Serialize, ser::Serializer};
27use size_of::SizeOf;
28
29pub struct FallbackValBatchFactories<K, V, T, R>
30where
31 K: DataTrait + ?Sized,
32 V: DataTrait + ?Sized,
33 T: Timestamp,
34 R: WeightTrait + ?Sized,
35{
36 file: FileValBatchFactories<K, V, T, R>,
37 vec: VecValBatchFactories<K, V, T, R>,
38}
39
40impl<K, V, T, R> Clone for FallbackValBatchFactories<K, V, T, R>
41where
42 K: DataTrait + ?Sized,
43 V: DataTrait + ?Sized,
44 T: Timestamp,
45 R: WeightTrait + ?Sized,
46{
47 fn clone(&self) -> Self {
48 Self {
49 file: self.file.clone(),
50 vec: self.vec.clone(),
51 }
52 }
53}
54
55impl<K, V, T, R> BatchReaderFactories<K, V, T, R> for FallbackValBatchFactories<K, V, T, R>
56where
57 K: DataTrait + ?Sized,
58 V: DataTrait + ?Sized,
59 T: Timestamp,
60 R: WeightTrait + ?Sized,
61{
62 fn new<KType, VType, RType>() -> Self
63 where
64 KType: DBData + Erase<K>,
65 VType: DBData + Erase<V>,
66 RType: DBWeight + Erase<R>,
67 {
68 Self {
69 file: FileValBatchFactories::new::<KType, VType, RType>(),
70 vec: VecValBatchFactories::new::<KType, VType, RType>(),
71 }
72 }
73
74 fn key_factory(&self) -> &'static dyn Factory<K> {
75 self.file.key_factory()
76 }
77
78 fn keys_factory(&self) -> &'static dyn Factory<DynVec<K>> {
79 self.file.keys_factory()
80 }
81
82 fn val_factory(&self) -> &'static dyn Factory<V> {
83 self.file.val_factory()
84 }
85
86 fn weight_factory(&self) -> &'static dyn Factory<R> {
87 self.file.weight_factory()
88 }
89}
90
91impl<K, V, T, R> BatchFactories<K, V, T, R> for FallbackValBatchFactories<K, V, T, R>
92where
93 K: DataTrait + ?Sized,
94 V: DataTrait + ?Sized,
95 T: Timestamp,
96 R: WeightTrait + ?Sized,
97{
98 fn item_factory(&self) -> &'static dyn Factory<DynPair<K, V>> {
99 self.file.item_factory()
100 }
101
102 fn weighted_item_factory(&self) -> &'static dyn Factory<WeightedItem<K, V, R>> {
103 self.file.weighted_item_factory()
104 }
105
106 fn weighted_items_factory(&self) -> &'static dyn Factory<DynWeightedPairs<DynPair<K, V>, R>> {
107 self.file.weighted_items_factory()
108 }
109
110 fn weighted_vals_factory(&self) -> &'static dyn Factory<DynWeightedPairs<V, R>> {
111 self.file.weighted_vals_factory()
112 }
113
114 fn time_diffs_factory(
115 &self,
116 ) -> Option<&'static dyn Factory<DynWeightedPairs<DynDataTyped<T>, R>>> {
117 self.file.time_diffs_factory()
118 }
119}
120
121#[derive(Debug, SizeOf)]
124pub struct FallbackValBatch<K, V, T, R>
125where
126 K: DataTrait + ?Sized,
127 V: DataTrait + ?Sized,
128 T: Timestamp,
129 R: WeightTrait + ?Sized,
130{
131 #[size_of(skip)]
132 #[debug(skip)]
133 factories: FallbackValBatchFactories<K, V, T, R>,
134 inner: Inner<K, V, T, R>,
135}
136
137#[derive(Debug, SizeOf)]
138enum Inner<K, V, T, R>
139where
140 K: DataTrait + ?Sized,
141 V: DataTrait + ?Sized,
142 T: Timestamp,
143 R: WeightTrait + ?Sized,
144{
145 Vec(VecValBatch<K, V, T, R>),
146 File(FileValBatch<K, V, T, R>),
147}
148
149impl<K, V, T, R> Clone for FallbackValBatch<K, V, T, R>
150where
151 K: DataTrait + ?Sized,
152 V: DataTrait + ?Sized,
153 T: Timestamp,
154 R: WeightTrait + ?Sized,
155{
156 fn clone(&self) -> Self {
157 Self {
158 factories: self.factories.clone(),
159 inner: match &self.inner {
160 Inner::Vec(vec) => Inner::Vec(vec.clone()),
161 Inner::File(file) => Inner::File(file.clone()),
162 },
163 }
164 }
165}
166
167impl<K, V, T, R> NumEntries for FallbackValBatch<K, V, T, R>
168where
169 K: DataTrait + ?Sized,
170 V: DataTrait + ?Sized,
171 T: Timestamp,
172 R: WeightTrait + ?Sized,
173{
174 const CONST_NUM_ENTRIES: Option<usize> = None;
175
176 #[inline]
177 fn num_entries_shallow(&self) -> usize {
178 match &self.inner {
179 Inner::Vec(vec) => vec.num_entries_shallow(),
180 Inner::File(file) => file.num_entries_shallow(),
181 }
182 }
183
184 #[inline]
185 fn num_entries_deep(&self) -> usize {
186 match &self.inner {
187 Inner::Vec(vec) => vec.num_entries_deep(),
188 Inner::File(file) => file.num_entries_deep(),
189 }
190 }
191}
192
193impl<K, V, T, R> Display for FallbackValBatch<K, V, T, R>
194where
195 K: DataTrait + ?Sized,
196 V: DataTrait + ?Sized,
197 T: Timestamp,
198 R: WeightTrait + ?Sized,
199{
200 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
201 match &self.inner {
202 Inner::Vec(vec) => Display::fmt(vec, f),
203 Inner::File(file) => Display::fmt(file, f),
204 }
205 }
206}
207
208impl<K, V, T, R> BatchReader for FallbackValBatch<K, V, T, R>
209where
210 K: DataTrait + ?Sized,
211 V: DataTrait + ?Sized,
212 T: Timestamp,
213 R: WeightTrait + ?Sized,
214{
215 type Factories = FallbackValBatchFactories<K, V, T, R>;
216 type Key = K;
217 type Val = V;
218 type Time = T;
219 type R = R;
220
221 type Cursor<'s> = DelegatingCursor<'s, K, V, T, R>;
222
223 fn factories(&self) -> Self::Factories {
224 self.factories.clone()
225 }
226
227 fn cursor(&self) -> Self::Cursor<'_> {
228 DelegatingCursor(match &self.inner {
229 Inner::Vec(vec) => Box::new(vec.cursor()),
230 Inner::File(file) => Box::new(file.cursor()),
231 })
232 }
233
234 fn push_cursor(
235 &self,
236 ) -> Box<dyn PushCursor<Self::Key, Self::Val, Self::Time, Self::R> + Send + '_> {
237 match &self.inner {
238 Inner::Vec(vec) => vec.push_cursor(),
239 Inner::File(file) => file.push_cursor(),
240 }
241 }
242
243 fn merge_cursor(
244 &self,
245 key_filter: Option<Filter<Self::Key>>,
246 value_filter: Option<GroupFilter<Self::Val>>,
247 ) -> Box<dyn MergeCursor<Self::Key, Self::Val, Self::Time, Self::R> + Send + '_> {
248 match &self.inner {
249 Inner::Vec(vec) => vec.merge_cursor(key_filter, value_filter),
250 Inner::File(file) => file.merge_cursor(key_filter, value_filter),
251 }
252 }
253
254 fn key_count(&self) -> usize {
255 match &self.inner {
256 Inner::Vec(vec) => vec.key_count(),
257 Inner::File(file) => file.key_count(),
258 }
259 }
260
261 fn len(&self) -> usize {
262 match &self.inner {
263 Inner::Vec(vec) => vec.len(),
264 Inner::File(file) => file.len(),
265 }
266 }
267
268 #[inline]
269 fn approximate_byte_size(&self) -> usize {
270 match &self.inner {
271 Inner::File(file) => file.approximate_byte_size(),
272 Inner::Vec(vec) => vec.approximate_byte_size(),
273 }
274 }
275
276 #[inline]
277 fn membership_filter_stats(&self) -> FilterStats {
278 match &self.inner {
279 Inner::File(file) => file.membership_filter_stats(),
280 Inner::Vec(vec) => vec.membership_filter_stats(),
281 }
282 }
283
284 #[inline]
285 fn membership_filter_kind(&self) -> FilterKind {
286 match &self.inner {
287 Inner::File(file) => file.membership_filter_kind(),
288 Inner::Vec(vec) => vec.membership_filter_kind(),
289 }
290 }
291
292 #[inline]
293 fn range_filter_stats(&self) -> FilterStats {
294 match &self.inner {
295 Inner::File(file) => file.range_filter_stats(),
296 Inner::Vec(vec) => vec.range_filter_stats(),
297 }
298 }
299
300 #[inline]
301 fn location(&self) -> BatchLocation {
302 match &self.inner {
303 Inner::Vec(vec) => vec.location(),
304 Inner::File(file) => file.location(),
305 }
306 }
307
308 fn cache_stats(&self) -> CacheStats {
309 match &self.inner {
310 Inner::Vec(vec) => vec.cache_stats(),
311 Inner::File(file) => file.cache_stats(),
312 }
313 }
314
315 fn sample_keys<RG>(&self, rng: &mut RG, sample_size: usize, output: &mut DynVec<Self::Key>)
316 where
317 RG: Rng,
318 {
319 match &self.inner {
320 Inner::Vec(vec) => vec.sample_keys(rng, sample_size, output),
321 Inner::File(file) => file.sample_keys(rng, sample_size, output),
322 }
323 }
324}
325
326impl<K, V, T, R> Batch for FallbackValBatch<K, V, T, R>
327where
328 K: DataTrait + ?Sized,
329 V: DataTrait + ?Sized,
330 T: Timestamp,
331 R: WeightTrait + ?Sized,
332{
333 type Timed<T2: Timestamp> = FallbackValBatch<K, V, T2, R>;
334 type Batcher = MergeBatcher<Self>;
335 type Builder = FallbackValBuilder<K, V, T, R>;
336
337 fn persisted(&self) -> Option<Self> {
338 match &self.inner {
339 Inner::Vec(vec) => {
340 let mut file = FileValBuilder::with_capacity(
341 &self.factories.file,
342 self.key_count(),
343 self.len(),
344 );
345 copy_to_builder(&mut file, vec.cursor());
346 Some(Self {
347 inner: Inner::File(file.done()),
348 factories: self.factories.clone(),
349 })
350 }
351 Inner::File(_) => None,
352 }
353 }
354
355 fn file_reader(&self) -> Option<Arc<dyn FileReader>> {
356 match &self.inner {
357 Inner::Vec(vec) => vec.file_reader(),
358 Inner::File(file) => file.file_reader(),
359 }
360 }
361
362 fn from_path(factories: &Self::Factories, path: &StoragePath) -> Result<Self, ReaderError> {
363 Ok(Self {
364 factories: factories.clone(),
365 inner: Inner::File(FileValBatch::<K, V, T, R>::from_path(
366 &factories.file,
367 path,
368 )?),
369 })
370 }
371
372 fn key_bounds(&self) -> Option<(&Self::Key, &Self::Key)> {
373 match &self.inner {
374 Inner::File(file) => file.key_bounds(),
375 Inner::Vec(vec) => vec.key_bounds(),
376 }
377 }
378
379 fn negative_weight_count(&self) -> Option<u64> {
380 match &self.inner {
381 Inner::File(file) => file.negative_weight_count(),
382 Inner::Vec(vec) => vec.negative_weight_count(),
383 }
384 }
385
386 fn touched_window_count(&self) -> TouchedWindowCount {
387 match &self.inner {
388 Inner::File(file) => file.touched_window_count(),
389 Inner::Vec(vec) => vec.touched_window_count(),
390 }
391 }
392}
393
394#[derive(SizeOf)]
396pub struct FallbackValBuilder<K, V, T, R>
397where
398 K: DataTrait + ?Sized,
399 V: DataTrait + ?Sized,
400 T: Timestamp,
401 R: WeightTrait + ?Sized,
402{
403 #[size_of(skip)]
404 factories: FallbackValBatchFactories<K, V, T, R>,
405 inner: BuilderInner<K, V, T, R>,
406}
407
408#[derive(SizeOf)]
409enum BuilderInner<K, V, T, R>
410where
411 K: DataTrait + ?Sized,
412 V: DataTrait + ?Sized,
413 T: Timestamp,
414 R: WeightTrait + ?Sized,
415{
416 Vec(VecValBuilder<K, V, T, R, usize>),
417 File(FileValBuilder<K, V, T, R>),
418}
419
420impl<K, V, T, R> Builder<FallbackValBatch<K, V, T, R>> for FallbackValBuilder<K, V, T, R>
421where
422 Self: SizeOf,
423 K: DataTrait + ?Sized,
424 V: DataTrait + ?Sized,
425 T: Timestamp,
426 R: WeightTrait + ?Sized,
427{
428 fn with_capacity_in_location(
429 factories: &FallbackValBatchFactories<K, V, T, R>,
430 key_capacity: usize,
431 value_capacity: usize,
432 location: Option<BatchLocation>,
433 ) -> Self {
434 Self {
435 factories: factories.clone(),
436 inner: BuilderInner::Vec(VecValBuilder::with_capacity_in_location(
437 &factories.vec,
438 key_capacity,
439 value_capacity,
440 location,
441 )),
442 }
443 }
444
445 fn for_merge<'a, B, I>(
446 factories: &FallbackValBatchFactories<K, V, T, R>,
447 batches: I,
448 location: Option<BatchLocation>,
449 ) -> Self
450 where
451 B: Batch<Key = K, Val = V, Time = T, R = R>,
452 I: IntoIterator<Item = &'a B> + Clone,
453 {
454 let key_capacity = batches.clone().into_iter().map(|b| b.key_count()).sum();
455 let value_capacity = batches.clone().into_iter().map(|b| b.len()).sum();
456 Self {
457 factories: factories.clone(),
458 inner: match pick_merge_destination(batches.clone(), location) {
459 BatchLocation::Memory => BuilderInner::Vec(VecValBuilder::with_capacity(
460 &factories.vec,
461 key_capacity,
462 value_capacity,
463 )),
464 BatchLocation::Storage => BuilderInner::File(FileValBuilder::for_merge(
465 &factories.file,
466 batches,
467 location,
468 )),
469 },
470 }
471 }
472
473 fn push_time_diff(&mut self, time: &T, weight: &R) {
474 match &mut self.inner {
475 BuilderInner::Vec(vec) => vec.push_time_diff(time, weight),
476 BuilderInner::File(file) => file.push_time_diff(time, weight),
477 }
478 }
479
480 fn push_val(&mut self, val: &V) {
481 match &mut self.inner {
482 BuilderInner::Vec(vec) => vec.push_val(val),
483 BuilderInner::File(file) => file.push_val(val),
484 }
485 }
486
487 fn push_key(&mut self, key: &K) {
488 match &mut self.inner {
489 BuilderInner::Vec(vec) => vec.push_key(key),
490 BuilderInner::File(file) => file.push_key(key),
491 }
492 }
493
494 fn push_time_diff_mut(&mut self, time: &mut T, weight: &mut R) {
495 match &mut self.inner {
496 BuilderInner::Vec(vec) => vec.push_time_diff_mut(time, weight),
497 BuilderInner::File(file) => file.push_time_diff_mut(time, weight),
498 }
499 }
500
501 fn push_val_mut(&mut self, val: &mut V) {
502 match &mut self.inner {
503 BuilderInner::Vec(vec) => vec.push_val_mut(val),
504 BuilderInner::File(file) => file.push_val_mut(val),
505 }
506 }
507
508 fn push_key_mut(&mut self, key: &mut K) {
509 match &mut self.inner {
510 BuilderInner::Vec(vec) => vec.push_key_mut(key),
511 BuilderInner::File(file) => file.push_key_mut(key),
512 }
513 }
514
515 fn push_val_diff(&mut self, val: &V, weight: &R)
516 where
517 T: PartialEq<()>,
518 {
519 match &mut self.inner {
520 BuilderInner::Vec(vec) => vec.push_val_diff(val, weight),
521 BuilderInner::File(file) => file.push_val_diff(val, weight),
522 }
523 }
524
525 fn push_val_diff_mut(&mut self, val: &mut V, weight: &mut R)
526 where
527 T: PartialEq<()>,
528 {
529 match &mut self.inner {
530 BuilderInner::Vec(vec) => vec.push_val_diff_mut(val, weight),
531 BuilderInner::File(file) => file.push_val_diff_mut(val, weight),
532 }
533 }
534
535 fn reserve(&mut self, additional: usize) {
536 match &mut self.inner {
537 BuilderInner::Vec(vec) => vec.reserve(additional),
538 BuilderInner::File(file) => file.reserve(additional),
539 }
540 }
541
542 fn done(self) -> FallbackValBatch<K, V, T, R> {
543 FallbackValBatch {
544 factories: self.factories,
545 inner: match self.inner {
546 BuilderInner::File(file) => Inner::File(file.done()),
547 BuilderInner::Vec(vec) => Inner::Vec(vec.done()),
548 },
549 }
550 }
551
552 fn num_keys(&self) -> usize {
553 match &self.inner {
554 BuilderInner::Vec(vec) => vec.num_keys(),
555 BuilderInner::File(file) => file.num_keys(),
556 }
557 }
558
559 fn num_tuples(&self) -> usize {
560 match &self.inner {
561 BuilderInner::Vec(vec) => vec.num_tuples(),
562 BuilderInner::File(file) => file.num_tuples(),
563 }
564 }
565}
566
567impl<K, V, T, R> Archive for FallbackValBatch<K, V, T, R>
568where
569 K: DataTrait + ?Sized,
570 V: DataTrait + ?Sized,
571 T: Timestamp,
572 R: WeightTrait + ?Sized,
573{
574 type Archived = ();
575 type Resolver = ();
576
577 unsafe fn resolve(&self, _pos: usize, _resolver: Self::Resolver, _out: *mut Self::Archived) {
578 unimplemented!();
579 }
580}
581
582impl<K, V, T, R, S> Serialize<S> for FallbackValBatch<K, V, T, R>
583where
584 K: DataTrait + ?Sized,
585 V: DataTrait + ?Sized,
586 T: Timestamp,
587 R: WeightTrait + ?Sized,
588 S: Serializer + ?Sized,
589{
590 fn serialize(&self, _serializer: &mut S) -> Result<Self::Resolver, S::Error> {
591 unimplemented!();
592 }
593}
594
595impl<K, V, T, R, D> Deserialize<FallbackValBatch<K, V, T, R>, D>
596 for Archived<FallbackValBatch<K, V, T, R>>
597where
598 K: DataTrait + ?Sized,
599 V: DataTrait + ?Sized,
600 T: Timestamp,
601 R: WeightTrait + ?Sized,
602 D: Fallible,
603{
604 fn deserialize(&self, _deserializer: &mut D) -> Result<FallbackValBatch<K, V, T, R>, D::Error> {
605 unimplemented!();
606 }
607}