Skip to content

loading: key precompile cache file names on the package's source paths - #63293

Closed
IanButterworth wants to merge 4 commits into
JuliaLang:masterfrom
IanButterworth:ib/compilecache-manifest-slug
Closed

IanButterworth wants to merge 4 commits into
JuliaLang:masterfrom
IanButterworth:ib/compilecache-manifest-slug

Conversation

@IanButterworth

@IanButterworth IanButterworth commented Sep 20, 2026 •

Copy link
Copy Markdown
Member

Fixes #63268

If we go ahead with this, we might want a more conservative fix for 1.13/1.10

Claude:


Cache file names are keyed on the active project path, so environments that share a path but resolve different versions (e.g. apps each mounting their project at /work in a container with a shared depot) overwrite each other's files. Alternating loads recompile every time, and concurrent precompilation fails with "Required dependency ... failed to load from a cache file" or "Module ... is missing from the cache".

Change

  • Key cache file names on the source paths of the package and of every module its cache requires (read back from the .ji header, like the preferences blob) instead of the project path. Registry packages live at packages/Name/<uuid+tree-hash slug>/, so the path identifies the version.
  • The project path is dropped from the key. Lookup reads file contents rather than names, so it never affected which file loads; with the source paths in the key it no longer affects which file is written either.
  • A version change leaves the old version's file behind (as preference changes already do) until the per-package LRU evicts it. To keep that short, a cache write drops sibling files whose depot source is gone (as after Pkg.gc) and that nothing has loaded for a week (loading touches the file). Sources outside a depot are not judged.

Why not hostname or the manifest

  • Hostname/username: containers with --network=host or fixed hostnames still collide, as do concurrent CI jobs on one runner using the same workspace path; macOS hostnames change with the network.
  • Whole manifest: works, but any manifest edit moves every package to a new file. This key only changes when the package or something in its closure changes version or location.

Test

Switches one project's manifest between two depot-resident versions of a package with a dev'd dependent: both versions' files coexist, switching back needs no recompile, and a version whose source was removed has its file dropped once a week old. Fails on nightly at the second load. The two-container case itself needs Linux mount namespaces.

Reviewed by Codex (gpt-6-astra); its finding that a source missing from this depot stack is not necessarily removed led to the one-week condition.

The precompile cache file slug is derived from the active project path (plus
julia binary, sysimage, flags, cpu target and preferences), on the assumption
that one project path holds one set of package versions. That breaks when
distinct environments share a path, e.g. apps that each mount their project at
`/work` in a container while sharing a depot: different versions of the same
package, and the same version compiled against different dependencies, map to
the same file name and overwrite each other. Alternating loads recompile every
time, and concurrent precompilation hits "Required dependency ... failed to load
from a cache file" and "Module ... is missing from the cache" when a file is
replaced between the staleness check and the load.

Hash the manifest contents into the slug as well, so environments that resolve
different versions get different cache files. Environments without a manifest,
and the pidfile path (which passes an empty project), are unchanged. Cache file
lookup scans the directory, so the naming change does not affect loading of
existing files. A version switch within one project now leaves the previous
version's cache file alongside the new one until the per-package LRU evicts it,
instead of overwriting it, which also makes switching back free.

Fixes JuliaLang#63268

Assisted-by: Claude Code (Opus 5)
Assisted-by: Codex (gpt-6-astra)
@IanButterworth IanButterworth added packages Package management and loading compiler:precompilation Precompilation of modules backport 1.10 Change should be backported to the 1.10 release backport 1.13 Change should be backported to release-1.13 labels Sep 20, 2026
Keying cache file names on the manifest means a version change leaves the
previous version's file behind until the per-package LRU evicts it. Once the
source of such a file has been removed from every depot (as `Pkg.gc` does after
its collect delay) the file can never load again, so drop it at the next cache
write for the package instead of letting it occupy an LRU slot. Only sources
under a depot are judged, and only files that have not been loaded for a week,
since loading touches the file: a process with another view of the depots
(another container with its own package sources) keeps the files it uses fresh.

Assisted-by: Claude Code (Opus 5)
Assisted-by: Codex (gpt-6-astra)
@IanButterworth
IanButterworth marked this pull request as draft September 20, 2026 17:12
…manifest

Hash the source path of the package and of every module its cache requires,
as resolved in the current environment, into the cache file name instead of the
whole manifest. The name then changes only when the package or something in its
dependency closure changes version or location, which are exactly the recompiles
that must not overwrite another environment's file. Unrelated manifest edits no
longer move a package to a new file, so a dev'd package keeps overwriting its
one file while other packages are added or updated around it. The required
modules are read back from the `.ji` header alongside the preferences blob.

Assisted-by: Claude Code (Opus 5)
Assisted-by: Codex (gpt-6-astra)
@IanButterworth IanButterworth changed the title loading: key precompile cache file names on the manifest contents loading: key precompile cache file names on the package's source paths Sep 20, 2026
With the package's source paths in the key, the active project path adds
nothing: environments that resolve the same versions produce interchangeable
cache files, so let them share one instead of each writing a copy.

Assisted-by: Claude Code (Opus 5)
Assisted-by: Codex (gpt-6-astra)
@IanButterworth IanButterworth removed backport 1.10 Change should be backported to the 1.10 release backport 1.13 Change should be backported to release-1.13 labels Sep 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

compiler:precompilation Precompilation of modules packages Package management and loading

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: cache file name keyed on project path collides across containers sharing a depot

1 participant