Skip to content

Commit

Permalink
Fix Pkg.precompile ext races (#3645)
Browse files Browse the repository at this point in the history
  • Loading branch information
IanButterworth authored Oct 10, 2023
1 parent debcade commit b02fb95
Showing 1 changed file with 18 additions and 7 deletions.
25 changes: 18 additions & 7 deletions src/API.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1110,6 +1110,7 @@ function precompile(ctx::Context, pkgs::Vector{PackageSpec}; internal_call::Bool
# make a flat map of each dep and its direct deps
depsmap = Dict{Base.PkgId, Vector{Base.PkgId}}()
pkg_specs = PackageSpec[]
pkg_exts_map = Dict{Base.PkgId, Vector{Base.PkgId}}()
for dep in ctx.env.manifest
pkg = Base.PkgId(first(dep), last(dep).name)
Base.in_sysimage(pkg) && continue
Expand All @@ -1118,6 +1119,7 @@ function precompile(ctx::Context, pkgs::Vector{PackageSpec}; internal_call::Bool
# add any extensions
weakdeps = last(dep).weakdeps
pkg_exts = Dict{Base.PkgId, Vector{Base.PkgId}}()
prev_ext = nothing
for (ext_name, extdep_names) in last(dep).exts
ext_deps = Base.PkgId[]
push!(ext_deps, pkg) # depends on parent package
Expand All @@ -1133,22 +1135,31 @@ function precompile(ctx::Context, pkgs::Vector{PackageSpec}; internal_call::Bool
end
end
all_extdeps_available || continue
if prev_ext isa Base.PkgId
# also make the exts depend on eachother sequentially to avoid race
push!(ext_deps, prev_ext)
end
ext_uuid = Base.uuid5(pkg.uuid, ext_name)
ext = Base.PkgId(ext_uuid, ext_name)
prev_ext = ext
push!(pkg_specs, PackageSpec(uuid = ext_uuid, name = ext_name)) # create this here as the name cannot be looked up easily later via the uuid
filter!(!Base.in_sysimage, ext_deps)
depsmap[ext] = ext_deps
exts[ext] = pkg.name
pkg_exts[ext] = ext_deps
end
if !isempty(pkg_exts)
# find any packages that depend on the extension(s)'s deps and replace those deps in their deps list with the extension(s),
# basically injecting the extension into the precompile order in the graph, to avoid race to precompile extensions
for (_pkg, deps) in depsmap # for each manifest dep
if !in(_pkg, keys(exts)) && pkg in deps # if not an extension and depends on pkg
append!(deps, keys(pkg_exts)) # add the package extensions to deps
filter!(!isequal(pkg), deps) # remove the pkg from deps
end
pkg_exts_map[pkg] = collect(keys(pkg_exts))
end
end
# this loop must be run after the full depsmap has been populated
for (pkg, pkg_exts) in pkg_exts_map
# find any packages that depend on the extension(s)'s deps and replace those deps in their deps list with the extension(s),
# basically injecting the extension into the precompile order in the graph, to avoid race to precompile extensions
for (_pkg, deps) in depsmap # for each manifest dep
if !in(_pkg, keys(exts)) && pkg in deps # if not an extension and depends on pkg
append!(deps, pkg_exts) # add the package extensions to deps
filter!(!isequal(pkg), deps) # remove the pkg from deps
end
end
end
Expand Down

0 comments on commit b02fb95

Please sign in to comment.