@@ -110,9 +110,15 @@ impl<T: Eq + Hash + Ord> ReadHolds<T> {
110
110
}
111
111
112
112
/// Extends a `ReadHolds` with the contents of another `ReadHolds`.
113
- pub fn extend ( & mut self , other : ReadHolds < T > ) {
114
- for ( time, id_bundle) in other. holds {
115
- self . holds . entry ( time) . or_default ( ) . extend ( & id_bundle) ;
113
+ /// Asserts that the newly added read holds don't coincide with any of the existing read holds in self.
114
+ pub fn extend_with_new ( & mut self , other : ReadHolds < T > ) {
115
+ for ( time, other_id_bundle) in other. holds {
116
+ let self_id_bundle = self . holds . entry ( time) . or_default ( ) ;
117
+ assert ! (
118
+ self_id_bundle. intersection( & other_id_bundle) . is_empty( ) ,
119
+ "extend_with_new encountered duplicate read holds" ,
120
+ ) ;
121
+ self_id_bundle. extend ( & other_id_bundle) ;
116
122
}
117
123
}
118
124
@@ -214,7 +220,7 @@ impl crate::coord::Coordinator {
214
220
. or_default ( )
215
221
. extend ( id_bundle) ;
216
222
}
217
- read_holds. extend ( new_read_holds) ;
223
+ read_holds. extend_with_new ( new_read_holds) ;
218
224
}
219
225
TimelineContext :: TimestampIndependent | TimelineContext :: TimestampDependent => {
220
226
id_bundles. entry ( None ) . or_default ( ) . extend ( & id_bundle) ;
@@ -382,14 +388,34 @@ impl crate::coord::Coordinator {
382
388
383
389
/// Attempt to acquire read holds on the indicated collections at the indicated `time`.
384
390
///
385
- /// If we are unable to acquire a read hold at the provided `time` for a specific id, then we
386
- /// will acquire a read hold at the lowest possible time for that id.
391
+ /// If we are unable to acquire a read hold at the provided `time` for a specific id, then
392
+ /// depending on the `precise` argument, we either fall back to acquiring a read hold at
393
+ /// the lowest possible time for that id, or return an error. The returned error contains
394
+ /// those collection sinces that were later than the specified time.
387
395
pub ( crate ) fn acquire_read_holds (
388
396
& mut self ,
389
- time : mz_repr :: Timestamp ,
397
+ time : Timestamp ,
390
398
id_bundle : & CollectionIdBundle ,
391
- ) -> ReadHolds < mz_repr:: Timestamp > {
399
+ precise : bool ,
400
+ ) -> Result < ReadHolds < Timestamp > , Vec < ( Antichain < Timestamp > , CollectionIdBundle ) > > {
392
401
let read_holds = self . initialize_read_holds ( time, id_bundle) ;
402
+ if precise {
403
+ // If we are not able to acquire read holds precisely at the specified time (only later), then error out.
404
+ let too_late = read_holds
405
+ . holds
406
+ . iter ( )
407
+ . filter_map ( |( antichain, ids) | {
408
+ if antichain. iter ( ) . all ( |hold_time| * hold_time == time) {
409
+ None
410
+ } else {
411
+ Some ( ( antichain. clone ( ) , ids. clone ( ) ) )
412
+ }
413
+ } )
414
+ . collect_vec ( ) ;
415
+ if !too_late. is_empty ( ) {
416
+ return Err ( too_late) ;
417
+ }
418
+ }
393
419
// Update STORAGE read policies.
394
420
let mut policy_changes = Vec :: new ( ) ;
395
421
for ( time, id) in read_holds. storage_ids ( ) {
@@ -418,26 +444,30 @@ impl crate::coord::Coordinator {
418
444
. unwrap_or_terminate ( "cannot fail to set read policy" ) ;
419
445
}
420
446
421
- read_holds
447
+ Ok ( read_holds)
422
448
}
423
449
424
450
/// Attempt to acquire read holds on the indicated collections at the indicated `time`.
425
451
/// This is similar to [Self::acquire_read_holds], but instead of returning the read holds,
426
452
/// it arranges for them to be automatically released at the end of the transaction.
427
453
///
428
- /// If we are unable to acquire a read hold at the provided `time` for a specific id, then we
429
- /// will acquire a read hold at the lowest possible time for that id.
454
+ /// If we are unable to acquire a read hold at the provided `time` for a specific id, then
455
+ /// depending on the `precise` argument, we either fall back to acquiring a read hold at
456
+ /// the lowest possible time for that id, or return an error. The returned error contains
457
+ /// those collection sinces that were later than the specified time.
430
458
pub ( crate ) fn acquire_read_holds_auto_cleanup (
431
459
& mut self ,
432
460
session : & Session ,
433
461
time : Timestamp ,
434
462
id_bundle : & CollectionIdBundle ,
435
- ) {
436
- let read_holds = self . acquire_read_holds ( time, id_bundle) ;
463
+ precise : bool ,
464
+ ) -> Result < ( ) , Vec < ( Antichain < Timestamp > , CollectionIdBundle ) > > {
465
+ let read_holds = self . acquire_read_holds ( time, id_bundle, precise) ?;
437
466
self . txn_read_holds
438
467
. entry ( session. conn_id ( ) . clone ( ) )
439
- . or_insert_with ( ReadHolds :: new)
440
- . extend ( read_holds) ;
468
+ . or_insert_with ( Vec :: new)
469
+ . push ( read_holds) ;
470
+ Ok ( ( ) )
441
471
}
442
472
443
473
/// Attempt to update the timestamp of the read holds on the indicated collections from the
@@ -446,10 +476,10 @@ impl crate::coord::Coordinator {
446
476
/// If we are unable to update a read hold at the provided `time` for a specific id, then we
447
477
/// leave it unchanged.
448
478
///
449
- /// This method relies on a previous call to `acquire_read_holds` with the same
450
- /// `read_holds` argument or a previous call to `update_read_hold` that returned
479
+ /// This method relies on a previous call to
480
+ /// `initialize_read_holds`, `acquire_read_holds`, or `update_read_hold` that returned
451
481
/// `read_holds`, and its behavior will be erratic if called on anything else.
452
- pub ( super ) fn update_read_hold (
482
+ pub ( super ) fn update_read_holds (
453
483
& mut self ,
454
484
read_holds : ReadHolds < mz_repr:: Timestamp > ,
455
485
new_time : mz_repr:: Timestamp ,
@@ -547,34 +577,46 @@ impl crate::coord::Coordinator {
547
577
548
578
new_read_holds
549
579
}
550
- /// Release read holds on the indicated collections at the indicated times.
580
+
581
+ /// Release the given read holds.
551
582
///
552
- /// This method relies on a previous call to `acquire_read_holds` with the same
553
- /// argument, or a previous call to `update_read_hold` that returned
554
- /// `read_holds `, and its behavior will be erratic if called on anything else,
583
+ /// This method relies on a previous call to
584
+ /// `initialize_read_holds`, `acquire_read_holds`, or `update_read_hold` that returned
585
+ /// `ReadHolds `, and its behavior will be erratic if called on anything else,
555
586
/// or if called more than once on the same bundle of read holds.
556
- pub ( super ) fn release_read_hold ( & mut self , read_holds : & ReadHolds < mz_repr :: Timestamp > ) {
587
+ pub ( super ) fn release_read_holds ( & mut self , read_holdses : Vec < ReadHolds < Timestamp > > ) {
557
588
// Update STORAGE read policies.
558
- let mut policy_changes = Vec :: new ( ) ;
559
- for ( time, id) in read_holds. storage_ids ( ) {
560
- // It's possible that a concurrent DDL statement has already dropped this GlobalId
561
- if let Some ( read_needs) = self . storage_read_capabilities . get_mut ( id) {
562
- read_needs. holds . update_iter ( time. iter ( ) . map ( |t| ( * t, -1 ) ) ) ;
563
- policy_changes. push ( ( * id, read_needs. policy ( ) ) ) ;
589
+ let mut storage_policy_changes = Vec :: new ( ) ;
590
+ for read_holds in read_holdses. iter ( ) {
591
+ for ( time, id) in read_holds. storage_ids ( ) {
592
+ // It's possible that a concurrent DDL statement has already dropped this GlobalId
593
+ if let Some ( read_needs) = self . storage_read_capabilities . get_mut ( id) {
594
+ read_needs. holds . update_iter ( time. iter ( ) . map ( |t| ( * t, -1 ) ) ) ;
595
+ storage_policy_changes. push ( ( * id, read_needs. policy ( ) ) ) ;
596
+ }
564
597
}
565
598
}
566
- self . controller . storage . set_read_policy ( policy_changes) ;
599
+ self . controller
600
+ . storage
601
+ . set_read_policy ( storage_policy_changes) ;
567
602
// Update COMPUTE read policies
568
603
let mut compute = self . controller . active_compute ( ) ;
569
- for ( compute_instance, compute_ids) in read_holds. compute_ids ( ) {
570
- let mut policy_changes = Vec :: new ( ) ;
571
- for ( time, id) in compute_ids {
572
- // It's possible that a concurrent DDL statement has already dropped this GlobalId
573
- if let Some ( read_needs) = self . compute_read_capabilities . get_mut ( id) {
574
- read_needs. holds . update_iter ( time. iter ( ) . map ( |t| ( * t, -1 ) ) ) ;
575
- policy_changes. push ( ( * id, read_needs. policy ( ) ) ) ;
604
+ let mut policy_changes_per_instance = BTreeMap :: new ( ) ;
605
+ for read_holds in read_holdses. iter ( ) {
606
+ for ( compute_instance, compute_ids) in read_holds. compute_ids ( ) {
607
+ let policy_changes = policy_changes_per_instance
608
+ . entry ( compute_instance)
609
+ . or_insert_with ( Vec :: new) ;
610
+ for ( time, id) in compute_ids {
611
+ // It's possible that a concurrent DDL statement has already dropped this GlobalId
612
+ if let Some ( read_needs) = self . compute_read_capabilities . get_mut ( id) {
613
+ read_needs. holds . update_iter ( time. iter ( ) . map ( |t| ( * t, -1 ) ) ) ;
614
+ policy_changes. push ( ( * id, read_needs. policy ( ) ) ) ;
615
+ }
576
616
}
577
617
}
618
+ }
619
+ for ( compute_instance, policy_changes) in policy_changes_per_instance {
578
620
if compute. instance_exists ( * compute_instance) {
579
621
compute
580
622
. set_read_policy ( * compute_instance, policy_changes)
0 commit comments