1
|
30
|
module SymbolServer
|
2
|
|
import Sockets
|
3
|
|
|
4
|
|
pipename = length(ARGS) > 1 ? ARGS[2] : nothing
|
5
|
|
|
6
|
|
conn = pipename !== nothing ? Sockets.connect(pipename) : nothing
|
7
|
|
|
8
|
|
start_time = time_ns()
|
9
|
|
|
10
|
|
# Try to lower the priority of this process so that it doesn't block the
|
11
|
|
# user system.
|
12
|
|
@static if Sys.iswindows()
|
13
|
|
# Get process handle
|
14
|
12
|
p_handle = ccall(:GetCurrentProcess, stdcall, Ptr{Cvoid}, ())
|
15
|
|
|
16
|
|
# Set BELOW_NORMAL_PRIORITY_CLASS
|
17
|
12
|
ret = ccall(:SetPriorityClass, stdcall, Cint, (Ptr{Cvoid}, Culong), p_handle, 0x00004000)
|
18
|
12
|
ret != 1 && @warn "Something went wrong when setting BELOW_NORMAL_PRIORITY_CLASS."
|
19
|
|
else
|
20
|
18
|
ret = ccall(:nice, Cint, (Cint,), 1)
|
21
|
|
# We don't check the return value because it doesn't really matter
|
22
|
|
end
|
23
|
|
|
24
|
30
|
module LoadingBay
|
25
|
|
end
|
26
|
|
|
27
|
|
# Make sure we can load stdlibs
|
28
|
|
!in("@stdlib", LOAD_PATH) && push!(LOAD_PATH, "@stdlib")
|
29
|
|
|
30
|
|
using Serialization, Pkg, SHA
|
31
|
|
using Base: UUID
|
32
|
|
|
33
|
|
include("faketypes.jl")
|
34
|
|
include("symbols.jl")
|
35
|
|
include("utils.jl")
|
36
|
|
|
37
|
|
store_path = length(ARGS) > 0 ? ARGS[1] : abspath(joinpath(@__DIR__, "..", "store"))
|
38
|
|
|
39
|
|
ctx = try
|
40
|
|
Pkg.Types.Context()
|
41
|
|
catch err
|
42
|
|
@info "Package environment can't be read."
|
43
|
|
exit()
|
44
|
|
end
|
45
|
|
# Add some methods to check whether a package is part of the standard library and so
|
46
|
|
# won't need recaching.
|
47
|
|
if isdefined(Pkg.Types, :is_stdlib)
|
48
|
20
|
is_stdlib(uuid::UUID) = Pkg.Types.is_stdlib(uuid)
|
49
|
|
else
|
50
|
10
|
is_stdlib(uuid::UUID) = uuid in keys(ctx.stdlibs)
|
51
|
|
end
|
52
|
|
|
53
|
|
server = Server(store_path, ctx, Dict{UUID,Package}())
|
54
|
|
|
55
|
|
function load_package(c::Pkg.Types.Context, uuid, conn)
|
56
|
30
|
isinmanifest(c, uuid isa String ? Base.UUID(uuid) : uuid) || return
|
57
|
30
|
pe_name = packagename(c, uuid)
|
58
|
30
|
pid = Base.PkgId(uuid isa String ? Base.UUID(uuid) : uuid, pe_name)
|
59
|
30
|
if pid in keys(Base.loaded_modules)
|
60
|
30
|
conn !== nothing && println(conn, "PROCESSPKG;$pe_name;$uuid;noversion")
|
61
|
30
|
LoadingBay.eval(:($(Symbol(pe_name)) = $(Base.loaded_modules[pid])))
|
62
|
30
|
m = getfield(LoadingBay, Symbol(pe_name))
|
63
|
|
else
|
64
|
30
|
m = try
|
65
|
30
|
conn !== nothing && println(conn, "STARTLOAD;$pe_name;$uuid;noversion")
|
66
|
30
|
LoadingBay.eval(:(import $(Symbol(pe_name))))
|
67
|
30
|
conn !== nothing && println(conn, "STOPLOAD;$pe_name")
|
68
|
30
|
m = getfield(LoadingBay, Symbol(pe_name))
|
69
|
|
catch e
|
70
|
30
|
return
|
71
|
|
end
|
72
|
|
end
|
73
|
|
end
|
74
|
|
|
75
|
|
function write_cache(name, pkg)
|
76
|
30
|
open(joinpath(server.storedir, name), "w") do io
|
77
|
10
|
serialize(io, pkg)
|
78
|
|
end
|
79
|
|
end
|
80
|
|
|
81
|
|
function write_depot(server, ctx, written_caches)
|
82
|
30
|
for (uuid, pkg) in server.depot
|
83
|
30
|
filename = get_filename_from_name(ctx.env.manifest, uuid)
|
84
|
30
|
filename === nothing && continue
|
85
|
30
|
cache_path = joinpath(server.storedir, filename)
|
86
|
30
|
cache_path in written_caches && continue
|
87
|
25
|
push!(written_caches, cache_path)
|
88
|
25
|
@info "Now writing to disc $uuid"
|
89
|
30
|
write_cache(cache_path, pkg)
|
90
|
|
end
|
91
|
|
end
|
92
|
|
# List of caches that have already been written
|
93
|
|
written_caches = String[]
|
94
|
|
|
95
|
|
# First get a list of all package UUIds that we want to cache
|
96
|
|
toplevel_pkgs = deps(project(ctx))
|
97
|
|
packages_to_load = []
|
98
|
|
# Next make sure the cache is up-to-date for all of these
|
99
|
|
for (pk_name, uuid) in toplevel_pkgs
|
100
|
|
file_name = get_filename_from_name(ctx.env.manifest, uuid)
|
101
|
|
# We sometimes have UUIDs in the project file that are not in the
|
102
|
|
# manifest file. That seems like something that shouldn't happen, but
|
103
|
|
# in practice is not under our control. For now, we just skip these
|
104
|
|
# packages
|
105
|
|
file_name === nothing && continue
|
106
|
|
cache_path = joinpath(server.storedir, file_name)
|
107
|
|
|
108
|
|
if isfile(cache_path)
|
109
|
|
if is_package_deved(ctx.env.manifest, uuid)
|
110
|
|
cached_version = open(cache_path) do io
|
111
|
0
|
deserialize(io)
|
112
|
|
end
|
113
|
|
if sha_pkg(frommanifest(ctx.env.manifest, uuid)) != cached_version.sha
|
114
|
|
@info "Outdated sha, will recache package $pk_name ($uuid)"
|
115
|
|
push!(packages_to_load, uuid)
|
116
|
|
else
|
117
|
|
@info "Package $pk_name ($uuid) is cached."
|
118
|
|
end
|
119
|
|
else
|
120
|
|
@info "Package $pk_name ($uuid) is cached."
|
121
|
|
end
|
122
|
|
else
|
123
|
|
@info "Will cache package $pk_name ($uuid)"
|
124
|
|
push!(packages_to_load, uuid)
|
125
|
|
end
|
126
|
|
end
|
127
|
|
|
128
|
|
# Load all packages together
|
129
|
20
|
for uuid in packages_to_load
|
130
|
30
|
load_package(ctx, uuid, conn)
|
131
|
|
end
|
132
|
|
|
133
|
|
# Create image of whole package env. This creates the module structure only.
|
134
|
|
env_symbols = getenvtree()
|
135
|
|
|
136
|
|
# Populate the above with symbols, skipping modules that don't need caching.
|
137
|
|
# symbols (env_symbols)
|
138
|
|
visited = Base.IdSet{Module}([Base, Core]) # don't need to cache these each time...
|
139
|
20
|
for (pid, m) in Base.loaded_modules
|
140
|
30
|
if pid.uuid !== nothing && is_stdlib(pid.uuid) &&
|
141
|
|
(file_name = get_filename_from_name(ctx.env.manifest, pid.uuid)) !== nothing &&
|
142
|
|
isfile(joinpath(server.storedir, file_name))
|
143
|
0
|
push!(visited, m)
|
144
|
5
|
delete!(env_symbols, Symbol(pid.name))
|
145
|
|
end
|
146
|
|
end
|
147
|
|
|
148
|
|
symbols(env_symbols, nothing, SymbolServer.getallns(), visited)
|
149
|
|
|
150
|
|
# Wrap the `ModuleStore`s as `Package`s.
|
151
|
20
|
for (pkg_name, cache) in env_symbols
|
152
|
30
|
pkg_name = String(pkg_name)
|
153
|
30
|
!isinmanifest(ctx, pkg_name) && continue
|
154
|
30
|
uuid = packageuuid(ctx, String(pkg_name))
|
155
|
30
|
pe = frommanifest(ctx, uuid)
|
156
|
30
|
server.depot[uuid] = Package(String(pkg_name), cache, version(pe), uuid, sha_pkg(pe))
|
157
|
|
end
|
158
|
|
|
159
|
|
# Write to disc
|
160
|
|
write_depot(server, server.context, written_caches)
|
161
|
|
end_time = time_ns()
|
162
|
|
|
163
|
|
elapsed_time_in_s = (end_time - start_time) / 1e9
|
164
|
|
@info "Symbol server indexing took $elapsed_time_in_s seconds."
|
165
|
|
|
166
|
|
end
|