Skip to content

Add size to DiskState to detect file changes - #49436

Merged
probably-neb merged 3 commits into
zed-industries:mainfrom
ImBIOS:fix/buffer-mtime-size-check
Mar 10, 2026
Merged

Add size to DiskState to detect file changes#49436
probably-neb merged 3 commits into
zed-industries:mainfrom
ImBIOS:fix/buffer-mtime-size-check

Conversation

@ImBIOS

@ImBIOS ImBIOS commented Feb 18, 2026

Copy link
Copy Markdown
Contributor

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 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_mtimeno 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 #38109

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>
@ImBIOS
ImBIOS requested review from a team as code owners February 18, 2026 05:27
@cla-bot cla-bot Bot added the cla-signed The user has signed the Contributor License Agreement label Feb 18, 2026
@zed-community-bot zed-community-bot Bot added the first contribution the author's first pull request to Zed. NOTE: the label application is automated via github actions label Feb 18, 2026
@maxdeviant maxdeviant changed the title fix: add size to DiskState to detect file changes Add size to DiskState to detect file changes Feb 18, 2026
@lex00

lex00 commented Mar 8, 2026

Copy link
Copy Markdown
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.

probably-neb and others added 2 commits March 10, 2026 12:43
Co-authored-by: Jakub Konka <kubkon@jakubkonka.com>
@probably-neb
probably-neb merged commit e9e7143 into zed-industries:main Mar 10, 2026
28 checks passed
@probably-neb

Copy link
Copy Markdown
Collaborator

Thanks for the fix @ImBIOS! Sorry it took so long for me to review.

@nojaf

nojaf commented Mar 11, 2026

Copy link
Copy Markdown

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>
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 first contribution the author's first pull request to Zed. NOTE: the label application is automated via github actions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Zed out of sync with changes made outside of editor

4 participants