Skip to content

Commit

Permalink
Merge #1481
Browse files Browse the repository at this point in the history
1481: feat(clone): snapshot allocated bytes to be updated based on parent snapshot for clone r=hrudaya21 a=hrudaya21



Co-authored-by: Hrudaya <[email protected]>
  • Loading branch information
mayastor-bors and hrudaya21 committed Aug 11, 2023
2 parents e73e289 + aed1013 commit ac45bb4
Show file tree
Hide file tree
Showing 10 changed files with 163 additions and 16 deletions.
7 changes: 7 additions & 0 deletions io-engine/src/bin/io-engine-client/v1/replica_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,11 @@ async fn replica_list(
r.uri.clone(),
r.is_snapshot.to_string(),
r.is_clone.to_string(),
usage.allocated_bytes_snapshots.to_string(),
usage
.allocated_bytes_snapshot_from_clone
.unwrap_or_default()
.to_string(),
]
})
.collect();
Expand All @@ -331,6 +336,8 @@ async fn replica_list(
"URI",
"IS_SNAPSHOT",
"IS_CLONE",
"SNAP_ANCESTOR_SIZE",
"CLONE_SNAP_ANCESTOR_SIZE",
],
table,
);
Expand Down
4 changes: 3 additions & 1 deletion io-engine/src/bin/io-engine-client/v1/snapshot_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ async fn list(mut ctx: Context, matches: &ArgMatches<'_>) -> crate::Result<()> {
r.txn_id.clone(),
r.valid_snapshot.to_string(),
r.discarded_snapshot.to_string(),
r.referenced_bytes.to_string(),
]
})
.collect();
Expand All @@ -470,7 +471,8 @@ async fn list(mut ctx: Context, matches: &ArgMatches<'_>) -> crate::Result<()> {
"ENTITY_ID",
"TXN_ID",
"VALID_SNAPSHOT",
"discarded_SNAPSHOT",
"DISCARD_SNAPSHOT",
"ANCESTOR_SIZE",
],
table,
);
Expand Down
4 changes: 4 additions & 0 deletions io-engine/src/core/logical_volume.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::lvs::LvolSpaceUsage;
/// LogicalVolume Trait Provide all the Generic Interface for Volume
pub trait LogicalVolume {
type InnerPtr;
type BlobPtr;

/// Get lvol inner ptr.
fn as_inner_ptr(&self) -> Self::InnerPtr;
Expand Down Expand Up @@ -31,6 +32,9 @@ pub trait LogicalVolume {
/// Return the committed size of the Logical Volume in bytes.
fn committed(&self) -> u64;

/// Get BlobPtr from spdk_lvol.
fn blob_checked(&self) -> Self::BlobPtr;

/// Returns Lvol disk space usage
fn usage(&self) -> LvolSpaceUsage;
}
7 changes: 7 additions & 0 deletions io-engine/src/core/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,13 @@ pub trait SnapshotOps {
/// pool import, do the garbage collection to clean the discarded snapshots
/// leftout in the system.
async fn destroy_pending_discarded_snapshot();

/// If self is clone or a snapshot whose parent is clone, then do ancestor
/// calculation for all snapshot linked to clone.
fn calculate_clone_source_snap_usage(
&self,
total_ancestor_snap_size: u64,
) -> Option<u64>;
}

/// Traits gives the Snapshots Related Parameters.
Expand Down
2 changes: 2 additions & 0 deletions io-engine/src/grpc/v1/replica.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ impl From<LvolSpaceUsage> for ReplicaSpaceUsage {
allocated_bytes_snapshots: u.allocated_bytes_snapshots,
num_allocated_clusters_snapshots: u
.num_allocated_clusters_snapshots,
allocated_bytes_snapshot_from_clone: u
.allocated_bytes_snapshot_from_clone,
}
}
}
Expand Down
10 changes: 8 additions & 2 deletions io-engine/src/grpc/v1/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,10 @@ impl From<ReplicaSnapshotDescriptor> for SnapshotInfo {
txn_id: snapshot_param.txn_id().unwrap_or_default(),
valid_snapshot: true,
ready_as_source: SNAPSHOT_READY_AS_SOURCE,
referenced_bytes: usage.allocated_bytes_snapshots,
referenced_bytes: match usage.allocated_bytes_snapshot_from_clone {
Some(size) => size,
_ => usage.allocated_bytes_snapshots,
},
discarded_snapshot: snapshot_param.discarded_snapshot(),
}
}
Expand Down Expand Up @@ -189,7 +192,10 @@ impl From<VolumeSnapshotDescriptor> for SnapshotInfo {
txn_id: s.snapshot_params().txn_id().unwrap_or_default(),
valid_snapshot: s.valid_snapshot(),
ready_as_source: SNAPSHOT_READY_AS_SOURCE,
referenced_bytes: usage.allocated_bytes_snapshots,
referenced_bytes: match usage.allocated_bytes_snapshot_from_clone {
Some(size) => size,
_ => usage.allocated_bytes_snapshots,
},
discarded_snapshot: s.snapshot_params().discarded_snapshot(),
}
}
Expand Down
40 changes: 40 additions & 0 deletions io-engine/src/lvs/lvol_snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -752,4 +752,44 @@ impl SnapshotOps for Lvol {
}
}
}
// if self is clone or a snapshot whose parent is clone, then do ancestor
// calculation for all snapshot linked to clone.
fn calculate_clone_source_snap_usage(
&self,
total_ancestor_snap_size: u64,
) -> Option<u64> {
// if self is snapshot created from clone.
if self.is_snapshot() {
match UntypedBdev::lookup_by_uuid_str(
&Lvol::get_blob_xattr(self, SnapshotXattrs::ParentId.name())
.unwrap_or_default(),
) {
Some(bdev) => match Lvol::try_from(bdev) {
Ok(l) => match l.is_snapshot_clone() {
Some(parent_snap_lvol) => {
let usage = parent_snap_lvol.usage();
Some(
total_ancestor_snap_size
- (usage.allocated_bytes_snapshots
+ usage.allocated_bytes),
)
}
None => None,
},
_ => None,
},
_ => None,
}
// if self is clone.
} else if self.is_snapshot_clone().is_some() {
Some(
self.list_snapshot_by_source_uuid()
.iter()
.map(|v| v.snapshot_lvol().usage().allocated_bytes)
.sum(),
)
} else {
None
}
}
}
38 changes: 26 additions & 12 deletions io-engine/src/lvs/lvs_lvol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ pub struct LvolSpaceUsage {
pub allocated_bytes_snapshots: u64,
/// Number of clusters allocated by snapshots of this volume.
pub num_allocated_clusters_snapshots: u64,
/// Actual Amount of disk space allocated by snapshot which is created from
/// clone.
pub allocated_bytes_snapshot_from_clone: Option<u64>,
}
#[derive(Clone)]
/// struct representing an lvol
Expand Down Expand Up @@ -274,14 +277,6 @@ impl Lvol {
unsafe { self.inner.as_ref() }
}

