Commit Graph

1759 Commits

Author SHA1 Message Date
overtrue 2ea71a8725 fix(ecstore): integrate verified rename preflight evidence 2026-09-05 12:30:42 +08:00
overtrue cbb494beb8 refactor(ecstore): preserve rename observations in commit module 2026-09-05 12:26:32 +08:00
overtrue c332ba3d41 test(ecstore): cover observed rename outer failures 2026-09-05 12:21:08 +08:00
overtrue 0658b228e1 fix(ecstore): preserve known preflight rename rejections 2026-09-05 12:08:28 +08:00
overtrue 03726fc322 test(ecstore): count decommission faults across retry restarts 2026-09-05 12:01:40 +08:00
overtrue 7b74dfddb0 fix(odm): resolve pagination Clippy failures 2026-09-05 11:55:42 +08:00
overtrue e1f8cb9b89 Merge remote-tracking branch 'origin/main' into overtrue/fix/ecstore-core-regressions 2026-09-05 10:10:36 +08:00
overtrue 8fa93227e9 refactor(ecstore): remove moved quota fence import 2026-09-05 10:10:36 +08:00
overtrue 8ddc3cd436 Merge remote-tracking branch 'origin/main' into overtrue/refactor/local-commit-boundary 2026-09-05 10:01:42 +08:00
overtrue ccf8e2362c test(ecstore): match sealed context fixture map type 2026-09-05 10:01:42 +08:00
overtrue 2cb0425380 Merge remote-tracking branch 'origin/main' into overtrue/fix/ecstore-write-completion 2026-09-05 09:57:43 +08:00
overtrue daba4f7b32 test(ecstore): match sealed context fixture map type 2026-09-05 09:57:43 +08:00
overtrue 5513dadb78 test(ecstore): mark rollback fixtures as inline data 2026-09-05 09:57:43 +08:00
overtrue 19690eba7b fix(ecstore): retain indeterminate rename recovery evidence 2026-09-05 09:57:43 +08:00
overtrue dbe0073362 fix(ecstore): retain per-disk rename rollback outcomes 2026-09-05 09:57:43 +08:00
overtrue 2a6b2f31c7 refactor(ecstore): remove moved quota fence import 2026-09-05 09:56:41 +08:00
overtrue fe079cd2e8 refactor(ecstore): isolate local object rename commit 2026-09-05 09:54:53 +08:00
overtrue a732698586 refactor(ecstore): isolate metadata quorum decisions 2026-09-05 09:54:53 +08:00
overtrue bbcc51c124 test(ecstore): mark rollback fixtures as inline data 2026-09-05 09:50:47 +08:00
cxymds b33693fc19 feat(tier): fence legacy state reconciliation (#7144) 2026-09-05 01:42:24 +00:00
overtrue dacb617ff1 refactor(ecstore): isolate local object rename commit 2026-09-05 09:37:50 +08:00
overtrue 664f8c92ed fix(ecstore): retain indeterminate rename recovery evidence 2026-09-05 09:32:22 +08:00
overtrue 544bd1d7cf docs(odm): clarify folded source probe pagination 2026-09-05 09:30:26 +08:00
overtrue 286a5bed18 fix(ecstore): drain backfill checkpoint before confirmation 2026-09-05 09:30:26 +08:00
overtrue e83ace9533 fix(ecstore): drain backfill checkpoint before confirmation 2026-09-05 09:29:01 +08:00
overtrue 9e71b92f91 test(ecstore): match sealed context fixture map type 2026-09-05 09:28:46 +08:00
overtrue dd3de6d1c4 fix(odm): reject non-progressing listing cursors 2026-09-05 09:26:58 +08:00
overtrue b3b3eb0d36 fix(ecstore): retain PUT staging after incomplete rollback 2026-09-05 09:26:34 +08:00
overtrue 70be76c54e fix(ecstore): retain PUT staging after incomplete rollback 2026-09-05 09:26:12 +08:00
overtrue d8d9c02dcf fix(ecstore): retain per-disk rename rollback outcomes 2026-09-05 09:25:35 +08:00
overtrue 413b880b23 fix(ecstore): drain durable control-plane write tails 2026-09-05 09:24:54 +08:00
overtrue de6ef09635 fix(ecstore): drain durable control-plane write tails 2026-09-05 09:24:29 +08:00
cxymds 6eb60f8e72 feat(tier): add durable probe intent protocol (#7151)
* feat(tier): add durable probe intent protocol

* test(tier): remove redundant intent clones
2026-09-05 09:06:05 +08:00
cxymds 8dd3cabd41 test(ecstore): stabilize transition generation fixture (#7140) 2026-09-05 00:46:19 +00:00
Zhengchao An e648f683bf fix: use BTreeMap for deterministic encryption context serialization (#7154)
SealScope::encryption_context() returned a HashMap whose key order is
non-deterministic. The FakeSealer test round-trips the context through
JSON serialization, and HashMap's random iteration order caused the
prefix comparison to intermittently fail with 'encryption context mismatch'.

Switch to BTreeMap which guarantees stable key ordering.
2026-09-05 07:21:25 +08:00
cxymds 193b1b7d3f test(ecstore): stabilize sealed context encoding (#7149) 2026-09-05 07:18:37 +08:00
cxymds 5f8b097172 fix(tier): bound distributed mutation latency (#7150) 2026-09-05 02:28:08 +08:00
Zhengchao An 146003a426 refactor(odm): separate source backends from namespace mapping (#7129)
refactor(odm): isolate read-only source backend contract
2026-09-04 21:40:07 +08:00
cxymds 65ed86f76e test(ecstore): run checkpoint publication test on large stack (#7134) 2026-09-04 12:39:18 +00:00
cxymds 3da3bcd9ee fix(tier): preserve credentials during backend validation (#7127)
* fix(tier): preserve credentials during backend validation

* test(tier): make clone redaction assertion clippy-clean
2026-09-04 12:24:02 +00:00
Zhengchao An 20e4fd7de6 feat(ecstore): add the sealed remote credential seam (#7137)
* feat(ecstore): add the sealed remote credential seam

Replication targets, remote tiers and on-demand migration sources will all
seal their stored secrets through one envelope rather than three
(rustfs/backlog#2168, design in docs/architecture/remote-credential-sealing-adr.md).

Adds the versioned envelope, the seal scope that binds a ciphertext to the
store, owner and field it belongs to, the sealer registration point, and the
fail-closed error type. ECStore still has no rustfs-kms dependency: the binary
installs a sealer the way it installs the event dispatch hook.

Nothing is wired to a consumer yet, so no stored format changes.

* docs(ecstore): name the event dispatch hook by module, not by symbol

The architecture guard keeps EVENT_DISPATCH_HOOK references inside the
event-notification owner module; the module doc cited the symbol only as an
example of the hook shape, so cite its file instead.
2026-09-04 12:11:49 +00:00
Zhengchao An 507447da12 fix(restore): reject SELECT restore and keep typed S3 errors (#7113)
* fix(restore): reject SELECT restore and keep typed S3 errors

RestoreObject accepted `Type=SELECT` requests, but the restore path can
only write the retrieved bytes back to the source key: `put_restore_opts`
built SELECT output options and `restore_transitioned_object` then PUT
them over the source bucket/object. On an unversioned bucket that dropped
`x-amz-restore`, user metadata and tags from the live object; on a
versioned bucket it published a bogus latest version. Nothing was ever
written to `OutputLocation.S3`, yet the response still carried a
fabricated `x-amz-restore-output-path`.

Reject SELECT at the API boundary with a typed NotImplemented, before any
guard or metadata write, and fail closed in `put_restore_opts` as the
backstop for any other caller.

Every other RestoreObject failure was collapsed into a `Custom` error
code, which serializes as a generic retryable 500: a missing key or
version, a malformed version-id, an object that was never transitioned,
an illegal `Days`, and authorization or storage failures all looked the
same to a client. Map them to their S3 identities instead — NoSuchKey,
NoSuchVersion, InvalidArgument, InvalidObjectState, InvalidRequest,
MalformedXML — by preserving `StorageError` through `post_restore_opts`
and letting `ApiError` do the mapping. The intentional 409
RestoreAlreadyInProgress and 503 SlowDown behaviour is unchanged, and
request validation now runs before any lock is taken.

backlog#1341, backlog#2205

* test(restore): give the typed-error regression the ecstore test stack

`execute_restore_object_maps_failures_to_typed_s3_errors` builds a real
ECStore fixture, and under nextest each test runs in a spawned thread with
libtest's 2 MiB stack. On Linux CI that overflowed: the test aborted with
SIGABRT / "fatal runtime error: stack overflow" while every other test in
the run passed.

Add it to the `ecstore-base-stack` filter in both the default and ci
profiles, alongside the other `package(rustfs)` tests that drive the same
store fixture. 4 MiB matches what the deeper multipart and access
roundtrips already use.
2026-09-04 12:04:28 +00:00
cxymds ff3c5a4989 fix(ilm): drain tier-delete recovery pages (#7133) 2026-09-04 10:46:19 +00:00
cxymds 4d226998e2 fix(ilm): chunk large tier-delete dispatches (#7123)
* fix(ilm): chunk large tier-delete dispatches

* fix(ilm): bound tier-delete chunk dispatch stack use
2026-09-04 10:30:32 +00:00
Zhengchao An 7ff578ff20 fix(ilm): notify on batch noncurrent version expiry (#7116)
The batch `NewerNoncurrentVersions` expiry path took a lifecycle event
argument and ignored it: after `delete_objects` committed it only evicted
the cache and scheduled replication deletes, so a successful noncurrent
version expiry was invisible to notification subscribers while the
equivalent current-version path emitted a lifecycle expiration event.

Emit that event from the batch path too, reusing the existing lifecycle
audit sink and event contract. Only entries that actually mutated
something are announced, and cache eviction and replication scheduling
keep their existing order and admission — the event is derived from the
committed result and a send failure never rolls back a delete.

"No error" is not enough to prove a mutation: the disk layer skips an
absent version and reports success, so a batch entry for a version that
was already gone came back indistinguishable from a committed delete.
The delete plan already resolves whether the source exists, so carry that
`source_missing` result on `DeletedObject` and let the lifecycle path
stay silent for versions it did not remove.

backlog#2202
2026-09-04 18:25:10 +08:00
Henry Guo f16a30b231 feat(scanner): expose authenticated dirty bucket snapshots (#7122)
* feat(scanner): add peer bucket dirty snapshots

* fix(scanner): keep dirty snapshot errors stable

* test(protos): satisfy dirty snapshot clippy

* fix(scanner): satisfy dirty snapshot clippy

---------

Co-authored-by: Henry Guo <marshawcoco@users.noreply.github.com>
2026-09-04 18:23:13 +08:00
cxymds 3654c147e2 fix(ilm): defer aborted dispatch cleanup to recovery (#7126) 2026-09-04 08:49:14 +00:00
cxymds fdb28e611f fix: bound tier free-version recovery sweeps (#7125) 2026-09-04 08:12:01 +00:00
Zhengchao An 9863f4848d feat(tier): report cluster tier stats and count tier requests (#7110)
`GET /v3/tier-stats` answered from whichever process received the
request, returning that node's rolling 24-hour transition counters as
if they were cluster totals, and the `TierRequestsSuccess` and
`TierRequestsFailure` metric names had no producer at all.

The body now separates the two quantities a tier carries. Stored
inventory comes from the persisted scanner usage snapshot, which is
already cluster-wide; rolling activity is summed over every member
through a new read-only `TierDailyStats` peer RPC. Rings are merged
rather than added, so an idle node's expired hours age out, and each
node counts only its own committed transitions, so a retry is counted
once. Coverage travels with the numbers: `activity.status` names the
reporting members and the ones that could not be asked, timed out, or
answered with a ring this build refuses to merge, and per-tier
inventory is absent rather than zero when the snapshot has no
accounting. The version 1 body stays reachable at `?format=legacy`.

Tier request counters are recorded at the two seams every remote
request passes through, so a new provider is counted by construction,
with a closed operation/outcome label set that can never grow a tier
name, endpoint or object key.

Closes rustfs/backlog#2207

Co-authored-by: cxymds <cxymds@gmail.com>
2026-09-04 09:40:03 +08:00
Zhengchao An 7dfc2ee5f0 feat(odm): merge the source listing into ListObjectsV2 (#7112)
* feat(odm): merge the source listing into ListObjectsV2

Adds policy.list_through: ListObjectsV2 merges the local and source
listings into one ordered page so clients see the whole namespace during
an on-demand migration. Local entries win a key both sides hold,
CommonPrefixes are unioned under a delimiter, and the continuation token
is an opaque versioned envelope carrying both cursors.

A source listing failure or an open breaker follows policy.source_error:
propagate answers 424, not_found answers from local state and marks the
response x-rustfs-on-demand-migration-list: local_only. Source listings
are capped at 10 per second per bucket.

* test(odm): refresh the e2e-full darwin selection digest

The list-through e2e module adds seven cases to the merge lane.
2026-09-04 09:08:35 +08:00