fix: serialize cold eval/task cache init across processes - #3156
Arshgill01 wants to merge 1 commit into
Conversation
🔍 Suggested ReviewersBased on git blame analysis of the changed lines, the following contributors have significant experience with the modified code:
Please consider reviewing this PR as you have authored significant portions of the code being modified. Your expertise would be valuable! 🙏 This comment was automatically generated by git-blame-auto-reviewer Last updated: 2026-09-22T03:49:29.191Z |
ed8bfab to
e543fb9
Compare
|
Rebased onto latest |
2518db0 to
7239326
Compare
|
Rebased onto latest |
5d3724c to
78f5a90
Compare
78f5a90 to
bfab7a4
Compare
Concurrent `devenv shell` entries into a project without `.devenv/` raced on SQLite create+migrate. One process succeeded; another failed with `database is locked` (and sometimes disk I/O 5898 after the loser deleted the database). Warm `.devenv/` was fine. Hold an exclusive flock around Database::new, never delete the DB on a busy/locked migration error, and treat concurrent GC-root removal as success when the symlink is already gone. Fixes cachix#3133 Co-authored-by: Arshdeep singh <arshgill6120@gmail.com>
bfab7a4 to
9b7a402
Compare
Fixes #3133.
Concurrent
devenv shellentries into a project that does not yet have.devenv/raced on eval-cache (and task-cache) SQLite initialization. One process created the database; another failed withFailed to initialize eval cache database: Database error: (code: 5) database is locked. Under more contention the same window also produced task-cache init failures,SQLITE_IOERR_DELETE_NOENT(code 5898) after a loser deleted the DB, andFailed to remove existing GC root: No such file or directory. Warm.devenv/was already fine.busy_timeout(10s)and WAL with DELETE fallback onSQLITE_IOERR_SHMMAPwere not enough:sqlite3_open(CREATE)/PRAGMA journal_mode=WALcan returnSQLITE_BUSYbefore the timeout is installed, and a migration error used to delete the database out from under the process that held it.Changes
*.db.init.lock, not the.dbitself) around create + migrate inDatabase::new, so eval cache and task cache share the same cold-init serialization.Database::new, concurrent coldTaskCache::new, andtests/cold-concurrent-shell(two concurrentdevenv shell -q -- trueagainst a missing.devenv/, then the same against a warm one).Test plan
cargo test -p devenv-cache-core(includesconcurrent_cold_open_succeeds/concurrent_warm_open_succeeds)cargo test -p devenv-tasks --lib -- test_cold_cache_allows_concurrent_open test_warm_cache_allows_concurrent_opencargo clippy -p devenv-cache-core --all-targets -- -D warningsdevenv-run-tests run tests --only cold-concurrent-shell(needs a full devenv/Nix environment; not run in this agent VM)