Close the three test-completeness items in rustfs/backlog#1180 that the earlier
hardening (rustfs/rustfs#4726, #4729) left unpinned; the other two of the five
(sharded cancel routing, bailout-handle error) already landed in rustfs/uring.
- rename_data end-to-end invalidation: drive the real `LocalDisk::rename_data`
commit (non-inline part, so `invalidate_part_paths` is non-empty) and assert
the destination part descriptor is dropped — not merely `rename_file`/`delete`.
Both production `rename_data` call sites share this invalidation, so a
"fix one copy, miss the other" regression is now caught. The test is
non-vacuous: it seeds the cache, removes the on-disk data dir out of band (the
cached fd keeps the old inode alive and clears the path for the directory
rename `rename_data` performs), and asserts a read still returns the OLD bytes
before the commit — which fails outright if the cache is off, so it cannot pass
without a live cache.
- FD_CACHE_TTL backstop: an injected short TTL proves the cache self-evicts a
descriptor with no explicit invalidation; a static check pins the 5s value.
- zero-length read bounds parity on the cache-HIT path: a `length == 0` read
past EOF must be rejected identically to the miss path and StdBackend, pinning
the #1173 fix against regression.
Refactors `FdCache::new` to delegate to a private `with_ttl(ttl)` helper so the
TTL backstop can be exercised with a short TTL instead of a multi-second wait.
Verified: `cargo test -p rustfs-ecstore` on Linux with real io_uring
(seccomp=unconfined, RLIMIT_NOFILE raised, RUSTFS_URING_TESTS_MUST_RUN=1 so a
degraded skip fails rather than passing vacuously).
Co-authored-by: heihutu <[email protected]>