Skip to content

Commit

Permalink
Pick a non-expunged clone source (oxidecomputer#7283)
Browse files Browse the repository at this point in the history
When performing region snapshot replacement, the associated start saga
chose the request's region snapshot as the clone source, but if that
region snapshot was backed by an expunged dataset then it may be gone.

This commit adds logic to choose another clone source, either another
region snapshot from the same snapshot, or one of the read-only regions
for that snapshot.

Basic sanity tests were added for ensuring that region replacements and
region snapshot replacements resulting from expungement can occur. It
was an oversight not to originally include these! Rn order to support
these new sanity tests, the simulated pantry has to fake activating
volumes in the background. This commit also refactors the simulated
Pantry to have one Mutex around an "inner" struct instead of many
Mutexes.

Fixes oxidecomputer#7209
  • Loading branch information
jmpesp authored Dec 19, 2024
1 parent f59c55e commit 460f038
Show file tree
Hide file tree
Showing 5 changed files with 1,043 additions and 73 deletions.
36 changes: 36 additions & 0 deletions nexus/db-queries/src/db/datastore/region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,42 @@ impl DataStore {

Ok(records)
}

/// Find regions not on expunged disks that match a volume id
pub async fn find_non_expunged_regions(
&self,
opctx: &OpContext,
volume_id: Uuid,
) -> LookupResult<Vec<Region>> {
let conn = self.pool_connection_authorized(opctx).await?;

use db::schema::dataset::dsl as dataset_dsl;
use db::schema::physical_disk::dsl as physical_disk_dsl;
use db::schema::region::dsl as region_dsl;
use db::schema::zpool::dsl as zpool_dsl;

region_dsl::region
.filter(region_dsl::dataset_id.eq_any(
dataset_dsl::dataset
.filter(dataset_dsl::time_deleted.is_null())
.filter(dataset_dsl::pool_id.eq_any(
zpool_dsl::zpool
.filter(zpool_dsl::time_deleted.is_null())
.filter(zpool_dsl::physical_disk_id.eq_any(
physical_disk_dsl::physical_disk
.filter(physical_disk_dsl::disk_policy.eq(PhysicalDiskPolicy::InService))
.select(physical_disk_dsl::id)
))
.select(zpool_dsl::id)
))
.select(dataset_dsl::id)
))
.filter(region_dsl::volume_id.eq(volume_id))
.select(Region::as_select())
.load_async(&*conn)
.await
.map_err(|e| public_error_from_diesel(e, ErrorHandler::Server))
}
}

#[cfg(test)]
Expand Down
36 changes: 36 additions & 0 deletions nexus/db-queries/src/db/datastore/region_snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,40 @@ impl DataStore {
.await
.map_err(|e| public_error_from_diesel(e, ErrorHandler::Server))
}

/// Find region snapshots not on expunged disks that match a snapshot id
pub async fn find_non_expunged_region_snapshots(
&self,
opctx: &OpContext,
snapshot_id: Uuid,
) -> LookupResult<Vec<RegionSnapshot>> {
let conn = self.pool_connection_authorized(opctx).await?;

use db::schema::dataset::dsl as dataset_dsl;
use db::schema::physical_disk::dsl as physical_disk_dsl;
use db::schema::region_snapshot::dsl as region_snapshot_dsl;
use db::schema::zpool::dsl as zpool_dsl;

region_snapshot_dsl::region_snapshot
.filter(region_snapshot_dsl::dataset_id.eq_any(
dataset_dsl::dataset
.filter(dataset_dsl::time_deleted.is_null())
.filter(dataset_dsl::pool_id.eq_any(
zpool_dsl::zpool
.filter(zpool_dsl::time_deleted.is_null())
.filter(zpool_dsl::physical_disk_id.eq_any(
physical_disk_dsl::physical_disk
.filter(physical_disk_dsl::disk_policy.eq(PhysicalDiskPolicy::InService))
.select(physical_disk_dsl::id)
))
.select(zpool_dsl::id)
))
.select(dataset_dsl::id)
))
.filter(region_snapshot_dsl::snapshot_id.eq(snapshot_id))
.select(RegionSnapshot::as_select())
.load_async(&*conn)
.await
.map_err(|e| public_error_from_diesel(e, ErrorHandler::Server))
}
}
Loading

0 comments on commit 460f038

Please sign in to comment.