@@ -5,7 +5,9 @@ use std::{
5
5
6
6
use itertools:: Itertools ;
7
7
use re_chunk:: { Chunk , LatestAtQuery , RangeQuery } ;
8
+ use re_log_types:: ResolvedTimeRange ;
8
9
use re_log_types:: { EntityPath , TimeInt , Timeline } ;
10
+ use re_types_core:: SizeBytes as _;
9
11
use re_types_core:: { ComponentName , ComponentNameSet } ;
10
12
11
13
use crate :: { store:: ChunkIdSetPerTime , ChunkStore } ;
@@ -61,6 +63,47 @@ impl ChunkStore {
61
63
}
62
64
}
63
65
66
+ /// Retrieve all the [`ComponentName`]s that have been written to for a given [`EntityPath`].
67
+ ///
68
+ /// Static components are always included in the results.
69
+ ///
70
+ /// Returns `None` if the entity has never had any data logged to it.
71
+ pub fn all_components_on_all_timelines (
72
+ & self ,
73
+ entity_path : & EntityPath ,
74
+ ) -> Option < ComponentNameSet > {
75
+ re_tracing:: profile_function!( ) ;
76
+
77
+ self . query_id . fetch_add ( 1 , Ordering :: Relaxed ) ;
78
+
79
+ let static_components: Option < ComponentNameSet > = self
80
+ . static_chunk_ids_per_entity
81
+ . get ( entity_path)
82
+ . map ( |static_chunks_per_component| {
83
+ static_chunks_per_component. keys ( ) . copied ( ) . collect ( )
84
+ } ) ;
85
+
86
+ let temporal_components: Option < ComponentNameSet > = self
87
+ . temporal_chunk_ids_per_entity_per_component
88
+ . get ( entity_path)
89
+ . map ( |temporal_chunk_ids_per_timeline| {
90
+ temporal_chunk_ids_per_timeline
91
+ . iter ( )
92
+ . flat_map ( |( _, temporal_chunk_ids_per_component) | {
93
+ temporal_chunk_ids_per_component. keys ( ) . copied ( )
94
+ } )
95
+ . collect ( )
96
+ } ) ;
97
+
98
+ match ( static_components, temporal_components) {
99
+ ( None , None ) => None ,
100
+ ( None , comps @ Some ( _) ) | ( comps @ Some ( _) , None ) => comps,
101
+ ( Some ( static_comps) , Some ( temporal_comps) ) => {
102
+ Some ( static_comps. into_iter ( ) . chain ( temporal_comps) . collect ( ) )
103
+ }
104
+ }
105
+ }
106
+
64
107
/// Check whether a given entity has a specific [`ComponentName`] either on the specified
65
108
/// timeline, or in its static data.
66
109
#[ inline]
@@ -75,6 +118,56 @@ impl ChunkStore {
75
118
. map_or ( false , |components| components. contains ( component_name) )
76
119
}
77
120
121
+ pub fn entity_has_component_on_any_timeline (
122
+ & self ,
123
+ entity_path : & EntityPath ,
124
+ component_name : & ComponentName ,
125
+ ) -> bool {
126
+ re_tracing:: profile_function!( ) ;
127
+
128
+ if self
129
+ . static_chunk_ids_per_entity
130
+ . get ( entity_path)
131
+ . and_then ( |static_chunks_per_component| static_chunks_per_component. get ( component_name) )
132
+ . and_then ( |id| self . chunks_per_chunk_id . get ( id) )
133
+ . is_some ( )
134
+ {
135
+ return true ;
136
+ }
137
+
138
+ for temporal_chunk_ids_per_component in self
139
+ . temporal_chunk_ids_per_entity_per_component
140
+ . get ( entity_path)
141
+ . iter ( )
142
+ . flat_map ( |temporal_chunk_ids_per_timeline| temporal_chunk_ids_per_timeline. values ( ) )
143
+ {
144
+ if temporal_chunk_ids_per_component
145
+ . get ( component_name)
146
+ . is_some ( )
147
+ {
148
+ return true ;
149
+ }
150
+ }
151
+
152
+ false
153
+ }
154
+
155
+ /// Returns true if the given entity has a specific component with static data.
156
+ #[ inline]
157
+ pub fn entity_has_static_component (
158
+ & self ,
159
+ entity_path : & EntityPath ,
160
+ component_name : & ComponentName ,
161
+ ) -> bool {
162
+ re_tracing:: profile_function!( ) ;
163
+
164
+ let Some ( static_components) = self . static_chunk_ids_per_entity . get ( entity_path) else {
165
+ return false ;
166
+ } ;
167
+
168
+ static_components. contains_key ( component_name)
169
+ }
170
+
78
171
/// Find the earliest time at which something was logged for a given entity on the specified
79
172
/// timeline.
80
173
///
@@ -413,3 +506,217 @@ impl ChunkStore {
413
506
. collect ( )
414
507
}
415
508
}
509
+
510
+ // Queries returning `usize` and `bool`
511
+ impl ChunkStore {
512
+ /// Returns the number of events logged for a given component on the given entity path across all timelines.
513
+ pub fn num_events_on_timeline_for_component (
514
+ & self ,
515
+ timeline : & Timeline ,
516
+ entity_path : & EntityPath ,
517
+ component_name : ComponentName ,
518
+ ) -> usize {
519
+ re_tracing:: profile_function!( ) ;
520
+
521
+ self . query_id . fetch_add ( 1 , Ordering :: Relaxed ) ;
522
+
523
+ self . num_events_for_static_component ( entity_path, component_name)
524
+ + self . num_events_on_timeline_for_temporal_component (
525
+ timeline,
526
+ entity_path,
527
+ component_name,
528
+ )
529
+ }
530
+
531
+ pub fn time_range_for_entity (
532
+ & self ,
533
+ timeline : & Timeline ,
534
+ entity_path : & EntityPath ,
535
+ ) -> Option < ResolvedTimeRange > {
536
+ re_tracing:: profile_function!( ) ;
537
+
538
+ self . query_id . fetch_add ( 1 , Ordering :: Relaxed ) ;
539
+
540
+ let temporal_chunk_ids_per_timeline =
541
+ self . temporal_chunk_ids_per_entity . get ( entity_path) ?;
542
+ let chunk_id_sets = temporal_chunk_ids_per_timeline. get ( timeline) ?;
543
+
544
+ let start = chunk_id_sets. per_start_time . keys ( ) . min ( ) ?;
545
+ let end = chunk_id_sets. per_end_time . keys ( ) . max ( ) ?;
546
+
547
+ Some ( ResolvedTimeRange :: new ( * start, * end) )
548
+ }
549
+
550
+ pub fn num_events_on_timeline_for_all_components (
551
+ & self ,
552
+ timeline : & Timeline ,
553
+ entity_path : & EntityPath ,
554
+ ) -> usize {
555
+ re_tracing:: profile_function!( ) ;
556
+
557
+ self . query_id . fetch_add ( 1 , Ordering :: Relaxed ) ;
558
+
559
+ let mut total_events = 0 ;
560
+
561
+ if let Some ( static_chunks_per_component) = self . static_chunk_ids_per_entity . get ( entity_path)
562
+ {
563
+ for chunk in static_chunks_per_component
564
+ . values ( )
565
+ . filter_map ( |id| self . chunks_per_chunk_id . get ( id) )
566
+ {
567
+ total_events += chunk. num_events_cumulative ( ) ;
568
+ }
569
+ }
570
+
571
+ if let Some ( chunk_ids) = self
572
+ . temporal_chunk_ids_per_entity
573
+ . get ( entity_path)
574
+ . and_then ( |temporal_chunks_events_per_timeline| {
575
+ temporal_chunks_events_per_timeline. get ( timeline)
576
+ } )
577
+ {
578
+ for chunk in chunk_ids
579
+ . per_start_time
580
+ . values ( )
581
+ . flat_map ( |ids| ids. iter ( ) . filter_map ( |id| self . chunks_per_chunk_id . get ( id) ) )
582
+ {
583
+ total_events += chunk. num_events_cumulative ( ) ;
584
+ }
585
+ }
586
+
587
+ total_events
588
+ }
589
+
590
+ pub fn entity_has_data_on_timeline (
591
+ & self ,
592
+ timeline : & Timeline ,
593
+ entity_path : & EntityPath ,
594
+ ) -> bool {
595
+ re_tracing:: profile_function!( ) ;
596
+
597
+ self . query_id . fetch_add ( 1 , Ordering :: Relaxed ) ;
598
+
599
+ if self . static_chunk_ids_per_entity . get ( entity_path) . is_some ( ) {
600
+ // Static data exists on all timelines
601
+ return true ;
602
+ }
603
+
604
+ if let Some ( temporal_chunk_ids_per_timeline) =
605
+ self . temporal_chunk_ids_per_entity . get ( entity_path)
606
+ {
607
+ if temporal_chunk_ids_per_timeline. contains_key ( timeline) {
608
+ return true ;
609
+ }
610
+ }
611
+
612
+ false
613
+ }
614
+
615
+ pub fn num_events_for_static_component (
616
+ & self ,
617
+ entity_path : & EntityPath ,
618
+ component_name : ComponentName ,
619
+ ) -> usize {
620
+ re_tracing:: profile_function!( ) ;
621
+
622
+ self . query_id . fetch_add ( 1 , Ordering :: Relaxed ) ;
623
+
624
+ if let Some ( static_chunk) = self
625
+ . static_chunk_ids_per_entity
626
+ . get ( entity_path)
627
+ . and_then ( |static_chunks_per_component| {
628
+ static_chunks_per_component. get ( & component_name)
629
+ } )
630
+ . and_then ( |chunk_id| self . chunks_per_chunk_id . get ( chunk_id) )
631
+ {
632
+ // Static data overrides temporal data
633
+ static_chunk
634
+ . num_events_for_component ( component_name)
635
+ . unwrap_or ( 0 )
636
+ } else {
637
+ 0
638
+ }
639
+ }
640
+
641
+ /// Returns the number of events logged for a given component on the given entity path across all timelines.
642
+ ///
643
+ /// This ignores static data.
644
+ pub fn num_events_on_timeline_for_temporal_component (
645
+ & self ,
646
+ timeline : & Timeline ,
647
+ entity_path : & EntityPath ,
648
+ component_name : ComponentName ,
649
+ ) -> usize {
650
+ re_tracing:: profile_function!( ) ;
651
+
652
+ self . query_id . fetch_add ( 1 , Ordering :: Relaxed ) ;
653
+
654
+ let Some ( temporal_chunk_ids_per_timeline) = self
655
+ . temporal_chunk_ids_per_entity_per_component
656
+ . get ( entity_path)
657
+ else {
658
+ return 0 ; // no events logged for the entity path
659
+ } ;
660
+
661
+ let Some ( temporal_chunk_ids_per_component) = temporal_chunk_ids_per_timeline. get ( timeline)
662
+ else {
663
+ return 0 ; // no events logged on this timeline
664
+ } ;
665
+
666
+ let Some ( chunk_ids) = temporal_chunk_ids_per_component. get ( & component_name) else {
667
+ return 0 ; // no events logged for the component on this timeline
668
+ } ;
669
+
670
+ let mut num_events = 0 ;
671
+ for chunk in chunk_ids
672
+ . per_start_time
673
+ . values ( )
674
+ . flat_map ( |ids| ids. iter ( ) . filter_map ( |id| self . chunks_per_chunk_id . get ( id) ) )
675
+ {
676
+ num_events += chunk. num_events_for_component ( component_name) . unwrap_or ( 0 ) ;
677
+ }
678
+
679
+ num_events
680
+ }
681
+
682
+ pub fn size_of_entity_on_timeline (
683
+ & self ,
684
+ timeline : & Timeline ,
685
+ entity_path : & EntityPath ,
686
+ ) -> usize {
687
+ re_tracing:: profile_function!( ) ;
688
+
689
+ self . query_id . fetch_add ( 1 , Ordering :: Relaxed ) ;
690
+
691
+ let mut total_size = 0 ;
692
+
693
+ if let Some ( static_chunks_per_component) = self . static_chunk_ids_per_entity . get ( entity_path)
694
+ {
695
+ for chunk in static_chunks_per_component
696
+ . values ( )
697
+ . filter_map ( |id| self . chunks_per_chunk_id . get ( id) )
698
+ {
699
+ total_size += Chunk :: total_size_bytes ( chunk) as usize ;
700
+ }
701
+ }
702
+
703
+ if let Some ( chunk_id_sets) = self
704
+ . temporal_chunk_ids_per_entity
705
+ . get ( entity_path)
706
+ . and_then ( |temporal_chunk_ids_per_timeline| {
707
+ temporal_chunk_ids_per_timeline. get ( timeline)
708
+ } )
709
+ {
710
+ for chunk in chunk_id_sets
711
+ . per_start_time
712
+ . values ( )
713
+ . flat_map ( |v| v. iter ( ) )
714
+ . filter_map ( |id| self . chunks_per_chunk_id . get ( id) )
715
+ {
716
+ total_size += Chunk :: total_size_bytes ( chunk) as usize ;
717
+ }
718
+ }
719
+
720
+ total_size
721
+ }
722
+ }
0 commit comments