Skip to content

worktree: Include file size in DiskState to fix stale buffer reload - #51038

Closed
lex00 wants to merge 2 commits into
zed-industries:mainfrom
lex00:fix/38109-diskstate-size
Closed

lex00 wants to merge 2 commits into
zed-industries:mainfrom
lex00:fix/38109-diskstate-size

Conversation

@lex00

@lex00 lex00 commented Mar 8, 2026

Copy link
Copy Markdown
Contributor

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 no DiskState change and never triggers a second reload. The buffer is permanently stuck empty.

Root cause analysis: #38109 (comment)

Fix

Add size: u64 to DiskState::Present { mtime, size }. The derived PartialEq now detects size changes even when mtime matches, so a 0→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 (the reload path checks !self.is_via_collab()).

Changes

6 files:

  • worktree.rs: Add size to DiskState::Present, thread through File::for_entry() and entry change handler
  • buffer.rs: Update DiskState enum and file_updated() comparison
  • buffer_store.rs: Pass size from entry to local_worktree_entry_changed()
  • image_store.rs: Same for images
  • copilot.rs: Pass size: 0 for virtual copilot buffers
  • project_tests.rs: Two new integration tests

Related 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.

  • Tests
  • Code Reviewed
  • Manual QA

Release Notes:

  • Fixed an issue where open buffers could become permanently empty when external tools (AI agents, formatters) wrote files while they were open in the editor.

lex00 and others added 2 commits March 7, 2026 20:38
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>
@cla-bot cla-bot Bot added the cla-signed The user has signed the Contributor License Agreement label Mar 8, 2026
@probably-neb

Copy link
Copy Markdown
Collaborator

Thanks for taking a crack at this. I'm going to close as duplicate of #49436.
I realize you've added tests, however they aren't actually reproducing the issue - just testing that the derived equals works with the size added so I don't think they're worth keeping. Especially given that real FS tests tend to be quite flaky in CI.
Thanks again!

@lex00

lex00 commented Mar 10, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for taking a crack at this. I'm going to close as duplicate of #49436. I realize you've added tests, however they aren't actually reproducing the issue - just testing that the derived equals works with the size added so I don't think they're worth keeping. Especially given that real FS tests tend to be quite flaky in CI. Thanks again!

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.

@lex00

lex00 commented Mar 10, 2026

Copy link
Copy Markdown
Contributor Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed The user has signed the Contributor License Agreement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants