File 7631-diameter-Add-new-servcie-option-bins_info.patch of Package erlang

From 47fe888b332f3ba7813e2f1a210587c74f60a750 Mon Sep 17 00:00:00 2001
From: Micael Karlberg <bmk@erlang.org>
Date: Thu, 22 Feb 2024 15:16:01 +0100
Subject: [PATCH 1/5] [diameter] Add new servcie option bins_info

---
 lib/diameter/src/base/diameter.erl           |  13 ++-
 lib/diameter/src/base/diameter_config.erl    |  20 +++-
 lib/diameter/src/base/diameter_service.erl   | 101 ++++++++++++++-----
 lib/diameter/test/diameter_traffic_SUITE.erl |  30 +++++-
 4 files changed, 127 insertions(+), 37 deletions(-)

diff --git a/lib/diameter/src/base/diameter.erl b/lib/diameter/src/base/diameter.erl
index 557c6ffdf7..3231327c64 100644
--- a/lib/diameter/src/base/diameter.erl
+++ b/lib/diameter/src/base/diameter.erl
@@ -1,7 +1,7 @@
 %%
 %% %CopyrightBegin%
 %%
-%% Copyright Ericsson AB 2010-2020. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2024. All Rights Reserved.
 %%
 %% Licensed under the Apache License, Version 2.0 (the "License");
 %% you may not use this file except in compliance with the License.
@@ -87,6 +87,13 @@
 -include_lib("diameter/include/diameter.hrl").
 -include("diameter_internal.hrl").
 
+%% Enable debug logging by set(ing) level to debug.
+%% For example: logger:set_primary_config(level, debug),
+%% -define(DBG(F,A),
+%%         logger:debug("~w:~w(~w) -> " ++ F ++ "~n",
+%%                      [?MODULE, ?FUNCTION_NAME, ?LINE | A])).
+
+
 %% ---------------------------------------------------------------------------
 %% start/0
 %% ---------------------------------------------------------------------------
@@ -98,6 +105,7 @@
 start() ->
     application:start(?APPLICATION).
 
+
 %% ---------------------------------------------------------------------------
 %% stop/0
 %% ---------------------------------------------------------------------------
@@ -109,6 +117,7 @@ start() ->
 stop() ->
     application:stop(?APPLICATION).
 
+
 %% ---------------------------------------------------------------------------
 %% start_service/2
 %% ---------------------------------------------------------------------------
@@ -121,6 +130,7 @@ start_service(SvcName, Opts)
   when is_list(Opts) ->
     diameter_config:start_service(SvcName, Opts).
 
+
 %% ---------------------------------------------------------------------------
 %% stop_service/1
 %% ---------------------------------------------------------------------------
@@ -382,6 +392,7 @@ call(SvcName, App, Message) ->
     | {string_decode, boolean()}
     | {traffic_counters, boolean()}
     | {use_shared_peers, remotes()}
+    | {bins_info, boolean() | non_neg_integer()}
     | common_opt().
 
 -type application_opt()
diff --git a/lib/diameter/src/base/diameter_config.erl b/lib/diameter/src/base/diameter_config.erl
index 495e57e456..0d6610b866 100644
--- a/lib/diameter/src/base/diameter_config.erl
+++ b/lib/diameter/src/base/diameter_config.erl
@@ -1,7 +1,7 @@
 %%
 %% %CopyrightBegin%
 %%
-%% Copyright Ericsson AB 2010-2020. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2024. All Rights Reserved.
 %%
 %% Licensed under the Apache License, Version 2.0 (the "License");
 %% you may not use this file except in compliance with the License.
@@ -68,6 +68,7 @@
 -include_lib("diameter/include/diameter.hrl").
 -include("diameter_internal.hrl").
 
+
 %% Server state.
 -record(state, {id = diameter_lib:now(),
                 role :: server | transport}).
@@ -127,6 +128,7 @@
 %%% The return values below assume the server diameter_config is started.
 %%% The functions will exit if it isn't.
 
+
 %% --------------------------------------------------------------------------
 %% # start_service/2
 %% --------------------------------------------------------------------------
@@ -655,6 +657,9 @@ opt(service = S, {sequence = K, F}) ->
             {error, {E, R, Stack}}
     end;
 
+opt(service, {bins_info, BI}) ->
+    is_boolean(BI) orelse (is_integer(BI) andalso (BI >= 0));
+
 opt(transport, {transport_module, M}) ->
     is_atom(M);
 
