File 2794-logger-Use-persistent_term-for-module-level-config.patch of Package erlang

From acfc294ad0ae9bbeb4787f70db49842d957821c6 Mon Sep 17 00:00:00 2001
From: Lukas Larsson <lukas@erlang.org>
Date: Wed, 21 Aug 2019 11:18:25 +0200
Subject: [PATCH 4/7] logger: Use persistent_term for module level config

Move the module level config into persistent_term for
faster and more scalable lookup.
---
 lib/kernel/src/logger_config.erl | 94 ++++++++++++++++++++++------------------
 lib/kernel/src/logger_server.erl | 10 +----
 lib/kernel/test/logger_SUITE.erl | 15 ++++---
 3 files changed, 63 insertions(+), 56 deletions(-)

diff --git a/lib/kernel/src/logger_config.erl b/lib/kernel/src/logger_config.erl
index 4b67325b69..31b5480cde 100644
--- a/lib/kernel/src/logger_config.erl
+++ b/lib/kernel/src/logger_config.erl
@@ -25,39 +25,51 @@
          get/2, get/3,
          create/3, set/3,
          set_module_level/3,unset_module_level/2,
-         get_module_level/1,cache_module_level/2,
+         get_module_level/1,
          level_to_int/1]).
 
 -include("logger_internal.hrl").
 
