Skip to content

Fix filesystem eviction races and recover missing cache files - #2762

Merged
MarcusSorealheis merged 1 commit into
mainfrom
filesystem-race-conditions-combined-prs
Sep 15, 2026
Merged

MarcusSorealheis merged 1 commit into
mainfrom
filesystem-race-conditions-combined-prs

Conversation

@MarcusSorealheis

@MarcusSorealheis MarcusSorealheis commented Sep 15, 2026 •

Copy link
Copy Markdown
Member

What and why

A delayed filesystem eviction can rename away a newer upload of the same key. The index then reports a file that is missing from disk, and subsequent uploads fail while opening it for duplicate comparison with No such file or directory, propagating through the inner store to ByteStream writes.

This combines generation-specific file ownership from #2715 with missing-file upload recovery from #2644:

  • Each upload owns a distinct content filename. Delayed eviction retires only its own generation, while existing readers retain access to that generation.
  • Rename completes before the entry becomes visible in the index. A failed publish preserves the previous entry, and an older upload finishing late cannot replace a newer generation.
  • Duplicate comparison repairs NotFound by conditionally removing the stale entry and continuing the upload. Other open errors still propagate. Read-side recovery also checks entry identity before removal.
  • Startup migrates legacy layouts, retains files whose migration fails, selects newer generations, and cleans up superseded files. Duplicate comparison now checks empty files and the last byte at chunk boundaries correctly.

How was this verified?

  • 194 passing tests on macOS ARM64 with Bazel 9.1.1 / Rust 1.97.1: filesystem (53), fast/slow (28), eviction map (25), worker directory cache (16), running actions (40), and ByteStream (32). Clippy also passes for both changed libraries and the test targets.
  • Deterministic regressions cover eviction paused across a re-upload, missing-file repair for digest and string keys, stale read cleanup racing a replacement, out-of-order uploads, cancellation during rename, failed publishes, and permission errors.
  • A real filesystem fast tier over a memory slow tier verifies upload recovery and read fallback/refill. Migration tests cover the flat and d//s/ layouts, string keys with numeric suffixes, failed migrations, replacement of unmigrated files, restart, and leftover generations.
  • Counterfactual checks: removing duplicate-check recovery reproduced the upload's NotFound/No such file or directory failure; making generations share a content filename made stale_unref_must_not_delete_reuploaded_file fail because cleanup deleted the replacement. Both fixes were restored before the final passing test run.
  • Pre-commit passes, including rustfmt, typos, and Vale. Docs snippet, anchor, navigation, and link checks pass; the LLM documentation index regenerates successfully. The production docs build also passes, including TypeScript and all 109 generated pages.

Production rollout and observation remain a follow-up.

Risk

On-disk layout change: new files use d2/<hash>-<size>-<generation> and s2/<key>-<generation>. Writable startup migrates existing cache files; failed migrations remain readable and retry at the next startup. Earlier NativeLink versions cannot read the new directories, so rollback requires a separate cache directory or a planned cache rebuild. The filesystem-store guide documents this behavior.

The ownership mechanism works without Unix inode checks or a shared rename-lock pool. Cleanup, restart selection, and concurrent replacement are the main correctness risks covered by the regression tests.


This change is Reviewable

@vercel

vercel Bot commented Sep 15, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
nativelink Ready Ready Preview Sep 15, 2026 8:50am UTC
nativelink-aidm Ready Ready Preview Sep 15, 2026 8:50am UTC

Request Review

Give each upload a distinct generation-owned content path, publish before
indexing, and repair missing files during duplicate comparison. Remove
stale read entries conditionally so recovery preserves concurrent uploads.

Combine the generation-based ownership design from #2715 with upload
self-healing from #2644, with regression coverage and layout migration.

Co-authored-by: Cormac Relf <web@cormacrelf.net>
Co-authored-by: Jiří Szkandera <jirik.sz@gmail.com>

@palfrey palfrey left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, definitely better than the previous tangle of actions

@MarcusSorealheis
MarcusSorealheis merged commit a9c7bae into main Sep 15, 2026
46 checks passed
@MarcusSorealheis
MarcusSorealheis deleted the filesystem-race-conditions-combined-prs branch September 15, 2026 09:17

This branch was successfully deployed

2 active deployments
Preview – nativelink — 4148f25d Deployed Sep 15, 2026 by vercel[bot]
Preview – nativelink-aidm — 4148f25d Deployed Sep 15, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants