diff options
author | Erlang/OTP <otp@erlang.org> | 2020-12-04 17:35:59 +0100 |
---|---|---|
committer | Erlang/OTP <otp@erlang.org> | 2020-12-04 17:35:59 +0100 |
commit | 9d0c7651a59fff8427488a77a4b26d2c876ccc9d (patch) | |
tree | 417e3c0322a0070c1c3d23309021b1299fddd059 | |
parent | 7d81561c87785966c1b053afd35d3e861649472a (diff) | |
parent | ce3dc7a30fe12fbd2cd01221c49fd2df4b83dcca (diff) | |
download | erlang-9d0c7651a59fff8427488a77a4b26d2c876ccc9d.tar.gz |
Merge branch 'bmk/snmp/agent/20201201/serialize_notifications/OTP-17022' into maint-22
* bmk/snmp/agent/20201201/serialize_notifications/OTP-17022:
[snmp|agent|doc] Add text about the new (extended) multi-threaded option
[snmp|agent|test] Add test cases for extended multi-threaded agent
[snmp|agent] Introduce notification specific worker
-rw-r--r-- | lib/snmp/doc/src/snmp_app.xml | 46 | ||||
-rw-r--r-- | lib/snmp/doc/src/snmp_config.xml | 31 | ||||
-rw-r--r-- | lib/snmp/src/agent/snmpa_agent.erl | 119 | ||||
-rw-r--r-- | lib/snmp/src/misc/snmp_verbosity.erl | 4 | ||||
-rw-r--r-- | lib/snmp/test/snmp_agent_SUITE.erl | 109 | ||||
-rw-r--r-- | lib/snmp/test/snmp_agent_test_lib.erl | 18 |
6 files changed, 224 insertions, 103 deletions
diff --git a/lib/snmp/doc/src/snmp_app.xml b/lib/snmp/doc/src/snmp_app.xml index b080301143..b4c1392b71 100644 --- a/lib/snmp/doc/src/snmp_app.xml +++ b/lib/snmp/doc/src/snmp_app.xml @@ -188,22 +188,46 @@ in the snmp_config file! <tag><marker id="agent_orig_disco_opts"></marker> <c><![CDATA[agent_originating_discovery_opts() = [agent_originating_discovery_opt()] <optional>]]></c></tag> <item> - <p><c>agent_originating_discovery_opt() = - {enable, boolean()}</c></p> - <p>These are options effecting discovery <c>originating</c> in this - agent. </p> - <p>The default values for the <c>originating</c> - discovery options are: </p> - <list type="bulleted"> - <item>enable: <c>true</c></item> + <p><c>agent_originating_discovery_opt() = {enable, boolean()}</c></p> + <p>These are options effecting discovery <c>originating</c> in this + agent. </p> + <p>The default values for the <c>originating</c> + discovery options are: </p> + <list type="bulleted"> + <item>enable: <c>true</c></item> </list> </item> <tag><marker id="agent_mt"></marker> - <c><![CDATA[multi_threaded() = bool() <optional>]]></c></tag> + <c><![CDATA[multi_threaded() = bool() | extended <optional>]]></c></tag> <item> - <p>If <c>true</c>, the agent is multi-threaded, with one - thread for each get request. </p> + <p>If <c>true</c> (or <c>extended</c>), the agent is multi-threaded, + with one thread for each get request.</p> + <p>The value <c>extended</c> means that a special 'process' + is also created intended to handle <em>all</em> notifications. </p> + <list> + <item> + <p><c>true</c> - One worker dedicated to 'set-requests' and one + (main) worker for all other requests ('get-request' and + notifications).</p> + <p>If the 'main' worker is busy, a temporary process is + spawned to handle that job ('get-request' or notification). </p> + </item> + <item> + <p><c>extended</c> - One worker dedicated to 'set-requests', + one worker dedicated to notifications and one + (main) worker for all 'get-requests'. </p> + <p>If the 'main' worker is busy, a temporary process is + spawned to handle that 'get-request'. </p> + </item> + </list> + <note> + <p>Even with multi-threaded set to <c>extended</c> + there is still a risk for 'reorder' when sending inform-requsts, + which require a response (and may therefor require resending). </p> + <p>Also, there is of course no way to guarantee order once the + package is on the network. </p> + </note> <p>Default is <c>false</c>.</p> </item> diff --git a/lib/snmp/doc/src/snmp_config.xml b/lib/snmp/doc/src/snmp_config.xml index 8ced577a8a..ea8973f4f8 100644 --- a/lib/snmp/doc/src/snmp_config.xml +++ b/lib/snmp/doc/src/snmp_config.xml @@ -184,10 +184,35 @@ </item> <tag><marker id="agent_mt"></marker> - <c><![CDATA[multi_threaded() = bool() <optional>]]></c></tag> + <c><![CDATA[multi_threaded() = bool() | extended<optional>]]></c></tag> <item> - <p>If <c>true</c>, the agent is multi-threaded, with one - thread for each get request. </p> + <p>If <c>true</c> (or <c>extended</c>), the agent is multi-threaded, + with one thread for each get request. </p> + <p>The value <c>extended</c> means that a special 'process' + is also created intended to handle <em>all</em> notifications. </p> + <list> + <item> + <p><c>true</c> - One worker dedicated to 'set-requests' and one + (main) worker for all other requests ('get-request' and + notifications).</p> + <p>If the 'main' worker is busy, a temporary process is + spawned to handle that job ('get-request' or notification). </p> + </item> + <item> + <p><c>extended</c> - One worker dedicated to 'set-requests', + one worker dedicated to notifications and one + (main) worker for all 'get-requests'. </p> + <p>If the 'main' worker is busy, a temporary process is + spawned to handle that 'get-request'. </p> + </item> + </list> + <note> + <p>Even with multi-threaded set to <c>extended</c> + there is still a risk for 'reorder' when sending inform-requsts, + which require a response (and may therefor require resending). </p> + <p>Also, there is of course no way to guarantee order once the + package is on the network. </p> + </note> <p>Default is <c>false</c>.</p> </item> diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl index cc3bef15af..649a54b844 100644 --- a/lib/snmp/src/agent/snmpa_agent.erl +++ b/lib/snmp/src/agent/snmpa_agent.erl @@ -63,7 +63,7 @@ -export([get_request_limit/1, set_request_limit/2]). -export([invalidate_ca_cache/0]). -export([increment_counter/3]). --export([restart_worker/1, restart_set_worker/1]). +-export([restart_worker/1, restart_set_worker/1, restart_notif_worker/1]). %% For backward compatibillity -export([send_trap/6, send_trap/7]). @@ -71,7 +71,7 @@ %% Internal exports -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3, tr_var/2, tr_varbind/1, - handle_pdu/8, worker/2, worker_loop/1, + handle_pdu/8, worker/4, worker_loop/2, do_send_trap/7, do_send_trap/8]). %% <BACKWARD-COMPAT> -export([handle_pdu/7, @@ -177,6 +177,7 @@ worker, worker_state = ready, set_worker, + notif_worker, multi_threaded, ref, vsns, @@ -249,6 +250,9 @@ restart_worker(Agent) -> restart_set_worker(Agent) -> call(Agent, restart_set_worker). +restart_notif_worker(Agent) -> + call(Agent, restart_notif_worker). + get_log_type(Agent) -> call(Agent, get_log_type). @@ -391,11 +395,12 @@ do_init(Prio, Parent, Ref, Options) -> put(net_if, NetIfPid), put(mibserver, MibPid), process_flag(trap_exit, true), - {Worker, SetWorker} = workers_start(MultiT), + {Worker, SetWorker, NotifWorker} = workers_start(MultiT), {ok, #state{type = Type, parent = Parent, worker = Worker, set_worker = SetWorker, + notif_worker = NotifWorker, multi_threaded = MultiT, ref = Ref, vsns = Vsns, @@ -975,9 +980,13 @@ handle_info({'EXIT', Pid, Reason}, #state{worker = Pid} = S) -> NewWorker = worker_start(), {noreply, S#state{worker = NewWorker}}; handle_info({'EXIT', Pid, Reason}, #state{set_worker = Pid} = S) -> - ?vlog("set-worker (~p) exited -> create new ~n ~p", [Pid,Reason]), + ?vlog("set-worker (~p) exited -> create new ~n ~p", [Pid, Reason]), NewWorker = set_worker_start(), {noreply, S#state{set_worker = NewWorker}}; +handle_info({'EXIT', Pid, Reason}, #state{notif_worker = Pid} = S) -> + ?vlog("notif-worker (~p) exited -> create new ~n ~p", [Pid, Reason]), + NewWorker = notif_worker_start(), + {noreply, S#state{notif_worker = NewWorker}}; handle_info({'EXIT', Pid, Reason}, #state{parent = Pid} = S) -> ?vlog("parent (~p) exited for reason ~n~p", [Pid,Reason]), {stop, {parent_died, Reason}, S}; @@ -1415,13 +1424,17 @@ handle_cast({verbosity, Verbosity}, S) -> ?vlog("verbosity: ~p -> ~p",[get(verbosity), Verbosity]), put(verbosity,snmp_verbosity:validate(Verbosity)), case S#state.worker of - Pid when is_pid(Pid) -> Pid ! ?mk_verbosity_wreq(Verbosity); + Pid1 when is_pid(Pid1) -> Pid1 ! ?mk_verbosity_wreq(Verbosity); _ -> ok end, case S#state.set_worker of Pid2 when is_pid(Pid2) -> Pid2 ! ?mk_verbosity_wreq(Verbosity); _ -> ok end, + case S#state.notif_worker of + Pid3 when is_pid(Pid3) -> Pid3 ! ?mk_verbosity_wreq(Verbosity); + _ -> ok + end, {noreply, S}; handle_cast({sub_agents_verbosity,Verbosity}, S) -> @@ -1447,14 +1460,16 @@ handle_cast(Msg, S) -> {noreply, S}. -terminate(shutdown, #state{worker = Worker, - set_worker = SetWorker, - backup = Backup, +terminate(shutdown, #state{worker = Worker, + set_worker = SetWorker, + notif_worker = NotifWorker, + backup = Backup, ref = Ref}) -> %% Ordered shutdown - stop misc-workers, net_if, mib-server and note-store. backup_server_stop(Backup), worker_stop(Worker, 100), worker_stop(SetWorker, 100), + worker_stop(NotifWorker, 100), snmpa_misc_sup:stop_net_if(Ref), snmpa_misc_sup:stop_mib_server(Ref); terminate(_Reason, _S) -> @@ -1600,20 +1615,26 @@ backup_server_stop(_) -> ok. +workers_start(extended) -> + ?vdebug("start worker, set-worker and notif-worker", []), + {worker_start(), set_worker_start(), notif_worker_start()}; workers_start(true) -> - ?vdebug("start worker and set-worker",[]), - {worker_start(), set_worker_start()}; + ?vdebug("start worker and set-worker", []), + {worker_start(), set_worker_start(), undefined}; workers_start(_) -> - {undefined, undefined}. + {undefined, undefined, undefined}. worker_start() -> - worker_start(get()). + worker_start(mw, true, get()). set_worker_start() -> - worker_start([{master, self()} | get()]). + worker_start(sw, false, [{master, self()} | get()]). + +notif_worker_start() -> + worker_start(nw, false, [{master, self()} | get()]). -worker_start(Dict) -> - proc_lib:spawn_link(?MODULE, worker, [self(), Dict]). +worker_start(SName, Report, Dict) -> + proc_lib:spawn_link(?MODULE, worker, [self(), SName, Report, Dict]). %% worker_stop(Pid) -> %% worker_stop(Pid, infinity). @@ -1783,13 +1804,13 @@ do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, snmpa_trap:send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID, ExtraInfo, get(net_if)). -worker(Master, Dict) -> +worker(Master, SName, Report, Dict) -> lists:foreach(fun({Key, Val}) -> put(Key, Val) end, Dict), - put(sname, worker_short_name(get(sname))), + put(sname, worker_short_name(get(sname), SName)), ?vlog("starting",[]), - worker_loop(Master). + worker_loop(Master, Report). -worker_loop(Master) -> +worker_loop(Master, Report) -> Res = receive #wrequest{cmd = handle_pdu, @@ -1813,7 +1834,7 @@ worker_loop(Master) -> C:E:S -> exit({worker_crash, Req, C, E, S}) end, - Master ! worker_available, + worker_maybe_announce_available(Master, Report), HandlePduRes; % For debugging... @@ -1840,7 +1861,7 @@ worker_loop(Master) -> C:E:S -> exit({worker_crash, Req, C, E, S}) end, - Master ! worker_available, + worker_maybe_announce_available(Master, Report), SendTrapRes; % For debugging... @@ -1853,8 +1874,10 @@ worker_loop(Master) -> #wrequest{cmd = terminate} -> ?vtrace("worker_loop -> received terminate request", []), exit(normal); - - + + + + %% ************************************************************* %% %% Kept for backward compatibillity reasons @@ -1904,7 +1927,12 @@ worker_loop(Master) -> end, ?vtrace("worker_loop -> wrap with" "~n ~p", [Res]), - ?MODULE:worker_loop(Master). + ?MODULE:worker_loop(Master, Report). + +worker_maybe_announce_available(Master, true) -> + Master ! worker_available; +worker_maybe_announce_available(_Master, _Report) -> + ok. %%----------------------------------------------------------------- @@ -2186,6 +2214,13 @@ do_handle_send_trap(S, TrapRec, NotifyName, ContextName, Recv, Varbinds, Recv, Vbs, LocalEngineID, ExtraInfo, get(net_if)), {ok, S}; + master_agent when (S#state.multi_threaded =:= extended) -> + %% Send to main worker + ?vtrace("do_handle_send_trap -> send to notif-worker",[]), + S#state.notif_worker ! ?mk_send_trap_wreq(TrapRec, NotifyName, + ContextName, Recv, Vbs, + LocalEngineID, ExtraInfo), + {ok, S}; master_agent when S#state.worker_state =:= busy -> %% Main worker busy => create new worker ?vtrace("do_handle_send_trap -> main worker busy: " @@ -2195,7 +2230,7 @@ do_handle_send_trap(S, TrapRec, NotifyName, ContextName, Recv, Varbinds, {ok, S}; master_agent -> %% Send to main worker - ?vtrace("do_handle_send_trap -> send to main worker",[]), + ?vtrace("do_handle_send_trap -> send to main worker", []), S#state.worker ! ?mk_send_trap_wreq(TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID, ExtraInfo), @@ -3225,8 +3260,10 @@ mapfoldl(_F, _Eas, Accu, []) -> {Accu,[]}. short_name(none) -> ma; short_name(_Pid) -> sa. -worker_short_name(ma) -> maw; -worker_short_name(_) -> saw. +worker_short_name(ma, mw) -> mamw; +worker_short_name(ma, sw) -> masw; +worker_short_name(ma, nw) -> manw; +worker_short_name(_, _) -> saw. trap_sender_short_name(ma) -> mats; trap_sender_short_name(_) -> sats. @@ -3318,27 +3355,33 @@ handle_set_request_limit(_, _) -> {error, not_supported}. -agent_info(#state{worker = W, set_worker = SW}) -> - case (catch get_agent_info(W, SW)) of +agent_info(#state{worker = W, set_worker = SW, notif_worker = NW}) -> + case (catch get_agent_info(W, SW, NW)) of Info when is_list(Info) -> Info; E -> [{error, E}] end. -get_agent_info(W, SW) -> +get_agent_info(W, SW, NW) -> MASz = proc_mem(self()), - WSz = proc_mem(W), - SWSz = proc_mem(SW), ATSz = tab_mem(snmp_agent_table), CCSz = tab_mem(snmp_community_cache), VacmSz = tab_mem(snmpa_vacm), - [{process_memory, [{master_agent, MASz}, - {worker, WSz}, - {set_worker, SWSz}]}, - {db_memory, [{agent, ATSz}, - {community_cache, CCSz}, - {vacm, VacmSz}]}]. + [{process_memory, + [{master_agent, MASz}] ++ + process_memory(worker, W) ++ + process_memory(set_worker, SW) ++ + process_memory(notif_worker, NW)}, + {db_memory, + [{agent, ATSz}, + {community_cache, CCSz}, + {vacm, VacmSz}]}]. + +process_memory(Tag, P) when is_pid(P) -> + [{Tag, proc_mem(P)}]; +process_memory(_, _) -> + []. proc_mem(P) when is_pid(P) -> case (catch erlang:process_info(P, memory)) of diff --git a/lib/snmp/src/misc/snmp_verbosity.erl b/lib/snmp/src/misc/snmp_verbosity.erl index 9bc3e2762f..0572ebea03 100644 --- a/lib/snmp/src/misc/snmp_verbosity.erl +++ b/lib/snmp/src/misc/snmp_verbosity.erl @@ -100,7 +100,9 @@ image_of_verbosity(_) -> "". %% ShortName image_of_sname(ma) -> "MASTER-AGENT"; -image_of_sname(maw) -> io_lib:format("MASTER-AGENT-worker(~p)",[self()]); +image_of_sname(mamw) -> io_lib:format("MASTER-AGENT-main_worker(~p)",[self()]); +image_of_sname(masw) -> io_lib:format("MASTER-AGENT-set_worker(~p)",[self()]); +image_of_sname(manw) -> io_lib:format("MASTER-AGENT-notif_worker(~p)",[self()]); image_of_sname(madis) -> io_lib:format("MASTER-AGENT-discovery_inform_sender(~p)", [self()]); image_of_sname(mais) -> io_lib:format("MASTER-AGENT-inform_sender(~p)", diff --git a/lib/snmp/test/snmp_agent_SUITE.erl b/lib/snmp/test/snmp_agent_SUITE.erl index 2a6cfbedbe..d433692b0a 100644 --- a/lib/snmp/test/snmp_agent_SUITE.erl +++ b/lib/snmp/test/snmp_agent_SUITE.erl @@ -204,7 +204,7 @@ v3_sha_auth/1, v3_des_priv/1, - %% all_tcs - test_multi_threaded + %% all_tcs - test_multi_threaded, test_multi_threaded_ext multi_threaded/1, mt_trap/1, @@ -319,7 +319,7 @@ db_notify_client_test/0, notify/2, multi_threaded_test/0, - mt_trap_test/1, + mt_trap_test/2, types_v2_test/0, implied_test/1, sparse_table_test/0, @@ -535,6 +535,7 @@ groups() -> {test_v3, [], v3_cases()}, {test_v3_ipv6, [], v3_cases_ipv6()}, {test_multi_threaded, [], mt_cases()}, + {test_multi_threaded_ext, [], mt_cases()}, {multiple_reqs, [], mul_cases()}, {multiple_reqs_2, [], mul_cases_2()}, {multiple_reqs_3, [], mul_cases_3()}, @@ -568,6 +569,7 @@ all_cases() -> {group, test_v1_v2_ipv6}, {group, test_v3_ipv6}, {group, test_multi_threaded}, + {group, test_multi_threaded_ext}, {group, mib_storage}, {group, tickets1} ]. @@ -654,7 +656,9 @@ init_per_group(multiple_reqs_2 = GroupName, Config) -> init_per_group(multiple_reqs_3 = GroupName, Config) -> init_mul(snmp_test_lib:init_group_top_dir(GroupName, Config)); init_per_group(test_multi_threaded = GroupName, Config) -> - init_mt(snmp_test_lib:init_group_top_dir(GroupName, Config)); + init_mt(snmp_test_lib:init_group_top_dir(GroupName, Config), true); +init_per_group(test_multi_threaded_ext = GroupName, Config) -> + init_mt(snmp_test_lib:init_group_top_dir(GroupName, Config), extended); init_per_group(test_v3 = GroupName, Config) -> case snmp_test_lib:crypto_start() of ok -> @@ -764,49 +768,51 @@ end_per_group(v2_inform, Config) -> end_per_group(v3_inform, Config) -> finish_v3_inform(Config); end_per_group(multiple_reqs, Config) -> - finish_mul(Config); + finish_mul(Config); end_per_group(multiple_reqs_2, Config) -> finish_mul(Config); end_per_group(multiple_reqs_3, Config) -> finish_mul(Config); end_per_group(test_multi_threaded, Config) -> - finish_mt(Config); + finish_mt(Config); +end_per_group(test_multi_threaded_ext, Config) -> + finish_mt(Config); end_per_group(test_v3_ipv6, Config) -> - finish_v3(Config); + finish_v3(Config); end_per_group(test_v1_v2_ipv6, Config) -> - finish_v1_v2(Config); + finish_v1_v2(Config); end_per_group(test_v2_ipv6, Config) -> - finish_v2(Config); + finish_v2(Config); end_per_group(test_v1_ipv6, Config) -> - finish_v1(Config); + finish_v1(Config); end_per_group(test_v3, Config) -> - finish_v3(Config); + finish_v3(Config); end_per_group(test_v1_v2, Config) -> - finish_v1_v2(Config); + finish_v1_v2(Config); end_per_group(test_v2, Config) -> - finish_v2(Config); + finish_v2(Config); end_per_group(test_v1, Config) -> - finish_v1(Config); + finish_v1(Config); end_per_group(misc, Config) -> - finish_misc(Config); + finish_misc(Config); end_per_group(mib_storage_varm_mnesia, Config) -> - finish_varm_mib_storage_mnesia(Config); + finish_varm_mib_storage_mnesia(Config); end_per_group(mib_storage_varm_dets, Config) -> - finish_varm_mib_storage_dets(Config); + finish_varm_mib_storage_dets(Config); end_per_group(mib_storage_size_check_mnesia, Config) -> - finish_size_check_msm(Config); + finish_size_check_msm(Config); end_per_group(mib_storage_size_check_dets, Config) -> - finish_size_check_msd(Config); + finish_size_check_msd(Config); end_per_group(mib_storage_size_check_ets, Config) -> - finish_size_check_mse(Config); + finish_size_check_mse(Config); end_per_group(mib_storage_mnesia, Config) -> - finish_mib_storage_mnesia(Config); + finish_mib_storage_mnesia(Config); end_per_group(mib_storage_dets, Config) -> - finish_mib_storage_dets(Config); + finish_mib_storage_dets(Config); end_per_group(mib_storage_ets, Config) -> - finish_mib_storage_ets(Config); + finish_mib_storage_ets(Config); end_per_group(_GroupName, Config) -> - Config. + Config. @@ -1040,8 +1046,8 @@ start_v3_agent(Config, Opts) -> start_bilingual_agent(Config) -> ?ALIB:start_bilingual_agent(Config). -start_multi_threaded_agent(Config) when is_list(Config) -> - ?ALIB:start_mt_agent(Config). +start_multi_threaded_agent(Config, MT) when is_list(Config) -> + [{multi_threaded, MT} | ?ALIB:start_mt_agent(Config, MT)]. stop_agent(Config) -> ?ALIB:stop_agent(Config). @@ -2117,7 +2123,7 @@ mt_cases() -> mt_trap ]. -init_mt(Config) when is_list(Config) -> +init_mt(Config, MT) when is_list(Config) -> SaNode = ?config(snmp_sa, Config), create_tables(SaNode), AgentConfDir = ?config(agent_conf_dir, Config), @@ -2125,7 +2131,7 @@ init_mt(Config) when is_list(Config) -> Ip = ?config(ip, Config), ?line ok = config([v2], MgrDir, AgentConfDir, tuple_to_list(Ip), tuple_to_list(Ip)), - [{vsn, v2} | start_multi_threaded_agent(Config)]. + [{vsn, v2} | start_multi_threaded_agent(Config, MT)]. finish_mt(Config) when is_list(Config) -> delete_tables(), @@ -2290,10 +2296,11 @@ mt_trap(Config) when is_list(Config) -> ?P(mt_trap), init_case(Config), MA = whereis(snmp_master_agent), + MT = ?config(multi_threaded, Config), ?line load_master("Test1"), ?line load_master("TestTrapv2"), - try_test(mt_trap_test, [MA]), + try_test(mt_trap_test, [MA, MT]), ?line unload_master("TestTrapv2"), ?line unload_master("Test1"), ok. @@ -3959,37 +3966,51 @@ multi_threaded_test() -> ?line ?expect1([{[sysLocation,0], "kalle"}]). %% Req. Test1, TestTrapv2 -mt_trap_test(MA) -> - ?NPRINT("Testing trap-sending with multi threaded agent..."), - ?DBG("mt_trap_test(01) -> issue testTrapv22 (standard trap)", []), +mt_trap_test(MA, MT) -> + ?NPRINT("Testing trap-sending with multi threaded (~w) agent...", [MT]), + ?IPRINT("mt_trap_test(01) -> issue testTrapv22 (standard trap)", []), snmpa:send_trap(MA, testTrapv22, "standard trap"), - ?DBG("mt_trap_test(02) -> await v2trap", []), + ?IPRINT("mt_trap_test(02) -> await v2trap", []), ?line ?expect2(v2trap, [{[sysUpTime, 0], any}, {[snmpTrapOID, 0], ?system ++ [0,1]}]), - ?DBG("mt_trap_test(03) -> issue mtTrap (standard trap)", []), + %% multi-threaded = true + %% This will *lock* the 'main thread' of a multi-threaded agent, + %% the worker state will be 'busy'. Therefor when a new request + %% arrives a new *temporary* worker will be spawned. + ?IPRINT("mt_trap_test(03) -> issue mtTrap (standard trap)", []), snmpa:send_trap(MA, mtTrap, "standard trap"), Pid = get_multi_pid(), - ?DBG("mt_trap_test(04) -> multi pid: ~p. Now request sysUpTime...", [Pid]), + ?IPRINT("mt_trap_test(04) -> multi pid: ~p. Now request sysUpTime...", [Pid]), g([[sysUpTime,0]]), - ?DBG("mt_trap_test(06) -> await sysUpTime", []), + ?IPRINT("mt_trap_test(06) -> await sysUpTime", []), ?line ?expect1([{[sysUpTime,0], any}]), - ?DBG("mt_trap_test(07) -> issue testTrapv22 (standard trap)", []), - snmpa:send_trap(MA, testTrapv22, "standard trap"), - ?DBG("mt_trap_test(08) -> await v2trap", []), - ?line ?expect2(v2trap, - [{[sysUpTime, 0], any}, - {[snmpTrapOID, 0], ?system ++ [0,1]}]), - ?DBG("mt_trap_test(09) -> send continue to multi-pid", []), + %% This will *only* work if multi-threaded is 'true', not 'extended' + %% since in the latter case all notifications are serialized through + %% a dedicated worker, which is now locked (see above). + + if + (MT =:= true) -> + ?IPRINT("mt_trap_test(07) -> issue testTrapv22 (standard trap)", []), + snmpa:send_trap(MA, testTrapv22, "standard trap"), + ?IPRINT("mt_trap_test(08) -> await v2trap", []), + ?line ?expect2(v2trap, + [{[sysUpTime, 0], any}, + {[snmpTrapOID, 0], ?system ++ [0,1]}]); + true -> + ok + end, + + ?IPRINT("mt_trap_test(09) -> send continue to multi-pid", []), Pid ! continue, - ?DBG("mt_trap_test(10) -> await v2trap", []), + ?IPRINT("mt_trap_test(10) -> await v2trap", []), ?line ?expect2(v2trap, [{[sysUpTime, 0], any}, {[snmpTrapOID, 0], ?testTrap ++ [2]}, {[multiStr,0], "ok"}]), - ?DBG("mt_trap_test(11) -> done", []), + ?IPRINT("mt_trap_test(11) -> done", []), ok. diff --git a/lib/snmp/test/snmp_agent_test_lib.erl b/lib/snmp/test/snmp_agent_test_lib.erl index 6a4c582f36..b3c492e4ce 100644 --- a/lib/snmp/test/snmp_agent_test_lib.erl +++ b/lib/snmp/test/snmp_agent_test_lib.erl @@ -26,7 +26,7 @@ start_v2_agent/1, start_v2_agent/2, start_v3_agent/1, start_v3_agent/2, start_bilingual_agent/1, start_bilingual_agent/2, - start_mt_agent/1, start_mt_agent/2, + start_mt_agent/1, start_mt_agent/2, start_mt_agent/3, stop_agent/1, %% start_sup/0, stop_sup/2, @@ -560,12 +560,18 @@ start_bilingual_agent(Config, Opts) when is_list(Config) andalso is_list(Opts) -> start_agent(Config, [v1,v2], Opts). -start_mt_agent(Config) when is_list(Config) -> - start_agent(Config, [v2], [{multi_threaded, true}]). - -start_mt_agent(Config, Opts) when is_list(Config) andalso is_list(Opts) -> - start_agent(Config, [v2], [{multi_threaded, true}|Opts]). +start_mt_agent(Config) -> + start_mt_agent(Config, true, []). +start_mt_agent(Config, MT) -> + start_mt_agent(Config, MT, []). + +start_mt_agent(Config, MT, Opts) + when is_list(Config) andalso + ((MT =:= true) orelse (MT =:= extended)) andalso + is_list(Opts) -> + start_agent(Config, [v2], [{multi_threaded, MT} | Opts]). + start_agent(Config, Vsns) -> start_agent(Config, Vsns, []). start_agent(Config, Vsns, Opts) -> |