File 1071-Use-code_server-path-cache-in-code-where_is_file-1.patch of Package erlang
From c878586fd494ba1ca0e9ef8cb3cd9cf4023339b6 Mon Sep 17 00:00:00 2001
From: Michael Davis <mcarsondavis@gmail.com>
Date: Tue, 30 Jan 2024 17:02:53 -0500
Subject: [PATCH 1/2] Use code_server path cache in code:where_is_file/1
`application:load/1` slows down as the number of directories in the code
path increases because the call to `code:where_is_file/1` for the '.app'
file must scan each directory for the app. The code_server maintains
a cache of the contents of directories in the path depending on their
`code:cache()` setting. Re-using and updating that cache when searching
for '.app' files in `application:load/1` can improve its runtime,
especially when loading multiple applications.
For a reasonably large project (RabbitMQ) with a high number of code
path dirs (111 at time of writing), loading an application might take
upwards of 20ms. With the code_server's cache, loading each application
takes at most around half of a millisecond instead. `application:load/1`
is used for loading plugins in Rabbit's CLI for example, and this change
can save as much as 750ms for a run of `rabbitmqctl --help` (30% of the
total run time). It also improves the boot time for the broker since
`application:load/1` is used by `application:start/2`.
---
lib/kernel/src/code.erl | 3 +--
lib/kernel/src/code_server.erl | 24 ++++++++++++++++++++++++
2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl
index 54082f21b6..f6b04ed190 100644
--- a/lib/kernel/src/code.erl
+++ b/lib/kernel/src/code.erl
@@ -1773,8 +1773,7 @@ locate application resource files.
Filename :: file:filename(),
Absname :: file:filename().
where_is_file(File) when is_list(File) ->
- Path = get_path(),
- where_is_file(Path, File).
+ call({where_is_file, File}).
%% To avoid unnecessary work when looking at many modules, this also
%% accepts pairs of directories and pre-fetched contents in the path
diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl
index 7689acf124..34ff7037d1 100644
--- a/lib/kernel/src/code_server.erl
+++ b/lib/kernel/src/code_server.erl
@@ -302,6 +302,11 @@ handle_call({replace_path,Name,Dir,Control}, _From,
handle_call(get_path, _From, S) ->
{reply,[P || {P, _Cache} <- S#state.path],S};
+handle_call({where_is_file,File}, _From,
+ #state{path=Path,path_cache=Cache0}=S) ->
+ {Resp,Cache} = where_is_file(Path, File, Cache0),
+ {reply,Resp,S#state{path_cache=Cache}};
+
handle_call(clear_cache, _From, S) ->
{reply,ok,S#state{path_cache=#{}}};
@@ -1485,3 +1490,22 @@ archive_extension() ->
to_list(X) when is_list(X) -> X;
to_list(X) when is_atom(X) -> atom_to_list(X).
+
+where_is_file([], _File, Cache) ->
+ {non_existing, Cache};
+where_is_file([{Dir, nocache} | Tail], File, Cache) ->
+ Full = filename:append(Dir, File),
+ case erl_prim_loader:read_file_info(Full) of
+ {ok,_} ->
+ {Full, Cache};
+ _Error ->
+ where_is_file(Tail, File, Cache)
+ end;
+where_is_file([{Dir, CacheKey} | Tail], File, Cache) when is_integer(CacheKey) ->
+ case with_cache(CacheKey, Dir, File, Cache) of
+ {true, Cache1} ->
+ Full = filename:append(Dir, File),
+ {Full, Cache1};
+ {false, Cache1} ->
+ where_is_file(Tail, File, Cache1)
+ end.
--
2.43.0