mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-30 00:47:13 +00:00
fix(ecstore): drain multipart uploads before decommission (#6414)
* fix(ecstore): drain multipart uploads before decommission * fix(ecstore): prioritize active multipart pools --------- Co-authored-by: houseme <housemecn@gmail.com>
This commit is contained in:
@@ -7152,6 +7152,9 @@ impl ECStore {
|
||||
let buckets = self.get_buckets_to_decommission().await?;
|
||||
let pool = self.pools[idx].clone();
|
||||
|
||||
self.ensure_decommission_multipart_uploads_drained(idx, &pool, &buckets)
|
||||
.await?;
|
||||
|
||||
for (set_index, set) in pool.disk_set.iter().enumerate() {
|
||||
for bucket_info in &buckets {
|
||||
let mut lifecycle_config = None;
|
||||
@@ -7320,6 +7323,48 @@ impl ECStore {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn ensure_decommission_multipart_uploads_drained(
|
||||
&self,
|
||||
idx: usize,
|
||||
pool: &Sets,
|
||||
buckets: &[DecomBucketInfo],
|
||||
) -> Result<()> {
|
||||
let mut bucket_names = buckets
|
||||
.iter()
|
||||
.filter(|bucket| bucket.name != RUSTFS_META_BUCKET)
|
||||
.map(|bucket| bucket.name.as_str())
|
||||
.collect::<Vec<_>>();
|
||||
bucket_names.sort_unstable();
|
||||
bucket_names.dedup();
|
||||
|
||||
// Take one bucket fence at a time so cross-bucket COPY cannot form an
|
||||
// ABBA cycle. Suspension prevents new source uploads after each fence.
|
||||
for bucket in bucket_names {
|
||||
let lifecycle_guard = self.acquire_bucket_lifecycle_write_lock(bucket).await?;
|
||||
if lifecycle_guard.is_lock_lost() {
|
||||
return Err(Error::other(format!(
|
||||
"decommission multipart drain lost the bucket lifecycle fence for `{bucket}`"
|
||||
)));
|
||||
}
|
||||
for set in &pool.disk_set {
|
||||
if let Some(upload_path) = set.first_multipart_upload_path_for_decommission(bucket).await? {
|
||||
return Err(Error::other(format!(
|
||||
"pool {idx} still contains multipart upload `{upload_path}` for bucket `{bucket}`; resolve it before retrying decommission"
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) async fn ensure_decommission_multipart_uploads_drained_for_test(self: &Arc<Self>, idx: usize) -> Result<()> {
|
||||
let buckets = self.get_buckets_to_decommission().await?;
|
||||
let pool = self.pools[idx].clone();
|
||||
self.ensure_decommission_multipart_uploads_drained(idx, pool.as_ref(), &buckets)
|
||||
.await
|
||||
}
|
||||
#[cfg(test)]
|
||||
pub(crate) async fn check_after_decommission_for_test(self: &Arc<Self>, idx: usize) -> Result<()> {
|
||||
let generation = self.active_decommission_generation(idx).await?;
|
||||
|
||||
Reference in New Issue
Block a user