6666 R1 : Component + Send + Sync + ' static ,
6767 F : FnMut (
6868 (
69- ( TimeInt , RowId ) ,
69+ ( Option < TimeInt > , RowId ) ,
7070 MaybeCachedComponentData < ' _ , InstanceKey > ,
7171 MaybeCachedComponentData < ' _ , R1 > ,
7272 ) ,
@@ -93,7 +93,7 @@ macro_rules! impl_query_archetype {
9393 $( $comp: Component + Send + Sync + ' static , ) *
9494 F : FnMut (
9595 (
96- ( TimeInt , RowId ) ,
96+ ( Option < TimeInt > , RowId ) ,
9797 MaybeCachedComponentData <' _, InstanceKey >,
9898 $( MaybeCachedComponentData <' _, $pov>, ) +
9999 $( MaybeCachedComponentData <' _, Option <$comp>>, ) *
@@ -107,7 +107,7 @@ macro_rules! impl_query_archetype {
107107 ) ;
108108
109109
110- let mut iter_results = |bucket: & crate :: CacheBucket | -> crate :: Result <( ) > {
110+ let mut iter_results = |timeless : bool , bucket: & crate :: CacheBucket | -> crate :: Result <( ) > {
111111 re_tracing:: profile_scope!( "iter" ) ;
112112
113113 let it = itertools:: izip!(
@@ -117,9 +117,9 @@ macro_rules! impl_query_archetype {
117117 . ok_or_else( || re_query:: ComponentNotFoundError ( <$pov>:: name( ) ) ) ?, ) +
118118 $( bucket. iter_component_opt:: <$comp>( )
119119 . ok_or_else( || re_query:: ComponentNotFoundError ( <$comp>:: name( ) ) ) ?, ) *
120- ) . map( |( time, instance_keys, $( $pov, ) + $( $comp, ) * ) | {
120+ ) . map( |( ( time, row_id ) , instance_keys, $( $pov, ) + $( $comp, ) * ) | {
121121 (
122- * time,
122+ ( ( !timeless ) . then_some ( * time) , * row_id ) ,
123123 MaybeCachedComponentData :: Cached ( instance_keys) ,
124124 $( MaybeCachedComponentData :: Cached ( $pov) , ) +
125125 $( MaybeCachedComponentData :: Cached ( $comp) , ) *
@@ -133,68 +133,102 @@ macro_rules! impl_query_archetype {
133133 Ok ( ( ) )
134134 } ;
135135
136+
137+ let upsert_results = |
138+ data_time: TimeInt ,
139+ arch_view: & :: re_query:: ArchetypeView <A >,
140+ bucket: & mut crate :: CacheBucket ,
141+ | -> crate :: Result <( ) > {
142+ re_log:: trace!( data_time=?data_time, ?data_time, "fill" ) ;
143+
144+ // Grabbing the current time is quite costly on web.
145+ #[ cfg( not( target_arch = "wasm32" ) ) ]
146+ let now = web_time:: Instant :: now( ) ;
147+
148+ bucket. [ <insert_pov$N _comp$M>] :: <A , $( $pov, ) + $( $comp, ) * >( data_time, & arch_view) ?;
149+
150+ #[ cfg( not( target_arch = "wasm32" ) ) ]
151+ {
152+ let elapsed = now. elapsed( ) ;
153+ :: re_log:: trace!(
154+ store_id=%store. id( ) ,
155+ %entity_path,
156+ archetype=%A :: name( ) ,
157+ "cached new entry in {elapsed:?} ({:0.3} entries/s)" ,
158+ 1f64 / elapsed. as_secs_f64( )
159+ ) ;
160+ }
161+
162+ Ok ( ( ) )
163+ } ;
164+
136165 let mut latest_at_callback = |query: & LatestAtQuery , latest_at_cache: & mut crate :: LatestAtCache | {
137166 re_tracing:: profile_scope!( "latest_at" , format!( "{query:?}" ) ) ;
138167
139- let crate :: LatestAtCache { per_query_time, per_data_time } = latest_at_cache;
168+ let crate :: LatestAtCache { per_query_time, per_data_time, timeless } = latest_at_cache;
140169
141170 let query_time_bucket_at_query_time = match per_query_time. entry( query. at) {
142171 std:: collections:: btree_map:: Entry :: Occupied ( query_time_bucket_at_query_time) => {
143172 // Fastest path: we have an entry for this exact query time, no need to look any
144173 // further.
145- return iter_results( & query_time_bucket_at_query_time. get( ) . read( ) ) ;
174+ re_log:: trace!( query_time=?query. at, "cache hit (query time)" ) ;
175+ return iter_results( false , & query_time_bucket_at_query_time. get( ) . read( ) ) ;
146176 }
147177 entry @ std:: collections:: btree_map:: Entry :: Vacant ( _) => entry,
148178 } ;
149179
150180 let arch_view = query_archetype:: <A >( store, & query, entity_path) ?;
151- // TODO(cmc): actual timeless caching support.
152- let data_time = arch_view. data_time( ) . unwrap_or( TimeInt :: MIN ) ;
181+ let data_time = arch_view. data_time( ) ;
153182
154183 // Fast path: we've run the query and realized that we already have the data for the resulting
155184 // _data_ time, so let's use that to avoid join & deserialization costs.
156- if let Some ( data_time_bucket_at_data_time) = per_data_time. get( & data_time) {
157- * query_time_bucket_at_query_time. or_default( ) = std:: sync:: Arc :: clone( & data_time_bucket_at_data_time) ;
185+ if let Some ( data_time) = data_time { // Reminder: `None` means timeless.
186+ if let Some ( data_time_bucket_at_data_time) = per_data_time. get( & data_time) {
187+ re_log:: trace!( query_time=?query. at, ?data_time, "cache hit (data time)" ) ;
188+
189+ * query_time_bucket_at_query_time. or_default( ) = std:: sync:: Arc :: clone( & data_time_bucket_at_data_time) ;
158190
159- // We now know for a fact that a query at that data time would yield the same
160- // results: copy the bucket accordingly so that the next cache hit for that query
161- // time ends up taking the fastest path.
162- let query_time_bucket_at_data_time = per_query_time. entry( data_time) ;
163- * query_time_bucket_at_data_time. or_default( ) = std:: sync:: Arc :: clone( & data_time_bucket_at_data_time) ;
191+ // We now know for a fact that a query at that data time would yield the same
192+ // results: copy the bucket accordingly so that the next cache hit for that query
193+ // time ends up taking the fastest path.
194+ let query_time_bucket_at_data_time = per_query_time. entry( data_time) ;
195+ * query_time_bucket_at_data_time. or_default( ) = std:: sync:: Arc :: clone( & data_time_bucket_at_data_time) ;
164196
165- return iter_results( & data_time_bucket_at_data_time. read( ) ) ;
197+ return iter_results( false , & data_time_bucket_at_data_time. read( ) ) ;
198+ }
199+ } else {
200+ if let Some ( timeless_bucket) = timeless. as_ref( ) {
201+ re_log:: trace!( query_time=?query. at, "cache hit (data time, timeless)" ) ;
202+ return iter_results( true , timeless_bucket) ;
203+ }
166204 }
167205
168206 let query_time_bucket_at_query_time = query_time_bucket_at_query_time. or_default( ) ;
169207
170208 // Slowest path: this is a complete cache miss.
171- {
172- re_tracing :: profile_scope! ( "fill ") ;
209+ if let Some ( data_time ) = data_time { // Reminder: `None` means timeless.
210+ re_log :: trace! ( query_time=?query . at , ?data_time , "cache miss ") ;
173211
174- // Grabbing the current time is quite costly on web.
175- #[ cfg( not( target_arch = "wasm32" ) ) ]
176- let now = web_time:: Instant :: now( ) ;
177-
178- let mut query_time_bucket_at_query_time = query_time_bucket_at_query_time. write( ) ;
179- query_time_bucket_at_query_time. [ <insert_pov$N _comp$M>] :: <A , $( $pov, ) + $( $comp, ) * >( query. at, & arch_view) ?;
180-
181- #[ cfg( not( target_arch = "wasm32" ) ) ]
182212 {
183- let elapsed = now. elapsed( ) ;
184- :: re_log:: trace!(
185- store_id=%store. id( ) ,
186- %entity_path,
187- archetype=%A :: name( ) ,
188- "cached new entry in {elapsed:?} ({:0.3} entries/s)" ,
189- 1f64 / elapsed. as_secs_f64( )
190- ) ;
213+ let mut query_time_bucket_at_query_time = query_time_bucket_at_query_time. write( ) ;
214+ upsert_results( data_time, & arch_view, & mut query_time_bucket_at_query_time) ?;
191215 }
192- }
193216
194- let data_time_bucket_at_data_time = per_data_time. entry( data_time) ;
195- * data_time_bucket_at_data_time. or_default( ) = std:: sync:: Arc :: clone( & query_time_bucket_at_query_time) ;
217+ let data_time_bucket_at_data_time = per_data_time. entry( data_time) ;
218+ * data_time_bucket_at_data_time. or_default( ) = std:: sync:: Arc :: clone( & query_time_bucket_at_query_time) ;
219+
220+ iter_results( false , & query_time_bucket_at_query_time. read( ) )
221+ } else {
222+ re_log:: trace!( query_time=?query. at, "cache miss (timeless)" ) ;
223+
224+ let mut timeless_bucket = crate :: CacheBucket :: default ( ) ;
196225
197- iter_results( & query_time_bucket_at_query_time. read( ) )
226+ upsert_results( TimeInt :: MIN , & arch_view, & mut timeless_bucket) ?;
227+ iter_results( true , & timeless_bucket) ?;
228+
229+ * timeless = Some ( timeless_bucket) ;
230+ Ok ( ( ) )
231+ }
198232 } ;
199233
200234
@@ -209,8 +243,7 @@ macro_rules! impl_query_archetype {
209243
210244 for arch_view in arch_views {
211245 let data = (
212- // TODO(cmc): actual timeless caching support.
213- ( arch_view. data_time( ) . unwrap_or( TimeInt :: MIN ) , arch_view. primary_row_id( ) ) ,
246+ ( arch_view. data_time( ) , arch_view. primary_row_id( ) ) ,
214247 MaybeCachedComponentData :: Raw ( arch_view. iter_instance_keys( ) . collect( ) ) ,
215248 $( MaybeCachedComponentData :: Raw ( arch_view. iter_required_component:: <$pov>( ) ?. collect( ) ) , ) +
216249 $( MaybeCachedComponentData :: Raw ( arch_view. iter_optional_component:: <$comp>( ) ?. collect( ) ) , ) *
@@ -228,8 +261,7 @@ macro_rules! impl_query_archetype {
228261 let arch_view = :: re_query:: query_archetype:: <A >( store, query, entity_path) ?;
229262
230263 let data = (
231- // TODO(cmc): actual timeless caching support.
232- ( arch_view. data_time( ) . unwrap_or( TimeInt :: MIN ) , arch_view. primary_row_id( ) ) ,
264+ ( arch_view. data_time( ) , arch_view. primary_row_id( ) ) ,
233265 MaybeCachedComponentData :: Raw ( arch_view. iter_instance_keys( ) . collect( ) ) ,
234266 $( MaybeCachedComponentData :: Raw ( arch_view. iter_required_component:: <$pov>( ) ?. collect( ) ) , ) +
235267 $( MaybeCachedComponentData :: Raw ( arch_view. iter_optional_component:: <$comp>( ) ?. collect( ) ) , ) *
@@ -286,7 +318,7 @@ where
286318 R1 : Component + Send + Sync + ' static ,
287319 F : FnMut (
288320 (
289- ( TimeInt , RowId ) ,
321+ ( Option < TimeInt > , RowId ) ,
290322 MaybeCachedComponentData < ' _ , InstanceKey > ,
291323 MaybeCachedComponentData < ' _ , R1 > ,
292324 ) ,
@@ -318,7 +350,7 @@ macro_rules! impl_query_archetype_with_history {
318350 $( $comp: Component + Send + Sync + ' static , ) *
319351 F : FnMut (
320352 (
321- ( TimeInt , RowId ) ,
353+ ( Option < TimeInt > , RowId ) ,
322354 MaybeCachedComponentData <' _, InstanceKey >,
323355 $( MaybeCachedComponentData <' _, $pov>, ) +
324356 $( MaybeCachedComponentData <' _, Option <$comp>>, ) *
0 commit comments