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

openSUSE Build Service is sponsored by