Skip to content

Commit 839c8eb

Browse files
leftwoAlan Hanson
and
Alan Hanson
authored
Add a clone option to downstairs create (#1249)
When creating a region, add the ability to optionally populate that region from an existing and running downstairs using the clone ability. This makes use of the already written clone subcommand functions, but calls them directly after creating the region. The current `clone` subcommand still exists and we can still use it directly if so desired. Changed some clap `name` to `value_name` as that is the proper arg for how we are using them. --------- Co-authored-by: Alan Hanson <[email protected]>
1 parent 5677c7b commit 839c8eb

File tree

3 files changed

+132
-15
lines changed

3 files changed

+132
-15
lines changed

downstairs/src/main.rs

+47-14
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ enum Args {
4747
/// the region here will be replaced.
4848
Clone {
4949
/// Directory where the region is located.
50-
#[clap(short, long, name = "DIRECTORY", action)]
50+
#[clap(short, long, value_name = "DIRECTORY", action)]
5151
data: PathBuf,
5252

5353
/// Source IP:Port where the extent files will come from.
@@ -58,26 +58,50 @@ enum Args {
5858
trace_endpoint: Option<String>,
5959
},
6060
Create {
61+
/// Block size.
6162
#[clap(long, default_value = "512", action)]
6263
block_size: u64,
6364

64-
#[clap(short, long, name = "DIRECTORY", action)]
65+
/// Directory where the region files we be located.
66+
#[clap(short, long, value_name = "DIRECTORY", action)]
6567
data: PathBuf,
6668

69+
/// Number of blocks per extent file.
6770
#[clap(long, default_value = "100", action)]
6871
extent_size: u64,
6972

73+
/// Number of extent files.
7074
#[clap(long, default_value = "15", action)]
7175
extent_count: u64,
7276

73-
#[clap(short, long, name = "FILE", action)]
77+
/// Import data for the extent from this file.
78+
#[clap(
79+
short,
80+
long,
81+
value_name = "FILE",
82+
action,
83+
conflicts_with = "clone_source"
84+
)]
7485
import_path: Option<PathBuf>,
7586

76-
#[clap(short, long, name = "UUID", action)]
87+
/// UUID for the region.
88+
#[clap(short, long, value_name = "UUID", action)]
7789
uuid: Uuid,
7890

91+
/// Will the region be encrypted.
7992
#[clap(long, action)]
8093
encrypted: bool,
94+
95+
/// Clone another downstairs after creating.
96+
///
97+
/// IP:Port where the extent files will come from.
98+
#[clap(
99+
long,
100+
value_name = "SOURCE",
101+
action,
102+
conflicts_with = "import_path"
103+
)]
104+
clone_source: Option<SocketAddr>,
81105
},
82106
/*
83107
* Dump region information.
@@ -90,7 +114,7 @@ enum Args {
90114
/*
91115
* Directories containing a region.
92116
*/
93-
#[clap(short, long, name = "DIRECTORY", action)]
117+
#[clap(short, long, value_name = "DIRECTORY", action)]
94118
data: Vec<PathBuf>,
95119

96120
/*
@@ -119,16 +143,16 @@ enum Args {
119143
/*
120144
* Number of blocks to export.
121145
*/
122-
#[clap(long, default_value = "0", name = "COUNT", action)]
146+
#[clap(long, default_value = "0", value_name = "COUNT", action)]
123147
count: u64,
124148

125-
#[clap(short, long, name = "DIRECTORY", action)]
149+
#[clap(short, long, value_name = "DIRECTORY", action)]
126150
data: PathBuf,
127151

128-
#[clap(short, long, name = "OUT_FILE", action)]
152+
#[clap(short, long, value_name = "OUT_FILE", action)]
129153
export_path: PathBuf,
130154

131-
#[clap(short, long, default_value = "0", name = "SKIP", action)]
155+
#[clap(short, long, default_value = "0", value_name = "SKIP", action)]
132156
skip: u64,
133157
},
134158
Run {
@@ -137,13 +161,13 @@ enum Args {
137161
short,
138162
long,
139163
default_value = "0.0.0.0",
140-
name = "ADDRESS",
164+
value_name = "ADDRESS",
141165
action
142166
)]
143167
address: IpAddr,
144168

145169
/// Directory where the region is located.
146-
#[clap(short, long, name = "DIRECTORY", action)]
170+
#[clap(short, long, value_name = "DIRECTORY", action)]
147171
data: PathBuf,
148172

