6248 Commits
Author SHA1 Message Date
唐小鸭andGitHub bd66fa9dca test(e2e): poll for listing convergence after rolling upgrade restarts (#6997)
The mixed-version rolling upgrade suite asserted a single list_objects_v2
snapshot seconds after restarting a node. Peers keep a restarted node's
drive in Suspect/Returning for ~probe_interval(2s) x success_threshold(3),
and while one drive is excluded the strict listing quorum (write quorum,
3 of 4) drops objects that were themselves legally written at 3/4 during
an earlier node's identical post-restart window, under-counting the
listing (observed as 254 vs 258 in CI) even though every object still
GETs correctly. Replace the snapshot asserts with a bounded convergence
poll; a real upgrade data-loss regression still fails after the deadline.
2026-09-01 18:43:09 +08:00
1aea7541c8 fix(release): normalize development package versions (#6994)
* fix(release): normalize development package versions

* ci: build only the rustfs release binary

---------

Co-authored-by: Zhengchao An <[email protected]>
2026-09-01 18:32:16 +08:00
唐小鸭andGitHub 9e6d34785b test(ecstore): deflake inline fanout gate assertion under load (#6992)
test(ecstore): assert inline fanout gate on deterministic scheduled metric

non_inline_data_read_early_stop_does_not_add_inline_fanout_on_unequal_layout
compared disk_call_counters::KIND_READ_VERSION totals between the two-phase
read-plan gate being off and on. That counter records inside each spawned
fanout task, so the single-pending inline hedge read races the early-stop
abort_all(): whether the hedge task gets its first poll before cancellation
decides a 4-vs-5 count per read. Under concurrent nextest load the two reads
can disagree (reproduced locally at ~5% when run beside one other test,
matching the CI failure on PR #6961).

Assert on the rustfs_io_get_object_metadata_fanout_scheduled histogram
instead, which records the scheduling decision synchronously in the fanout
loop and is deterministic, using the CapturingRecorder + current-thread
runtime pattern already used by the neighboring tests in this module.
2026-09-01 18:31:35 +08:00
cxymdsandGitHub 03aecc5c3e fix(heal): avoid pool metadata lock recursion (#6991) 2026-09-01 18:31:21 +08:00
cxymdsandGitHub 45fe54e389 fix(admin): align tier backend error contract (#6988) 2026-09-01 18:31:07 +08:00
cxymdsandGitHub 2ed5c297ac fix(deps): update mysql_async to 0.37.1 (#7007) 2026-09-01 18:30:10 +08:00
Zhengchao AnandGitHub 23ab078c56 fix(ecstore): reclaim stale object prefixes (#6974) 2026-09-01 10:09:00 +00:00
cxymdsandGitHub 80c629bfe0 test(ci): refresh e2e full selection manifests (#6983) 2026-09-01 09:26:13 +00:00
47304cc68d feat(build): allow overriding release version (#6998)
Allow release builds to set RUSTFS_BUILD_VERSION at compile time while keeping the existing tag, short commit, and package-version fallback when the variable is unset or empty.

Co-authored-by: heihutu <[email protected]>
2026-09-01 17:08:46 +08:00
cxymdsandGitHub cee84561e7 fix(heal): preserve resumable retry signals (#6995) 2026-09-01 16:55:57 +08:00
Zhengchao AnandGitHub b09ce8e6b5 docs: make pre-pr validation conditional (#7001) 2026-09-01 16:48:21 +08:00
cxymdsandGitHub a45951260a test(ecstore): stabilize activation race capacity (#6989) 2026-09-01 16:05:04 +08:00
housemeandGitHub a41134eb8a chore(deps): update s3s and Rust MSRV (#6990)
* chore(deps): update s3s and Rust MSRV

* fix: silence startup IAM test hook warning
2026-09-01 07:35:08 +00:00
cxymdsandGitHub 35ce8cdb80 test(tier): enforce structured two-topology gate (#6985) 2026-09-01 14:12:11 +08:00
housemeandGitHub 0b1a588da5 fix: adapt object metadata to s3s DTO changes (#6981) 2026-09-01 13:04:23 +08:00
cxymdsandGitHub f6c6736a01 docs(deps): expand tokio-tar cleanup contract (#6984) 2026-09-01 12:07:07 +08:00
ab44ae7e83 fix(scanner): add supported usage state reset (#6972)
Add an authenticated scanner usage-state reset endpoint that publishes a fenced bootstrap marker for full rebuilds instead of requiring operators to delete usage metadata by hand.

Guard the reset with the scanner leader lock, storage publication epoch, and per-slot revision preconditions, and make startup resumable across stale cleanup leftovers while still rejecting newer conflicting usage state.

Co-authored-by: heihutu <[email protected]>
Co-authored-by: Zhengchao An <[email protected]>
2026-09-01 01:51:46 +00:00
Zhengchao AnandGitHub b0256e3453 test(e2e): cover mixed-version rolling upgrades (#6975) 2026-09-01 07:09:00 +08:00
Zhengchao AnandGitHub 14a77f9d79 fix(ecstore): supplement split latest listings (#6977) 2026-09-01 07:08:25 +08:00
Zhengchao AnandGitHub 436a1be899 ci: allow macOS release builds to finish (#6976) 1.0.0-rc.5-preview.2 2026-09-01 05:01:23 +08:00
1ea1dfa0a1 fix(put): honor bucket default SSE in path selection (#6970)
Co-authored-by: heihutu <[email protected]>
2026-09-01 03:43:39 +08:00
Zhengchao AnandGitHub c45a8c35c4 test(ecstore): cover disk metric sequence snapshot (#6872) 2026-09-01 03:43:26 +08:00
唐小鸭andGitHub 4932d1dedf fix(admin): allow re-pairing non-empty sites in site replication add (#6961)
The add preflight unconditionally rejected any topology with data on
more than one site, which made `replicate remove` a one-way door: a DR
cluster whose sites both hold data could never be re-paired, and the
only way out was wiping one side by hand.

Admit a multi-non-empty add when every bucket held by more than one
requested site is provably safe to merge through the existing
backfill/resync convergence: versioning must be Enabled on every holder
(so a same-key object from the peer lands as another version instead of
replacing the only copy) and object-lock enablement must match (lock
cannot be toggled after bucket creation). Incompatible adds are still
rejected, now with the operator recovery steps (empty one side, re-run
replicate add, resync) instead of a bare refusal. Bucket configs that
fail to decode fail the preflight closed.

A committed add now also clears this site's own half-finished
pending_remove, mirroring the join receiver (rustfs/rustfs#5963);
otherwise the reconcile tick would replay the stale removal against the
freshly re-paired peer and dismantle the new pairing.

Refs rustfs/backlog#2070
2026-09-01 01:21:06 +08:00
cxymdsandGitHub 041af14143 perf(s3): bound snowball member imports (#6945)
* fix(s3): harden Snowball extract error boundaries

* fix(s3): close Snowball extract compatibility gaps

* fix(s3): verify Snowball request body completion

* test(s3): reject forged Snowball streaming signatures

* build(deps): pin Snowball archive parser limits

* fix(s3): preserve Snowball trailer and member errors

* docs(architecture): register Snowball tar fork cleanup

* refactor(s3): route Snowball errors through object boundary

* ci(deps): allow pinned tokio-tar source

* fix: align Snowball archive codec detection

* fix(s3): harden Snowball codec compatibility

* fix(s3): preserve Snowball codec compatibility

* test(zip): align yield wake assertion with Tokio

* fix(rio): preserve legacy large-block reads

* fix(zip): accept blank tar numeric fields

* fix(s3): align Snowball member import semantics

* fix(s3): authorize PAX legal-hold conditions

* refactor(s3): preserve Snowball error boundary

* fix(iam): support legal-hold policy conditions

* perf(s3): bound Snowball member imports

* fix(s3): preserve bounded Snowball import contracts

* fix(s3): preserve bounded import invariants

* fix(s3): route Snowball limits through app boundary

* refactor(s3): keep bounded import errors behind facade

* fix(s3): satisfy Snowball feature lint gates

* fix(s3): preserve Snowball safety guardrails
2026-08-31 16:45:32 +00:00
e44007012b fix(scanner): recover legacy usage floor from backup (#6964)
* fix(scanner): recover legacy usage floor from backup

Allow scanner usage-floor startup and leadership fencing to use a valid legacy backup when the legacy primary read fails with a corruption-shaped error.

Keep v2 primary read failures, stale metadata, transient I/O, and missing or invalid backups fail-closed.

Co-Authored-By: heihutu <[email protected]>

* fix(scanner): cover legacy backup fencing gaps (#6966)

* fix(scanner): recover legacy usage from valid backup

* fix(scanner): recover legacy usage floor from backup

Allow scanner usage-floor startup and leadership fencing to use a valid legacy backup when the legacy primary read fails with a corruption-shaped error.

Keep v2 primary read failures, stale metadata, transient I/O, and missing or invalid backups fail-closed.

Co-Authored-By: heihutu <[email protected]>

* fix(scanner): cover legacy backup fencing gaps

---------

Co-authored-by: houseme <[email protected]>
Co-authored-by: heihutu <[email protected]>

---------

Co-authored-by: heihutu <[email protected]>
Co-authored-by: Henry Guo <[email protected]>
2026-09-01 00:01:38 +08:00
Zhengchao AnandGitHub e3ca1ca54c chore(release): prepare 1.0.0-rc.5 (#6968) 1.0.0-rc.5-preview.1 2026-08-31 23:54:35 +08:00
cxymdsandGitHub ec0a65703a fix(s3): align snowball member semantics (#6944)
* fix(s3): harden Snowball extract error boundaries

* fix(s3): close Snowball extract compatibility gaps

* fix(s3): verify Snowball request body completion

* test(s3): reject forged Snowball streaming signatures

* build(deps): pin Snowball archive parser limits

* fix(s3): preserve Snowball trailer and member errors

* docs(architecture): register Snowball tar fork cleanup

* refactor(s3): route Snowball errors through object boundary

* ci(deps): allow pinned tokio-tar source

* fix: align Snowball archive codec detection

* fix(s3): harden Snowball codec compatibility

* fix(s3): preserve Snowball codec compatibility

* test(zip): align yield wake assertion with Tokio

* fix(rio): preserve legacy large-block reads

* fix(zip): accept blank tar numeric fields

* fix(s3): align Snowball member import semantics

* fix(s3): authorize PAX legal-hold conditions

* refactor(s3): preserve Snowball error boundary

* fix(iam): support legal-hold policy conditions
2026-08-31 15:18:28 +00:00
hectorandGitHub 0d1e40ee73 ci: add storage engine workflow to functional test chain (#6971) 2026-08-31 23:05:15 +08:00
281e40f1cc fix(scanner): fit usage persistence within publication lease (#6967)
Lower the default scanner cache save timeout so the derived usage persistence budget stays inside the effective distributed publication lease window.

Add focused regressions for the default publication budget and bootstrap-pending observational baselines, and update operator docs with the new default.

Co-authored-by: heihutu <[email protected]>
2026-08-31 22:58:29 +08:00
7541bb2c5d fix(ecstore): stabilize decommission capacity retries (#6959)
* fix(heal): retry unavailable recreate targets

* fix(heal): refresh put-file epochs after target restart

* test(e2e): harden heal restart evidence

Co-Authored-By: heihutu <[email protected]>

* test(e2e): cancel competing heal before restart

Co-Authored-By: heihutu <[email protected]>

* fix(ecstore): complete decommission capacity recovery

* fix(ecstore): stabilize decommission capacity tests

Keep decommission test capacity snapshots deterministic across startup and mutation probes, serialize capacity-ledger entries during retries, and avoid reacquiring a multipart fence already covered by the outer migration fence.

Co-Authored-By: heihutu <[email protected]>

* fix(ecstore): satisfy decommission test lint

Co-Authored-By: heihutu <[email protected]>

* fix(ecstore): restore free-version decommission owner

Co-Authored-By: heihutu <[email protected]>

---------

Co-authored-by: marshawcoco <[email protected]>
Co-authored-by: heihutu <[email protected]>
Co-authored-by: overtrue <[email protected]>
2026-08-31 22:52:47 +08:00
25dd879cf4 test(perf): add PUT after-probes and node telemetry (#6965)
Co-authored-by: heihutu <[email protected]>
2026-08-31 14:28:13 +00:00
唐小鸭andGitHub af1ebbfb8e fix(admin): converge site replication IAM deletions and retry backoff (#6962)
* fix(admin): replay recorded IAM deletions in site replication retry drain

An IAM deletion whose peer delivery failed during an outage window was
previously unrecoverable without a manual repair: the collapsed retry
entry carries no body, the snapshot resend cannot express "this entity
no longer exists", and the drain escalated the entry into a permanent
marker. The deleted user kept working credentials on the peer until an
operator intervened — a security exposure (backlog#2071).

Record the verbatim deletion body (user/policy/group-removal/
policy-mapping-clear/service-account) in the persisted state, in the
same transaction as the retry-event upsert. The drain now replays the
recorded deletions before the snapshot resend — snapshot-after ordering
restores any entity recreated locally in the meantime — and settles the
collapsed entry when its whole liability is provably replayed. Entries
that predate recording, merge with legacy rows, or overflow the
per-peer record cap keep the escalation semantics: only explicitly
recorded deletion events are ever replayed, never a cross-site diff.

The peer apply handlers become idempotent for deletion shapes (missing
policy/group/member tolerated, matching the existing user-delete
tolerance), so a replayed deletion that already converged settles
instead of wedging the drain. The IAM change hook now attempts every
peer instead of failing fast, so a multi-site broadcast books a retry
entry (and deletion record) for each unreachable peer rather than only
the first. Repair success and peer removal clear the affected peer's
records alongside the entries they accompany.

* fix(admin): probe recovered peers to lift retry drain backoff

A bucket created while a peer was unreachable accumulated three failed
deliveries and entered exponential backoff (2400s and up, capped at a
day). After the peer recovered, the reconcile tick's drain kept
skipping the entry until the backoff elapsed, so the site stayed
diverged — NoSuchBucket resync noise on the source, missing bucket on
the peer — for up to 24 hours with nothing else driving convergence
(backlog#2071, round-four R1.6).

Split reachability from replay: the drain now probes each peer whose
replayable backlog is held back only by backoff (one cheap devnull POST
per peer per tick) and promotes the backlog when the peer answers, so a
recovered peer converges at the next 600s tick. A failed probe advances
nothing — retry counts only move on real delivery attempts, keeping the
exponential schedule intact for a peer that is genuinely down. The base
backoff still floors re-attempts against a reachable peer that keeps
rejecting a delivery. SITE_REPLICATION_RETRY_FAILED_AFTER stays at 3:
the flag is retryStats visibility only, and with the probe in place an
early failed mark is a timely operator signal rather than a dead end.

The drain tick also logs an operator-visible warning whenever the queue
holds failed or escalated entries, instead of backing off in silence.
2026-08-31 22:16:51 +08:00
唐小鸭andGitHub 3e3eb4d8d5 fix(replication): let replicated version purges pass the peer WORM gate (#6960)
A replicated version purge reaches the peer without the governance
bypass header, so a GOVERNANCE-retained version deleted on the source
with x-amz-bypass-governance-retention was rejected by the peer's WORM
deletion gate forever: retryStats ended at a permanent failed count and
the sites stayed diverged (issue #6850).

The source is authoritative for such a purge: the same WORM gate
already ran there, and GOVERNANCE retention with an authorized bypass
is the only lock state it can purge through. The peer's commit-time
deletion gate now treats an authorized replication delete addressed to
an explicit version as carrying that judged bypass, reusing the same
trust judgment as the replication write exemption
(ObjectOptions::replication_request, set only after the handler
authorized ReplicateDeleteAction). COMPLIANCE retention and legal hold
keep blocking replicated purges, and a plain client delete without the
bypass header stays rejected.
2026-08-31 22:16:38 +08:00
cxymdsandGitHub 48b6548988 ci(pool): add stage-aware expansion diagnostics (#6963) 2026-08-31 13:55:31 +00:00
cxymdsandGitHub 655f6ae452 fix(s3): align Snowball codec compatibility (#6943)
* fix(s3): harden Snowball extract error boundaries

* fix(s3): close Snowball extract compatibility gaps

* fix(s3): verify Snowball request body completion

* test(s3): reject forged Snowball streaming signatures

* build(deps): pin Snowball archive parser limits

* fix(s3): preserve Snowball trailer and member errors

* docs(architecture): register Snowball tar fork cleanup

* refactor(s3): route Snowball errors through object boundary

* ci(deps): allow pinned tokio-tar source

* fix: align Snowball archive codec detection

* fix(s3): harden Snowball codec compatibility

* fix(s3): preserve Snowball codec compatibility

* test(zip): align yield wake assertion with Tokio

* fix(rio): preserve legacy large-block reads

* fix(zip): accept blank tar numeric fields
2026-08-31 13:09:51 +00:00
61821a6f3e fix(heal): resume remote rebuilds after target restart (#6941)
* fix(heal): retry unavailable recreate targets

* fix(heal): refresh put-file epochs after target restart

* test(e2e): harden heal restart evidence

Co-Authored-By: heihutu <[email protected]>

* test(e2e): cancel competing heal before restart

Co-Authored-By: heihutu <[email protected]>

---------

Co-authored-by: houseme <[email protected]>
Co-authored-by: heihutu <[email protected]>
2026-08-31 19:39:47 +08:00
hectorandGitHub 896781a52b feat(ci): add upgrade compatibility suite and reorder functional chain (#6950)
New RustFS Upgrade Test workflow (SUITE: upgrade) runs first in the
nightly functional chain:

- Nightly GNU Build -> Upgrade -> S3 -> KMS -> Tier -> Pool/Heal -> Security
- S3 compatibility now triggers on "RustFS Upgrade Test" completion, so an
  upgrade regression gates the rest of the chain.
- Security suite moves to the end, after pool/heal, on the shared VMs.
- The upgrade suite drives auto-testing's rustfs-upgrade-test.sh
  (UPG-101..402): seed golden data/identity/config on the OLD deb, upgrade
  in place to the NEW deb, verify byte-identical preservation, and publish
  functional-reports/upgrade/<date>.md.
- Add the Upgrade tab to every dashboard index writer so the shared
  functional/index.html stays consistent.
2026-08-31 19:32:07 +08:00
hectorandGitHub 612dd38fea ci(kms): add enforcement/frame/config-secret lane inputs (#6946)
New backlog#2024 KMS supplements (KMS-106..502) are gated behind node env
flags. Add workflow_dispatch inputs that append the corresponding
KEY=VALUE lines to /etc/default/rustfs via the suite's --extra-env option:

- enforce_sse_key_policy -> RUSTFS_KMS_ENFORCE_SSE_KEY_POLICY (KMS-401/402)
- frame_v2               -> RUSTFS_ENCRYPTION_FRAME_V2 (KMS-318)
- config_secret          -> RUSTFS_KMS_CONFIG_SECRET (KMS-107)

Nightly runs keep the default local+vault-kv2 lane unchanged.
2026-08-31 19:31:51 +08:00
cxymdsandGitHub ff28b79088 fix(s3): harden Snowball archive extraction (#6942)
* fix(s3): harden Snowball extract error boundaries

* fix(s3): close Snowball extract compatibility gaps

* fix(s3): verify Snowball request body completion

* test(s3): reject forged Snowball streaming signatures

* build(deps): pin Snowball archive parser limits

* fix(s3): preserve Snowball trailer and member errors

* docs(architecture): register Snowball tar fork cleanup

* refactor(s3): route Snowball errors through object boundary

* ci(deps): allow pinned tokio-tar source

* ci(e2e): refresh Snowball smoke selection
2026-08-31 11:18:09 +00:00
唐小鸭andGitHub 35456bcede test(scanner): serialize tests sharing process-global scanner state (#6940)
Under the cargo test fallback (threads in one process), tests that touch
the process-global scanner cycle recovery status or the global usage-save
metrics raced each other and failed randomly in full-suite runs.

Mark all touchers with #[serial] per docs/testing/README.md:
- 22 tests reading or writing scanner_cycle_recovery_status() via
  load_scanner_cycle_state_for_startup / reset_scanner_cycle_recovery
- 24 tests mutating global_metrics() usage-save counters via
  store_data_usage_in_backend*, which raced the existing serial
  test_deferred_usage_save_keeps_last_real_save_metric

No-op under nextest, which isolates each test in its own process.
2026-08-31 18:20:25 +08:00
Zhengchao AnandGitHub 9d4ccb7884 fix(ecstore): finalize decommission capacity recovery (#6955) 2026-08-31 18:09:09 +08:00
Zhengchao AnandGitHub 9a22cb85f3 fix(ecstore): complete decommission capacity recovery (#6949) 2026-08-31 16:53:14 +08:00
Zhengchao AnandGitHub 6c67086d0b fix(ecstore): reserve decommission capacity safely (#6917) 2026-08-31 15:20:09 +08:00
hectorandGitHub ea01cd339c fix(ci): continue functional chain and publish heal/pool reports (#6932) 2026-08-31 15:19:46 +08:00
bb37841362 chore(capacity): update default refresh tuning (#6938)
Align object-capacity refresh defaults with the production-oriented environment values and keep docs, script examples, and tests in sync.

Co-authored-by: heihutu <[email protected]>
2026-08-31 14:43:59 +08:00
GatewayJandGitHub 59a7194d7f feat(s3select): schedule streaming progress events (#6913)
* feat(s3select): schedule streaming progress events

* test(s3select): poll permit release until timeout
2026-08-31 13:36:47 +08:00
GatewayJandGitHub f647ada320 feat(table-catalog): update object namespace properties (#6815)
* feat(table-catalog): update object namespace properties

* test(table-catalog): cover object namespace properties

* fix(ci): use admin storage contract in catalog test

* fix(table-catalog): reject corrupt namespace properties
2026-08-31 13:36:23 +08:00
GatewayJandGitHub 589a954478 feat(s3select): support compressed CSV and JSON input (#6915) 2026-08-31 13:35:59 +08:00
1d606e1cf6 perf(ecstore): retry degraded GET with late parity (#6933)
Co-authored-by: heihutu <[email protected]>
2026-08-31 13:32:46 +08:00
Zhengchao AnandGitHub dc2e25b48c fix(admin): preserve raw XML in metadata backups (#6936) 2026-08-31 13:15:35 +08:00