@@ -792,6 +797,7 @@ stop_transport(SvcName, Refs) ->
 %% make_config/2
 
 make_config(SvcName, Opts) ->
+
     AppOpts = [T || {application, _} = T <- Opts],
     Apps = [init_app(T) || T <- AppOpts],
 
@@ -809,10 +815,14 @@ make_config(SvcName, Opts) ->
 
     D = proplists:get_value(string_decode, SvcOpts, true),
 
-    #service{name = SvcName,
-             rec = #diameter_service{applications = Apps,
-                                     capabilities = binary_caps(Caps, D)},
-             options = SvcOpts}.
+    Service =
+        #service{name = SvcName,
+                 rec = #diameter_service{applications = Apps,
+                                         capabilities = binary_caps(Caps, D)},
+                 options = SvcOpts},
+
+    Service.
+
 
 binary_caps(Caps, true) ->
     Caps;
diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl
index 6ff9de3341..22fecf74a5 100644
--- a/lib/diameter/src/base/diameter_service.erl
+++ b/lib/diameter/src/base/diameter_service.erl
@@ -1,7 +1,7 @@
 %%
 %% %CopyrightBegin%
 %%
-%% Copyright Ericsson AB 2010-2022. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2024. All Rights Reserved.
 %%
 %% Licensed under the Apache License, Version 2.0 (the "License");
 %% you may not use this file except in compliance with the License.
@@ -68,6 +68,7 @@
 -include_lib("diameter/include/diameter.hrl").
 -include("diameter_internal.hrl").
 
+
 %% RFC 3539 watchdog states.
 -define(WD_INITIAL, initial).
 -define(WD_OKAY,    okay).
@@ -107,6 +108,7 @@
          local  :: {ets:tid(), ets:tid(), ets:tid()},
          remote :: {ets:tid(), ets:tid(), ets:tid()},
          monitor = false :: false | pid(),   %% process to die with
+         bins_info = true :: boolean() | non_neg_integer(),
          options :: #{sequence := diameter:sequence(),  %% sequence mask
                       share_peers := diameter:remotes(),%% broadcast to
                       use_shared_peers := diameter:remotes(),%% use from
@@ -155,6 +157,7 @@
          watchdog :: match(pid()           %% key into watchdogT
                            | undefined)}). %% undefined if remote
 
+
 %% ---------------------------------------------------------------------------
 %% # start/1
 %% ---------------------------------------------------------------------------
@@ -690,9 +693,11 @@ cs(undefined, _) ->
 
 i(SvcName) ->
     %% Split the config into a server state and a list of transports.
+    Config = diameter_config:lookup(SvcName),
+
     {#state{} = S, CL} = lists:foldl(fun cfg_acc/2,
                                      {false, []},
-                                     diameter_config:lookup(SvcName)),
+                                     Config),
 
     %% Publish the state in order to be able to access it outside of
     %% the service process. Originally table identifiers were only
@@ -711,17 +716,20 @@ i(SvcName) ->
 
 cfg_acc({SvcName, #diameter_service{applications = Apps} = Rec, Opts},
         {false, Acc}) ->
+
     lists:foreach(fun init_mod/1, Apps),
     #{monitor := M}
         = SvcOpts
         = service_opts(Opts),
+
     S = #state{service_name = SvcName,
                service = Rec#diameter_service{pid = self()},
                local   = init_peers(),
                remote  = init_peers(),
                monitor = mref(M),
                options = maps:remove(monitor, SvcOpts)},
