feat(ecstore): seed relaxed durability for new buckets (#5971)

This commit is contained in:
houseme
2026-08-12 12:54:20 +08:00
committed by GitHub
parent b00b7ab8f1
commit 6850482247
8 changed files with 304 additions and 102 deletions
+77 -1
View File
@@ -457,7 +457,13 @@ impl ECStore {
None
};
let mut meta = existing_metadata.unwrap_or_else(|| BucketMetadata::new(bucket));
let mut meta = existing_metadata.unwrap_or_else(|| {
if confirmed_missing && !is_meta_bucketname(bucket) {
BucketMetadata::new_with_default_durability(bucket)
} else {
BucketMetadata::new(bucket)
}
});
let existing_incarnation_is_authoritative = meta.bucket_incarnation_sidecar;
if confirmed_missing || is_meta_bucketname(bucket) {
meta.set_created(opts.created_at);
@@ -1557,6 +1563,76 @@ mod tests {
);
}
#[tokio::test(flavor = "multi_thread")]
#[serial]
async fn make_bucket_seeds_new_bucket_durability_override() {
temp_env::async_with_vars([(crate::bucket::durability::ENV_NEW_BUCKET_DURABILITY_MODE, None::<&str>)], async {
let (_disk_paths, ecstore) = setup_bucket_delete_test_env().await;
let bucket = format!("bucket-default-durability-{}", Uuid::new_v4().simple());
ecstore
.make_bucket(&bucket, &MakeBucketOptions::default())
.await
.expect("new bucket should be created");
let metadata = metadata_sys::get_in(&ecstore.ctx, &bucket)
.await
.expect("metadata should load for the new bucket");
assert_eq!(
metadata.durability_config().and_then(|cfg| cfg.normalized_mode()).as_deref(),
Some(crate::bucket::durability::BUCKET_DURABILITY_MODE_RELAXED)
);
})
.await;
}
#[tokio::test(flavor = "multi_thread")]
#[serial]
async fn force_create_existing_bucket_keeps_durability_override() {
let (_disk_paths, ecstore) = setup_bucket_delete_test_env().await;
let bucket = format!("bucket-force-durability-{}", Uuid::new_v4().simple());
temp_env::async_with_vars([(crate::bucket::durability::ENV_NEW_BUCKET_DURABILITY_MODE, Some("inherit"))], async {
ecstore
.make_bucket(&bucket, &MakeBucketOptions::default())
.await
.expect("plain bucket should be created without a durability override");
})
.await;
assert!(
metadata_sys::get_in(&ecstore.ctx, &bucket)
.await
.expect("metadata should load after initial create")
.durability_config()
.is_none(),
"test setup: the existing bucket must start without an override"
);
temp_env::async_with_vars([(crate::bucket::durability::ENV_NEW_BUCKET_DURABILITY_MODE, None::<&str>)], async {
ecstore
.make_bucket(
&bucket,
&MakeBucketOptions {
force_create: true,
lock_enabled: true,
..Default::default()
},
)
.await
.expect("force create should update existing bucket metadata");
})
.await;
let metadata = metadata_sys::get_in(&ecstore.ctx, &bucket)
.await
.expect("metadata should load after force create");
assert!(metadata.lock_enabled, "force create sanity check: Object Lock should be enabled");
assert!(
metadata.durability_config().is_none(),
"force create must not apply the new-bucket default to existing bucket metadata"
);
}
/// `DeleteBucket`'s emptiness check is a raw disk scan (`has_xlmeta_files`),
/// not an S3-level listing, so "the client drained the bucket" and "the
/// bucket is deletable" are two different contracts. Nothing pinned the