Skip to content

fix(recent-files): serialize saves so overlapping pushes don't race on the tmp file - #391

Open
Yi-111-a wants to merge 1 commit into
pacifio:0.4.1from
Yi-111-a:Yi-111-a/372-recent-files-tmp-race
Open

Yi-111-a wants to merge 1 commit into
pacifio:0.4.1from
Yi-111-a:Yi-111-a/372-recent-files-tmp-race

Conversation

@Yi-111-a

@Yi-111-a Yi-111-a commented Oct 8, 2026

Copy link
Copy Markdown

What?

Recent-files saves for a project now run one at a time, and each save writes the project's current list. This stops the rename failed: No such file or directory warnings from #372, and an older list can no longer be the last one written to recent-files.json.

Why?

recent_files_push, recent_files_rename and recent_files_clear each start the save with tokio::task::spawn_blocking and don't wait for it, so a burst of pushes (like the one at startup in #372) saves several times at once. Every save writes the same <project>/.atlas/recent-files.json.tmp and then renames it, so one save can rename another's temp file away. The second rename then fails with ENOENT. As @ik0zy worked out on the issue, create_dir_all runs first, so a missing directory isn't the cause. Each save also wrote the list it captured when it was spawned, and the blocking pool doesn't keep them in order, so an older list could finish last and overwrite a newer one on disk.

No new dependencies. parking_lot is already a dependency of src-tauri.

How?

  • save_to_disk returns a Result with the same messages it used to log (mkdir failed, write tmp failed, rename failed, serialize failed).
  • save_latest takes a static SAVE_LOCK, reads the project's list under it, and saves that. Because the list is read inside the lock, the save that runs last writes the newest list.
  • persist calls save_latest and logs any error to atlas::recent_files, as before.
  • The push, rename and clear commands pass the project's items handle to persist instead of a copy of the list.
  • New test, overlapping_saves_all_succeed_and_the_newest_list_wins: 16 threads each add an entry and save 25 times. Every save must succeed, the file on disk must equal the in-memory list, and no .tmp file may be left over. Without the lock, saves fail with ENOENT on every run.

Fixes #372

Checklist

  • Targets the current version branch, unless it's a small standalone fix
  • New behaviour has a test; a bug fix has a test that fails without it
  • You've run the app and used the change in a window

I couldn't build the whole Tauri app on my Linux machine, so I haven't run the change in a window. I tested the changed functions on their own instead. I copied them unchanged (only atlas_profile::dir_in and the tracing call were swapped for local stand-ins) into a scratch crate with the same parking_lot version. There the new test passed 6/6 runs, and with the lock removed it failed every run with rename failed: No such file or directory. Clippy with the workspace deny list and the repo clippy.toml is clean, and so is rustfmt --check. CI's cargo test --lib and clippy for src-tauri will run the real build.

@coderabbitai

coderabbitai Bot commented Oct 8, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 9d2a606f-6dd6-47f2-90e7-29cdc8680a29

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

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.

1 participant