Skip to content

fix(aqua): restore bin_paths disk cache with fresh_file invalidation#8398

Merged
jdx merged 1 commit intomainfrom
fix/aqua-bin-paths-perf
Mar 1, 2026
Merged

fix(aqua): restore bin_paths disk cache with fresh_file invalidation#8398
jdx merged 1 commit intomainfrom
fix/aqua-bin-paths-perf

Conversation

@jdx
Copy link
Owner

@jdx jdx commented Mar 1, 2026

Summary

  • Restore the aqua bin_paths.msgpack.z disk cache that was removed in fix(aqua): remove unnecessary bin_paths disk cache #8383
  • Use with_fresh_file(tv.install_path()) for automatic cache invalidation when a tool is installed/updated
  • Restore PathExt::mount and PathExt::is_empty helpers needed for relative path handling

Context

PR #8383 removed the aqua bin_paths disk cache to fix staleness bugs (#8372) where concurrent mise hook-env during install could cache incomplete paths. However, this caused a ~8-17% performance regression on mise env, mise x -- echo, and mise hook-env (confirmed in CI hyperfine benchmarks on the 2026.2.24 release PR #8387).

The root cause of the regression: each mise command is a separate process, so in-memory caches provide no benefit. The disk cache was what persisted across invocations.

The original cache lacked fresh_file invalidation. This fix uses with_fresh_file(tv.install_path()) — the same pattern used by ExternalPluginCache for asdf backends — so the cache automatically invalidates when the install directory's mtime changes (i.e., after tool installation). This avoids the race condition from #8372 without sacrificing performance.

Local benchmark results (hyperfine, 100 runs)

Command Baseline (2026.2.23) No cache (2026.2.24) This fix
mise env 24.5ms 26.2ms (+7%) 23.8ms (restored)
mise x -- echo 23.5ms 26.0ms (+11%) 23.7ms (restored)

Test plan

  • cargo check passes
  • All lints pass (mise run lint-fix)
  • All 492 unit tests pass (mise run test:unit)
  • Local hyperfine benchmarks confirm regression is eliminated
  • CI hyperfine benchmarks pass

🤖 Generated with Claude Code


Note

Medium Risk
Medium risk because it changes list_bin_paths behavior and caching semantics for the aqua backend; incorrect invalidation or path mounting could lead to missing/incorrect PATH entries after installs/updates.

Overview
Restores a persistent disk cache for aqua list_bin_paths (bin_paths.msgpack.z) to avoid recomputing bin directories on each invocation.

The cache now uses with_fresh_file(tv.install_path()) (plus an existing freshness duration) so it automatically invalidates when the install directory changes, and it stores paths relative to install_path then re-mounts them via newly reintroduced PathExt::mount/PathExt::is_empty helpers.

Written by Cursor Bugbot for commit 8019d04. This will update automatically on new commits. Configure here.

PR #8383 removed the aqua bin_paths disk cache to fix staleness bugs,
but this caused ~8-17% regression on mise env/x/hook-env. Restore the
cache using with_fresh_file(tv.install_path()) so it automatically
invalidates when a tool is installed (install_path mtime changes),
avoiding the original race condition without sacrificing performance.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a significant performance regression introduced by the removal of the aqua bin_paths disk cache. By reintroducing the disk cache and implementing a robust fresh_file invalidation mechanism, the PR aims to restore mise command performance to pre-regression levels while preventing the staleness issues that led to the cache's initial removal. This ensures that mise commands benefit from persistent caching across process invocations without compromising data integrity.

Highlights

  • Disk Cache Restoration: The aqua bin_paths.msgpack.z disk cache, previously removed due to staleness issues, has been restored to improve performance.
  • Cache Invalidation: Automatic cache invalidation is now implemented using with_fresh_file(tv.install_path()), ensuring the cache is updated when a tool is installed or updated.
  • Path Helpers: The PathExt::mount and PathExt::is_empty helper methods were reintroduced to correctly handle relative path operations.
Changelog
  • src/backend/aqua.rs
    • Imported PathExt for new path helper methods.
    • Replaced direct bin_paths calculation with a CacheManager instance.
    • Configured the CacheManager with with_fresh_file pointing to the tool's install path and with_fresh_duration from settings.
    • Modified the path collection logic within the cache initialization to strip prefixes and then mount paths relative to the install path.
  • src/path.rs
    • Added mount and is_empty function signatures to the PathExt trait.
    • Implemented the mount function to join a path onto another, handling empty paths.
    • Implemented the is_empty function to check if a path's OS string representation is empty.
Activity
  • cargo check passed.
  • All lints passed.
  • All 492 unit tests passed.
  • Local hyperfine benchmarks confirmed the performance regression was eliminated.
  • CI hyperfine benchmarks are expected to pass.
  • The pull request was generated with Claude Code.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
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 restores the disk cache for aqua list_bin_paths to address a performance regression. It introduces cache invalidation based on file modification times using with_fresh_file to prevent staleness issues. The implementation stores relative paths in the cache and reconstructs absolute paths upon retrieval, for which PathExt::mount and PathExt::is_empty helpers have been re-introduced. My review did not find any issues of medium severity or higher.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 1, 2026

Greptile Summary

Reinstates the aqua backend's bin_paths.msgpack.z disk cache (removed in #8383) with automatic invalidation via with_fresh_file(tv.install_path()). This fixes the ~8-17% performance regression on mise env, mise x, and mise hook-env while preventing the stale cache bugs from #8372.

