Skip to content

Commit b85a479

Browse files
committed
add logic to prefer loading modules that are already loaded
Iterate over the list of existing loaded modules for PkgId whenever loading a new module for PkgId, so that we will use that existing build_id content if it otherwise passes the other stale_checks.
1 parent 3aad027 commit b85a479

File tree

2 files changed

+104
-82
lines changed

2 files changed

+104
-82
lines changed

base/Base.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,7 @@ function __init__()
649649
empty!(explicit_loaded_modules)
650650
empty!(loaded_precompiles) # If we load a packageimage when building the image this might not be empty
651651
for (mod, key) in module_keys
652-
loaded_precompiles[key => module_build_id(mod)] = mod
652+
push!(get!(Vector{Module}, loaded_precompiles, key), mod)
653653
end
654654
if haskey(ENV, "JULIA_MAX_NUM_PRECOMPILE_FILES")
655655
MAX_NUM_PRECOMPILE_FILES[] = parse(Int, ENV["JULIA_MAX_NUM_PRECOMPILE_FILES"])

base/loading.jl

Lines changed: 103 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1231,7 +1231,7 @@ function _include_from_serialized(pkg::PkgId, path::String, ocachepath::Union{No
12311231
dep = depmods[i]
12321232
dep isa Module && continue
12331233
_, depkey, depbuild_id = dep::Tuple{String, PkgId, UInt128}
1234-
dep = loaded_precompiles[depkey => depbuild_id]
1234+
dep = something(maybe_loaded_precompile(depkey, depbuild_id))
12351235
@assert PkgId(dep) == depkey && module_build_id(dep) === depbuild_id
12361236
depmods[i] = dep
12371237
end
@@ -1337,6 +1337,7 @@ end
13371337

13381338
function register_restored_modules(sv::SimpleVector, pkg::PkgId, path::String)
13391339
# This function is also used by PkgCacheInspector.jl
1340+
assert_havelock(require_lock)
13401341
restored = sv[1]::Vector{Any}
13411342
for M in restored
13421343
M = M::Module
@@ -1345,7 +1346,7 @@ function register_restored_modules(sv::SimpleVector, pkg::PkgId, path::String)
13451346
end
13461347
if parentmodule(M) === M
13471348
push!(loaded_modules_order, M)
1348-
loaded_precompiles[pkg => module_build_id(M)] = M
1349+
push!(get!(Vector{Module}, loaded_precompiles, pkg), M)
13491350
end
13501351
end
13511352

@@ -1943,90 +1944,102 @@ end
19431944
assert_havelock(require_lock)
19441945
paths = find_all_in_cache_path(pkg, DEPOT_PATH)
19451946
newdeps = PkgId[]
1946-
for path_to_try in paths::Vector{String}
1947-
staledeps = stale_cachefile(pkg, build_id, sourcepath, path_to_try; reasons, stalecheck)
1948-
if staledeps === true
1949-
continue
1950-
end
1951-
try
1952-
staledeps, ocachefile, newbuild_id = staledeps::Tuple{Vector{Any}, Union{Nothing, String}, UInt128}
1953-
# finish checking staledeps module graph
1954-
for i in eachindex(staledeps)
1955-
dep = staledeps[i]
1956-
dep isa Module && continue
1957-
modpath, modkey, modbuild_id = dep::Tuple{String, PkgId, UInt128}
1958-
modpaths = find_all_in_cache_path(modkey, DEPOT_PATH)
1959-
for modpath_to_try in modpaths
1960-
modstaledeps = stale_cachefile(modkey, modbuild_id, modpath, modpath_to_try; stalecheck)
1961-
if modstaledeps === true
1962-
continue
1963-
end
1964-
modstaledeps, modocachepath, _ = modstaledeps::Tuple{Vector{Any}, Union{Nothing, String}, UInt128}
1965-
staledeps[i] = (modpath, modkey, modbuild_id, modpath_to_try, modstaledeps, modocachepath)
1966-
@goto check_next_dep
1947+
try_build_ids = UInt128[build_id]
1948+
if build_id == UInt128(0)
1949+
let loaded = get(loaded_precompiles, pkg, nothing)
1950+
if loaded !== nothing
1951+
for mod in loaded # try these in reverse original load order to see if one is already valid
1952+
pushfirst!(try_build_ids, module_build_id(mod))
19671953
end
1968-
@debug "Rejecting cache file $path_to_try because required dependency $modkey with build ID $(UUID(modbuild_id)) is missing from the cache."
1969-
@goto check_next_path
1970-
@label check_next_dep
1971-
end
1972-
M = get(loaded_precompiles, pkg => newbuild_id, nothing)
1973-
if isa(M, Module)
1974-
stalecheck && register_root_module(M)
1975-
return M
19761954
end
1977-
if stalecheck
1978-
try
1979-
touch(path_to_try) # update timestamp of precompilation file
1980-
catch ex # file might be read-only and then we fail to update timestamp, which is fine
1981-
ex isa IOError || rethrow()
1982-
end
1955+
end
1956+
end
1957+
for build_id in try_build_ids
1958+
for path_to_try in paths::Vector{String}
1959+
staledeps = stale_cachefile(pkg, build_id, sourcepath, path_to_try; reasons, stalecheck)
1960+
if staledeps === true
1961+
continue
19831962
end
1984-
# finish loading module graph into staledeps
1985-
# TODO: call all start_loading calls (in reverse order) before calling any _include_from_serialized, since start_loading will drop the loading lock
1986-
for i in eachindex(staledeps)
1987-
dep = staledeps[i]
1988-
dep isa Module && continue
1989-
modpath, modkey, modbuild_id, modcachepath, modstaledeps, modocachepath = dep::Tuple{String, PkgId, UInt128, String, Vector{Any}, Union{Nothing, String}}
1990-
dep = start_loading(modkey, modbuild_id, stalecheck)
1991-
while true
1992-
if dep isa Module
1993-
if PkgId(dep) == modkey && module_build_id(dep) === modbuild_id
1994-
break
1995-
else
1996-
@debug "Rejecting cache file $path_to_try because module $modkey got loaded at a different version than expected."
1997-
@goto check_next_path
1963+
try
1964+
staledeps, ocachefile, newbuild_id = staledeps::Tuple{Vector{Any}, Union{Nothing, String}, UInt128}
1965+
# finish checking staledeps module graph
1966+
for i in eachindex(staledeps)
1967+
dep = staledeps[i]
1968+
dep isa Module && continue
1969+
modpath, modkey, modbuild_id = dep::Tuple{String, PkgId, UInt128}
1970+
modpaths = find_all_in_cache_path(modkey, DEPOT_PATH)
1971+
for modpath_to_try in modpaths
1972+
modstaledeps = stale_cachefile(modkey, modbuild_id, modpath, modpath_to_try; stalecheck)
1973+
if modstaledeps === true
1974+
continue
19981975
end
1976+
modstaledeps, modocachepath, _ = modstaledeps::Tuple{Vector{Any}, Union{Nothing, String}, UInt128}
1977+
staledeps[i] = (modpath, modkey, modbuild_id, modpath_to_try, modstaledeps, modocachepath)
1978+
@goto check_next_dep
1979+
end
1980+
@debug "Rejecting cache file $path_to_try because required dependency $modkey with build ID $(UUID(modbuild_id)) is missing from the cache."
1981+
@goto check_next_path
1982+
@label check_next_dep
1983+
end
1984+
M = maybe_loaded_precompile(pkg, newbuild_id)
1985+
if isa(M, Module)
1986+
stalecheck && register_root_module(M)
1987+
return M
1988+
end
1989+
if stalecheck
1990+
try
1991+
touch(path_to_try) # update timestamp of precompilation file
1992+
catch ex # file might be read-only and then we fail to update timestamp, which is fine
1993+
ex isa IOError || rethrow()
19991994
end
2000-
if dep === nothing
2001-
try
2002-
set_pkgorigin_version_path(modkey, modpath)
2003-
dep = _include_from_serialized(modkey, modcachepath, modocachepath, modstaledeps; register = stalecheck)
2004-
finally
2005-
end_loading(modkey, dep)
1995+
end
1996+
# finish loading module graph into staledeps
1997+
# TODO: call all start_loading calls (in reverse order) before calling any _include_from_serialized, since start_loading will drop the loading lock
1998+
for i in eachindex(staledeps)
1999+
dep = staledeps[i]
2000+
dep isa Module && continue
2001+
modpath, modkey, modbuild_id, modcachepath, modstaledeps, modocachepath = dep::Tuple{String, PkgId, UInt128, String, Vector{Any}, Union{Nothing, String}}
2002+
dep = start_loading(modkey, modbuild_id, stalecheck)
2003+
while true
2004+
if dep isa Module
2005+
if PkgId(dep) == modkey && module_build_id(dep) === modbuild_id
2006+
break
2007+
else
2008+
@debug "Rejecting cache file $path_to_try because module $modkey got loaded at a different version than expected."
2009+
@goto check_next_path
2010+
end
20062011
end
2007-
if !isa(dep, Module)
2008-
@debug "Rejecting cache file $path_to_try because required dependency $modkey failed to load from cache file for $modcachepath." exception=dep
2009-
@goto check_next_path
2010-
else
2011-
push!(newdeps, modkey)
2012+
if dep === nothing
2013+
try
2014+
set_pkgorigin_version_path(modkey, modpath)
2015+
dep = _include_from_serialized(modkey, modcachepath, modocachepath, modstaledeps; register = stalecheck)
2016+
finally
2017+
end_loading(modkey, dep)
2018+
end
2019+
if !isa(dep, Module)
2020+
@debug "Rejecting cache file $path_to_try because required dependency $modkey failed to load from cache file for $modcachepath." exception=dep
2021+
@goto check_next_path
2022+
else
2023+
push!(newdeps, modkey)
2024+
end
20122025
end
20132026
end
2027+
staledeps[i] = dep
20142028
end
2015-
staledeps[i] = dep
2016-
end
2017-
restored = get(loaded_precompiles, pkg => newbuild_id, nothing)
2018-
if !isa(restored, Module)
2019-
restored = _include_from_serialized(pkg, path_to_try, ocachefile, staledeps; register = stalecheck)
2020-
end
2021-
isa(restored, Module) && return restored
2022-
@debug "Deserialization checks failed while attempting to load cache from $path_to_try" exception=restored
2023-
@label check_next_path
2024-
finally
2025-
for modkey in newdeps
2026-
insert_extension_triggers(modkey)
2027-
stalecheck && run_package_callbacks(modkey)
2029+
restored = maybe_loaded_precompile(pkg, newbuild_id)
2030+
if !isa(restored, Module)
2031+
restored = _include_from_serialized(pkg, path_to_try, ocachefile, staledeps; register = stalecheck)
2032+
end
2033+
isa(restored, Module) && return restored
2034+
@debug "Deserialization checks failed while attempting to load cache from $path_to_try" exception=restored
2035+
@label check_next_path
2036+
finally
2037+
for modkey in newdeps
2038+
insert_extension_triggers(modkey)
2039+
stalecheck && run_package_callbacks(modkey)
2040+
end
2041+
empty!(newdeps)
20282042
end
2029-
empty!(newdeps)
20302043
end
20312044
end
20322045
return nothing
@@ -2045,7 +2058,7 @@ function start_loading(modkey::PkgId, build_id::UInt128, stalecheck::Bool)
20452058
loaded = stalecheck ? maybe_root_module(modkey) : nothing
20462059
loaded isa Module && return loaded
20472060
if build_id != UInt128(0)
2048-
loaded = get(loaded_precompiles, modkey => build_id, nothing)
2061+
loaded = maybe_loaded_precompile(modkey, build_id)
20492062
loaded isa Module && return loaded
20502063
end
20512064
loading = get(package_locks, modkey, nothing)
@@ -2375,12 +2388,21 @@ const pkgorigins = Dict{PkgId,PkgOrigin}()
23752388

23762389
const explicit_loaded_modules = Dict{PkgId,Module}() # Emptied on Julia start
23772390
const loaded_modules = Dict{PkgId,Module}() # available to be explicitly loaded
2378-
const loaded_precompiles = Dict{Pair{PkgId,UInt128},Module}() # extended (complete) list of modules, available to be loaded
2391+
const loaded_precompiles = Dict{PkgId,Vector{Module}}() # extended (complete) list of modules, available to be loaded
23792392
const loaded_modules_order = Vector{Module}()
23802393
const module_keys = IdDict{Module,PkgId}() # the reverse of loaded_modules
23812394

23822395
root_module_key(m::Module) = @lock require_lock module_keys[m]
23832396

2397+
function maybe_loaded_precompile(key::PkgId, buildid::UInt128)
2398+
assert_havelock(require_lock)
2399+
mods = get(loaded_precompiles, key, nothing)
2400+
mods === nothing && return
2401+
for mod in mods
2402+
module_build_id(mod) == buildid && return mod
2403+
end
2404+
end
2405+
23842406
function module_build_id(m::Module)
23852407
hi, lo = ccall(:jl_module_build_id, NTuple{2,UInt64}, (Any,), m)
23862408
return (UInt128(hi) << 64) | lo
@@ -2401,7 +2423,7 @@ end
24012423
end
24022424
end
24032425
end
2404-
haskey(loaded_precompiles, key => module_build_id(m)) || push!(loaded_modules_order, m)
2426+
maybe_loaded_precompile(key, module_build_id(m)) === nothing && push!(loaded_modules_order, m)
24052427
loaded_modules[key] = m
24062428
explicit_loaded_modules[key] = m
24072429
module_keys[m] = key
@@ -3781,8 +3803,8 @@ end
37813803
for i in 1:ndeps
37823804
req_key, req_build_id = required_modules[i]
37833805
# Check if module is already loaded
3784-
if !stalecheck && haskey(loaded_precompiles, req_key => req_build_id)
3785-
M = loaded_precompiles[req_key => req_build_id]
3806+
M = stalecheck ? nothing : maybe_loaded_precompile(req_key, req_build_id)
3807+
if M !== nothing
37863808
@assert PkgId(M) == req_key && module_build_id(M) === req_build_id
37873809
depmods[i] = M
37883810
elseif root_module_exists(req_key)

0 commit comments

Comments
 (0)