Skip to main content

bucketwarden_server/
small_object_optimization_support.rs

1use super::*;
2
3pub const SMALL_OBJECT_MODE_DIRECT: &str = "direct-small-object";
4pub const SMALL_OBJECT_MODE_PACKED: &str = "packed-small-object";
5pub const SMALL_OBJECT_MODE_INDEXED_PACK: &str = "indexed-pack";
6pub const SMALL_OBJECT_MODE_AMPLIFICATION_REDUCED: &str = "amplification-reduced";
7
8const SMALL_OBJECT_THRESHOLD_BYTES: usize = 16 * 1024;
9
10const SMALL_OBJECT_CAPABILITIES: &[&str] = &[
11    "packing",
12    "indexing",
13    "metadata-amplification",
14    "read-amplification",
15    "write-amplification",
16    "native-support-state",
17    "semantic-parity",
18    "configuration-admin-surface",
19    "security-governance-impact",
20    "observability-evidence",
21    "failure-mode-behavior",
22    "validation-test-coverage",
23    "product-specific-caveats",
24];
25
26const SMALL_OBJECT_CAVEATS: &[&str] = &[
27    "BucketWarden supports direct small-object writes, reads, lists, metadata, and evidence under the local runtime boundary.",
28    "Small-object threshold classification is explicit and observable, but objects are not packed into shared containers.",
29    "Packed small objects, pack indexes, and read/write/metadata amplification-reduction modes are tracked but fail closed.",
30    "Small-object proof does not claim container packing, compaction, shared-index recovery, or reduced IO amplification.",
31];
32
33const SMALL_OBJECT_FAILURE_MODES: &[&str] = &[
34    "unsupported-small-object-mode-rejected",
35    "packed-small-object-mode-rejected",
36    "indexed-pack-mode-rejected",
37    "amplification-reduction-mode-rejected",
38    "invalid-small-object-threshold-rejected",
39];
40
41#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
42pub struct SmallObjectOptimizationEntry {
43    pub mode: &'static str,
44    pub native_support: bool,
45    pub semantic_parity: &'static str,
46    pub storage_behavior: &'static str,
47    pub amplification_behavior: &'static str,
48    pub failure_mode: &'static str,
49    pub caveat: &'static str,
50}
51
52#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
53pub struct SmallObjectOptimizationReport {
54    pub active_mode: &'static str,
55    pub small_object_threshold_bytes: usize,
56    pub supported_modes: Vec<&'static str>,
57    pub unsupported_modes: Vec<&'static str>,
58    pub capabilities: Vec<&'static str>,
59    pub failure_modes: Vec<&'static str>,
60    pub caveats: Vec<&'static str>,
61    pub entries: Vec<SmallObjectOptimizationEntry>,
62}
63
64#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)]
65pub struct SmallObjectOptimizationPolicy {
66    pub mode: String,
67    pub threshold_bytes: Option<usize>,
68    pub pack_objects: bool,
69    pub external_index: bool,
70    pub reduce_read_amplification: bool,
71    pub reduce_write_amplification: bool,
72    pub reduce_metadata_amplification: bool,
73}
74
75impl BucketWarden {
76    pub fn small_object_optimization_report(&self) -> SmallObjectOptimizationReport {
77        SmallObjectOptimizationReport {
78            active_mode: SMALL_OBJECT_MODE_DIRECT,
79            small_object_threshold_bytes: SMALL_OBJECT_THRESHOLD_BYTES,
80            supported_modes: vec![SMALL_OBJECT_MODE_DIRECT],
81            unsupported_modes: vec![
82                SMALL_OBJECT_MODE_PACKED,
83                SMALL_OBJECT_MODE_INDEXED_PACK,
84                SMALL_OBJECT_MODE_AMPLIFICATION_REDUCED,
85            ],
86            capabilities: SMALL_OBJECT_CAPABILITIES.to_vec(),
87            failure_modes: SMALL_OBJECT_FAILURE_MODES.to_vec(),
88            caveats: SMALL_OBJECT_CAVEATS.to_vec(),
89            entries: vec![
90                SmallObjectOptimizationEntry {
91                    mode: SMALL_OBJECT_MODE_DIRECT,
92                    native_support: true,
93                    semantic_parity: "Small objects use the same committed object version, metadata, encryption, lock, list, and read semantics as larger objects.",
94                    storage_behavior: "Small object bodies are stored directly as object versions rather than packed into shared containers.",
95                    amplification_behavior: "No reduced amplification claim is made beyond direct runtime read/write/list paths.",
96                    failure_mode: "Invalid threshold or unsupported optimization policy is rejected before claiming support.",
97                    caveat: "Direct small-object support does not claim container packing or IO amplification reduction.",
98                },
99                SmallObjectOptimizationEntry {
100                    mode: SMALL_OBJECT_MODE_PACKED,
101                    native_support: false,
102                    semantic_parity: "No packed-object container, offset table, or compaction semantics are claimed.",
103                    storage_behavior: "Packed small-object storage is out of the current runtime boundary.",
104                    amplification_behavior: "Packing-related amplification reductions are not claimed.",
105                    failure_mode: "Packed small-object mode selection is rejected as unsupported.",
106                    caveat: "Packing needs container indexes, compaction, recovery, and garbage-collection proof.",
107                },
108                SmallObjectOptimizationEntry {
109                    mode: SMALL_OBJECT_MODE_INDEXED_PACK,
110                    native_support: false,
111                    semantic_parity: "No external pack index or packed-object lookup semantics are claimed.",
112                    storage_behavior: "Indexed pack storage is out of the current runtime boundary.",
113                    amplification_behavior: "Index-based read amplification reductions are not claimed.",
114                    failure_mode: "Indexed pack mode selection is rejected as unsupported.",
115                    caveat: "Pack indexing needs durable index and corruption-recovery contracts.",
116                },
117                SmallObjectOptimizationEntry {
118                    mode: SMALL_OBJECT_MODE_AMPLIFICATION_REDUCED,
119                    native_support: false,
120                    semantic_parity: "No metadata, read, or write amplification reduction semantics are claimed.",
121                    storage_behavior: "Amplification-reduced storage is out of the current runtime boundary.",
122                    amplification_behavior: "Reduced metadata/read/write amplification modes are rejected.",
123                    failure_mode: "Amplification-reduction mode selection is rejected as unsupported.",
124                    caveat: "Amplification reduction needs measurable storage engine behavior and benchmarks.",
125                },
126            ],
127        }
128    }
129
130    pub fn is_small_object(&self, body_len: usize) -> bool {
131        body_len <= SMALL_OBJECT_THRESHOLD_BYTES
132    }
133
134    pub fn ensure_small_object_mode_supported(&self, mode: &str) -> Result<(), RuntimeError> {
135        let report = self.small_object_optimization_report();
136        if report.supported_modes.contains(&mode) {
137            Ok(())
138        } else {
139            Err(RuntimeError::UnsupportedSmallObjectOptimization(
140                mode.to_string(),
141            ))
142        }
143    }
144
145    pub fn validate_small_object_optimization_policy(
146        &self,
147        policy: &SmallObjectOptimizationPolicy,
148    ) -> Result<(), RuntimeError> {
149        self.ensure_small_object_mode_supported(&policy.mode)?;
150        if policy
151            .threshold_bytes
152            .is_some_and(|threshold| threshold == 0)
153        {
154            return Err(RuntimeError::InvalidSmallObjectOptimizationPolicy(
155                "small-object threshold must be nonzero".to_string(),
156            ));
157        }
158        if policy.pack_objects {
159            return Err(RuntimeError::InvalidSmallObjectOptimizationPolicy(
160                "packed small-object containers are outside the current boundary".to_string(),
161            ));
162        }
163        if policy.external_index {
164            return Err(RuntimeError::InvalidSmallObjectOptimizationPolicy(
165                "external small-object indexes are outside the current boundary".to_string(),
166            ));
167        }
168        if policy.reduce_read_amplification
169            || policy.reduce_write_amplification
170            || policy.reduce_metadata_amplification
171        {
172            return Err(RuntimeError::InvalidSmallObjectOptimizationPolicy(
173                "amplification reduction is outside the current small-object boundary".to_string(),
174            ));
175        }
176        Ok(())
177    }
178}