Skip to content

Commit 3623158

Browse files
mayastor-borshrudaya21
mayastor-bors
andcommitted
Merge #1570
1570: feat(multireplicasnapshot): remove multi replica snapshot checks in dataplane r=hrudaya21 a=hrudaya21 Co-authored-by: Hrudaya <hrudayaranjan.sahoo@datacore.com>
2 parents 47a632e + bdfbb67 commit 3623158

File tree

4 files changed

+230
-75
lines changed

4 files changed

+230
-75
lines changed

io-engine-tests/src/nexus.rs

+49-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use super::{
1919
RemoveChildNexusRequest,
2020
ShutdownNexusRequest,
2121
},
22+
snapshot::SnapshotInfo,
2223
SharedRpcHandle,
2324
Status,
2425
},
@@ -33,10 +34,21 @@ use super::{
3334
},
3435
replica::ReplicaBuilder,
3536
};
36-
use io_engine::{constants::NVME_NQN_PREFIX, subsys::make_subsystem_serial};
37+
use io_engine::{
38+
constants::NVME_NQN_PREFIX,
39+
core::{SnapshotDescriptor, SnapshotParams},
40+
subsys::make_subsystem_serial,
41+
};
3742
use std::time::{Duration, Instant};
3843
use tonic::Code;
3944

