Skip to content

Commit 3828380

Browse files
leftwoAlan Hanson
and
Alan Hanson
authored
More multiple region support. (#1484)
Even more updates to support Volume layer activities. Added a new test to CI that will run "test_up.sh encrypted" with two region sets (6 downstairs). Crutest changes: Added some comments to crutest tests that were missing them. Crutest will now determine the total number of downstairs it expects to be using and compare that value when looking for an expected number of downstairs in an active state. Updated replay, replace, replace-before-active, and replace-while-reconcile tests to support having more than one region set. Fixed a bug in the replace-before-active test where previous tests could leave things broken in a way the test could not repair. Removed the no longer valid NEW columns from the DTrace `single_up_info.d` script. test_up.sh changes: Added support for running all the tests with a user supplied number of region sets instead of just defaulting to one (three downstairs). Some other misc cleanup of test_up.sh. Fixed a few other bugs in tests where we did not verify that new state requested of dsc had been reached before continuing. --------- Co-authored-by: Alan Hanson <[email protected]>
1 parent da58373 commit 3828380

File tree

8 files changed

+237
-70
lines changed

8 files changed

+237
-70
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#!/bin/bash
2+
#:
3+
#: name = "test-up-2region-encrypted"
4+
#: variety = "basic"
5+
#: target = "helios-2.0"
6+
#: output_rules = [
7+
#: "%/tmp/test_up*/*.txt",
8+
#: "%/tmp/test_up*/dsc/*.txt",
9+
#: "%/tmp/debug/*",
10+
#: "/tmp/core.*",
11+
#: ]
12+
#: skip_clone = true
13+
#:
14+
#: [dependencies.build]
15+
#: job = "build"
16+
17+
input="/input/build/work"
18+
19+
set -o errexit
20+
set -o pipefail
21+
set -o xtrace
22+
23+
banner cores
24+
pfexec coreadm -i /tmp/core.%f.%p \
25+
-g /tmp/core.%f.%p \
26+
-e global \
27+
-e log \
28+
-e proc-setid \
29+
-e global-setid
30+
31+
echo "input bins dir contains:"
32+
ls -ltr "$input"/bins || true
33+
34+
banner unpack
35+
mkdir -p /var/tmp/bins
36+
for t in "$input/bins/"*.gz; do
37+
b=$(basename "$t")
38+
b=${b%.gz}
39+
gunzip < "$t" > "/var/tmp/bins/$b"
40+
chmod +x "/var/tmp/bins/$b"
41+
done
42+
43+
export BINDIR=/var/tmp/bins
44+
45+
# Give this test one hour to finish
46+
jobpid=$$; (sleep $(( 60 * 60 )); banner fail-timeout; ps -ef; zfs list;kill $jobpid) &
47+
48+
echo "Setup debug logging"
49+
mkdir /tmp/debug
50+
psrinfo -v > /tmp/debug/psrinfo.txt
51+
df -h > /tmp/debug/df.txt || true
52+
prstat -d d -mLc 1 > /tmp/debug/prstat.txt 2>&1 &
53+
iostat -T d -xn 1 > /tmp/debug/iostat.txt 2>&1 &
54+
mpstat -T d 1 > /tmp/debug/mpstat.txt 2>&1 &
55+
vmstat -T d -p 1 < /dev/null > /tmp/debug/paging.txt 2>&1 &
56+
pfexec dtrace -Z -s $input/scripts/perf-downstairs-tick.d > /tmp/debug/dtrace.txt 2>&1 &
57+
pfexec dtrace -Z -s $input/scripts/upstairs_info.d > /tmp/debug/upstairs-info.txt 2>&1 &
58+
59+
banner test_up_encrypted
60+
ptime -m bash "$input/scripts/test_up.sh" -r 2 encrypted
61+
62+
echo "test-up-2region-encrypted ends"

.github/buildomat/jobs/test-up-encrypted.sh

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ done
4242

4343
export BINDIR=/var/tmp/bins
4444

45-
# Give this test two hours to finish
46-
jobpid=$$; (sleep $(( 120 * 60 )); banner fail-timeout; ps -ef; zfs list;kill $jobpid) &
45+
# Give this test one hour to finish
46+
jobpid=$$; (sleep $(( 60 * 60 )); banner fail-timeout; ps -ef; zfs list;kill $jobpid) &
4747

4848
echo "Setup debug logging"
4949
mkdir /tmp/debug

crutest/src/main.rs

+73-23
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ enum Workload {
114114
#[clap(flatten)]
115115
cfg: RandReadWriteWorkload,
116116
},
117+
/// Run IO, and as soon as we get a final ACK, drop the volume to
118+
/// see if we can leave IOs outstanding on one of the downstairs.
119+
/// This test works best if one of the downstairs is running with
120+
/// lossy option set, which will make it go slower than the others.
117121
Repair,
118122
/// Test the downstairs replay path.
119123
/// Stop a downstairs, then run some IO, then start that downstairs back
@@ -1006,6 +1010,9 @@ async fn main() -> Result<()> {
10061010
let (volume, mut targets) =
10071011
make_a_volume(&opt, volume_logger.clone(), &test_log, pr).await?;
10081012

1013+
let downstairs_in_volume = targets.len() - (targets.len() % 3);
1014+
info!(test_log, "Downstairs in volume = {downstairs_in_volume}");
1015+
10091016
if let Workload::CliServer { listen, port } = opt.workload {
10101017
cli::start_cli_server(
10111018
&volume,
@@ -1315,8 +1322,14 @@ async fn main() -> Result<()> {
13151322
bail!("Replay workload requires a dsc endpoint");
13161323
}
13171324
};
1318-
replay_workload(&volume, &mut wtq, &mut region_info, dsc_client)
1319-
.await?;
1325+
replay_workload(
1326+
&volume,
1327+
&mut wtq,
1328+
&mut region_info,
1329+
dsc_client,
1330+
downstairs_in_volume as u32,
1331+
)
1332+
.await?;
13201333
}
13211334
Workload::Replace {
13221335
fast_fill,
@@ -1367,6 +1380,18 @@ async fn main() -> Result<()> {
13671380
// Add to the list of targets for our volume the replacement
13681381
// target provided on the command line
13691382
targets.push(replacement);
1383+
1384+
// Verify the number of targets dsc has matches what the number
1385+
// of targets we found.
1386+
let res = dsc_client.dsc_get_region_count().await.unwrap();
1387+
let region_count = res.into_inner();
1388+
if region_count != targets.len() as u32 {
1389+
bail!(
1390+
"Downstairs targets:{} does not match dsc targets: {}",
1391+
region_count,
1392+
targets.len(),
1393+
);
1394+
}
13701395
replace_before_active(
13711396
&volume,
13721397
wtq,
@@ -1401,6 +1426,18 @@ async fn main() -> Result<()> {
14011426
// Add to the list of targets for our volume the replacement
14021427
// target provided on the command line
14031428
targets.push(replacement);
1429+
1430+
// Verify the number of targets dsc has matches what the number
1431+
// of targets we found.
1432+
let res = dsc_client.dsc_get_region_count().await.unwrap();
1433+
let region_count = res.into_inner();
1434+
if region_count != targets.len() as u32 {
1435+
bail!(
1436+
"Downstairs targets:{} does not match dsc targets: {}",
1437+
region_count,
1438+
targets.len(),
1439+
);
1440+
}
14041441
replace_while_reconcile(
14051442
&volume,
14061443
wtq,
@@ -1489,7 +1526,7 @@ async fn main() -> Result<()> {
14891526
return Ok(());
14901527
} else if opt.stable
14911528
&& wc.up_count + wc.ds_count == 0
1492-
&& wc.active_count == 3
1529+
&& wc.active_count == downstairs_in_volume
14931530
{
14941531
println!("CLIENT: All jobs finished, all DS active.");
14951532
return Ok(());
@@ -2211,13 +2248,14 @@ async fn replay_workload(
22112248
wtq: &mut WhenToQuit,
22122249
ri: &mut RegionInfo,
22132250
dsc_client: Client,
2251+
ds_count: u32,
22142252
) -> Result<()> {
22152253
let mut rng = rand_chacha::ChaCha8Rng::from_entropy();
22162254
let mut generic_wtq = WhenToQuit::Count { count: 300 };
22172255

22182256
for c in 1.. {
22192257
// Pick a DS at random
2220-
let stopped_ds = rng.gen_range(0..3);
2258+
let stopped_ds = rng.gen_range(0..ds_count);
22212259
dsc_client.dsc_stop(stopped_ds).await.unwrap();
22222260
loop {
22232261
let res = dsc_client.dsc_get_ds_state(stopped_ds).await.unwrap();
@@ -2290,10 +2328,12 @@ async fn replace_while_reconcile(
22902328
mut gen: u64,
22912329
log: Logger,
22922330
) -> Result<()> {
2293-
assert!(targets.len() == 4);
2331+
assert!(targets.len() % 3 == 1);
22942332

2333+
// The total number of downstairs we have that are part of the Volume.
2334+
let ds_total = targets.len() - 1;
22952335
let mut old_ds = 0;
2296-
let mut new_ds = 3;
2336+
let mut new_ds = targets.len() - 1;
22972337
let mut c = 1;
22982338
// How long we wait for reconcile to start before we replace
22992339
let mut active_wait = 6;
@@ -2431,15 +2471,15 @@ async fn replace_while_reconcile(
24312471
wc.ds_count,
24322472
wc.active_count
24332473
);
2434-
if wc.up_count + wc.ds_count == 0 && wc.active_count == 3 {
2435-
info!(log, "[{c}] Replay: All jobs finished, all DS active.");
2474+
if wc.up_count + wc.ds_count == 0 && wc.active_count == ds_total {
2475+
info!(log, "[{c}] All jobs finished, all DS active.");
24362476
break;
24372477
}
24382478
tokio::time::sleep(tokio::time::Duration::from_secs(4)).await;
24392479
}
24402480

2441-
old_ds = (old_ds + 1) % 4;
2442-
new_ds = (new_ds + 1) % 4;
2481+
old_ds = (old_ds + 1) % (ds_total as u32 + 1);
2482+
new_ds = (new_ds + 1) % (ds_total + 1);
24432483

24442484
c += 1;
24452485
match wtq {
@@ -2485,11 +2525,18 @@ async fn replace_before_active(
24852525
mut gen: u64,
24862526
log: Logger,
24872527
) -> Result<()> {
2488-
assert!(targets.len() == 4);
2528+
assert!(targets.len() % 3 == 1);
24892529

24902530
info!(log, "Begin replacement before activation test");
2531+
// We need to start from a known state and be sure that all three of the
2532+
// current downstairs are consistent with each other. To guarantee this
2533+
// we write to every block, then flush, then read. This way we know
2534+
// that the initial downstairs are all synced up on the same flush and
2535+
// generation numbers.
2536+
fill_workload(volume, ri, true).await?;
2537+
let ds_total = targets.len() - 1;
24912538
let mut old_ds = 0;
2492-
let mut new_ds = 3;
2539+
let mut new_ds = targets.len() - 1;
24932540
for c in 1.. {
24942541
info!(log, "[{c}] Touch every extent");
24952542
fill_sparse_workload(volume.as_ref(), ri).await?;
@@ -2586,15 +2633,15 @@ async fn replace_before_active(
25862633
wc.ds_count,
25872634
wc.active_count
25882635
);
2589-
if wc.up_count + wc.ds_count == 0 && wc.active_count == 3 {
2590-
info!(log, "[{c}] Replay: All jobs finished, all DS active.");
2636+
if wc.up_count + wc.ds_count == 0 && wc.active_count == ds_total {
2637+
info!(log, "[{c}] All jobs finished, all DS active.");
25912638
break;
25922639
}
25932640
tokio::time::sleep(tokio::time::Duration::from_secs(4)).await;
25942641
}
25952642

2596-
old_ds = (old_ds + 1) % 4;
2597-
new_ds = (new_ds + 1) % 4;
2643+
old_ds = (old_ds + 1) % (ds_total as u32 + 1);
2644+
new_ds = (new_ds + 1) % (ds_total + 1);
25982645

25992646
match wtq {
26002647
WhenToQuit::Count { count } => {
@@ -2637,7 +2684,10 @@ async fn replace_workload(
26372684
targets: Vec<SocketAddr>,
26382685
fill: bool,
26392686
) -> Result<()> {
2640-
assert!(targets.len() == 4);
2687+
assert!(targets.len() % 3 == 1);
2688+
2689+
// The total number of downstairs we have that are part of the Volume.
2690+
let ds_total = targets.len() - 1;
26412691

26422692
if fill {
26432693
fill_sparse_workload(volume.as_ref(), ri).await?;
@@ -2656,7 +2706,7 @@ async fn replace_workload(
26562706
let volume_c = volume.clone();
26572707
let handle = tokio::spawn(async move {
26582708
let mut old_ds = 0;
2659-
let mut new_ds = 3;
2709+
let mut new_ds = ds_total;
26602710
let mut c = 1;
26612711
loop {
26622712
println!(
@@ -2678,7 +2728,7 @@ async fn replace_workload(
26782728
}
26792729
// Wait for the replacement to be reflected in the downstairs status.
26802730
let mut wc = volume_c.show_work().await?;
2681-
while wc.active_count == 3 {
2731+
while wc.active_count == ds_total {
26822732
// Wait for one of the DS to start repair
26832733
println!(
26842734
"[{c}] Waiting for replace to start: up:{} ds:{} act:{}",
@@ -2689,7 +2739,7 @@ async fn replace_workload(
26892739
}
26902740

26912741
// We have started live repair, now wait for it to finish.
2692-
while wc.active_count != 3 {
2742+
while wc.active_count != ds_total {
26932743
println!(
26942744
"[{c}] Waiting for replace to finish: up:{} ds:{} act:{}",
26952745
wc.up_count, wc.ds_count, wc.active_count
@@ -2714,8 +2764,8 @@ async fn replace_workload(
27142764
}
27152765

27162766
// No stopping yet, let's do another loop.
2717-
old_ds = (old_ds + 1) % 4;
2718-
new_ds = (new_ds + 1) % 4;
2767+
old_ds = (old_ds + 1) % (ds_total + 1);
2768+
new_ds = (new_ds + 1) % (ds_total + 1);
27192769
c += 1;
27202770
}
27212771
println!("Replace tasks ends after {c} loops");
@@ -2771,7 +2821,7 @@ async fn replace_workload(
27712821
"Replace test done: up:{} ds:{} act:{}",
27722822
wc.up_count, wc.ds_count, wc.active_count
27732823
);
2774-
if wc.up_count + wc.ds_count == 0 && wc.active_count == 3 {
2824+
if wc.up_count + wc.ds_count == 0 && wc.active_count == ds_total {
27752825
println!("Replace: All jobs finished, all DS active.");
27762826
break;
27772827
}

tools/dtrace/single_up_info.d

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ crucible_upstairs*:::up-status
4141
* I'm not very happy about this, but if we don't print it all on one
4242
* line, then multiple sessions will clobber each others output.
4343
*/
44-
printf("%8s %17s %17s %17s %5s %5s %9s %5s %10s %5s %5s %5s %5s %5s %5s %5s %5s %5s %5s %5s %5s %5s %5s %5s %5s %5s %5s\n",
44+
printf("%8s %17s %17s %17s %5s %5s %9s %5s %10s %5s %5s %5s %5s %5s %5s %5s %5s %5s %5s %5s %5s %5s %5s %5s\n",
4545

4646
substr(session_id, 0, 8),
4747

tools/test_fail_live_repair.sh

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66
# `pstop` or kill the downstairs process
77
# wait for missing downstairs to be faulted
88
# `pstart` or restart the downstairs
9-
# Let the repair start.
9+
# Let the live repair start.
1010
# `pstop` or kill the same downstairs again.
1111
# wait for missing downstairs to be faulted again
1212
# `pstart` or restart the downstairs again
13-
# Let the upstairs repair start over and finish.
13+
# Let the upstairs live repair start over and finish.
1414
# Stop crutest, then restart and verify the whole disk.
1515

1616
err=0

tools/test_repair.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/bin/bash
22

3-
# A test to break, then Repair a downstairs region that is out of sync with
3+
# A test to break, then reconcile a downstairs region that is out of sync with
44
# the other regions. We pick a downstairs at random and restart it with
55
# the --lossy flag, meaning it will skip some IO requests (and have to
66
# come back and do them later) and will introduce some delay in completing

0 commit comments

Comments
 (0)