Commit Graph

5461 Commits

Author SHA1 Message Date
houseme d2b1003612 perf(storage): converge Wave 2 hot-path optimizations (#6065)
* perf(get): share inline shards and lock clients

Co-Authored-By: heihutu <heihutu@gmail.com>

* perf(ecstore): converge PUT encoding on contiguous blocks

Co-Authored-By: heihutu <heihutu@gmail.com>

* perf(get): cache codec streaming gate config

Co-Authored-By: heihutu <heihutu@gmail.com>

* fix(sse): redact projected customer headers

Co-Authored-By: heihutu <heihutu@gmail.com>

* perf(ecstore): collapse GET metadata snapshots

Co-Authored-By: heihutu <heihutu@gmail.com>

* perf(ecstore): reuse decode stripe scratch

Co-Authored-By: heihutu <heihutu@gmail.com>

* refactor(ecstore): trim decode scratch adapters

Co-Authored-By: heihutu <heihutu@gmail.com>

* test(ecstore): adapt transition checks to metadata snapshots

Co-Authored-By: heihutu <heihutu@gmail.com>

* perf(get): release metadata snapshots at ownership boundary

Co-Authored-By: heihutu <heihutu@gmail.com>

* refactor(ecstore): close cumulative fast-path findings

Co-Authored-By: heihutu <heihutu@gmail.com>

* fix(storage): preserve lock and header invariants

Co-Authored-By: heihutu <heihutu@gmail.com>

* test(ecstore): adapt cumulative paths after rebase

Co-Authored-By: heihutu <heihutu@gmail.com>

* fix(rio-v2): adapt generated metadata fixture

Co-Authored-By: heihutu <heihutu@gmail.com>

---------

Co-authored-by: heihutu <heihutu@gmail.com>
2026-08-13 16:34:28 +08:00
GatewayJ 36deab8670 perf(ecstore): retain remote shard HTTP chunks (#5991)
* perf(ecstore): retain remote shard HTTP chunks

* fix(ecstore): bound remote shard chunk retention

* fix(rio): persist empty chunk limit across polls
2026-08-13 15:00:44 +08:00
cxymds e11fcfbd08 fix(rebalance): converge multipart data movement retries (#6057)
* fix(rebalance): converge multipart data movement retries

* fix(rebalance): harden multipart retry replacement

* fix(rebalance): isolate internal multipart uploads

* test(ecstore): adapt metadata mutation fixtures

* fix(rebalance): preserve transition metadata semantics

* refactor(ecstore): reuse internal metadata matcher

* Revert "refactor(ecstore): reuse internal metadata matcher"

This reverts commit c87ca0328f.

* refactor(rebalance): reuse data movement log constants

* fix(rebalance): isolate migration-owned state

* fix(rebalance): preserve pre-gate retry compatibility
2026-08-13 06:12:26 +00:00
houseme 11eecdc888 perf(put): avoid eager body zero fill (#6063)
Use BytesMut spare capacity for direct and pooled small PUT body reads while preserving exact-length validation.

Co-authored-by: heihutu <heihutu@gmail.com>
2026-08-13 05:30:00 +00:00
houseme 80eb4244a3 chore(deps): refresh mimalloc revision (#6062) 2026-08-13 12:31:01 +08:00
Zhengchao An e4da9bd718 refactor(rustfs): move layer-neutral shared types out of server (#6061)
RemoteAddr, the DependencyReadiness family (DependencyReadiness, ReadinessDegradedReason, DependencyReadinessReport), and convert_ecstore_object_info (with its offset_date_time_to_timestamp helper) are consumed across app, infra, and interface layers but lived under server, so every lower-layer import was an upward app->interface or infra->interface edge the layer guard had to baseline.

They now live in a new layer-neutral rustfs/src/shared_types.rs (classified infra by the guard, making all consumer imports downward or lateral). server::readiness and server::event re-export for their own internals; the eight consumer sites (admin_usecase, bucket_usecase, object_usecase, cluster_snapshot, storage/access, storage/helper, plus the admin handler tests) import from the new home. Pure move: no type, impl, or behavior change.

The regenerated layer-dependency baseline shrinks by exactly eight lines with zero additions — the ratchet's intended direction. The two remaining readiness entries (collect/snapshot fn imports) need the collection machinery itself extracted from server and are left for the issue's PR5 scope.

Ref rustfs/backlog#1834 (PR4).
2026-08-13 12:29:49 +08:00
Zhengchao An e28430ab3d test(rustfs): un-ignore the fourteen ecfs_test global-state tests (#6046)
The 14 tests carried #[ignore = "requires isolated global object layer state"], and the only CI lane that runs ignored tests filters for lifecycle tests — so they executed nowhere. Under nextest, the authoritative runner, every test owns its process and the stale reason no longer applies; all 14 pass.

Ten of them assert the InternalError path taken while the global object layer is uninitialized, a premise a sibling test can destroy under the documented shared-process cargo test fallback. Those ten now start with an explicit premise guard: when a sibling already initialized the store the test skips with a message instead of asserting against a scenario it does not describe. Under nextest the guard never fires and the assertions always run.

Dual-runner evidence: nextest 79 passed; cargo test module-scoped 79 passed; the full storage-tree cargo test sweep returns to its pre-existing baseline (8 unrelated in-process failures, none introduced or worsened here). No test deleted.

Ref rustfs/backlog#1830 (PR1).
2026-08-13 12:29:06 +08:00
Zhengchao An db4707f187 chore(io-metrics): make the server label injected, drop two leaf-violating deps (#6051) 2026-08-13 03:20:18 +00:00
houseme 3a0dbccc2e perf(ecstore): reduce inline PUT commit overhead (#6033)
* perf(metrics): attribute PUT stage costs

Co-Authored-By: heihutu <heihutu@gmail.com>

* perf(ecstore): move PUT metadata during shuffle

Co-Authored-By: heihutu <heihutu@gmail.com>

* perf(s3): reuse PUT object lock state

Co-Authored-By: heihutu <heihutu@gmail.com>

* perf(ecstore): trim PUT metadata fanout clones

Build per-disk PUT metadata only for committed writer slots, move the response metadata out of the fanout vector, and preserve fresh FileInfo shuffle semantics.

Co-Authored-By: heihutu <heihutu@gmail.com>

* perf(metrics): make PUT stage attribution opt-in

Co-Authored-By: heihutu <heihutu@gmail.com>

* perf(ecstore): commit inline PUT shards directly

Co-Authored-By: heihutu <heihutu@gmail.com>

* perf(ecstore): streamline rename staging cleanup

Use the directory-specific removal operation for rename_data staging parents. This avoids a guaranteed failed file-removal probe on Unix-like hosts and lets Windows remove the empty directory directly while preserving best-effort non-empty handling.

Co-Authored-By: heihutu <heihutu@gmail.com>

* test(ecstore): cover inline PUT rename failures

Cache the detailed stage metrics gate once per PUT and exercise exact-quorum and quorum-minus-one failures after inline shard encoding.

Co-Authored-By: heihutu <heihutu@gmail.com>

---------

Co-authored-by: heihutu <heihutu@gmail.com>
2026-08-13 02:04:20 +00:00
houseme 846517625b fix(ecstore): bound remote metadata read retries (#6035)
* fix(ecstore): bound remote metadata read retries

Co-Authored-By: heihutu <heihutu@gmail.com>

* fix(ecstore): handle oversized read timeouts

Co-Authored-By: heihutu <heihutu@gmail.com>

---------

Co-authored-by: heihutu <heihutu@gmail.com>
2026-08-13 02:01:05 +00:00
houseme f21e88b112 perf(ecstore): avoid per-block shard vector allocation (#6037)
Keep encoded shards in one contiguous Bytes buffer while they cross the streaming write queue, and materialize Vec<Bytes> only for the existing public APIs.

Co-authored-by: heihutu <heihutu@gmail.com>
2026-08-13 01:55:24 +00:00
Zhengchao An a5594c3d89 fix(kms): construct wrap_budget_reserved in the VaultKeyData deserializer (#6055) 2026-08-13 00:59:13 +00:00
Zhengchao An fc927caadd docs(guards): make the layer-dependency baseline an explicit shrink-only ratchet (#6053) 2026-08-13 00:27:19 +00:00
Henry Guo b7e6334c13 fix(table-catalog): isolate metadata after table rename (#6050) 2026-08-13 00:15:31 +00:00
Zhengchao An 65091aa6a8 test: give the twenty-one bare #[ignore] attributes their reasons (#6049) 2026-08-13 08:10:47 +08:00
Zhengchao An 3c78a56ab0 test: un-ignore the remaining seven global-state tests, drop one stale premise (#6048) 2026-08-13 08:10:28 +08:00
Zhengchao An bdd7ecd205 test(rustfs): un-ignore the nine node_service global-state tests (#6047) 2026-08-13 08:10:11 +08:00
Zhengchao An a70a3787d8 fix(kms): tell an empty KV2 prefix from a missing mount on Vault's 404 (#6043) 2026-08-13 08:09:17 +08:00
Zhengchao An b2ae430805 chore(ecstore): compile the list-objects chaos injector out of production builds (#6042) 2026-08-13 08:09:03 +08:00
Zhengchao An 299eb0d965 docs(operations): record the two experimental GET-path switches (#6041) 2026-08-13 08:08:48 +08:00
Zhengchao An f5a780099b fix(kms): let the Vault Transit backend start against an empty transit engine (#6040) 2026-08-13 08:08:30 +08:00
Zhengchao An 5cfafcf39b chore(rustfs): remove the orphan starshard bucket-cache backend (#6038) 2026-08-13 08:08:15 +08:00
Zhengchao An a49243c671 test(kms): pin ILM behavior on SSE-KMS buckets under key-policy enforcement (#6027) 2026-08-13 08:06:42 +08:00
Zhengchao An c2a15f5214 refactor(utils): add shared retry_with_backoff and migrate target_descriptor (#6026) 2026-08-13 08:06:21 +08:00
Zhengchao An ee54f1e618 docs(checksums): cross-reference the three checksum registries (#6024) 2026-08-13 08:06:00 +08:00
Zhengchao An e6b85b60a8 test(io-metrics): assert metric emission in six modules of record_* smoke tests (#6021) 2026-08-13 08:05:43 +08:00
Zhengchao An 8c1e3c09ff refactor(admin): add authorize_admin_request and fold four local wrappers (#6020) 2026-08-13 08:05:28 +08:00
Zhengchao An ca06c7ec2c feat(kms): reserve and expose KV2 wrap-budget consumption (#6019) 2026-08-13 08:05:00 +08:00
Zhengchao An 4a41325d1a feat(sse): report the wrapping master-key version on S3 audit entries (#6005) 2026-08-13 08:04:30 +08:00
Zhengchao An 45e2bd0c28 chore(ecstore): collapse the expiry worker knobs to one documented env var (#6034)
init_background_expiry resolved its worker count through three env vars, none documented, none set in any known deployment: RUSTFS_MAX_EXPIRY_WORKERS, silently overridden by the underscore-prefixed _RUSTFS_ILM_EXPIRATION_WORKERS (a MinIO fossil, comment included), with a zero value then falling through to RUSTFS_DEFAULT_EXPIRY_WORKERS.

RUSTFS_MAX_EXPIRY_WORKERS stays as the canonical name per the rc constraint (no new env var names): the count is now resolved once — a set, parseable, non-zero value wins, anything else falls back to min(cpus, 16). The constant moves to rustfs-config's runtime constants alongside ENV_TRANSITION_WORKERS, the two dead names are gone repo-wide (rg-verified), and a serial four-state unit test (unset/zero/valid/garbage) pins the resolution, modeled on the transition-worker env harness.

Ref rustfs/backlog#1832 (PR2).
2026-08-12 20:46:06 +00:00
Zhengchao An e2fb0427f9 docs(io-metrics): remove stale unified-config docs left by #6008 (#6039)
PR #6008 deleted crates/io-metrics/src/config.rs but the crate docs still taught the deleted API: both READMEs kept the Unified Configuration sections, module-tree entries and ./src/config.rs links, the example kept an orphaned numbered comment, and the io-core/io-metrics changelog had no removal record. Scrub all of it; keep cache_config.rs references, which are still real.
2026-08-12 20:41:40 +00:00
Zhengchao An a825326ede test(e2e): fold seven identical POST-policy exact-mismatch tests into one table (#6016)
* test(e2e): fold seven identical POST-policy exact-mismatch tests into one table

The seven *_policy_mismatch tests in multipart_auth_test.rs were body-identical after literal normalization: the policy pins one field to an exact value, the form sends a different value, and the upload must be rejected with 400 InvalidPolicyDocument naming the field. Each test booted its own full server.

They fold into one table-driven test on the run_post_object_policy_case helper introduced by the PR1 fold. Every row keeps its original test's exact bucket, key, field name, policy value, mismatched form value, body bytes, and expected error strings — including the three rows that asserted the stronger <Code>InvalidPolicyDocument</Code> form. The pinned condition is built with an explicit serde_json::Map since the field name is now a table parameter.

cargo nextest list reports 97 tests for this module; the inventory row is updated in the same diff (103 -> 97).

Ref rustfs/backlog#1838 (PR2).

* test(e2e): fold the remaining POST-policy duplicate groups (15 tests) (#6018)

Completes the multipart_auth table-driven fold: the six remaining body-identical groups collapse onto the shared run_post_object_policy_case helper.

- Seven single-field exact-mismatch tests (cache-control, expires, tagging, storage-class, content-type, success_action_status, metadata-field-exact) join the existing exact-condition mismatch table as rows — same shape as the PR2 fold.
- The two object-lock mismatch tests become a two-row table (policy pins mode + retain-until-date, one form field mismatches).
- The three SSE-KMS parameter mismatch tests become a three-row table (policy pins the SSE mode plus one KMS parameter, form differs).
- The three SSE-KMS outside-policy tests become a three-row table pinning the distinct contract: an undeclared KMS parameter sails past policy validation and is rejected at runtime with 501 NotImplemented, not a policy error.

Every row keeps its original test's exact bucket, key, field names, values, body bytes, and expected status/code strings. cargo nextest list reports 85 tests for the module; the inventory row is updated in the same diff (97 -> 85).

Ref rustfs/backlog#1838 (PR3).
2026-08-12 20:18:36 +00:00
Zhengchao An e313276e49 fix(sse): align copy-path unknown-algorithm fallback with put path (#6022) 2026-08-13 03:42:03 +08:00
Zhengchao An 66af487978 docs(policy): pin the deliberate slash-only path.Clean duplication (#6013)
The policy crate's Go path.Clean port and rustfs-utils' Windows-aware clean look like duplicates but are not interchangeable: S3 ARN/resource matching must treat backslashes as object-name data, never as separators, so adopting the utils version would change policy evaluation semantics on Windows — a security-adjacent behavior change. Record that judgment as bidirectional do-not-merge notes on both implementations, per the issue's adversarial ruling.

Comment-only change.

Ref rustfs/backlog#1833 (PR7).
2026-08-13 03:41:09 +08:00
Zhengchao An d668a9293f chore(ecstore): remove test-only BitrotErrorType and pin wire-only disk variants (#6032)
BitrotErrorType (disk/error.rs) was constructed only by its own unit test: production bitrot mismatches never flow through it (they surface as DiskError::other strings). Delete the enum, its From<BitrotErrorType> for DiskError impl, the self-test, and the api facade re-export. The facade inventory doc does not name the type, so no doc change is needed.

DiskError::SourceStalled and DiskError::CrossDeviceLink are never constructed locally — they are reachable only through wire decoding and no current node sends them. Their decode arms stay per the cross-version compatibility constraint; each variant now carries a doc comment saying exactly that so the next dead-code sweep does not re-litigate them. Their consumer arms (heal classifier, batch processor) are left untouched — the values cannot appear, so removing the arms would be unobservable, and the heal classifier is pinned by the issue as do-not-touch.

Ref rustfs/backlog#1831 (PR4).
2026-08-12 19:37:00 +00:00
Zhengchao An ace28c1f85 chore(common): remove dead bucket_stats module and LastMinuteHistogram (#6011)
crates/common/src/bucket_stats.rs (ReplicationLatency plus a commented-out ReplicationLastMinute corpse) had zero consumers anywhere in the workspace — the live replication statistics implementation is crates/replication/src/stats.rs. LastMinuteHistogram in last_minute.rs (already carrying allow(dead_code)) was equally unreferenced, and size_to_tag / SIZE_LAST_ELEM_MARKER had no user besides the histogram, so the whole block goes with it. LastMinuteLatency and AccElem stay: common's metrics.rs uses them.

Ref rustfs/backlog#1833 (PR5).
2026-08-13 03:27:17 +08:00
Zhengchao An 2ad8ab534e fix(site-replication): admit same-generation peer-edit fan-out bodies (#6007)
The peer-edit delivery fence from #5882 treated an equal applied generation as stale. One edit legitimately fans out one delivery per peer record under a single generation (the ILM-expiry edit sends every peer's record), so the receiver applied only the first body, raised its high-water mark, and silently acked-success while dropping the rest — enableILMExpiryReplication never converged on receiving sites and the three-node nightly e2e failed deterministically (issue #5767).

Only a strictly newer applied generation is stale now. Equal generation implies the same logical edit and re-applying a delivery is idempotent (update_peer overwrites the peer record; the mark is raised with max), while strictly older deliveries — the cross-node ordering case the fence exists for — stay rejected.

Adds a composed unit test driving three same-generation bodies through the receiver's fenced sequence, and widens the replication e2e's two site-replication wait helpers from a 10s polling ceiling to the 30s deadline the file's other waits use.
2026-08-13 03:26:34 +08:00
Zhengchao An f7df4fa62a fix(versioning): reject suspending versioning while a replication config exists (#6006)
PutBucketVersioning with Status=Suspended on a bucket that carries a replication configuration now fails with InvalidBucketState, matching AWS S3 and MinIO. Suspension would start minting null versions that the versioned replication engine can never converge — the state is unreachable on AWS and MinIO, and the nightly acceptance-matrix e2e that tried to exercise it failed every night since it landed (issue #5767).

The acceptance-matrix test tail now pins the rejection contract (InvalidBucketState) and verifies a fresh matched PUT still replicates with a real version id after the rejected suspension.
2026-08-13 03:26:17 +08:00
Zhengchao An ca4e66daab chore(io-metrics): remove the zero-consumer config module (391 lines) (#6008)
crates/io-metrics/src/config.rs was a near-copy of io-core's Backpressure/Deadlock configuration with already-drifted field names (high_watermark vs io-core's high_water_mark) and had no consumer outside the crate's own example: the canonical BackpressureConfig lives in crates/io-core/src/backpressure.rs. Delete the module, its lib.rs re-exports, and the example's unified-config section, and settle the corresponding ARCHITECTURE.md ledger line that tracked this copy's removal.

Ref rustfs/backlog#1833 (PR4).
2026-08-13 03:25:30 +08:00
Zhengchao An 5b9c5289c2 fix(iam): remove eight dead error variants and make Clone variant-preserving (#6030)
* chore(iam): remove eight dead error variants

iam::Error mirrored policy::Error variant-for-variant, and eight of the twins had zero construction and zero match sites anywhere in the workspace: InvalidServiceType, ErrCredMalformed, CredNotInitialized, JWTError, NoAccessKey, InvalidToken, InvalidAccessKey, InvalidExpiration (each verified by repo-wide sweep; the InvalidToken hits elsewhere are KeystoneError's unrelated variant). Delete the variants along with their Clone and PartialEq arms.

The From<policy::Error> mapping keeps its exhaustive match: the eight orphaned arms now route through a grouped binding to Error::StringError(err.to_string()), so the rendered message is preserved; nothing could observe the old discriminants because no site ever matched on them.

Ref rustfs/backlog#1831 (PR1).

* fix(iam): make Error clone variant-preserving via Arc payloads

iam::Error's hand-written Clone demoted PolicyError and CryptoError to StringError because their payloads are not cloneable — a clone changed the variant identity. There is no production clone site today (the issue's refuter confirmed this is preventive hardening, not a live bug), but any future holder of a cloned error would match the wrong variant.

The two payloads are now Arc-wrapped, so Clone is a cheap reference bump that keeps the variant. Display strings are unchanged ({0} and crypto: {0}); the #[from] derives become manual From impls wrapping in Arc; the one behavioral trade-off is that source() is no longer forwarded for these two variants (Arc<E> does not implement std::error::Error), which nothing in the workspace consumed. A regression test pins discriminant and rendered message across clone for the hard-to-clone variants.

Ref rustfs/backlog#1831 (PR2).
2026-08-12 19:14:07 +00:00
Zhengchao An 3f9b84ec70 feat(kms): observe unknown fields in the last three silent persisted formats (#6003) 2026-08-13 03:08:49 +08:00
houseme 73bd5d9d95 perf(get): reduce request entry allocations (#6029)
Co-authored-by: heihutu <heihutu@gmail.com>
2026-08-12 19:07:59 +00:00
houseme 398d2d87c8 fix(ecstore): retry manual ILM job CAS updates (#6012)
Co-authored-by: heihutu <heihutu@gmail.com>
2026-08-12 18:40:10 +00:00
houseme 59d8d93832 perf(ecstore): release PUT lock before old-data cleanup (#6023)
Co-authored-by: heihutu <heihutu@gmail.com>
2026-08-12 17:40:32 +00:00
houseme 59494d5089 perf(get): reuse reader paths and lock namespaces (#6015)
Co-authored-by: heihutu <heihutu@gmail.com>
2026-08-12 17:37:25 +00:00
houseme 019e80a218 fix(admin): report live bucket count during usage scan (#6014)
Co-authored-by: heihutu <heihutu@gmail.com>
2026-08-12 17:32:05 +00:00
houseme 9546baf1ab perf(get): share metadata cache hits (#6010)
Keep fresh metadata fanout results owned while sharing cache-backed metadata through Arc, avoiding deep clones on eligible local cache hits without enabling unsafe distributed caching.

Co-authored-by: heihutu <heihutu@gmail.com>
2026-08-12 16:53:06 +00:00
Zhengchao An 60d8e8a20b refactor(kms): consolidate encryption metadata key constants into their shared home (#5995)
The shared module rustfs_utils::http::object_encryption_keys is the single source of truth for encryption metadata key names, but three call sites still carried their own copies or bare literals: crates/kms/src/service.rs (two private constants plus four bare x-rustfs-encryption-* literals on both the write and read path), rustfs/src/app/select_object.rs (six SELECT_* copies), and rustfs/src/storage/options.rs (two private prefix copies now imported from header_compat). All values are unchanged, so the change is a compiler-verified rename.

The reader-only x-rustfs-internal-server-side-encryption- family gets a named constant with the verified judgment recorded on it: no writer emits these keys anywhere in the repo (the SSE writer persists the MinIO-branded keys verbatim for interop), the two comments claiming the dual-key invariant writes this twin were wrong and are corrected, and the defensive redaction/strip readers are kept because removing them is risk-asymmetric.

rustfs-kms's rustfs-utils dependency now declares the http feature it uses instead of relying on feature unification from sibling crates.

Refs rustfs/backlog#1775, rustfs/backlog#1562.
2026-08-12 16:37:38 +00:00
houseme 24ca61eb6e perf(get): include small objects in codec streaming (#6004)
Co-authored-by: heihutu <heihutu@gmail.com>
2026-08-12 16:04:15 +00:00
houseme d92c563b9e perf(ecstore): keep decode scratch buffers inline (#6002)
Keep common shard-indexed decode scratch vectors inline while preserving heap fallback for larger supported erasure layouts. Consume scratch iterators directly at the stripe-state boundary to avoid reallocating.

Co-authored-by: heihutu <heihutu@gmail.com>
2026-08-12 15:40:32 +00:00