/// TODO
#[inline(always)]
fn blob_checked(&self) -> *mut spdk_blob {
let blob = self.as_inner_ref().blob;
assert!(!blob.is_null());
blob
}

/// Wipe the first 8MB if unmap is not supported on failure the operation
/// needs to be repeated.
pub async fn wipe_super(&self) -> Result<(), Error> {
Expand Down Expand Up @@ -602,6 +597,7 @@ pub trait LvsLvol: LogicalVolume + Share {
/// LogicalVolume implement Generic interface for Lvol.
impl LogicalVolume for Lvol {
type InnerPtr = *mut spdk_lvol;
type BlobPtr = *mut spdk_blob;

/// Get lvol inner ptr.
fn as_inner_ptr(&self) -> Self::InnerPtr {
Expand Down Expand Up @@ -642,14 +638,20 @@ impl LogicalVolume for Lvol {
self.as_bdev().size_in_bytes()
}

/// Get BlobPtr from spdk_lvol.
fn blob_checked(&self) -> Self::BlobPtr {
let blob = self.as_inner_ref().blob;
assert!(!blob.is_null());
blob
}

/// Return the committed size of the Logical Volume in bytes.
fn committed(&self) -> u64 {
match self.is_snapshot() {
true => self.usage().allocated_bytes,
false => self.size(),
}
}

/// Returns Lvol disk space usage.
fn usage(&self) -> LvolSpaceUsage {
let bs = self.lvs().blob_store();
Expand All @@ -673,16 +675,28 @@ impl LogicalVolume for Lvol {
}
}
};

let allocated_bytes_snapshots =
cluster_size * num_allocated_clusters_snapshots;
LvolSpaceUsage {
capacity_bytes: self.size(),
allocated_bytes: cluster_size * num_allocated_clusters,
cluster_size,
num_clusters,
num_allocated_clusters,
num_allocated_clusters_snapshots,
allocated_bytes_snapshots: cluster_size
* num_allocated_clusters_snapshots,
allocated_bytes_snapshots,
// If there are multiple snapshots created from replica and
// then a clone is created from snapshot, following multiple
// snapshots created from clones in following sequence,
// R1 => S1 -> S2 => S3 => C1 => S4 => S5
// For S5, allocated_bytes_snapshots will be S1+S2+S3+S4+S5
// Where as allocated_bytes_snapshot_from_clone will S4 + S5
// for the clone C1. For S5 allocated_bytes_snapshot_from_clone
// will consider ancestor value from C1.
allocated_bytes_snapshot_from_clone: self
.calculate_clone_source_snap_usage(
allocated_bytes_snapshots,
),
}
}
}
Expand Down
65 changes: 65 additions & 0 deletions io-engine/tests/snapshot_lvol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -878,6 +878,71 @@ async fn test_snapshot_referenced_size() {
2 * cluster_size,
"Snapshot size doesn't properly reflect wiped superblock"
);

// If snapshot is created from clone, the allocated bytes for these
// snapshot will not carry size calculation from parent snapshot of clone.

let clone_name = String::from("lvol8_snap2_clone_1");
let clone_uuid = Uuid::new_v4().to_string();
let source_uuid = snap_lvol.uuid();

let clone_param = CloneParams::new(
Some(clone_name),
Some(clone_uuid),
Some(source_uuid),
Some(Utc::now().to_string()),
);
let clone1 = snap_lvol
.create_clone(clone_param.clone())
.await
.expect("Failed to create a clone");
check_clone(clone1.clone(), clone_param).await;

bdev_io::write_some("lvol8_snap2_clone_1", 0, 16, 0xccu8)
.await
.expect("Failed to write data to volume");

let clone_1_snapshot1 = "lvol8_clone_1_snapshot1".to_string();
snapshot_params.set_name(clone_1_snapshot1.clone());
snapshot_params.set_snapshot_uuid(Uuid::new_v4().to_string());
snapshot_params.set_parent_id(clone1.uuid());
clone1.clone().create_snapshot(snapshot_params.clone())
.await
.expect("Failed to create the second snapshot for test volume");
let clone_snap_lvol = find_snapshot_device(&clone_1_snapshot1)
.await
.expect("Can't lookup snapshot lvol");
assert_eq!(
clone_snap_lvol.usage().allocated_bytes_snapshot_from_clone.unwrap_or_default(),
0,
"Clone Snapshot allocated size should not include snapshot created from the original replica before clone"
);
let mut total_clone_snapshot_alloc = clone_snap_lvol.usage().allocated_bytes;
bdev_io::write_some("lvol8_snap2_clone_1", 0, 16, 0xccu8)
.await
.expect("Failed to write data to volume");

let clone_1_snapshot2 = "lvol8_clone_1_snapshot2".to_string();
snapshot_params.set_name(clone_1_snapshot2.clone());
snapshot_params.set_snapshot_uuid(Uuid::new_v4().to_string());
snapshot_params.set_parent_id(clone1.uuid());
clone1.clone().create_snapshot(snapshot_params.clone())
.await
.expect("Failed to create the second snapshot for test volume");
let clone_snap_lvol = find_snapshot_device(&clone_1_snapshot2)
.await
.expect("Can't lookup snapshot lvol");
total_clone_snapshot_alloc += clone_snap_lvol.usage().allocated_bytes;
assert_eq!(
clone_snap_lvol.usage().allocated_bytes_snapshot_from_clone.unwrap_or_default(),
cluster_size,
"Clone Snapshot allocated size should not include snapshot created from the original replica before clone"
);
assert_eq!(
total_clone_snapshot_alloc,
clone1.usage().allocated_bytes_snapshot_from_clone.unwrap_or_default(),
"Clone Snapshot allocated size should not include snapshot created from the original replica before clone"
);
})
.await;
}
Expand Down
2 changes: 1 addition & 1 deletion rpc/mayastor-api

0 comments on commit ac45bb4

Please sign in to comment.