perf(WinFSP): Phase 33 Windows Async FilePointer Resolution#389
Conversation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add PendingFilePointer struct for channel-based async results - Add resolve_single_file_pointer async fn with 3-retry exponential backoff - Add file_pointer_tx/rx channel and resolving_file_pointers dedup guard to CipherBoxFS - Add drain_file_pointer_completions() method to consume resolved results - Replace blocking block_with_timeout() loop in drain_refresh_completions() with async task spawning - Scope FilePointer resolution to parent folder via get_unresolved_file_pointers_for_parent() - Re-export PendingFilePointer in desktop fuse module Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…constructors - Add file_pointer_tx/rx channel pair creation in Windows mount_filesystem() - Add file_pointer_tx/rx channel pair creation in macOS mount_filesystem() - Initialize resolving_file_pointers HashSet in both CipherBoxFS constructors - Both cargo check -p cipherbox-fuse and cargo check -p cipherbox-desktop pass Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add 33-01-SUMMARY.md with execution results - Update STATE.md with plan progress and decisions - Update ROADMAP.md with plan 01 completion Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…lepointer-resolution # Conflicts: # .planning/ROADMAP.md
…llbacks - Add status_device_not_ready() NTSTATUS helper (0xC00000A3) to operations.rs - Add drain_file_pointer_completions() calls to handle_open, handle_read, handle_read_directory - Add read-while-resolving poll loop in handle_read with 5s timeout for in-flight FilePointer resolution - Return STATUS_DEVICE_NOT_READY on poll timeout (Explorer retries automatically) - Use mutable cid/key/iv/mode locals for in-place update after resolution completes
- Add 33-02-SUMMARY.md with execution results - Update STATE.md with metrics and progress - Update ROADMAP.md with phase 33 completion
… drain logs Collapse redundant double InodeKind::File pattern match in FilePointer resolution poll loop into a single match with all fields extracted at once. Use the previously-unused ipns_name field in drain_file_pointer_completions log messages for better debuggability. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (12)
WalkthroughThis PR documents and implements Phase 33 (Windows Async FilePointer Resolution), completing project planning documents while adding Windows-specific async FilePointer resolution with polling-based retry behavior in read operations. Changes
Sequence Diagram(s)sequenceDiagram
participant Client as WinFsp Client
participant Handler as handle_read()
participant Drain as drain_file_pointer_completions()
participant Tasks as Async Resolution<br/>Tasks
participant Inode as Inode Table
Client->>Handler: read() with unresolved cid
Handler->>Inode: check metadata (cid empty,<br/>resolution in-flight)
alt Resolution in progress
Handler->>Handler: start 5s polling loop
loop Every ~100ms iteration
Handler->>Drain: drain pending completions
Drain->>Tasks: receive resolved FilePointers
Tasks-->>Inode: update file_meta_resolved
Handler->>Inode: check file_meta_resolved
alt Resolved
Inode-->>Handler: return resolved cid/keys
Handler->>Handler: update mutable bindings
Handler->>Handler: break loop
else Still resolving
Handler->>Handler: continue polling
end
end
alt Timeout elapsed
Handler-->>Client: return status_device_not_ready()
else Resolution completed
Handler->>Handler: decrypt & read with<br/>resolved metadata
Handler-->>Client: return data
end
else No in-flight resolution
Handler->>Handler: proceed with normal flow
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~18 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@coderabbitai please review |
|
A couple of notes based on long-term memory going into this review:
🧠 Learnings used✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Pull request overview
This PR implements Phase 33’s goal of preventing Windows Explorer hangs by moving FilePointer resolution off the WinFsp filesystem callback thread, using tokio-spawned background tasks and draining completions on subsequent callback entry.
Changes:
- Replaces the blocking FilePointer resolution loop in
drain_refresh_completions()with async task spawning + 3-retry exponential backoff, delivering results via an mpsc channel. - Wires Windows WinFsp callbacks (open/read/readdir) to drain FilePointer completions; adds a bounded read-while-resolving poll that returns
STATUS_DEVICE_NOT_READYafter 5s. - Updates desktop mount constructors to initialize the new FilePointer channel + dedup state; updates planning/state docs and workspace lockfile.
Reviewed changes
Copilot reviewed 16 out of 17 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
crates/fuse/src/lib.rs |
Adds PendingFilePointer channel + dedup set; async resolver with retry/backoff; spawns per-FilePointer tasks during refresh; drains completions into inode table. |
crates/fuse/src/platform/windows/read_ops.rs |
Drains FilePointer completions in open/read; polls up to 5s for in-flight resolution before returning STATUS_DEVICE_NOT_READY. |
crates/fuse/src/platform/windows/dir_ops.rs |
Drains FilePointer completions on read_directory entry. |
crates/fuse/src/platform/windows/operations.rs |
Adds status_device_not_ready() helper (0xC00000A3). |
apps/desktop/src-tauri/src/fuse/windows/mod.rs |
Initializes FilePointer channel + resolving set in Windows FS constructor. |
apps/desktop/src-tauri/src/fuse/mod.rs |
Re-exports PendingFilePointer; initializes FilePointer channel + resolving set in mount setup. |
Cargo.lock |
Bumps internal workspace crate versions to 0.4.0. |
.planning/phases/33-windows-async-filepointer-resolution/* |
Adds Phase 33 research/plan/summary/verification/validation artifacts. |
.planning/STATE.md / .planning/ROADMAP.md / .planning/PROJECT.md |
Marks Phase 33 complete and updates project state metadata. |
- Lower FilePointer resolution success log from info to debug to avoid log spam in folders with many files (Copilot review thread #2) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Phase 32 (main) introduced shared async FilePointer infrastructure with different naming (filepointer_rx/tx, drain_filepointer_completions, enum PendingFilePointer) and additional features (concurrency cap, timeout). Phase 33's Windows-specific code adapted to use Phase 32's conventions. Resolved: - PendingFilePointer: keep Phase 32's enum (Success/Failure variants) - Field names: filepointer_rx/tx (Phase 32) not file_pointer_rx/tx (Phase 33) - Drain function: drain_filepointer_completions (Phase 32 naming) - Spawn logic: Phase 32's concurrency cap + timeout + better error handling - Removed Phase 33's resolve_single_file_pointer (superseded by Phase 32 inline) - Planning docs: merged both phases' completion status
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #389 +/- ##
===========================================
+ Coverage 61.15% 71.17% +10.01%
===========================================
Files 132 111 -21
Lines 9750 6783 -2967
Branches 976 976
===========================================
- Hits 5963 4828 -1135
+ Misses 3573 1741 -1832
Partials 214 214
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
If async resolution fails quickly, drain_filepointer_completions removes the ino from resolving_file_pointers but the poll loop previously kept sleeping until the 5s timeout. Now breaks immediately when the ino is no longer in-flight, falling through to the existing empty-cid handler. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@coderabbitai please review |
|
One long-term memory housekeeping note: learning ⛔ Learnings removed🧠 Learnings used✅ Actions performedReview triggered.
|
Summary
Phase 33: Windows Async FilePointer Resolution
Goal: WinFsp FilePointer resolution no longer blocks the filesystem thread, eliminating Explorer hangs during metadata refresh on Windows
Status: Verified ✓ (9/9 must-haves + runtime verified on Windows 11 + WinFsp)
Replaces the blocking O(N × NETWORK_TIMEOUT) FilePointer resolution loop with async task spawning via tokio. Each unresolved FilePointer now resolves in a background task with 3-retry exponential backoff, while WinFsp callbacks drain completed results on entry. If a read hits an in-flight resolution, it polls for up to 5s before returning STATUS_DEVICE_NOT_READY (0xC00000A3) — a transient NTSTATUS that Explorer retries automatically.
Changes
Plan 33-01: Async FilePointer Resolution Infrastructure
Shared infrastructure used by both macOS and Windows platforms.
Key files modified:
crates/fuse/src/lib.rs—PendingFilePointerstruct,resolve_single_file_pointerasync fn (3-retry exponential backoff),drain_file_pointer_completions()method, non-blockingdrain_refresh_completions()with async task spawning, dedup guard viaresolving_file_pointersHashSetapps/desktop/src-tauri/src/fuse/windows/mod.rs— Windows constructor channel initializationapps/desktop/src-tauri/src/fuse/mod.rs— macOS constructor channel initializationPlan 33-02: Windows WinFsp Callback Wiring
Wires the async resolution into Windows WinFsp callback entry points.
Key files modified:
crates/fuse/src/platform/windows/read_ops.rs—drain_file_pointer_completions()inhandle_openandhandle_read, FilePointer resolution poll loop with 5s timeout,status_device_not_readyreturn on timeoutcrates/fuse/src/platform/windows/dir_ops.rs—drain_file_pointer_completions()inhandle_read_directorycrates/fuse/src/platform/windows/operations.rs—status_device_not_ready()NTSTATUS helper (0xC00000A3)Verification
cargo test -p cipherbox-fuse --features winfsp: 24/24 tests passedcargo check -p cipherbox-desktop --features winfsp: compiled (0 errors)Key Decisions
STATUS_DEVICE_NOT_READY(0xC00000A3) chosen overSTATUS_IO_DEVICE_ERROR— Explorer treats it as transient and retries automaticallyget_unresolved_file_pointers_for_parent(refresh.ino)to avoid wrong-folder-key decryption🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes
Documentation