Deduplicate PATHEXT extensions when resolving fallbacks#1937
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| let mut normalized = Vec::with_capacity(trimmed.len()); | ||
| normalized.extend(trimmed.iter().copied().map(ascii_uppercase_u16)); | ||
|
|
||
| if seen.insert(normalized) { | ||
| exts.push(OsString::from_wide(trimmed)); |
There was a problem hiding this comment.
Deduping PATHEXT removes required case variants on case-sensitive paths
The new HashSet in push_segment uppercases each PATHEXT segment and drops any later entry whose case differs only by ASCII (seen.insert(normalized)). On Windows directories that have case sensitivity enabled, the file system treats rsync.exe and rsync.EXE as distinct files. Users sometimes include both .exe and .EXE in PATHEXT to probe both cases. After this change only the first casing is ever tried, so a fallback binary that exists solely as the second casing will be skipped even though it is present on disk. The previous implementation probed all case variants and succeeded in this scenario, so this is a regression that can prevent fallback lookups from finding an installed binary on case-sensitive directories.
Useful? React with 👍 / 👎.
…3716) Static-analysis audit recording the runtime model decision for the io_uring integration. Recommends keeping io_uring synchronous and routing async callers through tokio::task::spawn_blocking (#1751) rather than adopting tokio-uring or building a custom poll-driven SQE submitter, on the grounds that fast_io must remain tokio-free and the session ring pool design (#1937) stays simpler when leases are synchronous.
…3894) Document that buffer-group ids are u16 in io_uring (max 65 535 per ring), audit current `BufferRing` lifecycle (kernel reclaims via `IORING_UNREGISTER_PBUF_RING` on drop, but no in-process allocator owns the namespace), sketch the long-running daemon worst case, and propose a hard-capped slab allocator with telemetry and a typed exhaustion error before #1936 / #1937 wire PBUF_RING through the per-session ring.
Rewrite the session-ring-pool design doc around the daemon-session framing: pool keyed by SessionId, lazy init, max-size and idle eviction, hazards around kernel-object lifetime and registered-fd reuse, and a bench plan that isolates session-startup latency. Recommend deferring implementation until #2243 (per-thread rings) lands so the pool layer does not inherit the SharedRing Arc<Mutex<RawIoUring>> bottleneck noted in #1876.
…4232) Records the signal layer, kernel constraints, and concrete trigger thresholds for adaptive sizing of the registered buffer pool under sustained pressure. Covers gaps left by the existing companion documents: CQE wait time, slot exhaustion counter, sustained backpressure window, IORING_REGISTER_BUFFERS_UPDATE shrink fast path, and cgroup v2 memory headroom. Recommends deferring the implementation until the session ring pool (#1937) lands so the sizer is tuned against the multi-ring workload that motivates it.
Introduces SessionRingPool, a small fleet of long-lived io_uring rings
that consumers lease for one submit/reap cycle, amortising
io_uring_setup(2) and IORING_REGISTER_* costs across daemon sessions.
The primitive lives in crates/fast_io/src/io_uring/session_pool.rs on
Linux with a stub in io_uring_stub.rs for other targets. Selection is
round-robin via a single relaxed AtomicUsize; per-ring contention falls
on individual std::sync::Mutex slots. Drop releases every ring
deterministically, including any SQPOLL kthread.
Existing shared_ring.rs consumers stay on the single-mutex pattern.
Migrations land one consumer at a time in follow-ups per the design
plan in docs/design/iouring-session-ring-pool-impl.md.
API surface:
- SessionRingPool::{new,try_new,acquire,acquire_slot,ring_count,config}
- SessionPoolConfig with from_io_uring_config / with_ring_count helpers
- RingLease: RAII handle dereferencing to &mut IoUring
… (#4285) Audits whether prerequisites for #1876 have landed and proposes splitting the work into reviewable subtasks (#1876-a through e). - #1874 (shared ring + POLL_ADD) shipped via PR #3553. - #1937 (session ring pool) shipped via PR #4275. - #1935 (hybrid tokio listener) shipped via PR #4278. - No io_uring task carries id #1875; the original dependency note most plausibly meant the session-pool and listener work above. Missing surface enumerated: pooled-ring constructors on the socket adapters, daemon plumbing for SessionRingPool, sync and async worker swaps, IORING_OP_LINK_TIMEOUT integration, and async-cancel discipline. Trigger conditions (kernel >= 5.6, io_uring feature, opt-in flag) and a five-step implementation plan included.
Catalogues the allocation site (BgidAllocator::allocate at crates/fast_io/src/io_uring/buffer_ring.rs:193) and the release site (BufferRing::Drop at buffer_ring.rs:720, deallocate at :245). Pins BgidExhausted definition (io_uring_common.rs:370) and the two raise sites. Identifies the gap that BGE-3 and BGE-4 need to close: no peak telemetry, unbounded free-list, no in-tree caller (production PBUF wiring is still pending under #1936/#1937). Lays out the free-list pool + Drop signal recycling plan for BGE-4 and the churn / loom / recovery stress matrix for BGE-5.
…3716) Static-analysis audit recording the runtime model decision for the io_uring integration. Recommends keeping io_uring synchronous and routing async callers through tokio::task::spawn_blocking (#1751) rather than adopting tokio-uring or building a custom poll-driven SQE submitter, on the grounds that fast_io must remain tokio-free and the session ring pool design (#1937) stays simpler when leases are synchronous.
…3894) Document that buffer-group ids are u16 in io_uring (max 65 535 per ring), audit current `BufferRing` lifecycle (kernel reclaims via `IORING_UNREGISTER_PBUF_RING` on drop, but no in-process allocator owns the namespace), sketch the long-running daemon worst case, and propose a hard-capped slab allocator with telemetry and a typed exhaustion error before #1936 / #1937 wire PBUF_RING through the per-session ring.
Rewrite the session-ring-pool design doc around the daemon-session framing: pool keyed by SessionId, lazy init, max-size and idle eviction, hazards around kernel-object lifetime and registered-fd reuse, and a bench plan that isolates session-startup latency. Recommend deferring implementation until #2243 (per-thread rings) lands so the pool layer does not inherit the SharedRing Arc<Mutex<RawIoUring>> bottleneck noted in #1876.
…4232) Records the signal layer, kernel constraints, and concrete trigger thresholds for adaptive sizing of the registered buffer pool under sustained pressure. Covers gaps left by the existing companion documents: CQE wait time, slot exhaustion counter, sustained backpressure window, IORING_REGISTER_BUFFERS_UPDATE shrink fast path, and cgroup v2 memory headroom. Recommends deferring the implementation until the session ring pool (#1937) lands so the sizer is tuned against the multi-ring workload that motivates it.
Introduces SessionRingPool, a small fleet of long-lived io_uring rings
that consumers lease for one submit/reap cycle, amortising
io_uring_setup(2) and IORING_REGISTER_* costs across daemon sessions.
The primitive lives in crates/fast_io/src/io_uring/session_pool.rs on
Linux with a stub in io_uring_stub.rs for other targets. Selection is
round-robin via a single relaxed AtomicUsize; per-ring contention falls
on individual std::sync::Mutex slots. Drop releases every ring
deterministically, including any SQPOLL kthread.
Existing shared_ring.rs consumers stay on the single-mutex pattern.
Migrations land one consumer at a time in follow-ups per the design
plan in docs/design/iouring-session-ring-pool-impl.md.
API surface:
- SessionRingPool::{new,try_new,acquire,acquire_slot,ring_count,config}
- SessionPoolConfig with from_io_uring_config / with_ring_count helpers
- RingLease: RAII handle dereferencing to &mut IoUring
… (#4285) Audits whether prerequisites for #1876 have landed and proposes splitting the work into reviewable subtasks (#1876-a through e). - #1874 (shared ring + POLL_ADD) shipped via PR #3553. - #1937 (session ring pool) shipped via PR #4275. - #1935 (hybrid tokio listener) shipped via PR #4278. - No io_uring task carries id #1875; the original dependency note most plausibly meant the session-pool and listener work above. Missing surface enumerated: pooled-ring constructors on the socket adapters, daemon plumbing for SessionRingPool, sync and async worker swaps, IORING_OP_LINK_TIMEOUT integration, and async-cancel discipline. Trigger conditions (kernel >= 5.6, io_uring feature, opt-in flag) and a five-step implementation plan included.
Catalogues the allocation site (BgidAllocator::allocate at crates/fast_io/src/io_uring/buffer_ring.rs:193) and the release site (BufferRing::Drop at buffer_ring.rs:720, deallocate at :245). Pins BgidExhausted definition (io_uring_common.rs:370) and the two raise sites. Identifies the gap that BGE-3 and BGE-4 need to close: no peak telemetry, unbounded free-list, no in-tree caller (production PBUF wiring is still pending under #1936/#1937). Lays out the free-list pool + Drop signal recycling plan for BGE-4 and the churn / loom / recovery stress matrix for BGE-5.
Rewrite the session-ring-pool design doc around the daemon-session framing: pool keyed by SessionId, lazy init, max-size and idle eviction, hazards around kernel-object lifetime and registered-fd reuse, and a bench plan that isolates session-startup latency. Recommend deferring implementation until #2243 (per-thread rings) lands so the pool layer does not inherit the SharedRing Arc<Mutex<RawIoUring>> bottleneck noted in #1876.
…4232) Records the signal layer, kernel constraints, and concrete trigger thresholds for adaptive sizing of the registered buffer pool under sustained pressure. Covers gaps left by the existing companion documents: CQE wait time, slot exhaustion counter, sustained backpressure window, IORING_REGISTER_BUFFERS_UPDATE shrink fast path, and cgroup v2 memory headroom. Recommends deferring the implementation until the session ring pool (#1937) lands so the sizer is tuned against the multi-ring workload that motivates it.
Introduces SessionRingPool, a small fleet of long-lived io_uring rings
that consumers lease for one submit/reap cycle, amortising
io_uring_setup(2) and IORING_REGISTER_* costs across daemon sessions.
The primitive lives in crates/fast_io/src/io_uring/session_pool.rs on
Linux with a stub in io_uring_stub.rs for other targets. Selection is
round-robin via a single relaxed AtomicUsize; per-ring contention falls
on individual std::sync::Mutex slots. Drop releases every ring
deterministically, including any SQPOLL kthread.
Existing shared_ring.rs consumers stay on the single-mutex pattern.
Migrations land one consumer at a time in follow-ups per the design
plan in docs/design/iouring-session-ring-pool-impl.md.
API surface:
- SessionRingPool::{new,try_new,acquire,acquire_slot,ring_count,config}
- SessionPoolConfig with from_io_uring_config / with_ring_count helpers
- RingLease: RAII handle dereferencing to &mut IoUring
… (#4285) Audits whether prerequisites for #1876 have landed and proposes splitting the work into reviewable subtasks (#1876-a through e). - #1874 (shared ring + POLL_ADD) shipped via PR #3553. - #1937 (session ring pool) shipped via PR #4275. - #1935 (hybrid tokio listener) shipped via PR #4278. - No io_uring task carries id #1875; the original dependency note most plausibly meant the session-pool and listener work above. Missing surface enumerated: pooled-ring constructors on the socket adapters, daemon plumbing for SessionRingPool, sync and async worker swaps, IORING_OP_LINK_TIMEOUT integration, and async-cancel discipline. Trigger conditions (kernel >= 5.6, io_uring feature, opt-in flag) and a five-step implementation plan included.
Catalogues the allocation site (BgidAllocator::allocate at crates/fast_io/src/io_uring/buffer_ring.rs:193) and the release site (BufferRing::Drop at buffer_ring.rs:720, deallocate at :245). Pins BgidExhausted definition (io_uring_common.rs:370) and the two raise sites. Identifies the gap that BGE-3 and BGE-4 need to close: no peak telemetry, unbounded free-list, no in-tree caller (production PBUF wiring is still pending under #1936/#1937). Lays out the free-list pool + Drop signal recycling plan for BGE-4 and the churn / loom / recovery stress matrix for BGE-5.
Summary
Testing
https://chatgpt.com/codex/tasks/task_e_6909b6f6f6d08323bd33c4e94f188fea