-    {S, Acc};
+    BinsInfo = proplists:get_value(bins_info, Opts, S#state.bins_info),
+    {S#state{bins_info = BinsInfo}, Acc};
 
 cfg_acc({_Ref, Type, _Opts} = T, {S, Acc})
   when Type == connect;
@@ -737,14 +745,17 @@ init_peers() ->
 
 %% Valid service options are all 2-tuples.
 service_opts(Opts) ->
-    remove([{strict_arities, true}, {avp_dictionaries, []}],
-           merge(lists:append([[{monitor, false}] | def_opts()]), Opts)).
+    remove([{bins_info, true}, {strict_arities, true}, {avp_dictionaries, []}],
+           merge(lists:append([[{monitor, false}] | def_opts()]),
+                 lists:keydelete(bins_info, 1, Opts))).
 
 merge(List1, List2) ->
     maps:merge(maps:from_list(List1), maps:from_list(List2)).
 
 remove(List, Map) ->
-    maps:filter(fun(K,V) -> not lists:member({K,V}, List) end,
+    maps:filter(fun(K,V) ->
+                        not lists:member({K,V}, List)
+                end,
                 Map).
 
 def_opts() ->  %% defaults on the options map
@@ -2049,9 +2060,13 @@ keys(connect = T, Opts) ->
 keys(_, _) ->
     [{listen, accept}].
 
-peer_dict(#state{watchdogT = WatchdogT, local = {PeerT, _, _}}, Dict0) ->
+peer_dict(#state{watchdogT = WatchdogT,
+                 local     = {PeerT, _, _},
+                 bins_info = BinsInfo}, Dict0) ->
     try ets:tab2list(WatchdogT) of
-        L -> lists:foldl(fun(T,A) -> peer_acc(PeerT, A, T) end, Dict0, L)
+        L -> lists:foldl(fun(T,A) ->
+                                 peer_acc(PeerT, A, T, BinsInfo)
+                         end, Dict0, L)
     catch
         error: badarg -> Dict0  %% service has gone down
     end.
@@ -2062,12 +2077,12 @@ peer_acc(PeerT, Acc, #watchdog{pid = Pid,
                                options = Opts,
                                state = WS,
                                started = At,
-                               peer = TPid}) ->
+                               peer = TPid}, BinsInfo) ->
     Info = [{type, Type},
             {options, Opts},
             {watchdog, {Pid, At, WS}}
             | info_peer(PeerT, TPid, WS)],
-    dict:append(Ref, Info ++ [{info, info_process_info(Info)}], Acc).
+    dict:append(Ref, Info ++ [{info, info_process_info(Info, BinsInfo)}], Acc).
 
 info_peer(PeerT, TPid, WS)
   when is_pid(TPid), WS /= ?WD_DOWN ->
@@ -2079,29 +2094,36 @@ info_peer(PeerT, TPid, WS)
 info_peer(_, _, _) ->
     [].
 
-info_process_info(Info) ->
-    lists:flatmap(fun ipi/1, Info).
+info_process_info(Info, BinsInfo) ->
+    lists:flatmap(fun(X) -> ipi(X, BinsInfo) end, Info).
 
-ipi({watchdog, {Pid, _, _}}) ->
-    info_pid(Pid);
+ipi({watchdog, {Pid, _, _}}, BinsInfo) ->
+    info_pid(Pid, BinsInfo);
 
-ipi({peer, {Pid, _}}) ->
-    info_pid(Pid);
+ipi({peer, {Pid, _}}, BinsInfo) ->
+    info_pid(Pid, BinsInfo);
 
-ipi({port, [{owner, Pid} | _]}) ->
-    info_pid(Pid);
+ipi({port, [{owner, Pid} | _]}, BinsInfo) ->
+    info_pid(Pid, BinsInfo);
 
-ipi(_) ->
+ipi(_, _) ->
     [].
 
-info_pid(Pid) ->
-    case process_info(Pid, [message_queue_len, memory, binary]) of
+info_pid(Pid, BinsInfo) ->
+    InfoItems = info_pid_items(BinsInfo),
+    case process_info(Pid, InfoItems) of
         undefined ->
             [];
         L ->
-            [{Pid, lists:map(fun({K,V}) -> {K, map_info(K,V)} end, L)}]
+            [{Pid, lists:map(fun({K,V}) -> {K, map_info(K,V,BinsInfo)} end, L)}]
     end.
 
+info_pid_items(false) ->
+    [message_queue_len, memory];
+info_pid_items(_) ->
+    [message_queue_len, memory, binary].
+
+
 %% The binary list consists of 3-tuples {Ptr, Size, Count}, where Ptr
 %% is a C pointer value, Size is the size of a referenced binary in
 %% bytes, and Count is a global reference count. The same Ptr can
@@ -2113,15 +2135,38 @@ info_pid(Pid) ->
 %% The list can be quite large, and we aren't often interested in the
 %% pointers or counts, so whittle this down to the number of binaries
 %% referenced and their total byte count.
-map_info(binary, L) ->
-    SzD = lists:foldl(fun({P,S,_}, D) -> dict:store(P,S,D) end,
-                      dict:new(),
-                      L),
-    {dict:size(SzD), dict:fold(fun(_,S,N) -> S + N end, 0, SzD)};
+map_info(binary, L, BinsInfo) ->
+    {RemainingL, SzD} = bins_sum(L, BinsInfo),
+    {dict:size(SzD), dict:fold(fun(_,S,N) -> S + N end, 0, SzD), RemainingL};
 
