fix(storage): expose truthful storage class capabilities (#5172)

This commit is contained in:
cxymds
2026-07-24 15:28:03 +08:00
committed by GitHub
parent 6765aca3f9
commit 358caa23cb
19 changed files with 835 additions and 81 deletions
+69
View File
@@ -46,6 +46,34 @@ pub const OUTPOSTS: &str = "OUTPOSTS";
pub const SNOW: &str = "SNOW";
pub const STANDARD_IA: &str = "STANDARD_IA";
/// Version of the client-discoverable storage-class write contract.
pub const CAPABILITY_CONTRACT_VERSION: u32 = 1;
/// Storage classes whose write semantics RustFS implements.
pub const SUPPORTED_WRITE_CLASSES: [&str; 2] = [STANDARD, RRS];
/// Stable S3 error code returned for unsupported write classes.
pub const UNSUPPORTED_WRITE_ERROR: &str = "InvalidStorageClass";
/// Compatibility behavior applied to historical label-only object metadata.
pub const LEGACY_LABEL_BEHAVIOR: &str = "normalized_to_effective_class";
/// Returns whether a client may select this storage class for a write.
pub fn is_supported_write_class(storage_class: &str) -> bool {
SUPPORTED_WRITE_CLASSES.contains(&storage_class)
}
/// Resolves the storage class that truthfully describes the stored object.
///
/// A completed lifecycle transition is a real storage tier and therefore keeps
/// its tier name. For local objects, only RRS has distinct layout semantics;
/// historical AWS class labels otherwise describe the effective STANDARD
/// layout.
pub fn effective_class<'a>(stored_class: Option<&'a str>, transitioned_tier: Option<&'a str>) -> &'a str {
if let Some(tier) = transitioned_tier.filter(|tier| !tier.is_empty()) {
return tier;
}
if stored_class == Some(RRS) { RRS } else { STANDARD }
}
// Standard constants for config info storage class
pub const CLASS_STANDARD: &str = "standard";
pub const CLASS_RRS: &str = "rrs";
@@ -556,6 +584,47 @@ mod tests {
}
}
#[test]
fn write_capability_contract_only_accepts_implemented_layouts() {
assert_eq!(SUPPORTED_WRITE_CLASSES, [STANDARD, RRS]);
assert!(is_supported_write_class(STANDARD));
assert!(is_supported_write_class(RRS));
for label_only_class in [
DEEP_ARCHIVE,
EXPRESS_ONEZONE,
GLACIER,
GLACIER_IR,
INTELLIGENT_TIERING,
ONEZONE_IA,
OUTPOSTS,
SNOW,
STANDARD_IA,
] {
assert!(
!is_supported_write_class(label_only_class),
"{label_only_class} must not be advertised as a supported write class"
);
}
assert!(!is_supported_write_class(""));
assert!(!is_supported_write_class("standard"));
assert!(!is_supported_write_class("UNKNOWN"));
}
#[test]
fn effective_class_normalizes_legacy_labels_and_preserves_real_tiers() {
assert_eq!(effective_class(None, None), STANDARD);
assert_eq!(effective_class(Some(STANDARD), None), STANDARD);
assert_eq!(effective_class(Some(RRS), None), RRS);
assert_eq!(effective_class(Some(STANDARD_IA), None), STANDARD);
assert_eq!(effective_class(Some(GLACIER), None), STANDARD);
assert_eq!(effective_class(Some("UNKNOWN"), None), STANDARD);
assert_eq!(effective_class(Some(STANDARD_IA), Some("WARM-TIER")), "WARM-TIER");
assert_eq!(effective_class(Some(STANDARD), Some(STANDARD_IA)), STANDARD_IA);
assert_eq!(effective_class(Some(RRS), Some("CUSTOM-RRS-TIER")), "CUSTOM-RRS-TIER");
}
#[test]
fn automatic_parity_is_resolved_per_pool() {
let cfg = lookup_config_for_pools_with_env(&KVS::new(), &[4, 2], no_env_overrides())