Skip to content

fix(conda): avoid temp file collisions during parallel package downloads#9293

Merged
jdx merged 1 commit intojdx:mainfrom
salim-b:fix-conda-dep-concurrency
Apr 22, 2026
Merged

fix(conda): avoid temp file collisions during parallel package downloads#9293
jdx merged 1 commit intojdx:mainfrom
salim-b:fix-conda-dep-concurrency

Conversation

@salim-b
Copy link
Copy Markdown
Contributor

@salim-b salim-b commented Apr 22, 2026

The old code derived the temporary filename from the destination path and the PID. When multiple conda tools are installed concurrently in the same process (as in GH CI with mise-action), and the tools share a common transitive dependency (e.g. libgcc, _openmp_mutex, libgomp), all parallel installers produce the exact same temp path for the same shared package, because they all have the same PID and the same dest. This leads to multiple concurrent tasks all downloading to the same temp file and then competing to rename/delete it, which results in No such file or directory errors during file::rename(&temp, dest).

Besides adding an atomic counter to the temp path to make it unique, we add a second line of defense with a race-tolerant finalize to cover edge cases where file::rename() fails for any reason, i.e. another concurrent installer won the race (cross-device rename (EXDEV) or possible filesystem/permission errors unrelated to concurrency).

@salim-b salim-b changed the title fix(conda): avoid temp file collisions fix(conda): avoid temp file collisions during parallel package downloads Apr 22, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 22, 2026

Greptile Summary

This PR fixes a temp-file collision race in CondaBackend::download_to where parallel installers sharing the same PID and destination path would clobber each other's temp files. It adds a process-global AtomicU64 counter to make each temp path unique, and a race-tolerant finalize that treats a failed rename as success when another concurrent installer already wrote a verified dest.

Confidence Score: 5/5

Safe to merge — the fix is correct and both previously flagged issues have been resolved.

All findings are P2 or lower. The atomic counter correctly ensures unique temp paths within a process; Ordering::Relaxed is appropriate here since only uniqueness (not ordering) is required. The race-tolerant finalize cleanly handles the cross-device and concurrent-rename edge cases. The Ok(()) and temp-file cleanup that were previously missing are now both present. The unit test validates path uniqueness end-to-end.

No files require special attention.

Important Files Changed

Filename Overview
src/backend/conda.rs Adds temp_download_path with a PID + atomic-counter suffix to eliminate temp-file collisions; adds race-tolerant finalize with checksum re-verification on rename failure; adds a unit test verifying path uniqueness. Both previously flagged issues (missing Ok(()) and missing temp cleanup) are resolved.

Sequence Diagram

sequenceDiagram
    participant A as Installer A
    participant B as Installer B
    participant FS as Filesystem

    par Parallel downloads
        A->>FS: download_file → libgcc.tmp.1234.0
        B->>FS: download_file → libgcc.tmp.1234.1
    end

    A->>FS: verify_checksum(tmp.1234.0) ✓
    B->>FS: verify_checksum(tmp.1234.1) ✓

    A->>FS: rename(tmp.1234.0 → libgcc.conda) ✓
    A-->>A: return Ok(())

    B->>FS: rename(tmp.1234.1 → libgcc.conda) ✗ (EEXIST/EXDEV)
    B->>FS: remove_all(tmp.1234.1)
    B->>FS: dest.exists() && verify_checksum(dest) ✓
    B-->>B: return Ok(()) [race-tolerant fallback]
Loading

Reviews (3): Last reviewed commit: "fix(conda): avoid temp file collisions" | Re-trigger Greptile

Comment thread src/backend/conda.rs
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces unique temporary download paths for Conda packages by incorporating the process ID and an atomic counter. It also enhances the file finalization logic to handle race conditions between concurrent installers by verifying the checksum of an existing destination file if a rename operation fails. Additionally, a unit test has been included to verify the uniqueness of the generated temporary paths. I have no feedback to provide.

@salim-b salim-b force-pushed the fix-conda-dep-concurrency branch from 63a8cb8 to b56ec1d Compare April 22, 2026 11:22
Comment thread src/backend/conda.rs
during parallel package downloads

The old code derived the temporary filename from the destination path
and the PID. When multiple conda tools are installed concurrently in the
same process (as in GH CI with `mise-action`), and the tools share a
common transitive dependency (e.g. `libgcc`, `_openmp_mutex`,
`libgomp`), all parallel installers produce the exact same `temp` path
for the same shared package, because they all have the same PID and the
same `dest`. This leads to multiple concurrent tasks all downloading to
the same `temp` file and then competing to rename/delete it, which
results in `No such file or directory` errors during
`file::rename(&temp, dest)`.

Besides adding an atomic counter to the `temp` path to make it unique,
we add a second line of defense with a race-tolerant finalize to cover
edge cases where `file::rename()` fails for any reason, i.e. another
concurrent installer won the race (cross-device rename (`EXDEV`) or
possible filesystem/permission errors unrelated to concurrency).

Co-authored-by: salim-b <20040931+salim-b@users.noreply.github.com>
@salim-b salim-b force-pushed the fix-conda-dep-concurrency branch from b56ec1d to cff9486 Compare April 22, 2026 11:28
@jdx jdx merged commit b9401a8 into jdx:main Apr 22, 2026
32 of 34 checks passed
@salim-b salim-b deleted the fix-conda-dep-concurrency branch April 22, 2026 13:42
salim-b added a commit to DigitaleGesellschaft/workflows that referenced this pull request Apr 23, 2026
issue has been fixed upstream in mise and released with v2026.4.19, cf.
jdx/mise#9293
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.

3 participants