From daf5b0eeb6f0d8c805f7a0e2fc117c8c788b855c Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Mon, 9 Jan 2012 17:50:47 +0100 Subject: [snmp/agent] Creating a unique temporary file whe dumping vacm Attempting to create a unique temporary file when dumping the vacm table to disk. OTP-9851 --- lib/snmp/src/agent/snmpa_vacm.erl | 43 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) (limited to 'lib/snmp/src/agent') diff --git a/lib/snmp/src/agent/snmpa_vacm.erl b/lib/snmp/src/agent/snmpa_vacm.erl index 892dc265f1..c31b8e61a3 100644 --- a/lib/snmp/src/agent/snmpa_vacm.erl +++ b/lib/snmp/src/agent/snmpa_vacm.erl @@ -266,9 +266,24 @@ dump_table(true) -> dump_table(_) -> ok. + +%% We should really make an effort to serialize the dumping +%% to ensure that several processes that dump at-the-same-time +%% do not trash each others dumps. +%% +%% Send the request to the master agent, which, if there is no +%% dumper already running, spawns a (temporary) dumper process. +%% If there is already a running dumper process, instead increment +%% the dump_request counter. +%% When the dumper process exits, the master agent checks the +%% the dump_request counter, and if that is greated than zero, +%% create another dumper process and resets the counter. +%% In this way the dumping is serializede, but the master-agent +%% process is not burdened by the dumping. +%% dump_table() -> [{_, FName}] = ets:lookup(snmp_agent_table, snmpa_vacm_file), - TmpName = FName ++ ".tmp", + TmpName = unique(FName), case ets:tab2file(snmpa_vacm, TmpName) of ok -> case file:rename(TmpName, FName) of @@ -283,6 +298,32 @@ dump_table() -> [FName, Reason]) end. +%% This little thing is an attempt to create a "unique" filename +%% in order to minimize the risk of two processes at the same +%% time dumping the table. +unique(Pre) -> + {A, B, C} = os:timestamp(), + {D, _} = erlang:statistics(reductions), + {E, _} = erlang:statistics(runtime), + {F, _} = erlang:statistics(wall_clock), + {G, H, _} = erlang:statistics(garbage_collection), + Data = [A, B, C, D, E, F, G, H], + unique(Pre, Data, 0). + +unique(Pre, [], Unique) -> + PidPart = unique_pid(), + lists:flatten(io_lib:format("~s.~s~w.tmp", [Pre, PidPart, Unique])); +unique(Pre, [H|T], Unique) -> + unique(Pre, T, Unique bxor H). + +unique_pid() -> + case string:tokens(pid_to_list(self()), [$<,$.,$>]) of + [A, B, C] -> + A ++ B ++ C ++ "."; + _ -> + "" + end. + %%----------------------------------------------------------------- %% Alg. -- cgit v1.2.3 From 411f6240932aab3721ff842c674d9610216cfd88 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 10 Jan 2012 14:52:00 +0100 Subject: [snmp/agent] Synchronization feature added OTP-9851 --- lib/snmp/src/agent/snmpa_agent.erl | 110 +++++++++++++++++++++++++++++++++++-- lib/snmp/src/agent/snmpa_vacm.erl | 77 +++++++++++++++----------- 2 files changed, 150 insertions(+), 37 deletions(-) (limited to 'lib/snmp/src/agent') diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl index 46c634969d..b78f520c50 100644 --- a/lib/snmp/src/agent/snmpa_agent.erl +++ b/lib/snmp/src/agent/snmpa_agent.erl @@ -69,7 +69,7 @@ -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/7, worker/2, worker_loop/1, - do_send_trap/7, do_send_trap/8]). + do_send_trap/7, do_send_trap/8, serialize/2, serialize/3]). -include("snmpa_internal.hrl"). @@ -271,6 +271,14 @@ update_mibs_cache_age(Agent, Age) -> call(Agent, {mibs_cache_request, {update_age, Age}}). +serialize(Tag, Exec) -> + serialize(snmp_master_agent, Tag, Exec). + +serialize(Agent, Tag, Exec) + when (is_pid(Agent) orelse is_atom(Agent)) andalso is_function(Exec, 0) -> + call(Agent, {serialize, Tag, Exec}). + + increment_counter(Counter, Initial, Max) -> %% This is to make sure no one else increments our counter Key = {Counter, self()}, @@ -934,6 +942,7 @@ handle_info({'EXIT', Pid, Reason}, S) -> end, {noreply, S} end; + handle_info({'DOWN', Ref, process, Pid, {mibs_cache_reply, Reply}}, #state{mibs_cache_request = {Pid, Ref, From}} = S) -> ?vlog("reply from the mibs cache request handler (~p): ~n~p", @@ -941,6 +950,11 @@ handle_info({'DOWN', Ref, process, Pid, {mibs_cache_reply, Reply}}, gen_server:reply(From, Reply), {noreply, S#state{mibs_cache_request = undefined}}; +handle_info({'DOWN', Mon, process, _Pid, {serializer_done, Tag}}, S) -> + ?vlog("handle_info(DOWN) -> serializer done (~w)", [Tag]), + handle_serializer_down(Mon, Tag), + {noreply, S}; + handle_info(Info, S) -> warning_msg("received unexpected info: ~n~p", [Info]), {noreply, S}. @@ -1283,27 +1297,33 @@ handle_call({me_of, Oid}, _From, S) -> {reply, Reply, S}; handle_call(get_log_type, _From, S) -> - ?vlog("get_log_type", []), + ?vlog("handle_call(get_log_type) -> entry with", []), Reply = handle_get_log_type(S), {reply, Reply, S}; handle_call({set_log_type, NewType}, _From, S) -> - ?vlog("set_log_type -> " + ?vlog("handle_call(set_log_type) -> entry with" "~n NewType: ~p", [NewType]), Reply = handle_set_log_type(S, NewType), {reply, Reply, S}; handle_call(get_request_limit, _From, S) -> - ?vlog("get_request_limit", []), + ?vlog("handle_call(get_request_limit) -> entry with", []), Reply = handle_get_request_limit(S), {reply, Reply, S}; handle_call({set_request_limit, NewLimit}, _From, S) -> - ?vlog("set_request_limit -> " + ?vlog("handle_call(set_request_limit) -> entry with" "~n NewLimit: ~p", [NewLimit]), Reply = handle_set_request_limit(S, NewLimit), {reply, Reply, S}; - + +handle_call({serialize, Tag, Exec}, From, S) -> + ?vlog("handle_call(serialize) -> entry with" + "~n Tag: ~p", [Tag]), + handle_serialize(Tag, Exec, From), + {noreply, S}; + handle_call(stop, _From, S) -> {stop, normal, ok, S}; @@ -3859,6 +3879,7 @@ mapfoldl(F, Eas, Accu0, [Hd|Tail]) -> {Accu2,[R|Rs]}; mapfoldl(_F, _Eas, Accu, []) -> {Accu,[]}. + %%----------------------------------------------------------------- %% Runtime debugging of the agent. %%----------------------------------------------------------------- @@ -3983,6 +4004,83 @@ handle_set_request_limit(_, _) -> {error, not_supported}. +%% ------------------------------------------------------------------------ +%% Funtions handling the serialize mechanism +%% ------------------------------------------------------------------------ + +serialize_key(Mon) -> {Mon, serialize}. +storage_key(Tag) -> {Tag, storage}. + +start_serializer(Exec, Tag) -> + Serializer = fun() -> + (catch Exec()), + exit({serializer_done, Tag}) + end, + {_Pid, Mon} = erlang:spawn_opt(Serializer, [monitor]), + Mon. + +handle_serialize(Tag, Exec, From) -> + StorageKey = storage_key(Tag), + case ets:lookup(snmp_agent_table, StorageKey) of + [] -> + %% We are first + ?vtrace("handle_serialize -> nothing found" + "~n (for ~p)", [StorageKey]), + Mon = start_serializer(Exec, Tag), + SerializeKey = serialize_key(Mon), + %% These are waiting for reply + ets:insert(snmp_agent_table, {SerializeKey, [From]}), + %% These are waiting for exec: That is none at the moment + ets:insert(snmp_agent_table, {StorageKey, {Exec, []}}), + ok; + [{_StorageKey, {_Exec, Froms}}] -> + %% There is a process already running, so store the request + ?vtrace("handle_serialize -> found" + "~n (for ~p)" + "~n Forms: ~p", [StorageKey]), + NewStorage = {Exec, [From|Froms]}, + ets:insert(snmp_agent_table, {StorageKey, NewStorage}), + ok + end. + + +deliver_serialize_reply([From]) -> + %% This is the normal case, so we handle it here to optimize + gen_server:reply(From, ok); +deliver_serialize_reply(SerializeReqs) -> + lists:foreach(fun(From) -> gen_server:reply(From, ok) end, + lists:reverse(SerializeReqs)). + +handle_serializer_down(Mon, Tag) -> + SerializeKey = serialize_key(Mon), + [{_, SerializeReqs}] = ets:lookup(snmp_agent_table, SerializeKey), + ?vtrace("handle_serializer_down -> found" + "~n (for ~p)" + "~n ~p", + [SerializeKey, SerializeReqs]), + deliver_serialize_reply(SerializeReqs), + ets:delete(snmp_agent_table, SerializeKey), + StorageKey = storage_key(Tag), + case ets:lookup(snmp_agent_table, StorageKey) of + [{_StorageKey, {_Exec, []}}] -> + %% We are done + ?vtrace("handle_serializer_down -> we are done", []), + ets:delete(snmp_agent_table, StorageKey), + ok; + [{_StorageKey, {Exec, Froms}}] -> + %% We have some waiting, so start a new one + ?vtrace("handle_serializer_down -> waiting requests for ~p: " + "~n ~p", [StorageKey, Froms]), + Mon2 = start_serializer(Exec, Tag), + SerializeKey2 = serialize_key(Mon2), + ets:insert(snmp_agent_table, {SerializeKey2, Froms}), + ets:insert(snmp_agent_table, {StorageKey, {Exec, []}}), + ok + end. + + +%% ------------------------------------------------------------------------ + agent_info(#state{worker = W, set_worker = SW}) -> case (catch get_agent_info(W, SW)) of Info when is_list(Info) -> diff --git a/lib/snmp/src/agent/snmpa_vacm.erl b/lib/snmp/src/agent/snmpa_vacm.erl index c31b8e61a3..efe6378105 100644 --- a/lib/snmp/src/agent/snmpa_vacm.erl +++ b/lib/snmp/src/agent/snmpa_vacm.erl @@ -276,45 +276,60 @@ dump_table(_) -> %% If there is already a running dumper process, instead increment %% the dump_request counter. %% When the dumper process exits, the master agent checks the -%% the dump_request counter, and if that is greated than zero, +%% the dump_request counter, and if that is greater than zero, %% create another dumper process and resets the counter. -%% In this way the dumping is serializede, but the master-agent -%% process is not burdened by the dumping. +%% In this way the dumping is serialized, but the master-agent +%% process is not burdend by the dumping. %% dump_table() -> - [{_, FName}] = ets:lookup(snmp_agent_table, snmpa_vacm_file), - TmpName = unique(FName), - case ets:tab2file(snmpa_vacm, TmpName) of - ok -> - case file:rename(TmpName, FName) of - ok -> - ok; - Else -> % What is this? Undocumented return code... - user_err("Warning: could not move VACM db ~p" - " (~p)", [FName, Else]) - end; - {error, Reason} -> - user_err("Warning: could not save vacm db ~p (~p)", - [FName, Reason]) - end. + %% The dumper fun is executed in a specially started process, + %% that does that one thing and then exits. + %% Also, to prevent the system to run "wild" (keep calling + %% dump function before they are done), the agents serialize + %% function return when that dump is done! + Dumper = + fun() -> + [{_, FName}] = ets:lookup(snmp_agent_table, snmpa_vacm_file), + %% TmpName = FName ++ ".tmp", + TmpName = unique_name(FName), + case ets:tab2file(snmpa_vacm, TmpName) of + ok -> + case file:rename(TmpName, FName) of + ok -> + ok; + Else -> % What is this? Undocumented return code... + user_err("Warning: could not move VACM db ~p" + " (~p)", [FName, Else]) + end; + {error, Reason} -> + user_err("Warning: could not save vacm db ~p (~p)", + [FName, Reason]) + end + end, + snmpa_agent:serialize(snmpa_vacm_dump_request, Dumper). + %% This little thing is an attempt to create a "unique" filename %% in order to minimize the risk of two processes at the same %% time dumping the table. -unique(Pre) -> - {A, B, C} = os:timestamp(), - {D, _} = erlang:statistics(reductions), - {E, _} = erlang:statistics(runtime), - {F, _} = erlang:statistics(wall_clock), - {G, H, _} = erlang:statistics(garbage_collection), - Data = [A, B, C, D, E, F, G, H], - unique(Pre, Data, 0). - -unique(Pre, [], Unique) -> +%% The serialization handled by the agent does this much better, +%% but this also gives us a "timestamp" which could be usefull for +%% debugging reasons. +unique_name(Pre) -> + unique_name(Pre, os:timestamp()). + +unique_name(Pre, {_A, _B, C} = Timestamp) -> + {Date, Time} = calendar:now_to_datetime(Timestamp), + {YYYY, MM, DD} = Date, + {Hour, Min, Sec} = Time, + FormatDate = + io_lib:format("~.4w~.2.0w~.2.0w_~.2.0w~.2.0w~.2.0w_~w", + [YYYY, MM, DD, Hour, Min, Sec, round(C/1000)]), + unique_name2(Pre, FormatDate). + +unique_name2(Pre, FormatedDate) -> PidPart = unique_pid(), - lists:flatten(io_lib:format("~s.~s~w.tmp", [Pre, PidPart, Unique])); -unique(Pre, [H|T], Unique) -> - unique(Pre, T, Unique bxor H). + lists:flatten(io_lib:format("~s.~s~s.tmp", [Pre, PidPart, FormatedDate])). unique_pid() -> case string:tokens(pid_to_list(self()), [$<,$.,$>]) of -- cgit v1.2.3 From c2de50f0acc5f30579d0ca0a03cbaf42847dfa9e Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 11 Jan 2012 17:56:29 +0100 Subject: [snmp/agent] Use unique temporary file name during vacm table dumnping Removed the use synchronization mechanism during vacm table dumping. This could not be placed in the master agent since it was sometimes used from the master agent. Also is was credated and used from the top agent supervisor, befor the master agent process was created... OTP-9851 --- lib/snmp/src/agent/snmp_view_based_acm_mib.erl | 29 ++++------ lib/snmp/src/agent/snmpa_agent.erl | 4 +- lib/snmp/src/agent/snmpa_vacm.erl | 80 +++++++++----------------- 3 files changed, 41 insertions(+), 72 deletions(-) (limited to 'lib/snmp/src/agent') diff --git a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl index 37f6dd3f26..2cee91b081 100644 --- a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl +++ b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2011. All Rights Reserved. +%% Copyright Ericsson AB 1999-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -203,18 +203,16 @@ init_sec2group_table([Row | T]) -> init_sec2group_table(T); init_sec2group_table([]) -> true. -init_access_table([{GN, Prefix, Model, Level, Row} | T]) -> -%% ?vtrace("init access table: " -%% "~n GN: ~p" -%% "~n Prefix: ~p" -%% "~n Model: ~p" -%% "~n Level: ~p" -%% "~n Row: ~p",[GN, Prefix, Model, Level, Row]), - Key = [length(GN) | GN] ++ [length(Prefix) | Prefix] ++ [Model, Level], - snmpa_vacm:insert([{Key, Row}], false), - init_access_table(T); -init_access_table([]) -> - snmpa_vacm:dump_table(). +make_access_key(GN, Prefix, Model, Level) -> + [length(GN) | GN] ++ [length(Prefix) | Prefix] ++ [Model, Level]. + +make_access_entry({GN, Prefix, Model, Level, Row}) -> + Key = make_access_key(GN, Prefix, Model, Level), + {Key, Row}. + +init_access_table(TableData) -> + TableData2 = [make_access_entry(E) || E <- TableData], + snmpa_vacm:insert(TableData2, true). init_view_table([Row | T]) -> %% ?vtrace("init view table: " @@ -276,10 +274,7 @@ add_access(GroupName, Prefix, SecModel, SecLevel, Match, RV, WV, NV) -> Match, RV, WV, NV}, case (catch check_vacm(Access)) of {ok, {vacmAccess, {GN, Pref, SM, SL, Row}}} -> - Key1 = [length(GN) | GN], - Key2 = [length(Pref) | Pref], - Key3 = [SM, SL], - Key = Key1 ++ Key2 ++ Key3, + Key = make_access_key(GN, Pref, SM, SL), snmpa_vacm:insert([{Key, Row}], false), snmpa_agent:invalidate_ca_cache(), {ok, Key}; diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl index b78f520c50..5db3eab012 100644 --- a/lib/snmp/src/agent/snmpa_agent.erl +++ b/lib/snmp/src/agent/snmpa_agent.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -4081,7 +4081,7 @@ handle_serializer_down(Mon, Tag) -> %% ------------------------------------------------------------------------ -agent_info(#state{worker = W, set_worker = SW}) -> +agent_info(#state{worker = W, set_worker = SW}) -> case (catch get_agent_info(W, SW)) of Info when is_list(Info) -> Info; diff --git a/lib/snmp/src/agent/snmpa_vacm.erl b/lib/snmp/src/agent/snmpa_vacm.erl index efe6378105..2cbc11d280 100644 --- a/lib/snmp/src/agent/snmpa_vacm.erl +++ b/lib/snmp/src/agent/snmpa_vacm.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2010. All Rights Reserved. +%% Copyright Ericsson AB 1999-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -267,71 +267,45 @@ dump_table(_) -> ok. -%% We should really make an effort to serialize the dumping -%% to ensure that several processes that dump at-the-same-time -%% do not trash each others dumps. -%% -%% Send the request to the master agent, which, if there is no -%% dumper already running, spawns a (temporary) dumper process. -%% If there is already a running dumper process, instead increment -%% the dump_request counter. -%% When the dumper process exits, the master agent checks the -%% the dump_request counter, and if that is greater than zero, -%% create another dumper process and resets the counter. -%% In this way the dumping is serialized, but the master-agent -%% process is not burdend by the dumping. -%% dump_table() -> - %% The dumper fun is executed in a specially started process, - %% that does that one thing and then exits. - %% Also, to prevent the system to run "wild" (keep calling - %% dump function before they are done), the agents serialize - %% function return when that dump is done! - Dumper = - fun() -> - [{_, FName}] = ets:lookup(snmp_agent_table, snmpa_vacm_file), - %% TmpName = FName ++ ".tmp", - TmpName = unique_name(FName), - case ets:tab2file(snmpa_vacm, TmpName) of - ok -> - case file:rename(TmpName, FName) of - ok -> - ok; - Else -> % What is this? Undocumented return code... - user_err("Warning: could not move VACM db ~p" - " (~p)", [FName, Else]) - end; - {error, Reason} -> - user_err("Warning: could not save vacm db ~p (~p)", - [FName, Reason]) - end - end, - snmpa_agent:serialize(snmpa_vacm_dump_request, Dumper). - + [{_, FName}] = ets:lookup(snmp_agent_table, snmpa_vacm_file), + TmpName = unique_table_name(FName), + case ets:tab2file(snmpa_vacm, TmpName) of + ok -> + case file:rename(TmpName, FName) of + ok -> + ok; + Else -> % What is this? Undocumented return code... + user_err("Warning: could not move VACM db ~p" + " (~p)", [FName, Else]) + end; + {error, Reason} -> + user_err("Warning: could not save vacm db ~p (~p)", + [FName, Reason]) + end. %% This little thing is an attempt to create a "unique" filename %% in order to minimize the risk of two processes at the same %% time dumping the table. -%% The serialization handled by the agent does this much better, -%% but this also gives us a "timestamp" which could be usefull for -%% debugging reasons. -unique_name(Pre) -> - unique_name(Pre, os:timestamp()). - -unique_name(Pre, {_A, _B, C} = Timestamp) -> - {Date, Time} = calendar:now_to_datetime(Timestamp), +unique_table_name(Pre) -> + %% We want something that is guaranteed to be unique, + %% therefor we use erlang:now() instead of os:timestamp() + unique_table_name(Pre, erlang:now()). + +unique_table_name(Pre, {_A, _B, C} = Now) -> + {Date, Time} = calendar:now_to_datetime(Now), {YYYY, MM, DD} = Date, {Hour, Min, Sec} = Time, FormatDate = io_lib:format("~.4w~.2.0w~.2.0w_~.2.0w~.2.0w~.2.0w_~w", [YYYY, MM, DD, Hour, Min, Sec, round(C/1000)]), - unique_name2(Pre, FormatDate). + unique_table_name2(Pre, FormatDate). -unique_name2(Pre, FormatedDate) -> - PidPart = unique_pid(), +unique_table_name2(Pre, FormatedDate) -> + PidPart = unique_table_name_pid(), lists:flatten(io_lib:format("~s.~s~s.tmp", [Pre, PidPart, FormatedDate])). -unique_pid() -> +unique_table_name_pid() -> case string:tokens(pid_to_list(self()), [$<,$.,$>]) of [A, B, C] -> A ++ B ++ C ++ "."; -- cgit v1.2.3 From 9f0191d456ae36a887ba08e689670aa78d3de20d Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 12 Jan 2012 12:04:08 +0100 Subject: [snmp/agent] Removed the (unused) serializer part OTP-9851 --- lib/snmp/src/agent/snmpa_agent.erl | 98 +------------------------------------- 1 file changed, 1 insertion(+), 97 deletions(-) (limited to 'lib/snmp/src/agent') diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl index 5db3eab012..d3eeca2290 100644 --- a/lib/snmp/src/agent/snmpa_agent.erl +++ b/lib/snmp/src/agent/snmpa_agent.erl @@ -69,7 +69,7 @@ -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/7, worker/2, worker_loop/1, - do_send_trap/7, do_send_trap/8, serialize/2, serialize/3]). + do_send_trap/7, do_send_trap/8]). -include("snmpa_internal.hrl"). @@ -271,14 +271,6 @@ update_mibs_cache_age(Agent, Age) -> call(Agent, {mibs_cache_request, {update_age, Age}}). -serialize(Tag, Exec) -> - serialize(snmp_master_agent, Tag, Exec). - -serialize(Agent, Tag, Exec) - when (is_pid(Agent) orelse is_atom(Agent)) andalso is_function(Exec, 0) -> - call(Agent, {serialize, Tag, Exec}). - - increment_counter(Counter, Initial, Max) -> %% This is to make sure no one else increments our counter Key = {Counter, self()}, @@ -950,11 +942,6 @@ handle_info({'DOWN', Ref, process, Pid, {mibs_cache_reply, Reply}}, gen_server:reply(From, Reply), {noreply, S#state{mibs_cache_request = undefined}}; -handle_info({'DOWN', Mon, process, _Pid, {serializer_done, Tag}}, S) -> - ?vlog("handle_info(DOWN) -> serializer done (~w)", [Tag]), - handle_serializer_down(Mon, Tag), - {noreply, S}; - handle_info(Info, S) -> warning_msg("received unexpected info: ~n~p", [Info]), {noreply, S}. @@ -1318,12 +1305,6 @@ handle_call({set_request_limit, NewLimit}, _From, S) -> Reply = handle_set_request_limit(S, NewLimit), {reply, Reply, S}; -handle_call({serialize, Tag, Exec}, From, S) -> - ?vlog("handle_call(serialize) -> entry with" - "~n Tag: ~p", [Tag]), - handle_serialize(Tag, Exec, From), - {noreply, S}; - handle_call(stop, _From, S) -> {stop, normal, ok, S}; @@ -4004,83 +3985,6 @@ handle_set_request_limit(_, _) -> {error, not_supported}. -%% ------------------------------------------------------------------------ -%% Funtions handling the serialize mechanism -%% ------------------------------------------------------------------------ - -serialize_key(Mon) -> {Mon, serialize}. -storage_key(Tag) -> {Tag, storage}. - -start_serializer(Exec, Tag) -> - Serializer = fun() -> - (catch Exec()), - exit({serializer_done, Tag}) - end, - {_Pid, Mon} = erlang:spawn_opt(Serializer, [monitor]), - Mon. - -handle_serialize(Tag, Exec, From) -> - StorageKey = storage_key(Tag), - case ets:lookup(snmp_agent_table, StorageKey) of - [] -> - %% We are first - ?vtrace("handle_serialize -> nothing found" - "~n (for ~p)", [StorageKey]), - Mon = start_serializer(Exec, Tag), - SerializeKey = serialize_key(Mon), - %% These are waiting for reply - ets:insert(snmp_agent_table, {SerializeKey, [From]}), - %% These are waiting for exec: That is none at the moment - ets:insert(snmp_agent_table, {StorageKey, {Exec, []}}), - ok; - [{_StorageKey, {_Exec, Froms}}] -> - %% There is a process already running, so store the request - ?vtrace("handle_serialize -> found" - "~n (for ~p)" - "~n Forms: ~p", [StorageKey]), - NewStorage = {Exec, [From|Froms]}, - ets:insert(snmp_agent_table, {StorageKey, NewStorage}), - ok - end. - - -deliver_serialize_reply([From]) -> - %% This is the normal case, so we handle it here to optimize - gen_server:reply(From, ok); -deliver_serialize_reply(SerializeReqs) -> - lists:foreach(fun(From) -> gen_server:reply(From, ok) end, - lists:reverse(SerializeReqs)). - -handle_serializer_down(Mon, Tag) -> - SerializeKey = serialize_key(Mon), - [{_, SerializeReqs}] = ets:lookup(snmp_agent_table, SerializeKey), - ?vtrace("handle_serializer_down -> found" - "~n (for ~p)" - "~n ~p", - [SerializeKey, SerializeReqs]), - deliver_serialize_reply(SerializeReqs), - ets:delete(snmp_agent_table, SerializeKey), - StorageKey = storage_key(Tag), - case ets:lookup(snmp_agent_table, StorageKey) of - [{_StorageKey, {_Exec, []}}] -> - %% We are done - ?vtrace("handle_serializer_down -> we are done", []), - ets:delete(snmp_agent_table, StorageKey), - ok; - [{_StorageKey, {Exec, Froms}}] -> - %% We have some waiting, so start a new one - ?vtrace("handle_serializer_down -> waiting requests for ~p: " - "~n ~p", [StorageKey, Froms]), - Mon2 = start_serializer(Exec, Tag), - SerializeKey2 = serialize_key(Mon2), - ets:insert(snmp_agent_table, {SerializeKey2, Froms}), - ets:insert(snmp_agent_table, {StorageKey, {Exec, []}}), - ok - end. - - -%% ------------------------------------------------------------------------ - agent_info(#state{worker = W, set_worker = SW}) -> case (catch get_agent_info(W, SW)) of Info when is_list(Info) -> -- cgit v1.2.3