Add size to DiskState to detect file changes - #49436
Merged
probably-neb merged 3 commits intoMar 10, 2026
Merged
Conversation
The buffer's file_updated() method was only comparing mtime to determine if a buffer needed to be reloaded. This caused a race condition when external tools write files using std::fs::write(), which uses O_TRUNC and creates a brief window where the file is 0 bytes. If Zed's scanner reads during that window, the buffer could get stuck with stale/empty content. This fix adds the file size to DiskState::Present, so that even when mtime stays the same (or has same-second granularity), size changes (0 -> N bytes) will trigger a reload. Fixes zed-industries#38109 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Contributor
|
Hey @ImBIOS — I independently identified the same root cause and had a PR up for this back in February (#48691, opened Feb 7). I'm refiling it now with a rebased branch. My version includes integration tests covering both the truncate-then-write race and the mtime-differs recovery path, plus threading the size through image_store and copilot callers. Happy to coordinate — let me know if you'd prefer to merge efforts or if you'd like me to reference your PR from mine. |
3 tasks
Collaborator
|
Thanks for the fix @ImBIOS! Sorry it took so long for me to review. |
|
This didn't make the https://zed.dev/releases/stable/0.227.1 cut right? |
jonx
pushed a commit
to jonx/zed-aros
that referenced
this pull request
Jul 17, 2026
## Summary This fix addresses the cross-platform root cause identified in issue zed-industries#38109 where open buffers go stale or empty when external tools write files. ## The Problem The buffer's `file_updated()` method was only comparing `mtime` to determine if a buffer needed to be reloaded. This caused a race condition when external tools write files using `std::fs::write()`, which uses `O_TRUNC` and creates a brief window where the file is 0 bytes: 1. Scanner re-stats → sees 0 bytes, mtime T 2. `file_updated()` sees mtime changed → emits `ReloadNeeded` 3. Buffer reloads to empty, stamps `saved_mtime = T` 4. Tool finishes writing → file has content, but mtime is still T (or same-second granularity) 5. Scanner re-stats → mtime T matches `saved_mtime` → **no reload triggered** 6. Buffer permanently stuck empty ## The Fix Release Notes: - Add the file `size` to `DiskState::Present`, so that even when mtime stays the same, size changes (0 → N bytes) will trigger a reload. This is the same fix that was identified in the issue by @lex00. ## Changes - `crates/language/src/buffer.rs`: Add `size: u64` to `DiskState::Present`, add `size()` method - `crates/worktree/src/worktree.rs`: Pass size when constructing File and DiskState::Present - `crates/project/src/buffer_store.rs`: Pass size when constructing File - `crates/project/src/image_store.rs`: Pass size when constructing File - `crates/copilot/src/copilot.rs`: Update test mock ## Test plan - [ ] Open a file in Zed - [ ] Write to that file from an external tool (e.g., `echo "content" > file`) - [ ] Verify the buffer updates correctly without needing to reload Fixes zed-industries#38109 --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> Co-authored-by: Ben Kunkle <ben.kunkle@gmail.com> Co-authored-by: Jakub Konka <kubkon@jakubkonka.com>
jolutz
pushed a commit
to jolutz/zed
that referenced
this pull request
Aug 8, 2026
## Summary This fix addresses the cross-platform root cause identified in issue zed-industries#38109 where open buffers go stale or empty when external tools write files. ## The Problem The buffer's `file_updated()` method was only comparing `mtime` to determine if a buffer needed to be reloaded. This caused a race condition when external tools write files using `std::fs::write()`, which uses `O_TRUNC` and creates a brief window where the file is 0 bytes: 1. Scanner re-stats → sees 0 bytes, mtime T 2. `file_updated()` sees mtime changed → emits `ReloadNeeded` 3. Buffer reloads to empty, stamps `saved_mtime = T` 4. Tool finishes writing → file has content, but mtime is still T (or same-second granularity) 5. Scanner re-stats → mtime T matches `saved_mtime` → **no reload triggered** 6. Buffer permanently stuck empty ## The Fix Release Notes: - Add the file `size` to `DiskState::Present`, so that even when mtime stays the same, size changes (0 → N bytes) will trigger a reload. This is the same fix that was identified in the issue by @lex00. ## Changes - `crates/language/src/buffer.rs`: Add `size: u64` to `DiskState::Present`, add `size()` method - `crates/worktree/src/worktree.rs`: Pass size when constructing File and DiskState::Present - `crates/project/src/buffer_store.rs`: Pass size when constructing File - `crates/project/src/image_store.rs`: Pass size when constructing File - `crates/copilot/src/copilot.rs`: Update test mock ## Test plan - [ ] Open a file in Zed - [ ] Write to that file from an external tool (e.g., `echo "content" > file`) - [ ] Verify the buffer updates correctly without needing to reload Fixes zed-industries#38109 --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> Co-authored-by: Ben Kunkle <ben.kunkle@gmail.com> Co-authored-by: Jakub Konka <kubkon@jakubkonka.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This fix addresses the cross-platform root cause identified in issue #38109 where open buffers go stale or empty when external tools write files.
The Problem
The buffer's
file_updated()method was only comparingmtimeto determine if a buffer needed to be reloaded. This caused a race condition when external tools write files usingstd::fs::write(), which usesO_TRUNCand creates a brief window where the file is 0 bytes:file_updated()sees mtime changed → emitsReloadNeededsaved_mtime = Tsaved_mtime→ no reload triggeredThe Fix
Release Notes:
sizetoDiskState::Present, so that even when mtime stays the same, size changes (0 → N bytes) will trigger a reload. This is the same fix that was identified in the issue by @lex00.Changes
crates/language/src/buffer.rs: Addsize: u64toDiskState::Present, addsize()methodcrates/worktree/src/worktree.rs: Pass size when constructing File and DiskState::Presentcrates/project/src/buffer_store.rs: Pass size when constructing Filecrates/project/src/image_store.rs: Pass size when constructing Filecrates/copilot/src/copilot.rs: Update test mockTest plan
echo "content" > file)Fixes #38109