Skip to content

Commit c40c140

Browse files
committed
Postpone deletion of modules to avoid code server bottleneck
1 parent 7fef1c5 commit c40c140

File tree

3 files changed

+29
-30
lines changed

3 files changed

+29
-30
lines changed

lib/elixir/src/elixir_code_server.erl

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,9 @@ handle_call(retrieve_compiler_module, _From, Config) ->
6969

7070
handle_call(purge_compiler_modules, _From, Config) ->
7171
{Used, Unused, Counter} = Config#elixir_code_server.mod_pool,
72-
_ = [code:purge(Module) || Module <- Used],
73-
ModPool = {[], Used ++ Unused, Counter},
72+
purge_used(Used),
73+
Mods = lists:map(fun({Mod, _}) -> Mod end, Used),
74+
ModPool = {[], Mods ++ Unused, Counter},
7475
{reply, {ok, length(Used)}, Config#elixir_code_server{mod_pool=ModPool}};
7576

7677
handle_call(Request, _From, Config) ->
@@ -95,9 +96,9 @@ handle_cast({unrequire_files, Files}, Config) ->
9596
Unrequired = maps:without(Files, Current),
9697
{noreply, Config#elixir_code_server{required=Unrequired}};
9798

98-
handle_cast({return_compiler_module, Module}, Config) ->
99+
handle_cast({return_compiler_module, Module, Purgeable}, Config) ->
99100
{Used, Unused, Counter} = Config#elixir_code_server.mod_pool,
100-
ModPool = {[Module | Used], Unused, Counter},
101+
ModPool = {[{Module, Purgeable} | Used], Unused, Counter},
101102
{noreply, Config#elixir_code_server{mod_pool=ModPool}};
102103

103104
handle_cast(purge_compiler_modules, Config) ->
@@ -111,11 +112,9 @@ handle_cast(purge_compiler_modules, Config) ->
111112
%% purge them asynchronously, especially because they can
112113
%% block the code server. Ideally we would purge them in
113114
%% batches, but that's not supported at the moment.
114-
Opts = [{monitor, [{tag, {purged, Used}}]}],
115-
erlang:spawn_opt(fun() ->
116-
[code:purge(Module) || Module <- Used],
117-
ok
118-
end, Opts)
115+
Mods = lists:map(fun({Mod, _}) -> Mod end, Used),
116+
Opts = [{monitor, [{tag, {purged, Mods}}]}],
117+
erlang:spawn_opt(fun() -> purge_used(Used) end, Opts)
119118
end,
120119

121120
ModPool = {[], Unused, Counter},
@@ -144,6 +143,13 @@ code_change(_Old, Config, _Extra) ->
144143
compiler_module(I) ->
145144
list_to_atom("elixir_compiler_" ++ integer_to_list(I)).
146145

146+
purge_used(Used) ->
147+
[begin
148+
code:delete(Module),
149+
Purgeable andalso code:purge(Module)
150+
end || {Module, Purgeable} <- Used],
151+
ok.
152+
147153
defmodule(Pid, Tuple, #elixir_code_server{mod_ets=ModEts} = Config) ->
148154
ets:insert(elixir_modules, Tuple),
149155
Ref = erlang:monitor(process, Pid),

lib/elixir/src/elixir_compiler.erl

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,7 @@ do_is_purgeable(<<_:4/binary, Size:32, Beam/binary>>) ->
7979

8080
dispatch(Module, Fun, Args, Purgeable) ->
8181
Res = Module:Fun(Args),
82-
code:delete(Module),
83-
Purgeable andalso return_compiler_module(Module),
82+
return_compiler_module(Module, Purgeable),
8483
Res.
8584

8685
code_fun(nil) -> '__FILE__';
@@ -105,8 +104,8 @@ code_mod(Fun, Expr, Line, File, Module, Vars) when is_binary(File), is_integer(L
105104
retrieve_compiler_module() ->
106105
elixir_code_server:call(retrieve_compiler_module).
107106

108-
return_compiler_module(Module) ->
109-
elixir_code_server:cast({return_compiler_module, Module}).
107+
return_compiler_module(Module, Purgeable) ->
108+
elixir_code_server:cast({return_compiler_module, Module, Purgeable}).
110109

111110
allows_fast_compilation({'__block__', _, Exprs}) ->
112111
lists:all(fun allows_fast_compilation/1, Exprs);

lib/elixir/test/elixir/code_test.exs

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -803,23 +803,6 @@ defmodule Code.SyncTest do
803803
refute to_charlist(path) in :code.get_path()
804804
end
805805

806-
test "purges compiler modules" do
807-
quoted = quote(do: :ok)
808-
Code.compile_quoted(quoted)
809-
810-
{:ok, claimed} = Code.purge_compiler_modules()
811-
assert claimed > 0
812-
813-
{:ok, claimed} = Code.purge_compiler_modules()
814-
assert claimed == 0
815-
816-
quoted = quote(do: Agent.start_link(fn -> :ok end))
817-
Code.compile_quoted(quoted)
818-
819-
{:ok, claimed} = Code.purge_compiler_modules()
820-
assert claimed == 0
821-
end
822-
823806
test "returns previous options when setting compiler options" do
824807
Code.compiler_options(debug_info: false)
825808
assert Code.compiler_options(debug_info: true) == %{debug_info: false}
@@ -843,4 +826,15 @@ defmodule Code.SyncTest do
843826
:code.purge(CompileSample)
844827
:code.delete(CompileSample)
845828
end
829+
830+
test "purges compiler modules" do
831+
quoted = quote(do: :ok)
832+
Code.compile_quoted(quoted)
833+
834+
{:ok, claimed} = Code.purge_compiler_modules()
835+
assert claimed > 0
836+
837+
{:ok, claimed} = Code.purge_compiler_modules()
838+
assert claimed == 0
839+
end
846840
end

0 commit comments

Comments
 (0)