149173
/// Test option, makes the search for new work sleep and sometimes
@@ -156,7 +180,7 @@ enum Args {
156180
* oximeter server, the downstairs will publish stats.
157181
*/
158182
/// Use this address:port to send stats to an Oximeter server.
159-
#[clap(long, name = "OXIMETER_ADDRESS:PORT", action)]
183+
#[clap(long, value_name = "OXIMETER_ADDRESS:PORT", action)]
160184
oximeter: Option<SocketAddr>,
161185

162186
/// Listen on this port for the upstairs to connect to us.
@@ -204,7 +228,7 @@ enum Args {
204228
#[clap(long, default_value_t = 512)]
205229
block_size: u64,
206230

207-
#[clap(short, long, name = "DIRECTORY")]
231+
#[clap(short, long, value_name = "DIRECTORY")]
208232
data: PathBuf,
209233

210234
#[clap(long, default_value_t = 100)]
@@ -287,10 +311,11 @@ async fn main() -> Result<()> {
287311
import_path,
288312
uuid,
289313
encrypted,
314+
clone_source,
290315
} => {
291316
let mut region = create_region(
292317
block_size,
293-
data,
318+
data.clone(),
294319
extent_size,
295320
extent_count,
296321
uuid,
@@ -306,6 +331,13 @@ async fn main() -> Result<()> {
306331
* new data and inital flush number is written to disk.
307332
*/
308333
region.region_flush(1, 0, &None, JobId(0), None).await?;
334+
} else if let Some(ref clone_source) = clone_source {
335+
info!(log, "Cloning from: {:?}", clone_source);
336+
let d = Downstairs::new_builder(&data, false)
337+
.set_logger(log.clone())
338+
.build()
339+
.await?;
340+
clone_region(d, *clone_source).await?
309341
}
310342

311343
info!(log, "UUID: {:?}", region.def().uuid());
@@ -315,6 +347,7 @@ async fn main() -> Result<()> {
315347
region.def().extent_size().value,
316348
region.def().extent_count(),
317349
);
350+
// Now, clone it!
318351
Ok(())
319352
}
320353
Args::Dump {

integration_tests/src/lib.rs

+76
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ mod test {
3838
}
3939

4040
impl TestDownstairs {
41+
#[allow(clippy::too_many_arguments)]
4142
pub async fn new(
4243
address: IpAddr,
4344
encrypted: bool,
@@ -46,6 +47,7 @@ mod test {
4647
extent_count: u32,
4748
problematic: bool,
4849
backend: Backend,
50+
clone_source: Option<SocketAddr>,
4951
) -> Result<Self> {
5052
let tempdir = tempfile::Builder::new()
5153
.prefix(&"downstairs-")
@@ -74,6 +76,10 @@ mod test {
7476
.build()
7577
.await?;
7678

79+
if let Some(ref clone_source) = clone_source {
80+
clone_region(downstairs.clone(), *clone_source).await?
81+
}
82+
7783
let _join_handle = start_downstairs(
7884
downstairs.clone(),
7985
address,
@@ -252,6 +258,7 @@ mod test {
252258
extent_count,
253259
problematic,
254260
backend,
261+
None,
255262
)
256263
.await?;
257264
let downstairs2 = TestDownstairs::new(
@@ -262,6 +269,7 @@ mod test {
262269
extent_count,
263270
problematic,
264271
backend,
272+
None,
265273
)
266274
.await?;
267275
let downstairs3 = TestDownstairs::new(
@@ -272,6 +280,7 @@ mod test {
272280
extent_count,
273281
problematic,
274282
backend,
283+
None,
275284
)
276285
.await?;
277286

@@ -360,6 +369,7 @@ mod test {
360369
self.extent_count,
361370
false,
362371
Backend::RawFile,
372+
None,
363373
)
364374
.await
365375
}
@@ -2657,6 +2667,9 @@ mod test {
26572667
// Clone a read only downstairs to the new downstairs
26582668
// Make a new volume with two old and the one new downstairs and verify
26592669
// the original data we wrote.
2670+
// Create a new downstairs directly from the clone.
2671+
// Make a new volume with two old and the one new downstairs and verify
2672+
// the original data we wrote.
26602673
const BLOCK_SIZE: usize = 512;
26612674

26622675
// boot three downstairs, write some data to them, then change to
@@ -2708,6 +2721,7 @@ mod test {
27082721
2,
27092722
false,
27102723
Backend::RawFile,
2724+
None,
27112725
)
27122726
.await
27132727
.unwrap();
@@ -2751,6 +2765,56 @@ mod test {
27512765

27522766
assert_eq!(&buffer[BLOCK_SIZE..], &random_buffer[BLOCK_SIZE..]);
27532767

2768+
// Clone an original downstairs directly to our new downstairs
2769+
let clone_source =
2770+
test_downstairs_set.downstairs1.repair_address().await;
2771+
let mut new_ds = TestDownstairs::new(
2772+
"127.0.0.1".parse().unwrap(),
2773+
true,
2774+
true,
2775+
5,
2776+
2,
2777+
false,
2778+
Backend::RawFile,
2779+
Some(clone_source),
2780+
)
2781+
.await
2782+
.unwrap();
2783+
2784+
// Restart the new downstairs read only.
2785+
new_ds.reboot_read_only().await.unwrap();
2786+
let new_target = new_ds.address().await;
2787+
2788+
// Take our original opts, and replace a target with the downstairs
2789+
// we just cloned.
2790+
let mut new_opts = test_downstairs_set.opts();
2791+
new_opts.target[0] = new_target;
2792+
2793+
let mut volume = Volume::new(BLOCK_SIZE as u64, csl());
2794+
volume
2795+
.add_subvolume_create_guest(
2796+
new_opts,
2797+
volume::RegionExtentInfo {
2798+
block_size: BLOCK_SIZE as u64,
2799+
blocks_per_extent: test_downstairs_set.blocks_per_extent(),
2800+
extent_count: test_downstairs_set.extent_count(),
2801+
},
2802+
3,
2803+
None,
2804+
)
2805+
.await?;
2806+
2807+
volume.activate().await?;
2808+
2809+
// Verify our volume still has the random data we wrote.
2810+
let volume_size = volume.total_size().await? as usize;
2811+
let mut buffer = Buffer::new(volume_size / BLOCK_SIZE, BLOCK_SIZE);
2812+
volume
2813+
.read(Block::new(0, BLOCK_SIZE.trailing_zeros()), &mut buffer)
2814+
.await?;
2815+
2816+
assert_eq!(&buffer[BLOCK_SIZE..], &random_buffer[BLOCK_SIZE..]);
2817+
27542818
Ok(())
27552819
}
27562820

@@ -2823,6 +2887,7 @@ mod test {
28232887
2,
28242888
false,
28252889
Backend::RawFile,
2890+
None,
28262891
)
28272892
.await
28282893
.unwrap();
@@ -2884,6 +2949,7 @@ mod test {
28842949
2,
28852950
false,
28862951
Backend::RawFile,
2952+
None,
28872953
)
28882954
.await
28892955
.unwrap();
@@ -2918,6 +2984,7 @@ mod test {
29182984
2,
29192985
false,
29202986
Backend::RawFile,
2987+
None,
29212988
)
29222989
.await
29232990
.unwrap();
@@ -2951,6 +3018,7 @@ mod test {
29513018
3,
29523019
false,
29533020
Backend::RawFile,
3021+
None,
29543022
)
29553023
.await
29563024
.unwrap();
@@ -2966,6 +3034,7 @@ mod test {
29663034
2, // <- Different than above
29673035
false,
29683036
Backend::RawFile,
3037+
None,
29693038
)
29703039
.await
29713040
.unwrap();
@@ -2987,6 +3056,7 @@ mod test {
29873056
2,
29883057
false,
29893058
Backend::RawFile,
3059+
None,
29903060
)
29913061
.await
29923062
.unwrap();
@@ -3002,6 +3072,7 @@ mod test {
30023072
2,
30033073
false,
30043074
Backend::RawFile,
3075+
None,
30053076
)
30063077
.await
30073078
.unwrap();
@@ -3023,6 +3094,7 @@ mod test {
30233094
2,
30243095
false,
30253096
Backend::RawFile,
3097+
None,
30263098
)
30273099
.await
30283100
.unwrap();
@@ -3037,6 +3109,7 @@ mod test {
30373109
2,
30383110
false,
30393111
Backend::RawFile,
3112+
None,
30403113
)
30413114
.await
30423115
.unwrap();
@@ -3058,6 +3131,7 @@ mod test {
30583131
2,
30593132
false,
30603133
Backend::RawFile,
3134+
None,
30613135
)
30623136
.await
30633137
.unwrap();
@@ -3072,6 +3146,7 @@ mod test {
30723146
2,
30733147
false,
30743148
Backend::RawFile,
3149+
None,
30753150
)
30763151
.await
30773152
.unwrap();
@@ -3244,6 +3319,7 @@ mod test {
32443319
2,
32453320
false,
32463321
Backend::RawFile,
3322+
None,
32473323
)
32483324
.await
32493325
.unwrap();

0 commit comments

Comments
 (0)