Conversation
When an external tool writes a file using `std::fs::write()` (truncate +
write), the scanner can read the 0-byte file during the truncation window.
The buffer reloads to empty. If the subsequent write produces the same
mtime, `file_updated()` sees no DiskState change and never triggers a
second reload — the buffer is permanently stuck empty.
Add `size: u64` to `DiskState::Present { mtime, size }`. The derived
PartialEq now detects size changes even when mtime matches, so a 0-to-N
byte transition always triggers ReloadNeeded. The scanner already tracks
file size in `Entry.size` — this threads it through `File::for_entry()`
and `local_worktree_entry_changed()` into the reload comparison.
Remote/collab callers pass `size: 0` since remote buffers don't make
local reload decisions.
Closes #38109
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Thanks for taking a crack at this. I'm going to close as duplicate of #49436. |
It wasn't really about the tests :) I was the one who first called it out on 38109 in the comments and made a PR fixing it, which I accidentally closed, my mistake. The PR that re-established the commit references me. Anyway no biggie, take care. |
|
original for reference: |
Related to #38109
Supersedes #48691
See also #49436 (independent implementation of the same fix)
Problem
When an external tool writes a file using
std::fs::write()(truncate + write), the scanner can read the 0-byte file during the truncation window. The buffer reloads to empty. If the subsequent write produces the same mtime,file_updated()sees noDiskStatechange and never triggers a second reload. The buffer is permanently stuck empty.Root cause analysis: #38109 (comment)
Fix
Add
size: u64toDiskState::Present { mtime, size }. The derivedPartialEqnow detects size changes even when mtime matches, so a 0→N byte transition always triggersReloadNeeded. The scanner already tracks file size inEntry.size— this threads it throughFile::for_entry()andlocal_worktree_entry_changed()into the reload comparison.Remote/collab callers pass
size: 0since remote buffers don't make local reload decisions (the reload path checks!self.is_via_collab()).Changes
6 files:
worktree.rs: AddsizetoDiskState::Present, thread throughFile::for_entry()and entry change handlerbuffer.rs: UpdateDiskStateenum andfile_updated()comparisonbuffer_store.rs: Pass size from entry tolocal_worktree_entry_changed()image_store.rs: Same for imagescopilot.rs: Passsize: 0for virtual copilot buffersproject_tests.rs: Two new integration testsRelated issues:
Note: the two integration tests use
allow_parking()+flush_fs_events()and must be run individually (--exact), not in parallel with other RealFs tests.Release Notes: