Commit Graph

1563 Commits

Author SHA1 Message Date
Zhengchao An 9db1d6f06b fix(ci): restore merged main Clippy lanes (#6612) 2026-08-26 10:19:47 +08:00
Zhengchao An 0ad6bf72cb fix(ci): restore merged main static gates (#6609) 2026-08-26 09:51:37 +08:00
唐小鸭 9118a6e344 feat(ecstore): closed-form range seek for single-part v2 encrypted objects (#6601)
Single-part encrypted objects in the legacy format could not serve range
reads without decrypting from byte 0: v1 frames are emitted per upstream
read, so no closed-form plaintext-to-ciphertext mapping exists. The v2
layout fixed the frame length (8218 ciphertext bytes per 8 KiB plaintext
frame), making the mapping closed-form.

Consume it:
- Single-part PUTs that encrypt locally under the v2 write switch stamp
  the frame-layout marker, valued with the object's data_dir token -
  ciphertext passthrough, data movement and copies mint a new data_dir
  or strip the marker, so a re-homed marker disqualifies itself.
- The encrypted read plan seeks marked, uncompressed single-part objects
  to frame_index * 8218 and decrypts from that frame: the frame index
  rides the plan's sequence-number slot into DecryptReader::new_at_block,
  whose nonce and AAD bind absolute indices. New metric path label
  frame_seek.
- A lying marker fails closed: v2 authentication rejects bytes at a fake
  frame boundary; plaintext is never served from the wrong offset.

Compressed objects and multipart sub-part seeks keep the conservative
paths (follow-up work); reading needs no switch - seekability follows
the marker.
2026-08-26 09:43:34 +08:00
唐小鸭 f469869620 feat(rio): authenticated fixed-frame v2 encryption layout behind a write switch (#6600)
The legacy rio v1 stream format authenticates only each frame's
ciphertext: the 8-byte header (length + plaintext CRC32) and the end
marker sit outside the AEAD, frames carry no position binding, and
nothing marks the last frame - header rewrites, frame reordering and
truncation of trailing frames are not cryptographically detected.

Add a v2 layout in the same format family, dispatched per frame by the
type byte:
- the header plus the frame's index are AEAD associated data (0x01), so
  header tampering, reordering and cross-position splicing fail
  authentication;
- the final frame carries its own authenticated type byte (0x02); a
  clean EOF or an end marker before it is an error, every stream
  (including the empty one) ends in an authenticated final frame, and a
  v2 multipart stream fails if it ends before all listed part segments;
- the writer accumulates full 8 KiB blocks, so non-final frames are
  fixed-length (8218 ciphertext bytes) and single-part objects gain a
  closed-form offset mapping for the follow-up range seek.

Key hierarchy, nonce derivation, envelopes and metadata are unchanged;
v1 objects stay readable forever, while v2 frames reject the historical
nonce fallbacks and unknown frame types become a hard error.

Write side ships off by default (RUSTFS_ENCRYPTION_FRAME_V2): mixed
version clusters cannot read v2 frames, and encrypted ciphertext travels
verbatim through transition, decommission and SSE-C replication
passthrough. This release ships read support; the default flips in a
following release.
2026-08-26 09:36:00 +08:00
唐小鸭 f51b06f0ae perf(ecstore): enable encrypted range part-seek by default (#6598)
Range GETs on encrypted objects read the whole ciphertext from offset 0
and discarded the decrypted prefix, because the part-boundary seek
shipped behind RUSTFS_ENCRYPTED_RANGE_SEEK defaulted to false
(backlog#1316 Phase A).

Flip the default to true. Safety rests on the marker chain: MPUs created
without a candidate layout marker never become seek-eligible,
CompleteMultipartUpload promotes the candidate to the quorum marker only
after revalidating it against the object's data_dir under the uploadId
write lock, and reads seek only when the quorum marker matches the
current data_dir. Single-part, compressed and markerless objects keep
the full-read path; RUSTFS_ENCRYPTED_RANGE_SEEK=false remains the kill
switch.

The stale default-off regression test becomes
test_legacy_range_seek_defaults_enabled: the unset-env default must
match the explicit opt-in plan, seek past the leading parts, and not
span the whole ciphertext.
2026-08-26 09:35:48 +08:00
houseme 59fd318192 perf(ecstore): optimize opts.clone() and FileInfo clone patterns (#6587)
* feat(mimalloc): add arena diagnostics and configuration

Based on mimalloc maintainer feedback (microsoft/mimalloc#1372),
add diagnostics to check mimalloc arena configuration at runtime.

Changes:
- Add rustfs-mimalloc-sys to workspace dependencies
- Add log_mimalloc_diagnostics() function to check:
  - arena_max_object_size
  - pagemap_commit status
  - mimalloc version
- Add memory_observability module with mimalloc diagnostics

This helps diagnose why allocations might be going outside arenas,
which is the suspected root cause of futex contention.

Ref: rustfs/backlog#2005
Ref: microsoft/mimalloc#1372

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

* perf(ecstore): add Vec<u8> buffer pool for EC operations

Add a general-purpose buffer pool to reduce Vec<u8> allocations
in hot paths like EC encoding/decoding.

Changes:
- Add BufferPool struct in crates/ecstore/src/erasure/codec/buffer_pool.rs
- Thread-safe pool with capacity-based bucketing (power-of-two)
- Global EC_BUFFER_POOL instance with 16 buffers per bucket
- Add buffer_pool module to codec/mod.rs

Expected impact:
- Reduce heap allocations in EC encode/decode paths
- Avoid memzero overhead (proven 4.8% CPU saving in ShardBufferPool)
- Reduce mimalloc lock contention

Note: Main bottleneck remains mimalloc internal synchronization
(futex 98.64% time). Buffer pool provides modest improvement (+2-5%).

Ref: rustfs/backlog#2005

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

* style: apply cargo fmt to buffer pool and related files

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

* fix(ecstore): add #[allow(dead_code)] to buffer pool

The BufferPool infrastructure is ready but not yet integrated
into the EC hot paths. Add #[allow(dead_code)] with clear
documentation about integration status.

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

* perf(ecstore): integrate BufferPool into bitrot verify path

Replace vec![0; shard_size] with get_ec_buffer() in the bitrot
verification hot path to reduce heap allocations and avoid memzero.

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

* style: apply cargo fmt to buffer pool and bitrot changes

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

* refactor(ecstore): clean up buffer pool code

- Remove unnecessary #[allow(dead_code)] attributes
- Update module documentation to reflect current integration status
- Simplify code structure

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

* perf(runtime): cap default worker threads at 16

Testing showed 16 worker threads outperforms 32+ for 1KiB PUT
workloads due to reduced mimalloc lock contention.

A/B test results (testing 4-node cluster, c=64):
- worker_threads=32: 740 obj/s (baseline)
- worker_threads=16: 785 obj/s (+6.1%)

The default was detect_cores() which returned 32 on our testing
nodes. Cap at 16 for optimal small-object performance.

Ref: rustfs/backlog#2005

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

* style: apply cargo fmt to buffer pool and runtime changes

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

* fix(ecstore): remove unused BufferPool::new() function

The new() function was never used since EC_BUFFER_POOL
initializes directly with with_limits(16).

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

* fix(ecstore): update buffer_pool tests to use with_limits

Replace BufferPool::new() with BufferPool::with_limits(16) in tests
since new() was removed in favor of with_limits().

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

* perf(ecstore): optimize opts.clone() and FileInfo clone patterns

## Changes

1. ObjectOptions helper methods:
   - add as_commit_opts(): creates commit options with no_lock=true,
     metadata_cache_safe=false, include_part_checksums=true
   - add as_read_opts(): creates read options with
     include_part_checksums=true
   - add with_no_lock(): creates options with modified no_lock field

2. Replace opts.clone() in hot paths:
   - commit_opts = opts.as_commit_opts() (was 4-line manual clone)
   - read_opts = opts.as_read_opts() (was 2-line manual clone)

3. Optimize FileInfo clone in rename path:
   - avoid double clone: clone once and modify erasure.index in place
   - pass &file_info reference to rename_data_borrowed_with_fence

## A/B Results (4-node cluster, c=64)

| Size | main | optimized | Change |
|------|------|-----------|--------|
| 1KiB | 892 obj/s | 920-976 obj/s | +3%~+9% |
| 4KiB | 957 obj/s | 903 obj/s | -5.7% |
| 16KiB | 922 obj/s | 855 obj/s | -7.3% |

Note: 1KiB improvement is consistent. 4KiB/16KiB variance
likely due to test noise; needs more rounds to confirm.

Ref: rustfs/backlog#2005

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

* perf(ecstore): add BytesMut buffer pool to EC encoding path

Pre-allocate a Vec<BytesMut> pool in the EC encoding loop to avoid
repeated heap allocations for ingest buffers.

Changes:
- Pre-allocate buffer pool with capacity 4
- Reuse buffers from pool after encoding
- Return buffers to pool when capacity is sufficient

Expected impact: +10-20% in EC encoding path by reducing
BytesMut allocation overhead.

Ref: rustfs/backlog#2005

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

---------

Co-authored-by: hector <hetor@rustfs.com>
Co-authored-by: heihutu <heihutu@gmail.com>
2026-08-26 09:35:09 +08:00
Zhengchao An 1bcb396752 fix(ecstore): version pool metadata transactions (#6604)
* fix(connect): adapt offline array predicate

* test(e2e): update smoke selection baseline

* test(ecstore): make slowtail oracle deterministic

* test(get): stage relocated fixture after reader opens

* ci: bound feature test link concurrency

* test: give lifecycle transition futures a larger stack

* fix(ecstore): version pool metadata transactions
2026-08-26 09:33:51 +08:00
Zhengchao An 51449f0975 test(e2e): update smoke selection baseline (#6582)
* fix(connect): adapt offline array predicate

* test(e2e): update smoke selection baseline

* test(ecstore): make slowtail oracle deterministic (#6583)
2026-08-26 09:32:53 +08:00
houseme 0f987714a1 fix(ecstore): handle metadata-less bucket residue (#6591)
* fix(ecstore): handle metadata-less bucket residue

Diagnose metadata-less on-disk residue before non-force DeleteBucket reaches physical deletion, and keep scanner-discovered metadata-missing objects on a non-destructive heal path.

Add explicit heal --remove cleanup for unversioned metadata-less data directories, using the existing data-dir delete primitive and fail-closed shape checks so pre-commit or unknown residue is preserved.

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

* fix(connect): adapt offline array validator

Wrap the filesystem summary validator in a closure so Option::is_some_and can pass the concrete array reference accepted by serde_json::Value::as_array.

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

* fix(connect): remove redundant offline test clones

Move the temporary path into the swap closure after deriving the output path, keeping clippy's redundant-clone lint clean for offline bundle tests.

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

---------

Co-authored-by: heihutu <heihutu@gmail.com>
2026-08-26 09:17:19 +08:00
GatewayJ 5a0367969a fix(replication): retry startup resync lock failures (#6570) 2026-08-25 21:21:30 +08:00
GatewayJ 0c155b1656 fix(put): reap cancelled eager commit owners (#6569) 2026-08-25 21:21:05 +08:00
Henry Guo 9db29c8a6f fix(heal): reconcile dangling objects after node reconnect (#6567) 2026-08-25 21:20:47 +08:00
Zhengchao An b15928220f test(ecstore): avoid virtual timeout for sync batch (#6551) 2026-08-25 14:30:49 +08:00
houseme 0c4c1caef8 perf(ecstore): add Vec<u8> buffer pool for EC operations (#6538)
* feat(mimalloc): add arena diagnostics and configuration

Based on mimalloc maintainer feedback (microsoft/mimalloc#1372),
add diagnostics to check mimalloc arena configuration at runtime.

Changes:
- Add rustfs-mimalloc-sys to workspace dependencies
- Add log_mimalloc_diagnostics() function to check:
  - arena_max_object_size
  - pagemap_commit status
  - mimalloc version
- Add memory_observability module with mimalloc diagnostics

This helps diagnose why allocations might be going outside arenas,
which is the suspected root cause of futex contention.

Ref: rustfs/backlog#2005
Ref: microsoft/mimalloc#1372

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

* perf(ecstore): add Vec<u8> buffer pool for EC operations

Add a general-purpose buffer pool to reduce Vec<u8> allocations
in hot paths like EC encoding/decoding.

Changes:
- Add BufferPool struct in crates/ecstore/src/erasure/codec/buffer_pool.rs
- Thread-safe pool with capacity-based bucketing (power-of-two)
- Global EC_BUFFER_POOL instance with 16 buffers per bucket
- Add buffer_pool module to codec/mod.rs

Expected impact:
- Reduce heap allocations in EC encode/decode paths
- Avoid memzero overhead (proven 4.8% CPU saving in ShardBufferPool)
- Reduce mimalloc lock contention

Note: Main bottleneck remains mimalloc internal synchronization
(futex 98.64% time). Buffer pool provides modest improvement (+2-5%).

Ref: rustfs/backlog#2005

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

* style: apply cargo fmt to buffer pool and related files

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

* fix(ecstore): add #[allow(dead_code)] to buffer pool

The BufferPool infrastructure is ready but not yet integrated
into the EC hot paths. Add #[allow(dead_code)] with clear
documentation about integration status.

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

* perf(ecstore): integrate BufferPool into bitrot verify path

Replace vec![0; shard_size] with get_ec_buffer() in the bitrot
verification hot path to reduce heap allocations and avoid memzero.

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

* style: apply cargo fmt to buffer pool and bitrot changes

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

* refactor(ecstore): clean up buffer pool code

- Remove unnecessary #[allow(dead_code)] attributes
- Update module documentation to reflect current integration status
- Simplify code structure

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

* perf(runtime): cap default worker threads at 16

Testing showed 16 worker threads outperforms 32+ for 1KiB PUT
workloads due to reduced mimalloc lock contention.

A/B test results (testing 4-node cluster, c=64):
- worker_threads=32: 740 obj/s (baseline)
- worker_threads=16: 785 obj/s (+6.1%)

The default was detect_cores() which returned 32 on our testing
nodes. Cap at 16 for optimal small-object performance.

Ref: rustfs/backlog#2005

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

* style: apply cargo fmt to buffer pool and runtime changes

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

* fix(ecstore): remove unused BufferPool::new() function

The new() function was never used since EC_BUFFER_POOL
initializes directly with with_limits(16).

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

* fix(ecstore): update buffer_pool tests to use with_limits

Replace BufferPool::new() with BufferPool::with_limits(16) in tests
since new() was removed in favor of with_limits().

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

---------

Co-authored-by: hector <hetor@rustfs.com>
Co-authored-by: heihutu <heihutu@gmail.com>
2026-08-25 10:45:44 +08:00
Zhengchao An 7be0d56be8 fix(storage): stabilize nextest regressions (#6543) 2026-08-24 23:34:18 +08:00
唐小鸭 3d75e7b51f fix(ecstore): heap-allocate durable ILM receipt futures (#6527)
PR #6369 awaits record_durable_ilm_decommission_progress/terminal inline
from save/delete_transition_transaction_record. Their state machines are
large and sit on the already-deep transition worker poll chain
(worker -> transition -> transaction record -> delete_config -> full
store delete fanout), which overflowed the default 2 MiB tokio worker
stack in debug builds: app::lifecycle_transition_api_test::
compensation_driven_complete_multipart_upload_still_transitions died
with SIGABRT in under a second (first-bad commit via git bisect
1.0.0-rc.3..1ec1a8d90: 34bbc1adb, #6369).

41546dee5 already unblocked the test by moving it onto a dedicated
32 MiB thread; this change removes the underlying stack growth so every
caller of the transaction-record helpers keeps its previous headroom.
With it, the test also passes on a plain 2 MiB tokio worker.
2026-08-24 20:38:46 +08:00
Zhengchao An e4dfc6f45b fix(quota): release reconciled delete holds (#6526) 2026-08-24 20:34:42 +08:00
Zhengchao An c1c6a1e23f fix(storage): stabilize main regressions (#6525) 2026-08-24 20:26:03 +08:00
Zhengchao An e2193cc42c fix(ecstore): enforce monotonic transition cursors (#6522) 2026-08-24 19:33:58 +08:00
Zhengchao An 6f14a79089 fix(quota): reconcile matching scanner usage (#6521) 2026-08-24 19:33:53 +08:00
cxymds c2b2b4ffd4 fix(ci): repair post-merge test gates 2026-08-24 17:01:29 +08:00
Zhengchao An 507faf3a6a fix(ci): restore post-merge test gates 2026-08-24 16:42:03 +08:00
Zhengchao An 7d3f5545e7 fix(ci): repair post-merge build gates 2026-08-24 16:10:24 +08:00
houseme 114bb4acec perf(ecstore): add bucket existence cache and allocator feature flags (#6496)
## Bucket existence cache
- Add BucketExistenceCache in crates/ecstore/src/disk/fs.rs
- Cache bucket directory existence checks with 60s TTL
- Replace access() calls with cached_access() in local.rs
- Add invalidate_bucket_cache() for cache invalidation on create/delete
- Reduces statx syscalls by 89% (from 10,716/s to 1,186/s)

## Allocator feature flags
- Add mimalloc and jemalloc features to rustfs/Cargo.toml
- Default: system allocator (Rust built-in)
- --features mimalloc: mimalloc allocator
- --features jemalloc: jemalloc allocator
- Allows A/B testing different allocators

## Performance impact
- 1KiB PUT: 861 obj/s (unchanged, futex is main bottleneck)
- statx reduction: 89% (from 10,716/s to 1,186/s)
- Main bottleneck remains mimalloc internal synchronization

Ref: rustfs/backlog#2005
Ref: microsoft/mimalloc#1372

Co-authored-by: hector <hetor@rustfs.com>
Co-authored-by: heihutu <heihutu@gmail.com>
Co-authored-by: overtrue <anzhengchao@gmail.com>
2026-08-24 14:35:04 +08:00
Zhengchao An 86e969f63c fix(ecstore): complete rename tails after quorum ack (#6489) 2026-08-24 14:30:50 +08:00
Henry Guo 60a0b1d6e7 fix(ecstore): avoid nested prefix listing amplification (#6473)
* fix(ecstore): avoid nested prefix listing probes

* fix(app): scope usage overlay import to tests

---------

Co-authored-by: Henry Guo <marshawcoco@users.noreply.github.com>
2026-08-24 14:29:35 +08:00
Zhengchao An 170a4c7640 fix(scanner): bootstrap pristine usage baseline (#6471)
* fix(ecstore): fence pool metadata replica updates

* fix(ecstore): block decommission on unsafe pool metadata

* fix(ecstore): block writes after pool metadata save errors

* fix(ecstore): latch pool metadata writes before await

* fix(scanner): bootstrap pristine usage baseline
2026-08-24 14:29:09 +08:00
唐小鸭 fc98dbb654 fix(replication): tolerate orphaned resync intents at startup (#6470)
* fix(replication): tolerate orphaned resync intents at startup

Since #5215 (1.0.0-beta.12) startup reconciles every pending/started
resync intent in resync.bin against the bucket's configured targets and
aborts the whole server when an intent has no matching target ARN. A
resync whose remote target was later removed leaves exactly such an
orphan on disk, so every later start fails with "accepted replication
resync target ... is not configured" regardless of the binary version.

Skip orphaned intents with a warning instead of failing startup; the
resync routine already settles them to ResyncFailed. Cancel the intent
when its remote target is removed so the orphan is not created again.

Fixes #4784

* fix(replication): cancel removed-target resync under the admission lock

Canceling through this node's cached whole-bucket status map could
persist a map that predates another node's admission, erasing that
node's durable restart intent. Reload resync.bin under the bucket
admission lock, publish the fresh map, and only then mark the removed
target's intent canceled. Two-node regression covers the clobber.

* fix(replication): persist resync status via ETag CAS merge

mark_status, the periodic saver, admission, and removed-target
cancellation all persisted their node's cached whole-bucket map, so any
one node's stale cache could resurrect states another node had already
finalized (a canceled intent flipping back to Pending, an admission
vanishing). All resync.bin writers now go through update_resync_status_cas:
load the freshest document with its ETag, apply a per-target mutation
with staleness and canceled-is-terminal guards re-checked against the
persisted entry, and save conditionally, retrying on concurrent writes.
The periodic saver merges per target, letting terminal states and newer
admissions recorded elsewhere win. Cache convergence stays per-target so
locally running resyncs keep their authoritative progress counters.

Regressions: stale_peer_status_write_cannot_resurrect_canceled_intent
(node B's pre-cancel cache marking its own run Started must not revive
node A's canceled intent) plus unit coverage for the periodic-save merge.

* test(ecstore): rename resync test helper off the guarded contract name

fn resync_target is on the architecture guard's reserved list for
crates/replication operation contracts; the merge-test helper now reads
resync_target_state.

* fix(replication): serialize resync status updates

---------

Co-authored-by: overtrue <anzhengchao@gmail.com>
2026-08-24 14:25:44 +08:00
Zhengchao An e091a7e702 fix(ecstore): fence pool metadata replica updates (#6466)
* fix(ecstore): fence pool metadata replica updates

* fix(ecstore): block decommission on unsafe pool metadata

* fix(ecstore): block writes after pool metadata save errors

* fix(ecstore): latch pool metadata writes before await
2026-08-24 14:25:19 +08:00
cxymds eec0e0e056 fix(scanner): fence movement generation publication (#6461)
* feat(scanner): add movement generation fencing

* fix(scanner): prioritize unverified cycle deferral

* feat(ecstore): add scanner publication lease fence

* feat(rpc): add scanner publication lease protocol

* feat(scanner): hold remote leases through usage publish

* test(scanner): cover publication lease fencing

* fix(scanner): fence remote leases across restart and delay

* feat(rpc): fence scanner publication rename writes

* fix(scanner): fence observed cleanup deletes

* fix(proto): qualify lease release test types

* fix(scanner): pin movement notifications

* fix(scanner): clean publication imports

* fix(ecstore): satisfy scanner fence clippy

* refactor(scanner): group wait and publication options

* fix(scanner): satisfy final lint and facade guards

* fix(rpc): resolve facade export conflicts

* fix(ci): remove unused decommission and healing facades

* fix(ci): cfg-gate test-only usage overlay import

* fix(scanner): wake on remote scanner restart
2026-08-24 14:17:35 +08:00
Zhengchao An f52a389652 fix(ecstore): persist unresolved decommission entries (#6415)
* fix(ecstore): persist unresolved decommission entries

* fix(ecstore): type decommission completion result

* fix(ecstore): allow intentional decommission listing signatures under strict clippy

The sftp/swift feature-matrix clippy gates run with -D warnings and
flag the unresolved-entry resolver (large Err payload by design, 8
context parameters) and the decommission listing driver (9 args).
Document why and align with the existing decommission_entry precedent.
2026-08-24 14:05:08 +08:00
Zhengchao An 73cd1b5be2 fix(ecstore): fence rebalance and decommission activation (#6400)
* fix(ecstore): fence rebalance and decommission activation

* fix(ecstore): fence lost activation locks

* fix(ecstore): bind rebalance workers to activation id

* fix(ecstore): close rebalance activation races

* test(ecstore): exercise lost rebalance commit fence

* fix(ecstore): repair rebalance fence test wiring

* test(ecstore): reuse rebalance metadata fixture

* fix(ecstore): satisfy rebalance activation clippy checks

* fix(ecstore): fence stale rebalance workers

* fix(ecstore): commit rebalance activation after persistence

* fix(ecstore): fence rebalance commits and unblock stop

* test(ecstore): exercise real rebalance fences

* fix(rebalance): cancel admin stop before activation wait

* fix(ecstore): fence multipart staging on rebalance lock loss

* fix(ecstore): adopt activations after durable commit

* fix(rebalance): preserve committed activation recovery

* fix(rebalance): make prepared stop terminal-safe

* fix(ecstore): repair rebalance test imports

* fix(ecstore): repair rebalance entry runtime failures

* test(ecstore): fix activation fence synchronization

* test(ecstore): scope rebalance disk trait import

* test(ecstore): observe decommission lock attempt

* fix(ecstore): align activation fence test imports

* fix(ecstore): remove duplicate activation test import

* fix(ecstore): resolve CI clippy failures

* fix: satisfy activation merge lint gates

---------

Co-authored-by: houseme <housemecn@gmail.com>
2026-08-24 14:03:21 +08:00
Zhengchao An 40bf9f0425 fix(ecstore): prefer active pool reads during decommission (#6475) 2026-08-24 09:36:35 +08:00
Zhengchao An 57eaa8228d fix(ecstore): migrate tier free versions during decommission (#6393) 2026-08-24 09:21:53 +08:00
Zhengchao An aa0a374aa4 style: rustfmt decommission import groups on main (#6474)
cargo fmt --check has been failing since #6410 landed: the merged
decommission import groups in core/pools.rs were not canonical
rustfmt output. Apply formatting verbatim, no code changes.
2026-08-24 03:07:49 +08:00
Zhengchao An 1ec1a8d90d fix(ecstore): run metadata decommission before buckets (#6410)
* fix(ecstore): run decommission metadata first

* fix(ecstore): clear clippy warnings

---------

Co-authored-by: houseme <housemecn@gmail.com>
2026-08-24 00:22:46 +08:00
Zhengchao An 28b3ecf547 fix(ci): restore main checks (#6467) 2026-08-24 00:15:58 +08:00
Zhengchao An 33341d5fcf fix(ecstore): unify decommission resume queue (#6403)
* fix(ecstore): unify decommission resume queue

* fix(ecstore): clear swift clippy warnings

* fix(ecstore): serialize decommission recovery

---------

Co-authored-by: houseme <housemecn@gmail.com>
2026-08-23 23:51:33 +08:00
Zhengchao An 2a43e021c9 fix(ecstore): fence bucket heal during decommission (#6416)
* fix(ecstore): fence bucket heal during decommission

* fix(ecstore): preserve unfenced heal compatibility

---------

Co-authored-by: houseme <housemecn@gmail.com>
2026-08-23 23:38:16 +08:00
Zhengchao An d269b90201 fix(ci): restore main branch checks (#6465)
* fix(protocols): add missing test dependency

* style(ecstore): fix decommission formatting
2026-08-23 23:34:46 +08:00
Zhengchao An 7f32c675ac fix(ecstore): recover pool metadata from replicas (#6457) 2026-08-23 23:22:03 +08:00
Zhengchao An 8ccf7151f3 fix(ecstore): persist cancel before signaling (#6423)
* fix(ecstore): persist decommission cancel before signaling

* test(ecstore): align cancel regressions with movement gate

---------

Co-authored-by: houseme <housemecn@gmail.com>
2026-08-23 23:17:14 +08:00
Zhengchao An 8c3aeaebed fix(ecstore): drain multipart uploads before decommission (#6414)
* fix(ecstore): drain multipart uploads before decommission

* fix(ecstore): prioritize active multipart pools

---------

Co-authored-by: houseme <housemecn@gmail.com>
2026-08-23 23:04:35 +08:00
唐小鸭 3ce01dcc73 fix(object-lock): unblock authorized replication writes on locked versions and tolerate cleared lock metadata (#6413) 2026-08-23 22:35:23 +08:00
Zhengchao An 18cde00fad fix(ecstore): retry decommission entries safely on source changes (#6419)
A single object's SourceChanged during decommission cleanup no longer
cancels the shared worker token and fails the whole pool operation.
Cleanup preflight and source-cleanup outcomes now retry per entry with
bounded attempts and cancellation-aware backoff, applied uniformly to
ordinary versions, delete markers, and tiered copies (removing the
try-once-only branches); every retry re-lists the entry and redoes
version multiset validation before touching the source. Only quorum
loss, unrecoverable system errors, or exceeding a pool-level
SourceChanged exhaustion threshold still fails the decommission, and
exhausted entries never delete their source versions.

Retry attempts, backoff, and deferred/exhausted reasons are logged per
entry for observability. Heavy regression tests spawn on dedicated
32MiB stacks following the existing store-test pattern.

Fixes rustfs/backlog#1913

Co-authored-by: houseme <housemecn@gmail.com>
2026-08-23 21:32:49 +08:00
Zhengchao An 5cedf73d7c fix(ecstore): terminate walk directory streams (#6462)
* fix(ecstore): terminate walk directory streams

* test(e2e): refresh node service selection

* fix(filemeta): initialize empty metacache streams
2026-08-23 21:32:39 +08:00
Zhengchao An 43a10e3c24 fix(ecstore): tolerate migration identity rewrites (#6447) 2026-08-23 20:24:04 +08:00
唐小鸭 31933c32f9 fix(replication): apply receiver-side LWW to inbound metadata categories (#6379) 2026-08-23 20:17:50 +08:00
唐小鸭 0e88a27d05 fix(admin): use madmin key names in list-remote-targets response (#6377) 2026-08-23 20:17:34 +08:00
houseme 3f3b9fd426 perf(ecstore): attribute batch read version wait stages (#6456) 2026-08-23 19:31:14 +08:00