45+
use io_engine_api::v1::snapshot::{
46+
ListSnapshotsRequest,
47+
NexusCreateSnapshotReplicaDescriptor,
48+
NexusCreateSnapshotReplicaStatus,
49+
NexusCreateSnapshotRequest,
50+
};
51+
4052
#[derive(Clone)]
4153
pub struct NexusBuilder {
4254
rpc: SharedRpcHandle,
@@ -264,6 +276,42 @@ impl NexusBuilder {
264276
self.add_child(&self.replica_uri(r), norebuild).await
265277
}
266278

279+
pub async fn create_nexus_snapshot(
280+
&self,
281+
params: &SnapshotParams,
282+
replicas: &[NexusCreateSnapshotReplicaDescriptor],
283+
) -> Result<Vec<NexusCreateSnapshotReplicaStatus>, Status> {
284+
self.rpc()
285+
.lock()
286+
.await
287+
.snapshot
288+
.create_nexus_snapshot(NexusCreateSnapshotRequest {
289+
nexus_uuid: self.uuid(),
290+
entity_id: params.entity_id().unwrap(),
291+
txn_id: params.txn_id().unwrap(),
292+
snapshot_name: params.name().unwrap(),
293+
replicas: replicas.to_vec(),
294+
})
295+
.await
296+
.map(|r| r.into_inner().replicas_done)
297+
}
298+
299+
pub async fn list_snapshot(&self) -> Vec<SnapshotInfo> {
300+
self.rpc()
301+
.lock()
302+
.await
303+
.snapshot
304+
.list_snapshot(ListSnapshotsRequest {
305+
source_uuid: None,
306+
snapshot_uuid: None,
307+
query: None,
308+
})
309+
.await
310+
.map(|s| s.into_inner().snapshots)
311+
.ok()
312+
.unwrap()
313+
}
314+
267315
pub async fn remove_child_bdev(&self, bdev: &str) -> Result<Nexus, Status> {
268316
self.rpc()
269317
.lock()

io-engine/src/bdev/nexus/nexus_bdev_snapshot.rs

+6-25
Original file line numberDiff line numberDiff line change
@@ -267,24 +267,13 @@ impl ReplicaSnapshotExecutor {
267267
impl<'n> Nexus<'n> {
268268
fn check_nexus_state(&self) -> Result<(), Error> {
269269
self.check_nexus_operation(NexusOperation::NexusSnapshot)?;
270-
271-
// Check that nexus has exactly 1 replica.
272-
match self.children().len() {
273-
0 => {
274-
return Err(Error::FailedCreateSnapshot {
275-
name: self.bdev_name(),
276-
reason: "Nexus has no replicas".to_string(),
277-
})
278-
}
279-
1 => {} // Only one replica nexuses are supported.
280-
_ => {
281-
return Err(Error::FailedCreateSnapshot {
282-
name: self.bdev_name(),
283-
reason: "Nexus has more than one replica".to_string(),
284-
})
285-
}
270+
// Check that nexus has no children.
271+
if self.children().is_empty() {
272+
return Err(Error::FailedCreateSnapshot {
273+
name: self.bdev_name(),
274+
reason: "Nexus has no replicas".to_string(),
275+
});
286276
}
287-
288277
// Check that nexus is healthy and not being reconfigured.
289278
let state = *self.state.lock();
290279
if state != NexusState::Open {
@@ -332,14 +321,6 @@ impl<'n> Nexus<'n> {
332321

333322
self.check_nexus_state()?;
334323

335-
// For now only single replica nexus is supported.
336-
if self.children_iter().len() != 1 {
337-
return Err(Error::FailedCreateSnapshot {
338-
name: self.bdev_name(),
339-
reason: "Nexus has more than one replica".to_string(),
340-
});
341-
}
342-
343324
// Step 1: Pause I/O subsystem for nexus.
344325
self.as_mut().pause().await.map_err(|error| {
345326
error!(

io-engine/src/bin/io-engine-client/v1/snapshot_cli.rs

+17-7
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,9 @@ pub fn subcommands() -> Command {
172172
.subcommand(create_clone)
173173
.subcommand(list_clone)
174174
}
175-
175+
/// For multiple replicas, replica_uuid will be given in a single string,
176+
/// separated by comma. Same for snapshot_uuid. replica_uuid and snapshot_uuid
177+
/// will be matched by index.
176178
async fn create_for_nexus(
177179
mut ctx: Context,
178180
matches: &ArgMatches,
@@ -202,24 +204,32 @@ async fn create_for_nexus(
202204
})?
203205
.to_owned();
204206
let replica_uuid = matches
205-
.get_many::<String>("replica_uuid")
207+
.get_one::<String>("replica_uuid")
206208
.ok_or_else(|| ClientError::MissingValue {
207209
field: "replica_uuid".to_string(),
208210
})?
209-
.map(|c| c.to_string())
210-
.collect::<Vec<String>>();
211+
.to_owned();
211212
let snapshot_uuid = matches
212-
.get_many::<String>("snapshot_uuid")
213+
.get_one::<String>("snapshot_uuid")
213214
.ok_or_else(|| ClientError::MissingValue {
214215
field: "snapshot_uuid".to_string(),
215216
})?
216-
.cloned()
217-
.collect::<Vec<_>>();
217+
.to_owned();
218+
219+
let replica_uuid: Vec<String> = replica_uuid
220+
.split(',')
221+
.map(|r| r.trim().to_string())
222+
.collect();
223+
let snapshot_uuid: Vec<String> = snapshot_uuid
224+
.split(',')
225+
.map(|s| s.trim().to_string())
226+
.collect();
218227
if replica_uuid.len() != snapshot_uuid.len() {
219228
return Err(ClientError::MissingValue {
220229
field: "Parameter count doesn't match between replica_uuid and snapshot_uuid".to_string()
221230
});
222231
}
232+
223233
let replicas: Vec<v1_rpc::snapshot::NexusCreateSnapshotReplicaDescriptor> =
224234
replica_uuid
225235
.into_iter()

io-engine/tests/snapshot_nexus.rs

+158-42
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,22 @@ use common::{
1111
bdev::ListBdevOptions,
1212
pool::CreatePoolRequest,
1313
replica::{CreateReplicaRequest, ListReplicaOptions},
14-
snapshot::{ListSnapshotsRequest, SnapshotInfo},
14+
snapshot::{
15+
ListSnapshotsRequest,
16+
NexusCreateSnapshotReplicaDescriptor,
17+
SnapshotInfo,
18+
},
1519
GrpcConnect,
1620
},
21+
Binary,
1722
Builder,
1823
ComposeTest,
1924
MayastorTest,
2025
},
26+
nexus::NexusBuilder,
2127
nvme::{list_mayastor_nvme_devices, nvme_connect, nvme_disconnect_all},
28+
pool::PoolBuilder,
29+
replica::ReplicaBuilder,
2230
};
2331

2432
use io_engine::{
@@ -319,47 +327,6 @@ async fn test_replica_handle_snapshot() {
319327
);
320328
}
321329

322-
#[tokio::test]
323-
async fn test_multireplica_nexus_snapshot() {
324-
let ms = get_ms();
325-
let (_test, urls) = launch_instance(true).await;
326-
327-
ms.spawn(async move {
328-
let nexus = create_nexus(&urls).await;
329-
330-
let snapshot_params = SnapshotParams::new(
331-
Some(String::from("e1")),
332-
Some(String::from("p1")),
333-
Some(Uuid::new_v4().to_string()),
334-
Some(String::from("s1")),
335-
Some(Uuid::new_v4().to_string()),
336-
Some(Utc::now().to_string()),
337-
false,
338-
);
339-
340-
let replicas = vec![
341-
NexusReplicaSnapshotDescriptor {
342-
replica_uuid: replica1_uuid(),
343-
skip: false,
344-
snapshot_uuid: Some(Uuid::new_v4().to_string()),
345-
},
346-
NexusReplicaSnapshotDescriptor {
347-
replica_uuid: replica2_uuid(),
348-
skip: false,
349-
snapshot_uuid: Some(Uuid::new_v4().to_string()),
350-
},
351-
];
352-
353-
nexus
354-
.create_snapshot(snapshot_params, replicas)
355-
.await
356-
.expect_err(
357-
"Snapshot successfully created for a multireplica nexus",
358-
);
359-
})
360-
.await;
361-
}
362-
363330
#[tokio::test]
364331
async fn test_list_no_snapshots() {
365332
let (test, _urls) = launch_instance(false).await;
@@ -1282,3 +1249,152 @@ async fn test_replica_listing_with_query() {
12821249
assert!(!replicas[0].is_clone && !replicas[0].is_snapshot);
12831250
assert!(!replicas[1].is_clone && !replicas[1].is_snapshot);
12841251
}
1252+
1253+
#[tokio::test]
1254+
async fn test_multireplica_nexus_snapshot() {
1255+
const POOL_SIZE: u64 = 60;
1256+
const REPL_SIZE: u64 = 22;
1257+
1258+
common::composer_init();
1259+
let test = Builder::new()
1260+
.name("cargo-test")
1261+
.network("10.1.0.0/16")
1262+
.unwrap()
1263+
.add_container_bin(
1264+
"ms_nexus",
1265+
Binary::from_dbg("io-engine").with_args(vec!["-l", "1"]),
1266+
)
1267+
.add_container_bin(
1268+
"ms_repl_1",
1269+
Binary::from_dbg("io-engine").with_args(vec!["-l", "2"]),
1270+
)
1271+
.add_container_bin(
1272+
"ms_repl_2",
1273+
Binary::from_dbg("io-engine").with_args(vec!["-l", "3"]),
1274+
)
1275+
.add_container_bin(
1276+
"ms_repl_3",
1277+
Binary::from_dbg("io-engine").with_args(vec!["-l", "4"]),
1278+
)
1279+
.with_clean(true)
1280+
.build()
1281+
.await
1282+
.unwrap();
1283+
1284+
let conn = GrpcConnect::new(&test);
1285+
let ms_nexus = conn.grpc_handle_shared("ms_nexus").await.unwrap();
1286+
let ms_repl_1 = conn.grpc_handle_shared("ms_repl_1").await.unwrap();
1287+
let ms_repl_2 = conn.grpc_handle_shared("ms_repl_2").await.unwrap();
1288+
let ms_repl_3 = conn.grpc_handle_shared("ms_repl_3").await.unwrap();
1289+
// Create Pool-1 and Replica-1.
1290+
let mut pool_1 = PoolBuilder::new(ms_repl_1.clone())
1291+
.with_name("pool1")
1292+
.with_new_uuid()
1293+
.with_malloc("mem1", POOL_SIZE);
1294+
1295+
let mut repl_1 = ReplicaBuilder::new(ms_repl_1.clone())
1296+
.with_pool(&pool_1)
1297+
.with_name("r1")
1298+
.with_new_uuid()
1299+
.with_size_mb(REPL_SIZE)
1300+
.with_thin(true);
1301+
1302+
pool_1.create().await.unwrap();
1303+
repl_1.create().await.unwrap();
1304+
repl_1.share().await.unwrap();
1305+
1306+
// Create Pool-2 and Replica-2.
1307+
let mut pool_2 = PoolBuilder::new(ms_repl_2.clone())
1308+
.with_name("pool2")
1309+
.with_new_uuid()
1310+
.with_malloc("mem2", POOL_SIZE);
1311+
1312+
let mut repl_2 = ReplicaBuilder::new(ms_repl_2.clone())
1313+
.with_pool(&pool_2)
1314+
.with_name("r2")
1315+
.with_new_uuid()
1316+
.with_size_mb(REPL_SIZE)
1317+
.with_thin(true);
1318+
1319+
pool_2.create().await.unwrap();
1320+
repl_2.create().await.unwrap();
1321+
repl_2.share().await.unwrap();
1322+
// Create Pool-3 and Replica-3.
1323+
let mut pool_3 = PoolBuilder::new(ms_repl_3.clone())
1324+
.with_name("pool3")
1325+
.with_new_uuid()
1326+
.with_malloc("mem3", POOL_SIZE);
1327+
1328+
let mut repl_3 = ReplicaBuilder::new(ms_repl_3.clone())
1329+
.with_pool(&pool_3)
1330+
.with_name("r3")
1331+
.with_new_uuid()
1332+
.with_size_mb(REPL_SIZE)
1333+
.with_thin(true);
1334+
1335+
pool_3.create().await.unwrap();
1336+
repl_3.create().await.unwrap();
1337+
repl_3.share().await.unwrap();
1338+
1339+
// Create nexus.
1340+
let mut nex_0 = NexusBuilder::new(ms_nexus.clone())
1341+
.with_name("nexus0")
1342+
.with_new_uuid()
1343+
.with_size_mb(REPL_SIZE)
1344+
.with_replica(&repl_1)
1345+
.with_replica(&repl_2)
1346+
.with_replica(&repl_3);
1347+
1348+
nex_0.create().await.unwrap();
1349+
nex_0.publish().await.unwrap();
1350+
1351+
let snapshot_params = SnapshotParams::new(
1352+
Some(String::from("e1")),
1353+
Some(String::from("p1")),
1354+
Some(Uuid::new_v4().to_string()),
1355+
Some(String::from("s1")),
1356+
Some(Uuid::new_v4().to_string()),
1357+
Some(Utc::now().to_string()),
1358+
false,
1359+
);
1360+
1361+
let mut replicas = vec![
1362+
NexusCreateSnapshotReplicaDescriptor {
1363+
replica_uuid: repl_1.uuid(),
1364+
snapshot_uuid: Some(Uuid::new_v4().to_string()),
1365+
skip: false,
1366+
},
1367+
NexusCreateSnapshotReplicaDescriptor {
1368+
replica_uuid: repl_2.uuid(),
1369+
snapshot_uuid: Some(Uuid::new_v4().to_string()),
1370+
skip: false,
1371+
},
1372+
];
1373+
// check for error when snapshot uuid is not provided for all replicas.
1374+
let result = nex_0
1375+
.create_nexus_snapshot(&snapshot_params, &replicas)
1376+
.await;
1377+
assert!(result.is_err());
1378+
1379+
replicas.push(NexusCreateSnapshotReplicaDescriptor {
1380+
replica_uuid: repl_2.uuid(),
1381+
snapshot_uuid: replicas[1].snapshot_uuid.clone(),
1382+
skip: false,
1383+
});
1384+
// check for error when snapshot uuid is duplicated.
1385+
let result = nex_0
1386+
.create_nexus_snapshot(&snapshot_params, &replicas)
1387+
.await;
1388+
assert!(result.is_err());
1389+
replicas.pop();
1390+
replicas.push(NexusCreateSnapshotReplicaDescriptor {
1391+
replica_uuid: repl_3.uuid(),
1392+
snapshot_uuid: Some(Uuid::new_v4().to_string()),
1393+
skip: false,
1394+
});
1395+
let snap_list = nex_0
1396+
.create_nexus_snapshot(&snapshot_params, &replicas)
1397+
.await
1398+
.unwrap();
1399+
assert_eq!(snap_list.len(), 3);
1400+
}

0 commit comments

Comments
 (0)