-map_info(_, T) ->
+
+map_info(_, T, _) ->
     T.
 
+bins_sum(L, true = _BinsInfo) ->
+    {0, bins_sum2(L, dict:new())};
+bins_sum(L, BinsInfo) when is_integer(BinsInfo) ->
+    bins_sum3(L, BinsInfo, dict:new());
+bins_sum(_, _) ->
+    %% We should actually not get here, but just in case
+    %% we have a logic error somewhere...
+    dict:new().
+
+bins_sum2([], D) ->
+    D;
+bins_sum2([{P, S, _} | T], D) ->
+    bins_sum2(T, dict:store(P,S,D)).
+
+bins_sum3([], _, D) ->
+    {0, D};
+bins_sum3(L, N, D) when (N =< 0) ->
+    {length(L), D};
+bins_sum3([{P, S, _} | T], N, D) ->
+    bins_sum3(T, N-1, dict:store(P,S,D)).
+
+
+    
+
 %% The point of extracting the config here is so that 'transport' info
 %% has one entry for each transport ref, the peer table only
 %% containing entries that have a living watchdog.
diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl
index 95ea6be020..37fc2d9446 100644
--- a/lib/diameter/test/diameter_traffic_SUITE.erl
+++ b/lib/diameter/test/diameter_traffic_SUITE.erl
@@ -1,7 +1,7 @@
 %%
 %% %CopyrightBegin%
 %%
-%% Copyright Ericsson AB 2010-2022. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2024. All Rights Reserved.
 %%
 %% Licensed under the Apache License, Version 2.0 (the "License");
 %% you may not use this file except in compliance with the License.
@@ -263,6 +263,7 @@ parallel(_Config) ->
 %% configuration results in sufficient coverage over time.
 
 run() ->
+    %% ok = logger:set_primary_config(level, debug),
     Svc = ?util:unique_string(),
     run(#group{transport = ?util:choose(?TRANSPORTS),
                strings = bool(),
@@ -296,6 +297,12 @@ traffic(#group{} = Cfg) ->
     LRef = server(Cfg),
     ok = client(Cfg, LRef),
     [] = send(Cfg),
+
+    io:format("Service(s) info: "
+              "~n   ~p"
+              "~n", [[{SvcName, diameter:service_info(SvcName, all)} ||
+                         SvcName <- diameter:services()]]),
+
     ok = stop_services(Cfg),
     [] = ets:tab2list(diameter_request).
 
@@ -340,6 +347,10 @@ wait(MRef) ->
 %% server/1
 
 server(Config) ->
+
+    logger:debug("entry with"
+                 "~n   Config: ~p", [Config]),
+
     #group{transport = T,
            client_sender = CS,
            server_service = SN,
@@ -349,7 +360,8 @@ server(Config) ->
         = Grp
         = group(Config),
     ok = start_service(SN, [{traffic_counters, bool()},
-                            {decode_format, SD}
+                            {decode_format, SD},
+                            {bins_info, bins_info()}
                             | ?SERVICE(SN, Grp)]),
     Cfg = [{sender, SS},
            {message_cb, ST andalso {?MODULE, message, [0]}}]
@@ -363,6 +375,10 @@ server(Config) ->
 %% client/1
 
 client(Config, LRef) ->
+
+    logger:debug("entry with"
+                 "~n   Config: ~p", [Config]),
+
     #group{transport = T,
            encoding = E,
            client_service = CN,
@@ -372,7 +388,8 @@ client(Config, LRef) ->
     ok = start_service(CN, [{traffic_counters, bool()},
                             {sequence, ?CLIENT_MASK},
                             {decode_format, map},
-                            {strict_arities, decode}
+                            {strict_arities, decode},
+                            {bins_info, bins_info()}
                             | ?SERVICE(CN, Grp)]),
     _ = [?util:connect(CN, [T | C], LRef, O)
          || C <- [[{sender, CS} | client_opts(T)]],
@@ -387,6 +404,13 @@ client(Config, LRef) ->
 bool() ->
     0.5 =< rand:uniform().
 
+bins_info() ->
+    %% Three possibilities: true | false | non_neg_integer()
+    %% We choose a low range, 42, only because our test does not
+    %% actually stress the system, so no point in picking a large
+    %% number.
+    ?util:choose([true, false, rand:uniform(42)]).
+
 unordered() ->
     ?util:choose([true, false, 1, 2]).
 
-- 
2.35.3

openSUSE Build Service is sponsored by