You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
refresh_listing: short-circuit on watcher-backed (M1)
- `refresh_listing` now checks the listing's volume `listing_is_watched(path)` and returns `TimedOut { timed_out: false }` immediately when the volume is keeping the cache fresh via `notify_mutation`. Eliminates the redundant post-transfer full re-read that wedged MTP (17 s + USB collision after every cancel/complete/error).
- Logs at debug under `target: "refresh_listing"` with `listing_id`, `volume_id`, and `path` when the short-circuit fires.
- New `caching::get_listing_volume_id_and_path` helper reads both fields in one lock acquisition.
- Tests: short-circuit on watched, fall-through on unwatched, fall-through on missing listing, fall-through on unregistered volume.
- Docs: extended `refresh_listing` rustdoc, updated `commands/CLAUDE.md` file map, added `refresh_listing` as the third consumer of `listing_is_watched` in `volume/CLAUDE.md`.
- Watcher-driven `handle_directory_change` callers (FSEvents debouncer, incremental fallback, full re-read fallback) are intentionally NOT gated — they're how the cache stays in sync.
| `file_system/` | File listing & writes | Directory module split by operation type. `mod.rs` has `expand_tilde()`, re-exports, and tests. `listing.rs`: streaming + virtual-scroll listing API, path queries, `find_first_fuzzy_match` (type-to-jump), benchmarking, `get_brief_column_text_widths` (per-column widest-filename text widths for Brief mode; replaces the removed `get_max_filename_width`). `refresh_listing` short-circuits on watcher-backed listings (`Volume::listing_is_watched(path) == true`): the cache is already kept fresh by `notify_mutation`, so a redundant full re-read after every transfer outcome (the FE's `refreshPanesAfterTransfer`) used to wedge slow volumes (MTP 17 s + USB session collision). Logs at debug `target: "refresh_listing"` when the short-circuit fires. `write_ops.rs`: create, copy, move, delete, trash, scan preview, conflict resolution, synthetic diff helpers. `volume_copy.rs`: cross-volume copy/move/scan, `SourceItemInput`. `drag.rs`: native drag, self-drag overlay. `e2e_support.rs`: feature-gated E2E/debug commands. |
Copy file name to clipboardExpand all lines: apps/desktop/src-tauri/src/file_system/volume/CLAUDE.md
+5-1Lines changed: 5 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -49,7 +49,11 @@ Optional methods default to `Err(VolumeError::NotSupported)` or `false`, so new
49
49
-`on_unmount()`: lifecycle hook called before unregistration. `SmbVolume` uses it to disconnect its smb2 session. Default is no-op.
50
50
-`scanner()` / `watcher()`: drive indexing hooks; `None` by default.
51
51
-`space_poll_interval()`: recommended interval for the live disk-space poller (`space_poller.rs`). Default 2 s (local volumes). `SmbVolume` and `MtpVolume` override to 5 s. `InMemoryVolume` returns `None` (no polling). The poller uses this to tick each volume at its own cadence.
52
-
- `listing_is_watched(path)`: returns `true` when this volume's cached listing for `path` is being kept in sync by a live watcher. Used by `file_system::listing::caching::try_get_watched_listing` (the "fresh-listing oracle") to decide whether write-op pre-flight scans can reuse a cached listing instead of re-reading. Default `false` so a new backend without a real watcher won't accidentally claim freshness. **Freshness contract**: a `true` result does NOT mean the cache is byte-perfect with the device right now. Every backend has a debounce or settling window between a real change and the cache reflecting it: local FS ≈ 10 ms (FSEvents coalesce), SMB 200 ms (watcher debounce; > 50 events/dir triggers a `FullRefresh`), MTP 500 ms (event debouncer plus per-device polling; many cameras emit no events at all, so on those `true` means only "the device is reachable"). Callers must treat the result as "fresh as our most recent observation" — the same guarantee a `list_directory` call gives. The MTP and SMB checks are volume-level, not path-level: when the gate flips true, every path on that volume becomes oracle-eligible.
52
+
-`listing_is_watched(path)`: returns `true` when this volume's cached listing for `path` is being kept in sync by a live watcher. Three consumers today:
53
+
1.`file_system::listing::caching::try_get_watched_listing` (the "fresh-listing oracle") — write-op pre-flight scans reuse a cached listing instead of re-reading.
54
+
2.`write_operations::delete::scan_volume_recursive` (the oracle-aware delete walker) — same idea, per-recursion-level.
55
+
3. The `refresh_listing` Tauri command (`commands/file_system/listing.rs`) — short-circuits the post-transfer redundant `list_directory` re-read entirely when the volume is keeping the cache fresh via `notify_mutation`. Without this, a 1k-entry MTP folder paid ~17 s + USB session collision after every transfer outcome, wedging the next user op.
56
+
Default `false` so a new backend without a real watcher won't accidentally claim freshness. **Freshness contract**: a `true` result does NOT mean the cache is byte-perfect with the device right now. Every backend has a debounce or settling window between a real change and the cache reflecting it: local FS ≈ 10 ms (FSEvents coalesce), SMB 200 ms (watcher debounce; > 50 events/dir triggers a `FullRefresh`), MTP 500 ms (event debouncer plus per-device polling; many cameras emit no events at all, so on those `true` means only "the device is reachable"). Callers must treat the result as "fresh as our most recent observation" — the same guarantee a `list_directory` call gives. The MTP and SMB checks are volume-level, not path-level: when the gate flips true, every path on that volume becomes oracle-eligible.
0 commit comments