@@ -2516,9 +2516,17 @@ async fn replace_before_active(
25162516 // that the initial downstairs are all synced up on the same flush and
25172517 // generation numbers.
25182518 fill_workload ( volume, di, true ) . await ?;
2519+
2520+ // Track which SocketAddr corresponds to which region. This shifts over
2521+ // time as the test runs, so we have to track it correctly disable 2
2522+ // downstairs for a given region.
2523+ let mut regions = vec ! [ ] ;
2524+ for i in 0 ..targets. len ( ) - 1 {
2525+ regions. push ( Some ( i as u32 / 3 ) ) ;
2526+ }
2527+ regions. push ( None ) ;
25192528 let ds_total = targets. len ( ) - 1 ;
2520- let mut old_ds_a = 0 ;
2521- let mut old_ds_b = 1 ;
2529+ let mut old_ds = 0 ;
25222530 let mut new_ds = targets. len ( ) - 1 ;
25232531 for c in 1 .. {
25242532 info ! ( log, "[{c}] Touch every extent" ) ;
@@ -2534,11 +2542,24 @@ async fn replace_before_active(
25342542 tokio:: time:: sleep ( tokio:: time:: Duration :: from_secs ( 4 ) ) . await ;
25352543 }
25362544
2537- // Stop two downstairs, wait for dsc to confirm they are stopped.
2538- for old_ds in [ old_ds_a, old_ds_b] {
2539- dsc_client. dsc_stop ( old_ds) . await . unwrap ( ) ;
2545+ // Pick a second downstairs that's in the same region, so we can stop
2546+ // two downstairs and prevent activation. This is linear-time with the
2547+ // number of targets, but that's fine (so is writing to every block).
2548+ assert ! ( regions[ new_ds] . is_none( ) ) ;
2549+ let region = regions[ old_ds] . unwrap ( ) ;
2550+ let ( other_ds, _) = regions
2551+ . iter ( )
2552+ . enumerate ( )
2553+ . find ( |( i, d) | * i != old_ds && * * d == Some ( region) )
2554+ . unwrap ( ) ;
2555+
2556+ // Stop two downstairs in the same region, then wait for dsc to confirm
2557+ // they are stopped. Having two downstairs stopped blocks activation.
2558+ for old_ds in [ old_ds, other_ds] {
2559+ dsc_client. dsc_stop ( old_ds as u32 ) . await . unwrap ( ) ;
25402560 loop {
2541- let res = dsc_client. dsc_get_ds_state ( old_ds) . await . unwrap ( ) ;
2561+ let res =
2562+ dsc_client. dsc_get_ds_state ( old_ds as u32 ) . await . unwrap ( ) ;
25422563 let state = res. into_inner ( ) ;
25432564 if state == DownstairsState :: Exit {
25442565 break ;
@@ -2564,14 +2585,14 @@ async fn replace_before_active(
25642585
25652586 info ! (
25662587 log,
2567- "[{c}] Replacing DS {old_ds_a }:{} with {new_ds}:{}" ,
2568- targets[ old_ds_a as usize ] ,
2588+ "[{c}] Replacing DS {old_ds }:{} with {new_ds}:{}" ,
2589+ targets[ old_ds ] ,
25692590 targets[ new_ds] ,
25702591 ) ;
25712592 match volume
25722593 . replace_downstairs (
25732594 Uuid :: new_v4 ( ) ,
2574- targets[ old_ds_a as usize ] ,
2595+ targets[ old_ds ] ,
25752596 targets[ new_ds] ,
25762597 )
25772598 . await
@@ -2610,8 +2631,8 @@ async fn replace_before_active(
26102631
26112632 // Start up all the stopped downstairs so they are ready for the next
26122633 // loop.
2613- for old_ds in [ old_ds_a , old_ds_b ] {
2614- let res = dsc_client. dsc_start ( old_ds) . await ;
2634+ for old_ds in [ old_ds , other_ds ] {
2635+ let res = dsc_client. dsc_start ( old_ds as u32 ) . await ;
26152636 info ! ( log, "[{c}] Replay: started {old_ds}, returned:{:?}" , res) ;
26162637 }
26172638
@@ -2632,8 +2653,8 @@ async fn replace_before_active(
26322653 tokio:: time:: sleep ( tokio:: time:: Duration :: from_secs ( 4 ) ) . await ;
26332654 }
26342655
2635- old_ds_a = ( old_ds_a + 1 ) % ( ds_total as u32 + 1 ) ;
2636- old_ds_b = ( old_ds_b + 1 ) % ( ds_total as u32 + 1 ) ;
2656+ regions . swap ( old_ds , new_ds ) ;
2657+ old_ds = ( old_ds + 1 ) % ( ds_total + 1 ) ;
26372658 new_ds = ( new_ds + 1 ) % ( ds_total + 1 ) ;
26382659
26392660 match wtq {
0 commit comments