From 78b3dc6eea23a728a20947ccc425a7860ef39d97 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 10 Jun 2013 13:08:08 +0200 Subject: Make spawn options for request processes configurable That is, for the process that's spawned for each incoming Diameter request message. --- lib/diameter/doc/src/diameter.xml | 24 ++++++++++++++++++++++++ lib/diameter/src/base/diameter.erl | 4 +++- lib/diameter/src/base/diameter_config.erl | 9 ++++++++- lib/diameter/src/base/diameter_service.erl | 24 ++++++++++++++++++++---- lib/diameter/src/base/diameter_traffic.erl | 25 ++++++++++++++++++------- lib/diameter/test/diameter_traffic_SUITE.erl | 4 +++- 6 files changed, 76 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml index 318c98f786..161bcd33e6 100644 --- a/lib/diameter/doc/src/diameter.xml +++ b/lib/diameter/doc/src/diameter.xml @@ -1,5 +1,7 @@ erlang:spawn_opt/2'> erlang:nodes/0'> +{spawn_opt, [term()]} + +

+An options list passed to &spawn_opt; when spawning a process for an +incoming Diameter request, unless the transport in question +specifies another value.

+ +

+Defaults to the empty list.

+
+ {use_shared_peers, boolean() | [node()] | evaluable()}

@@ -1161,6 +1174,17 @@ Defaults to 30000 for a connecting transport and 60000 for a listening transport.

+ +{spawn_opt, [term()]} + +

+An options list passed to &spawn_opt; when spawning a process for an +incoming Diameter request.

+ +

+Defaults to the list configured on the service if not specified.

