@@ -205,8 +205,9 @@ impl DataStore {
205
205
/// Queries the datastore for the cells of the specified `components`, as seen from the point
206
206
/// of view of the so-called `primary` component.
207
207
///
208
- /// Returns an array of [`DataCell`]s on success, or `None` otherwise.
209
- /// Success is defined by one thing and thing only: whether a cell could be found for the
208
+ /// Returns an array of [`DataCell`]s (as well as the associated _data_ time and `RowId`) on
209
+ /// success.
210
+ /// Success is defined by one thing and one thing only: whether a cell could be found for the
210
211
/// `primary` component.
211
212
/// The presence or absence of secondary components has no effect on the success criteria.
212
213
///
@@ -238,7 +239,10 @@ impl DataStore {
238
239
/// let components = &[cluster_key, primary];
239
240
/// let (_, cells) = store
240
241
/// .latest_at(&query, ent_path, primary, components)
241
- /// .unwrap_or((RowId::ZERO, [(); 2].map(|_| None)));
242
+ /// .map_or_else(
243
+ /// || (RowId::ZERO, [(); 2].map(|_| None)),
244
+ /// |(_, row_id, cells)| (row_id, cells),
245
+ /// );
242
246
///
243
247
/// let series: Result<Vec<_>, _> = cells
244
248
/// .iter()
@@ -266,7 +270,7 @@ impl DataStore {
266
270
ent_path : & EntityPath ,
267
271
primary : ComponentName ,
268
272
components : & [ ComponentName ; N ] ,
269
- ) -> Option < ( RowId , [ Option < DataCell > ; N ] ) > {
273
+ ) -> Option < ( Option < TimeInt > , RowId , [ Option < DataCell > ; N ] ) > {
270
274
// TODO(cmc): kind & query_id need to somehow propagate through the span system.
271
275
self . query_id . fetch_add ( 1 , Ordering :: Relaxed ) ;
272
276
@@ -282,7 +286,7 @@ impl DataStore {
282
286
"query started…"
283
287
) ;
284
288
285
- let cells = self
289
+ let results = self
286
290
. tables
287
291
. get ( & ( ent_path_hash, query. timeline ) )
288
292
. and_then ( |table| {
@@ -301,11 +305,11 @@ impl DataStore {
301
305
302
306
// If we've found everything we were looking for in the temporal table, then we can
303
307
// return the results immediately.
304
- if cells
308
+ if results
305
309
. as_ref ( )
306
- . map_or ( false , |( _, cells) | cells. iter ( ) . all ( Option :: is_some) )
310
+ . map_or ( false , |( _, _ , cells) | cells. iter ( ) . all ( Option :: is_some) )
307
311
{
308
- return cells;
312
+ return results . map ( | ( data_time , row_id , cells) | ( Some ( data_time ) , row_id , cells ) ) ;
309
313
}
310
314
311
315
let cells_timeless = self . timeless_tables . get ( & ent_path_hash) . and_then ( |table| {
@@ -324,21 +328,28 @@ impl DataStore {
324
328
} ) ;
325
329
326
330
// Otherwise, let's see what's in the timeless table, and then..:
327
- match ( cells , cells_timeless) {
331
+ match ( results , cells_timeless) {
328
332
// nothing in the timeless table: return those partial cells we got.
329
- ( Some ( cells) , None ) => return Some ( cells) ,
333
+ ( results @ Some ( _) , None ) => {
334
+ return results. map ( |( data_time, row_id, cells) | ( Some ( data_time) , row_id, cells) )
335
+ }
336
+
330
337
// no temporal cells, but some timeless ones: return those as-is.
331
- ( None , Some ( cells_timeless) ) => return Some ( cells_timeless) ,
338
+ ( None , results @ Some ( _) ) => {
339
+ return results. map ( |( row_id, cells) | ( None , row_id, cells) )
340
+ }
341
+
332
342
// we have both temporal & timeless cells: let's merge the two when it makes sense
333
343
// and return the end result.
334
- ( Some ( ( row_id, mut cells) ) , Some ( ( _, cells_timeless) ) ) => {
344
+ ( Some ( ( data_time , row_id, mut cells) ) , Some ( ( _, cells_timeless) ) ) => {
335
345
for ( i, row_idx) in cells_timeless. into_iter ( ) . enumerate ( ) {
336
346
if cells[ i] . is_none ( ) {
337
347
cells[ i] = row_idx;
338
348
}
339
349
}
340
- return Some ( ( row_id, cells) ) ;
350
+ return Some ( ( Some ( data_time ) , row_id, cells) ) ;
341
351
}
352
+
342
353
// no cells at all.
343
354
( None , None ) => { }
344
355
}
@@ -428,7 +439,10 @@ impl DataStore {
428
439
/// let query = LatestAtQuery::new(query.timeline, latest_time);
429
440
/// let (_, cells) = store
430
441
/// .latest_at(&query, ent_path, primary, &components)
431
- /// .unwrap_or((RowId::ZERO, [(); 2].map(|_| None)));
442
+ /// .map_or_else(
443
+ /// || (RowId::ZERO, [(); 2].map(|_| None)),
444
+ /// |(_, row_id, cells)| (row_id, cells),
445
+ /// );
432
446
/// dataframe_from_cells(cells)
433
447
/// };
434
448
///
@@ -519,14 +533,14 @@ impl IndexedTable {
519
533
/// Queries the table for the cells of the specified `components`, as seen from the point
520
534
/// of view of the so-called `primary` component.
521
535
///
522
- /// Returns an array of [`DataCell`]s on success, or `None` iff no cell could be found for
523
- /// the `primary` component.
536
+ /// Returns an array of [`DataCell`]s (as well as the associated _data_ time and `RowId`) on
537
+ /// success, or `None` iff no cell could be found for the `primary` component.
524
538
pub fn latest_at < const N : usize > (
525
539
& self ,
526
- time : TimeInt ,
540
+ query_time : TimeInt ,
527
541
primary : ComponentName ,
528
542
components : & [ ComponentName ; N ] ,
529
- ) -> Option < ( RowId , [ Option < DataCell > ; N ] ) > {
543
+ ) -> Option < ( TimeInt , RowId , [ Option < DataCell > ; N ] ) > {
530
544
// Early-exit if this entire table is unaware of this component.
531
545
if !self . all_components . contains ( & primary) {
532
546
return None ;
@@ -542,22 +556,22 @@ impl IndexedTable {
542
556
// multiple indexed buckets within the same table!
543
557
544
558
let buckets = self
545
- . range_buckets_rev ( ..=time )
559
+ . range_buckets_rev ( ..=query_time )
546
560
. map ( |( _, bucket) | bucket)
547
561
. enumerate ( ) ;
548
562
for ( attempt, bucket) in buckets {
549
563
trace ! (
550
564
kind = "latest_at" ,
551
565
timeline = %timeline. name( ) ,
552
- time = timeline. typ( ) . format_utc( time ) ,
566
+ time = timeline. typ( ) . format_utc( query_time ) ,
553
567
%primary,
554
568
?components,
555
569
attempt,
556
570
bucket_time_range = timeline. typ( ) . format_range_utc( bucket. inner. read( ) . time_range) ,
557
571
"found candidate bucket"
558
572
) ;
559
- if let cells @ Some ( _) = bucket. latest_at ( time , primary, components) {
560
- return cells ; // found at least the primary component!
573
+ if let ret @ Some ( _) = bucket. latest_at ( query_time , primary, components) {
574
+ return ret ; // found at least the primary component!
561
575
}
562
576
}
563
577
@@ -717,14 +731,14 @@ impl IndexedBucket {
717
731
/// Queries the bucket for the cells of the specified `components`, as seen from the point
718
732
/// of view of the so-called `primary` component.
719
733
///
720
- /// Returns an array of [`DataCell`]s on success, or `None` iff no cell could be found for
721
- /// the `primary` component.
734
+ /// Returns an array of [`DataCell`]s (as well as the associated _data_ time and `RowId`) on
735
+ /// success, or `None` iff no cell could be found for the `primary` component.
722
736
pub fn latest_at < const N : usize > (
723
737
& self ,
724
- time : TimeInt ,
738
+ query_time : TimeInt ,
725
739
primary : ComponentName ,
726
740
components : & [ ComponentName ; N ] ,
727
- ) -> Option < ( RowId , [ Option < DataCell > ; N ] ) > {
741
+ ) -> Option < ( TimeInt , RowId , [ Option < DataCell > ; N ] ) > {
728
742
self . sort_indices_if_needed ( ) ;
729
743
730
744
let IndexedBucketInner {
@@ -748,11 +762,12 @@ impl IndexedBucket {
748
762
%primary,
749
763
?components,
750
764
timeline = %self . timeline. name( ) ,
751
- time = self . timeline. typ( ) . format_utc( time ) ,
765
+ query_time = self . timeline. typ( ) . format_utc( query_time ) ,
752
766
"searching for primary & secondary cells…"
753
767
) ;
754
768
755
- let time_row_nr = col_time. partition_point ( |t| * t <= time. as_i64 ( ) ) as i64 ;
769
+ let time_row_nr =
770
+ col_time. partition_point ( |data_time| * data_time <= query_time. as_i64 ( ) ) as i64 ;
756
771
757
772
// The partition point is always _beyond_ the index that we're looking for.
758
773
// A partition point of 0 thus means that we're trying to query for data that lives
@@ -769,7 +784,7 @@ impl IndexedBucket {
769
784
%primary,
770
785
?components,
771
786
timeline = %self . timeline. name( ) ,
772
- time = self . timeline. typ( ) . format_utc( time ) ,
787
+ query_time = self . timeline. typ( ) . format_utc( query_time ) ,
773
788
%primary_row_nr,
774
789
"found primary row number" ,
775
790
) ;
@@ -783,7 +798,7 @@ impl IndexedBucket {
783
798
%primary,
784
799
?components,
785
800
timeline = %self . timeline. name( ) ,
786
- time = self . timeline. typ( ) . format_utc( time ) ,
801
+ query_time = self . timeline. typ( ) . format_utc( query_time ) ,
787
802
%primary_row_nr,
788
803
"no secondary row number found" ,
789
804
) ;
@@ -797,7 +812,7 @@ impl IndexedBucket {
797
812
%primary,
798
813
?components,
799
814
timeline = %self . timeline. name( ) ,
800
- time = self . timeline. typ( ) . format_utc( time ) ,
815
+ query_time = self . timeline. typ( ) . format_utc( query_time ) ,
801
816
%primary_row_nr, %secondary_row_nr,
802
817
"found secondary row number" ,
803
818
) ;
@@ -812,7 +827,7 @@ impl IndexedBucket {
812
827
%primary,
813
828
%component,
814
829
timeline = %self . timeline. name( ) ,
815
- time = self . timeline. typ( ) . format_utc( time ) ,
830
+ query_time = self . timeline. typ( ) . format_utc( query_time ) ,
816
831
%primary_row_nr, %secondary_row_nr,
817
832
"found cell" ,
818
833
) ;
@@ -821,7 +836,11 @@ impl IndexedBucket {
821
836
}
822
837
}
823
838
824
- Some ( ( col_row_id[ secondary_row_nr as usize ] , cells) )
839
+ Some ( (
840
+ col_time[ secondary_row_nr as usize ] . into ( ) ,
841
+ col_row_id[ secondary_row_nr as usize ] ,
842
+ cells,
843
+ ) )
825
844
}
826
845
827
846
/// Iterates the bucket in order to return the cells of the specified `components`,
0 commit comments