Key changes:

  • Cache now invalidates automatically when install_path mtime changes (during install/update)
  • Paths stored as relative paths in cache, reconstructed to absolute on read using new PathExt::mount()
  • Follows the same pattern as ExternalPluginCache for asdf backends

Important note: There's still a narrow race window where concurrent mise hook-env during active installation could cache incomplete paths, but the cache self-corrects on the next invocation when it detects the install_path was modified after the cache was created.

Confidence Score: 4/5

  • Safe to merge with low risk - well-tested performance fix using established caching patterns
  • The implementation correctly follows existing cache patterns (ExternalPluginCache), includes comprehensive testing, and has validated performance improvements. Minor theoretical race condition during concurrent install exists but self-corrects automatically
  • No files require special attention - both changes are straightforward

Important Files Changed

Filename Overview
src/backend/aqua.rs Restores disk cache with mtime-based invalidation using with_fresh_file(install_path), stores relative paths and remounts them
src/path.rs Adds mount() and is_empty() helper methods for path handling, used to convert between relative and absolute paths

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[list_bin_paths called] --> B{Cache exists?}
    B -->|No| E[Compute paths]
    B -->|Yes| C{Cache fresh?}
    C -->|Yes| D[Return cached paths]
    C -->|No| E
    E --> F[Get package from registry]
    F --> G[Compute srcs]
    G --> H[Filter existing paths]
    H --> I[Strip install_path prefix]
    I --> J[Store relative paths in cache]
    J --> K[Mount paths back to absolute]
    K --> L[Return paths]
    
    M[Installation starts] --> N[remove install_path]
    N --> O[install_path mtime changes]
    O --> P[Next list_bin_paths call]
    P --> Q{Cache older than install_path?}
    Q -->|Yes| R[Cache stale - recompute]
    Q -->|No| S[Cache fresh - use it]
Loading

Last reviewed commit: 8019d04

@jdx jdx enabled auto-merge (squash) March 1, 2026 23:20
@jdx jdx merged commit 5794f53 into main Mar 1, 2026
38 checks passed
@jdx jdx deleted the fix/aqua-bin-paths-perf branch March 1, 2026 23:23
@github-actions
Copy link

github-actions bot commented Mar 1, 2026

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.23 x -- echo 25.0 ± 0.7 24.1 34.1 1.00
mise x -- echo 25.0 ± 0.4 24.4 28.6 1.00 ± 0.03

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.23 env 24.4 ± 0.8 23.3 32.3 1.00
mise env 24.5 ± 0.6 23.7 31.7 1.00 ± 0.04

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.23 hook-env 24.9 ± 0.3 24.3 28.3 1.00
mise hook-env 25.2 ± 0.6 24.4 34.1 1.01 ± 0.03

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.23 ls 22.8 ± 0.4 22.1 24.8 1.00
mise ls 23.0 ± 0.6 22.2 29.7 1.01 ± 0.03

xtasks/test/perf

Command mise-2026.2.23 mise Variance
install (cached) 157ms 157ms +0%
ls (cached) 88ms 88ms +0%
bin-paths (cached) 93ms 93ms +0%
task-ls (cached) 825ms 836ms -1%

jdx pushed a commit that referenced this pull request Mar 2, 2026
### 🚀 Features

- **(hooks)** add task references to hooks and watch_files by @jdx in
[#8400](#8400)
- **(prepare)** add git-submodule built-in provider by @jdx in
[#8407](#8407)
- **(prepare)** add human-readable stale reasons to prepare output by
@jdx in [#8408](#8408)
- **(prepare)** add dependency ordering to prepare steps by @jdx in
[#8401](#8401)
- **(prepare)** add --explain flag for provider diagnostics by @jdx in
[#8409](#8409)
- **(prepare)** add per-provider timeout support by @jdx in
[#8405](#8405)
- **(prepare)** add blake3 content-hash freshness checking by @jdx in
[#8404](#8404)
- **(tasks)** monorepo vars and per-task vars by @halms in
[#8248](#8248)

### 🐛 Bug Fixes

- **(aqua)** restore bin_paths disk cache with fresh_file invalidation
by @jdx in [#8398](#8398)
- **(idiomatic)** use generic parser for idiomatic files by @risu729 in
[#8171](#8171)
- **(install)** apply precompiled options to all platforms in lockfile
by @jdx in [#8396](#8396)
- **(install)** normalize "v" prefix when matching lockfile versions by
@jdx in [#8413](#8413)
- **(prepare)** improve git submodule parser and fix check_staleness
error handling by @jdx in [#8412](#8412)
- **(python)** respect precompiled settings in lock file generation by
@jdx in [#8399](#8399)
- **(python)** clarify uv_venv_auto docs + prevent uv shim recursion in
venv creation by @halms in
[#8402](#8402)
- **(task)** remove deprecated `# mise` task header syntax by @jdx in
[#8403](#8403)
- **(vfox)** avoid eager metadata loading during config file detection
by @jdx in [#8397](#8397)
- clarify GitHub attestations to be artifact ones by @scop in
[#8394](#8394)
- ignore comments in idiomatic version files by @iloveitaly in
[#7682](#7682)

### 🚜 Refactor

- unify archive detection by @risu729 in
[#8137](#8137)

### 📚 Documentation

- remove duplicated docs for npm.package_manager by @risu729 in
[#8414](#8414)
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