+
+ {transport_config, term()} {transport_config, term(), &dict_Unsigned32; | infinity} diff --git a/lib/diameter/src/base/diameter.erl b/lib/diameter/src/base/diameter.erl index 57730cad61..77200cc7d0 100644 --- a/lib/diameter/src/base/diameter.erl +++ b/lib/diameter/src/base/diameter.erl @@ -306,7 +306,8 @@ call(SvcName, App, Message) -> | {restrict_connections, restriction()} | {sequence, sequence() | evaluable()} | {share_peers, remotes()} - | {use_shared_peers, remotes()}. + | {use_shared_peers, remotes()} + | {spawn_opt, list()}. -type application_opt() :: {alias, app_alias()} @@ -345,6 +346,7 @@ call(SvcName, App, Message) -> | {reconnect_timer, 'Unsigned32'()} | {watchdog_timer, 'Unsigned32'() | {module(), atom(), list()}} | {watchdog_config, [{okay|suspect, non_neg_integer()}]} + | {spawn_opt, list()} | {private, any()}. %% Predicate passed to remove_transport/2 diff --git a/lib/diameter/src/base/diameter_config.erl b/lib/diameter/src/base/diameter_config.erl index 2a145c874b..fc5c284bf2 100644 --- a/lib/diameter/src/base/diameter_config.erl +++ b/lib/diameter/src/base/diameter_config.erl @@ -549,6 +549,9 @@ opt({watchdog_timer, Tmo}) -> opt({watchdog_config, L}) -> is_list(L) andalso lists:all(fun wdopt/1, L); +opt({spawn_opt, Opts}) -> + is_list(Opts); + %% Options that we can't validate. opt({K, _}) when K == transport_config; @@ -632,7 +635,8 @@ make_config(SvcName, Opts) -> {false, use_shared_peers}, {false, monitor}, {?NOMASK, sequence}, - {nodes, restrict_connections}]), + {nodes, restrict_connections}, + {[], spawn_opt}]), #service{name = SvcName, rec = #diameter_service{applications = Apps, @@ -647,6 +651,9 @@ make_opts(Opts, Defs) -> [{K, opt(K,V)} || {K,V} <- Known]. +opt(spawn_opt, L) -> + is_list(L); + opt(K, false = B) when K /= sequence -> B; diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl index 112e83476d..9dd8aafc61 100644 --- a/lib/diameter/src/base/diameter_service.erl +++ b/lib/diameter/src/base/diameter_service.erl @@ -770,10 +770,8 @@ start(Ref, Type, Opts, #state{watchdogT = WatchdogT, = Svc = merge_service(Opts, Svc0), {_,_} = Mask = proplists:get_value(sequence, SvcOpts), - Pid = s(Type, Ref, {diameter_traffic:make_recvdata([SvcName, - PeerT, - Apps, - Mask]), + RecvData = diameter_traffic:make_recvdata([SvcName, PeerT, Apps, Mask]), + Pid = s(Type, Ref, {{spawn_opts([Opts, SvcOpts]), RecvData}, Opts, SvcOpts, Svc}), @@ -787,6 +785,12 @@ start(Ref, Type, Opts, #state{watchdogT = WatchdogT, %% record so that each watchdog may get a different record. This %% record is what is passed back into application callbacks. +spawn_opts(Optss) -> + SpawnOpts = get_value(spawn_opt, Optss, []), + [T || T <- SpawnOpts, + T /= link, + T /= monitor]. + s(Type, Ref, T) -> {_MRef, Pid} = diameter_watchdog:start({Type, Ref}, T), Pid. @@ -986,6 +990,18 @@ keyfind([Key | Rest], Pos, L) -> T end. +%% get_value/3 + +get_value(_, [], Def) -> + Def; +get_value(Key, [L | Rest], Def) -> + case lists:keyfind(Key, 1, L) of + {_,V} -> + V; + _ -> + get_value(Key, Rest, Def) + end. + %% find_outgoing_app/2 find_outgoing_app(Alias, Apps) -> diff --git a/lib/diameter/src/base/diameter_traffic.erl b/lib/diameter/src/base/diameter_traffic.erl index 0b15e68ec7..6f81ade30e 100644 --- a/lib/diameter/src/base/diameter_traffic.erl +++ b/lib/diameter/src/base/diameter_traffic.erl @@ -48,6 +48,7 @@ -define(BASE, ?DIAMETER_DICT_COMMON). %% Note: the RFC 3588 dictionary -define(DEFAULT_TIMEOUT, 5000). %% for outgoing requests +-define(DEFAULT_SPAWN_OPTS, []). %% Table containing outgoing requests for which a reply has yet to be %% received. @@ -153,13 +154,8 @@ receive_message(TPid, Pkt, Dict0, RecvData) RecvData). %% Incoming request ... -recv(true, false, TPid, Pkt, Dict0, RecvData) -> - try - spawn(fun() -> recv_request(TPid, Pkt, Dict0, RecvData) end) - catch - error: system_limit = E -> %% discard - ?LOG({error, E}, now()) - end; +recv(true, false, TPid, Pkt, Dict0, T) -> + spawn_request(TPid, Pkt, Dict0, T); %% ... answer to known request ... recv(false, #request{ref = Ref, handler = Pid} = Req, _, Pkt, Dict0, _) -> @@ -177,6 +173,21 @@ recv(false, #request{ref = Ref, handler = Pid} = Req, _, Pkt, Dict0, _) -> recv(false, false, _, _, _, _) -> ok. +%% spawn_request/4 + +spawn_request(TPid, Pkt, Dict0, {Opts, RecvData}) -> + spawn_request(TPid, Pkt, Dict0, Opts, RecvData); +spawn_request(TPid, Pkt, Dict0, RecvData) -> + spawn_request(TPid, Pkt, Dict0, ?DEFAULT_SPAWN_OPTS, RecvData). + +spawn_request(TPid, Pkt, Dict0, Opts, RecvData) -> + try + spawn_opt(fun() -> recv_request(TPid, Pkt, Dict0, RecvData) end, Opts) + catch + error: system_limit = E -> %% discard + ?LOG({error, E}, now()) + end. + %% --------------------------------------------------------------------------- %% recv_request/4 %% --------------------------------------------------------------------------- diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index 38bdf55af8..a97c54fc04 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -171,7 +171,8 @@ {'Product-Name', "OTP/diameter"}, {'Auth-Application-Id', [?DIAMETER_APP_ID_COMMON]}, {'Acct-Application-Id', [?DIAMETER_APP_ID_ACCOUNTING]}, - {restrict_connections, false} + {restrict_connections, false}, + {spawn_opt, [{min_heap_size, 5000}]} | [{application, [{dictionary, D}, {module, ?MODULE}, {answer_errors, callback}]} @@ -321,6 +322,7 @@ add_transports(Config) -> LRef = ?util:listen(?SERVER, tcp, [{capabilities_cb, fun capx/2}, + {spawn_opt, [{min_heap_size, 8096}]}, {applications, apps(rfc3588)}]), Cs = [?util:connect(?CLIENT, tcp, -- cgit v1.2.3