+-compile({inline,[get_primary_level/0,level_to_int/1]}).
+
+-define(LEVEL_TO_CACHE(Level),Level + 16#10).
+-define(PRIMARY_TO_CACHE(Level),Level).
+-define(IS_CACHED(Level),(Level =< ?LOG_ALL)).
+-define(CACHE_TO_LEVEL(Level),if ?IS_CACHED(Level) -> Level; true -> Level - 16#10 end).
+
+-define(IS_MODULE(Module),is_atom(Module) andalso Module =/= ?PRIMARY_KEY).
+
 new(Name) ->
     _ = ets:new(Name,[set,protected,named_table,
                       {read_concurrency,true},
                       {write_concurrency,true}]),
     ets:whereis(Name).
 
-delete(Tid,Id) ->
-    ets:delete(Tid,table_key(Id)).
+delete(Tid,What) ->
+    persistent_term:put({?MODULE,table_key(What)},undefined),
+    ets:delete(Tid,table_key(What)).
 
 %% Optimized for speed.
-allow(Tid,Level,Module) ->
-    LevelInt = level_to_int(Level),
-    case ets:lookup(Tid,Module) of
-        [{Module,{ModLevel,cached}}] when is_integer(ModLevel),
-                                          LevelInt =< ModLevel ->
-            less_or_equal_level(Level,ModLevel);
-        [{Module,ModLevel}] when is_integer(ModLevel),
-                                 LevelInt =< ModLevel ->
-            less_or_equal_level(Level,ModLevel);
-        [] ->
-            logger_server:cache_module_level(Module),
-            allow(Tid,Level);
-        _ ->
-            false
-    end.
+allow(_Tid,Level,Module) ->
+    ModLevel =
+        case persistent_term:get({?MODULE,Module},undefined) of
+            undefined ->
+                %% This is where the module cache takes place. We insert the module level
+                %% plus 16 into the pt and then when looking it up we need to do a check
+                %% and subtraction.
+                %% The reason why we do this dance and not just wrap it all in a tuple
+                %% is because updates of immediates (i.e. small ints in this case)
+                %% is cheap even in pt, so we cannot put any complex terms in there.
+                IntLevel = get_primary_level(),
+                persistent_term:put({?MODULE,Module},?PRIMARY_TO_CACHE(IntLevel)),
+                IntLevel;
+            IntLevel ->
+                ?CACHE_TO_LEVEL(IntLevel)
+        end,
+    less_or_equal_level(Level,ModLevel).
 
 allow(_Tid,Level) ->
-    PrimaryLevelInt = persistent_term:get({?MODULE,?PRIMARY_KEY}, ?NOTICE),
+    PrimaryLevelInt = get_primary_level(),
     less_or_equal_level(Level,PrimaryLevelInt).
 
 less_or_equal_level(emergency,ModLevel) -> ?EMERGENCY =< ModLevel;
@@ -72,6 +84,9 @@ less_or_equal_level(debug,ModLevel) -> ?DEBUG =< ModLevel.
 exist(Tid,What) ->
     ets:member(Tid,table_key(What)).
 
+get_primary_level() ->
+    persistent_term:get({?MODULE,?PRIMARY_KEY},?NOTICE).
+
 get(Tid,What) ->
     case ets:lookup(Tid,table_key(What)) of
         [{_,_,Config}] ->
@@ -108,14 +123,12 @@ set(Tid,proxy,Config) ->
     ok;
 set(Tid,What,Config) ->
     LevelInt = level_to_int(maps:get(level,Config)),
-    %% Should do this only if the level has actually changed. Possibly
-    %% overwrite instead of delete?
     case What of
         primary ->
-            _ = ets:select_delete(Tid,[{{'_',{'$1',cached}},
-                                        [{'=/=','$1',LevelInt}],
-                                        [true]}]),
             ok = persistent_term:put({?MODULE,?PRIMARY_KEY}, LevelInt),
+            [persistent_term:put(Key, ?PRIMARY_TO_CACHE(LevelInt))
+             || {{?MODULE, Module} = Key,L} <- persistent_term:get(),
+                Module =/= ?PRIMARY_KEY, L > ?LOG_ALL],
             ok;
         _ ->
             ok
@@ -123,29 +136,28 @@ set(Tid,What,Config) ->
     ets:update_element(Tid,table_key(What),[{2,LevelInt},{3,Config}]),
     ok.
 
-set_module_level(Tid,Modules,Level) ->
+set_module_level(_Tid,Modules,Level) ->
     LevelInt = level_to_int(Level),
-    [ets:insert(Tid,{Module,LevelInt}) || Module <- Modules],
+    [persistent_term:put({?MODULE,Module},?LEVEL_TO_CACHE(LevelInt)) || Module <- Modules],
     ok.
 
-%% should possibly overwrite instead of delete?
-unset_module_level(Tid,all) ->
-    MS = [{{'$1','$2'},[{is_atom,'$1'},{is_integer,'$2'}],[true]}],
-    _ = ets:select_delete(Tid,MS),    
+%% We overwrite instead of delete because that is more efficient
+%% when using persistent_term
+unset_module_level(_Tid,all) ->
+    PrimaryLevel = get_primary_level(),
+    [persistent_term:put(Key, ?PRIMARY_TO_CACHE(PrimaryLevel))
+     || {{?MODULE, Module} = Key,_} <- persistent_term:get(), ?IS_MODULE(Module)],
     ok;
-unset_module_level(Tid,Modules) ->
-    [ets:delete(Tid,Module) || Module <- Modules],
+unset_module_level(_Tid,Modules) ->
+    PrimaryLevel = get_primary_level(),
+    [persistent_term:put({?MODULE,Module}, ?PRIMARY_TO_CACHE(PrimaryLevel)) || Module <- Modules],
     ok.
 
-get_module_level(Tid) ->
-    MS = [{{'$1','$2'},[{is_atom,'$1'},{is_integer,'$2'}],[{{'$1','$2'}}]}],
-    Modules = ets:select(Tid,MS),
-    lists:sort([{M,int_to_level(L)} || {M,L} <- Modules]).
-
-cache_module_level(Tid,Module) ->
-    GlobalLevelInt = ets:lookup_element(Tid,?PRIMARY_KEY,2),
-    ets:insert_new(Tid,{Module,{GlobalLevelInt,cached}}),
-    ok.
+get_module_level(_Tid) ->
+    lists:sort(
+      [{Module,int_to_level(?CACHE_TO_LEVEL(Level))}
+       || {{?MODULE, Module},Level} <- persistent_term:get(),
+          ?IS_MODULE(Module), not ?IS_CACHED(Level)]).
 
 level_to_int(none) -> ?LOG_NONE;
 level_to_int(emergency) -> ?EMERGENCY;
diff --git a/lib/kernel/src/logger_server.erl b/lib/kernel/src/logger_server.erl
index 722246e82c..1ca9adbf19 100644
--- a/lib/kernel/src/logger_server.erl
+++ b/lib/kernel/src/logger_server.erl
@@ -25,7 +25,7 @@
 -export([start_link/0, add_handler/3, remove_handler/1,
          add_filter/2, remove_filter/2,
          set_module_level/2, unset_module_level/0,
-         unset_module_level/1, cache_module_level/1,
+         unset_module_level/1,
          set_config/2, set_config/3,
          update_config/2, update_config/3,
          update_formatter_config/2]).
@@ -104,9 +104,6 @@ unset_module_level(Modules) when is_list(Modules) ->
 unset_module_level(Modules) ->
     {error,{not_a_list_of_modules,Modules}}.
 
-cache_module_level(Module) ->
-    gen_server:cast(?SERVER,{cache_module_level,Module}).
-
 set_config(Owner,Key,Value) ->
     case sanity_check(Owner,Key,Value) of
         ok ->
@@ -333,10 +330,7 @@ handle_call({unset_module_level,Modules}, _From, #state{tid=Tid}=State) ->
     {reply,Reply,State}.
 
 handle_cast({async_req_reply,_Ref,_Reply} = Reply,State) ->
-    call_h_reply(Reply,State);
-handle_cast({cache_module_level,Module}, #state{tid=Tid}=State) ->
-    logger_config:cache_module_level(Tid,Module),
-    {noreply, State}.
+    call_h_reply(Reply,State).
 
 %% Interface for those who can't call the API - e.g. the emulator, or
 %% places related to code loading.
diff --git a/lib/kernel/test/logger_SUITE.erl b/lib/kernel/test/logger_SUITE.erl
index f8f3d27778..c6b563e4a9 100644
--- a/lib/kernel/test/logger_SUITE.erl
+++ b/lib/kernel/test/logger_SUITE.erl
@@ -478,14 +478,15 @@ set_application_level(cleanup,_Config) ->
     ok.
 
 cache_module_level(_Config) ->
-    ok = logger:unset_module_level(?MODULE),
-    [] = ets:lookup(?LOGGER_TABLE,?MODULE), %dirty - add API in logger_config?
+
+    %% This test does a lot of whitebox tests so be prepared for that
+    persistent_term:erase({logger_config,?MODULE}),
+
+    primary = persistent_term:get({logger_config,?MODULE}, primary),
     ?LOG_NOTICE(?map_rep),
-    %% Caching is done asynchronously, so wait a bit for the update
-    timer:sleep(100),
-    [_] = ets:lookup(?LOGGER_TABLE,?MODULE), %dirty - add API in logger_config?
-    ok = logger:unset_module_level(?MODULE),
-    [] = ets:lookup(?LOGGER_TABLE,?MODULE), %dirty - add API in logger_config?
+    5 = persistent_term:get({logger_config,?MODULE}, primary),
+    logger:set_primary_config(level, info),
+    6 = persistent_term:get({logger_config,?MODULE}, primary),
     ok.
 
 cache_module_level(cleanup,_Config) ->
-- 
2.16.4

openSUSE Build Service is sponsored by