diff options
author | Micael Karlberg <[email protected]> | 2010-06-07 12:00:00 +0200 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2010-08-20 08:57:11 +0200 |
commit | 61b1feed86ccf574613b913c5eea57d138eeb178 (patch) | |
tree | f4e25826fff8e222c95741ff401c5a112a912456 /lib/megaco/src | |
parent | 6769f83da0f193052a30ff8933a014e9cf3b0cdf (diff) | |
download | otp-61b1feed86ccf574613b913c5eea57d138eeb178.tar.gz otp-61b1feed86ccf574613b913c5eea57d138eeb178.tar.bz2 otp-61b1feed86ccf574613b913c5eea57d138eeb178.zip |
megaco: Patch 1123
OTP-8561 A minor compiler related performance improvement.
OTP-8529 A raise condition when, during high load, processing both
the original and a resent message and delivering this as
two separate messages to the user. Note that this solution
only protects against multiple reply deliveries!
OTP-8627 Fix shared libraries installation. The flex shared lib(s)
were incorrectly installed as data files.
OTP-8634 Eliminated a possible raise condition while creating pending
counters.
Diffstat (limited to 'lib/megaco/src')
-rw-r--r-- | lib/megaco/src/app/megaco.appup.src | 23 | ||||
-rw-r--r-- | lib/megaco/src/app/megaco_internal.hrl | 26 | ||||
-rw-r--r-- | lib/megaco/src/engine/megaco_config.erl | 427 | ||||
-rw-r--r-- | lib/megaco/src/engine/megaco_messenger.erl | 239 | ||||
-rw-r--r-- | lib/megaco/src/engine/megaco_monitor.erl | 33 | ||||
-rw-r--r-- | lib/megaco/src/flex/Makefile.in | 2 |
6 files changed, 494 insertions, 256 deletions
diff --git a/lib/megaco/src/app/megaco.appup.src b/lib/megaco/src/app/megaco.appup.src index 4f781478ef..f939f5e6cf 100644 --- a/lib/megaco/src/app/megaco.appup.src +++ b/lib/megaco/src/app/megaco.appup.src @@ -124,14 +124,25 @@ %% | %% v %% 3.14 +%% | +%% v +%% 3.14.1 %% %% {"%VSN%", [ + {"3.14", + [ + {load_module, megaco_messenger, soft_purge, soft_purge, [megaco_monitor]}, + {update, megaco_monitor, soft, soft_purge, soft_purge, []}, + {update, megaco_config, soft, soft_purge, soft_purge, []} + ] + }, {"3.13", [ - {load_module, megaco_messenger, soft_purge, soft_purge, []}, + {load_module, megaco_messenger, soft_purge, soft_purge, [megaco_monitor]}, {load_module, megaco_filter, soft_purge, soft_purge, []}, + {update, megaco_monitor, soft, soft_purge, soft_purge, []}, {update, megaco_config, soft, soft_purge, soft_purge, []}, {update, megaco_flex_scanner_handler, {advanced, downgrade_to_pre_3_13_1}, soft_purge, soft_purge, []} @@ -163,10 +174,18 @@ } ], [ + {"3.14", + [ + {load_module, megaco_messenger, soft_purge, soft_purge, [megaco_monitor]}, + {update, megaco_monitor, soft, soft_purge, soft_purge, []}, + {update, megaco_config, soft, soft_purge, soft_purge, []} + ] + }, {"3.13", [ - {load_module, megaco_messenger, soft_purge, soft_purge, []}, + {load_module, megaco_messenger, soft_purge, soft_purge, [megaco_monitor]}, {load_module, megaco_filter, soft_purge, soft_purge, []}, + {update, megaco_monitor, soft, soft_purge, soft_purge, []}, {update, megaco_config, soft, soft_purge, soft_purge, []}, {update, megaco_flex_scanner_handler, {advanced, upgrade_from_pre_3_13_1}, soft_purge, soft_purge, []} diff --git a/lib/megaco/src/app/megaco_internal.hrl b/lib/megaco/src/app/megaco_internal.hrl index adbaacacef..2c124e9060 100644 --- a/lib/megaco/src/app/megaco_internal.hrl +++ b/lib/megaco/src/app/megaco_internal.hrl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1999-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1999-2010. 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 %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -139,6 +139,22 @@ [?APPLICATION, ?MODULE, self()|A]))). +-define(megaco_ereport(Label, Report), + ?megaco_report(error_report, Label, Report)). + +-define(megaco_wreport(Label, Report), + ?megaco_report(warning_report, Label, Report)). + +-define(megaco_ireport(Label, Report), + ?megaco_report(info_report, Label, Report)). + +-define(megaco_report(Func, Label, Report), + (catch error_logger:Func([{label, Label}, + {application, ?APPLICATION}, + {module, ?MODULE}, + {process, self()} | Report]))). + + %%%---------------------------------------------------------------------- %%% Default (ignore) value of the Extra argument to the %%% megaco:receive_message/5 and process_received_message functions/5. diff --git a/lib/megaco/src/engine/megaco_config.erl b/lib/megaco/src/engine/megaco_config.erl index 1c7a141be7..6805db790d 100644 --- a/lib/megaco/src/engine/megaco_config.erl +++ b/lib/megaco/src/engine/megaco_config.erl @@ -224,149 +224,278 @@ update_user_info(UserMid, orig_pending_limit, Val) -> update_user_info(UserMid, Item, Val) -> call({update_user_info, UserMid, Item, Val}). -conn_info(CH, Item) - when is_record(CH, megaco_conn_handle) andalso (Item /= cancel) -> - case Item of - conn_handle -> - CH; - mid -> - CH#megaco_conn_handle.local_mid; - local_mid -> - CH#megaco_conn_handle.local_mid; - remote_mid -> - CH#megaco_conn_handle.remote_mid; - conn_data -> - case lookup_local_conn(CH) of - [] -> - exit({no_such_connection, CH}); - [ConnData] -> - ConnData - end; - _ -> - case lookup_local_conn(CH) of - [] -> - exit({no_such_connection, CH}); - [ConnData] -> - conn_info(ConnData, Item) - end + +conn_info(Data, Item) -> + %% The purpose of this is a compiler optimization... + %% Args are processed from left to right. + do_conn_info(Item, Data). + +do_conn_info(mid = _Item, #megaco_conn_handle{local_mid = Mid}) -> + Mid; +do_conn_info(local_mid = _Item, #megaco_conn_handle{local_mid = LMid}) -> + LMid; +do_conn_info(remote_mid = _Item, #megaco_conn_handle{remote_mid = RMid}) -> + RMid; +do_conn_info(conn_handle = _Item, CH) when is_record(CH, megaco_conn_handle) -> + CH; +do_conn_info(conn_data = _Item, CH) when is_record(CH, megaco_conn_handle) -> + case lookup_local_conn(CH) of + [] -> + exit({no_such_connection, CH}); + [ConnData] -> + ConnData + end; +do_conn_info(Item, CH) when is_record(CH, megaco_conn_handle) -> + case lookup_local_conn(CH) of + [] -> + exit({no_such_connection, CH}); + [ConnData] -> + do_conn_info(Item, ConnData) end; -conn_info(#conn_data{conn_handle = CH}, cancel) -> + +do_conn_info(cancel = _Item, #conn_data{conn_handle = CH}) -> + %% To minimise raise-condition propabillity, + %% we always look in the table instead of + %% in the record for this one + ets:lookup_element(megaco_local_conn, CH, #conn_data.cancel); +do_conn_info(cancel = _Item, CH) when is_record(CH, megaco_conn_handle) -> %% To minimise raise-condition propabillity, %% we always look in the table instead of %% in the record for this one ets:lookup_element(megaco_local_conn, CH, #conn_data.cancel); -conn_info(CD, Item) when is_record(CD, conn_data) -> - case Item of - all -> - Tags0 = record_info(fields, conn_data), - Tags1 = replace(serial, trans_id, Tags0), - Tags = [mid, local_mid, remote_mid] ++ - replace(max_serial, max_trans_id, Tags1), - [{Tag, conn_info(CD,Tag)} || Tag <- Tags, - Tag /= conn_data, - Tag /= trans_sender, - Tag /= cancel]; - conn_data -> CD; - conn_handle -> CD#conn_data.conn_handle; - mid -> (CD#conn_data.conn_handle)#megaco_conn_handle.local_mid; - local_mid -> (CD#conn_data.conn_handle)#megaco_conn_handle.local_mid; - remote_mid -> (CD#conn_data.conn_handle)#megaco_conn_handle.remote_mid; - trans_id -> CH = CD#conn_data.conn_handle, - LocalMid = CH#megaco_conn_handle.local_mid, - Item2 = {LocalMid, trans_id_counter}, - case (catch ets:lookup(megaco_config, Item2)) of - {'EXIT', _} -> - undefined_serial; - [] -> - user_info(LocalMid, min_trans_id); - [{_, Serial}] -> - Max = CD#conn_data.max_serial, - if - ((Max =:= infinity) andalso - is_integer(Serial) andalso - (Serial < 4294967295)) -> - Serial + 1; - (Max =:= infinity) andalso - is_integer(Serial) andalso - (Serial =:= 4294967295) -> - user_info(LocalMid, - min_trans_id); - Serial < Max -> - Serial + 1; - Serial =:= Max -> - user_info(LocalMid, - min_trans_id); - Serial =:= 4294967295 -> - user_info(LocalMid, - min_trans_id); - true -> - undefined_serial - end - end; - max_trans_id -> CD#conn_data.max_serial; - request_timer -> CD#conn_data.request_timer; - long_request_timer -> CD#conn_data.long_request_timer; - - auto_ack -> CD#conn_data.auto_ack; - - trans_ack -> CD#conn_data.trans_ack; - trans_ack_maxcount -> CD#conn_data.trans_ack_maxcount; - - trans_req -> CD#conn_data.trans_req; - trans_req_maxcount -> CD#conn_data.trans_req_maxcount; - trans_req_maxsize -> CD#conn_data.trans_req_maxsize; - - trans_timer -> CD#conn_data.trans_timer; - - pending_timer -> CD#conn_data.pending_timer; - orig_pending_limit -> CD#conn_data.sent_pending_limit; - sent_pending_limit -> CD#conn_data.sent_pending_limit; - recv_pending_limit -> CD#conn_data.recv_pending_limit; - reply_timer -> CD#conn_data.reply_timer; - control_pid -> CD#conn_data.control_pid; - monitor_ref -> CD#conn_data.monitor_ref; - send_mod -> CD#conn_data.send_mod; - send_handle -> CD#conn_data.send_handle; - encoding_mod -> CD#conn_data.encoding_mod; - encoding_config -> CD#conn_data.encoding_config; - protocol_version -> CD#conn_data.protocol_version; - auth_data -> CD#conn_data.auth_data; - user_mod -> CD#conn_data.user_mod; - user_args -> CD#conn_data.user_args; - reply_action -> CD#conn_data.reply_action; - reply_data -> CD#conn_data.reply_data; - threaded -> CD#conn_data.threaded; - strict_version -> CD#conn_data.strict_version; - long_request_resend -> CD#conn_data.long_request_resend; - call_proxy_gc_timeout -> CD#conn_data.call_proxy_gc_timeout; - cancel -> CD#conn_data.cancel; - resend_indication -> CD#conn_data.resend_indication; - segment_reply_ind -> CD#conn_data.segment_reply_ind; - segment_recv_acc -> CD#conn_data.segment_recv_acc; - segment_recv_timer -> CD#conn_data.segment_recv_timer; - segment_send -> CD#conn_data.segment_send; - segment_send_timer -> CD#conn_data.segment_send_timer; - max_pdu_size -> CD#conn_data.max_pdu_size; - request_keep_alive_timeout -> CD#conn_data.request_keep_alive_timeout; - receive_handle -> - LocalMid = (CD#conn_data.conn_handle)#megaco_conn_handle.local_mid, - #megaco_receive_handle{local_mid = LocalMid, - encoding_mod = CD#conn_data.encoding_mod, - encoding_config = CD#conn_data.encoding_config, - send_mod = CD#conn_data.send_mod}; - _ -> - exit({no_such_item, Item}) +do_conn_info(all = _Item, + #conn_data{conn_handle = CH, + serial = TransId, + max_serial = MaxTransId, + request_timer = ReqTmr, + long_request_timer = LongReqTmr, + auto_ack = AutoAck, + trans_ack = TransAck, + trans_ack_maxcount = TransAckMaxCount, + trans_req = TransReq, + trans_req_maxcount = TransReqMaxCount, + trans_req_maxsize = TransReqMaxSz, + trans_timer = TransTmr, + %% trans_sender, + pending_timer = PendingTmr, + sent_pending_limit = SentPendingLimit, + recv_pending_limit = RecvPendingLimit, + reply_timer = ReplyTmr, + control_pid = CtrlPid, + monitor_ref = MonRef, + send_mod = SendMod, + send_handle = SendHandle, + encoding_mod = EncodingMod, + encoding_config = EncodingConf, + protocol_version = ProtoVersion, + auth_data = AuthData, + user_mod = UserMod, + user_args = UserArgs, + reply_action = ReplyAction, + reply_data = ReplyData, + threaded = Threaded, + strict_version = StrictVersion, + long_request_resend = LongReqResend, + call_proxy_gc_timeout = CallProxyGCTimeout, + %% cancel, + resend_indication = ResendInd, + segment_reply_ind = SegReplyInd, + segment_recv_acc = SegRecvAcc, + segment_recv_timer = SegRecvTmr, + segment_send = SegSend, + segment_send_timer = SegSendTmr, + max_pdu_size = MaxPduSz, + request_keep_alive_timeout = RequestKeepAliveTmr}) -> + [{conn_handle, CH}, + {trans_id, TransId}, + {max_trans_id, MaxTransId}, + {request_timer, ReqTmr}, + {long_request_timer, LongReqTmr}, + {mid, CH#megaco_conn_handle.local_mid}, + {local_mid, CH#megaco_conn_handle.local_mid}, + {remote_mid, CH#megaco_conn_handle.remote_mid}, + {auto_ack, AutoAck}, + {trans_ack, TransAck}, + {trans_ack_maxcount, TransAckMaxCount}, + {trans_req, TransReq}, + {trans_req_maxcount, TransReqMaxCount}, + {trans_req_maxsize, TransReqMaxSz}, + {trans_timer, TransTmr}, + {pending_timer, PendingTmr}, + {sent_pending_limit, SentPendingLimit}, + {recv_pending_limit, RecvPendingLimit}, + {reply_timer, ReplyTmr}, + {control_pid, CtrlPid}, + {monitor_ref, MonRef}, + {send_mod, SendMod}, + {send_handle, SendHandle}, + {encoding_mod, EncodingMod}, + {encoding_config, EncodingConf}, + {protocol_version, ProtoVersion}, + {auth_data, AuthData}, + {user_mod, UserMod}, + {user_args, UserArgs}, + {reply_action, ReplyAction}, + {reply_data, ReplyData}, + {threaded, Threaded}, + {strict_version, StrictVersion}, + {long_request_resend, LongReqResend}, + {call_proxy_gc_timeout, CallProxyGCTimeout}, + {resend_indication, ResendInd}, + {segment_reply_ind, SegReplyInd}, + {segment_recv_acc, SegRecvAcc}, + {segment_recv_timer, SegRecvTmr}, + {segment_send, SegSend}, + {segment_send_timer, SegSendTmr}, + {max_pdu_size, MaxPduSz}, + {request_keep_alive_timeout, RequestKeepAliveTmr}]; + +do_conn_info(conn_data = _Item, CD) -> + CD; +do_conn_info(conn_handle = _Item, #conn_data{conn_handle = Val}) -> + Val; +do_conn_info(mid = _Item, + #conn_data{conn_handle = #megaco_conn_handle{local_mid = Val}}) -> + Val; +do_conn_info(local_mid = _Item, + #conn_data{conn_handle = #megaco_conn_handle{local_mid = Val}}) -> + Val; +do_conn_info(remote_mid = _Item, + #conn_data{conn_handle = #megaco_conn_handle{remote_mid = Val}}) -> + Val; +do_conn_info(trans_id = _Item, + #conn_data{conn_handle = #megaco_conn_handle{local_mid = LMid}, + max_serial = Max}) -> + Item2 = {LMid, trans_id_counter}, + case (catch ets:lookup(megaco_config, Item2)) of + {'EXIT', _} -> + undefined_serial; + [] -> + user_info(LMid, min_trans_id); + [{_, Serial}] -> + if + ((Max =:= infinity) andalso + is_integer(Serial) andalso + (Serial < 4294967295)) -> + Serial + 1; + ((Max =:= infinity) andalso + is_integer(Serial) andalso + (Serial =:= 4294967295)) -> + user_info(LMid, min_trans_id); + Serial < Max -> + Serial + 1; + Serial =:= Max -> + user_info(LMid, min_trans_id); + Serial =:= 4294967295 -> + user_info(LMid, min_trans_id); + true -> + undefined_serial + end end; -conn_info(BadHandle, _Item) -> - {error, {no_such_connection, BadHandle}}. - -replace(_, _, []) -> - []; -replace(Item, WithItem, [Item|List]) -> - [WithItem|List]; -replace(Item, WithItem, [OtherItem|List]) -> - [OtherItem | replace(Item, WithItem, List)]. +do_conn_info(max_trans_id = _Item, #conn_data{max_serial = Val}) -> + Val; +do_conn_info(request_timer = _Item, #conn_data{request_timer = Val}) -> + Val; +do_conn_info(long_request_timer = _Item, #conn_data{long_request_timer = Val}) -> + Val; +do_conn_info(auto_ack = _Item, #conn_data{auto_ack = Val}) -> + Val; +do_conn_info(trans_ack = _Item, #conn_data{trans_ack = Val}) -> + Val; +do_conn_info(trans_ack_maxcount = _Item, #conn_data{trans_ack_maxcount = Val}) -> + Val; +do_conn_info(trans_req = _Item, #conn_data{trans_req = Val}) -> + Val; +do_conn_info(trans_req_maxcount = _Item, #conn_data{trans_req_maxcount = Val}) -> + Val; +do_conn_info(trans_req_maxsize = _Item, #conn_data{trans_req_maxsize = Val}) -> + Val; +do_conn_info(trans_timer = _Item, #conn_data{trans_timer = Val}) -> + Val; +do_conn_info(pending_timer = _Item, #conn_data{pending_timer = Val}) -> + Val; +do_conn_info(orig_pending_limit = _Item, #conn_data{sent_pending_limit = Val}) -> + Val; +do_conn_info(sent_pending_limit = _Item, #conn_data{sent_pending_limit = Val}) -> + Val; +do_conn_info(recv_pending_limit = _Item, #conn_data{recv_pending_limit = Val}) -> + Val; +do_conn_info(reply_timer = _Item, #conn_data{reply_timer = Val}) -> + Val; +do_conn_info(control_pid = _Item, #conn_data{control_pid = Val}) -> + Val; +do_conn_info(send_mod = _Item, #conn_data{send_mod = Val}) -> + Val; +do_conn_info(send_handle = _Item, #conn_data{send_handle = Val}) -> + Val; +do_conn_info(encoding_mod = _Item, #conn_data{encoding_mod = Val}) -> + Val; +do_conn_info(encoding_config = _Item, #conn_data{encoding_config = Val}) -> + Val; +do_conn_info(protocol_version = _Item, #conn_data{protocol_version = Val}) -> + Val; +do_conn_info(auth_data = _Item, #conn_data{auth_data = Val}) -> + Val; +do_conn_info(user_mod = _Item, #conn_data{user_mod = Val}) -> + Val; +do_conn_info(user_args = _Item, #conn_data{user_args = Val}) -> + Val; +do_conn_info(reply_action = _Item, #conn_data{reply_action = Val}) -> + Val; +do_conn_info(reply_data = _Item, #conn_data{reply_data = Val}) -> + Val; +do_conn_info(threaded = _Item, #conn_data{threaded = Val}) -> + Val; +do_conn_info(strict_version = _Item, #conn_data{strict_version = Val}) -> + Val; +do_conn_info(long_request_resend = _Item, + #conn_data{long_request_resend = Val}) -> + Val; +do_conn_info(call_proxy_gc_timeout = _Item, + #conn_data{call_proxy_gc_timeout = Val}) -> + Val; +do_conn_info(resend_indication = _Item, #conn_data{resend_indication = Val}) -> + Val; +do_conn_info(segment_reply_ind = _Item, #conn_data{segment_reply_ind = Val}) -> + Val; +do_conn_info(segment_recv_acc = _Item, #conn_data{segment_recv_acc = Val}) -> + Val; +do_conn_info(segment_recv_timer = _Item, + #conn_data{segment_recv_timer = Val}) -> + Val; +do_conn_info(segment_send = _Item, #conn_data{segment_send = Val}) -> + Val; +do_conn_info(segment_send_timer = _Item, + #conn_data{segment_send_timer = Val}) -> + Val; +do_conn_info(max_pdu_size = _Item, #conn_data{max_pdu_size = Val}) -> + Val; +do_conn_info(request_keep_alive_timeout = _Item, + #conn_data{request_keep_alive_timeout = Val}) -> + Val; +do_conn_info(receive_handle = _Item, + #conn_data{conn_handle = #megaco_conn_handle{local_mid = LMid}, + encoding_mod = EM, + encoding_config = EC, + send_mod = SM}) -> + #megaco_receive_handle{local_mid = LMid, + encoding_mod = EM, + encoding_config = EC, + send_mod = SM}; +do_conn_info(Item, Data) + when is_record(Data, conn_data) orelse is_record(Data, megaco_conn_handle) -> + exit({no_such_item, Item}); +do_conn_info(_Item, BadData) -> + {error, {no_such_connection, BadData}}. + + +%% replace(_, _, []) -> +%% []; +%% replace(Item, WithItem, [Item|List]) -> +%% [WithItem|List]; +%% replace(Item, WithItem, [OtherItem|List]) -> +%% [OtherItem | replace(Item, WithItem, List)]. update_conn_info(#conn_data{conn_handle = CH}, Item, Val) -> @@ -499,31 +628,19 @@ incr_counter(Item, Incr) -> end catch error:_ -> + %% Counter does not exist, so try creat it try begin cre_counter(Item, Incr) end catch exit:_ -> - %% Ok, some other process got there before us, - %% so try again + %% This is a raise condition. + %% When we tried to update the counter above, it + %% did not exist, but now it does... ets:update_counter(megaco_config, Item, Incr) end end. -%% incr_counter(Item, Incr) -> -%% case (catch ets:update_counter(megaco_config, Item, Incr)) of -%% {'EXIT', _} -> -%% case (catch cre_counter(Item, Incr)) of -%% {'EXIT', _} -> -%% %% Ok, some other process got there before us, -%% %% so try again -%% ets:update_counter(megaco_config, Item, Incr); -%% NewVal -> -%% NewVal -%% end; -%% NewVal -> -%% NewVal -%% end. cre_counter(Item, Initial) -> case whereis(?SERVER) =:= self() of @@ -531,8 +648,8 @@ cre_counter(Item, Initial) -> case call({cre_counter, Item, Initial}) of {ok, Value} -> Value; - Error -> - exit(Error) + {error, Reason} -> + exit({failed_creating_counter, Item, Initial, Reason}) end; true -> %% Check that the counter does not already exists @@ -542,7 +659,7 @@ cre_counter(Item, Initial) -> ets:insert(megaco_config, {Item, Initial}), {ok, Initial}; [_] -> - %% Ouch, now what? + %% Possibly a raise condition {error, already_exists} end diff --git a/lib/megaco/src/engine/megaco_messenger.erl b/lib/megaco/src/engine/megaco_messenger.erl index 5756e8e896..5fad29931b 100644 --- a/lib/megaco/src/engine/megaco_messenger.erl +++ b/lib/megaco/src/engine/megaco_messenger.erl @@ -1541,30 +1541,6 @@ check_pending_limit(Limit, Direction, TransId) -> aborted end. -%% check_pending_limit(infinity, _, _) -> -%% {ok, 0}; -%% check_pending_limit(Limit, Direction, TransId) -> -%% ?rt2("check pending limit", [Direction, Limit, TransId]), -%% case (catch megaco_config:get_pending_counter(Direction, TransId)) of -%% {'EXIT', _} -> -%% %% This function is only called when we "know" the -%% %% counter to exist. So, the only reason that this -%% %% would happen is of the counter has been removed. -%% %% This only happen if the pending limit has been -%% %% reached. In any case, this is basically the same -%% %% as aborted! -%% ?rt2("check pending limit - exit", []), -%% aborted; -%% Val when Val =< Limit -> -%% %% Since we have no intention to increment here, it -%% %% is ok to be _at_ the limit -%% ?rt2("check pending limit - ok", [Val]), -%% {ok, Val}; -%% _Val -> -%% ?rt2("check pending limit - aborted", [_Val]), -%% aborted -%% end. - check_and_maybe_incr_pending_limit(infinity, _, _) -> ok; @@ -1572,59 +1548,42 @@ check_and_maybe_incr_pending_limit(Limit, Direction, TransId) -> %% %% We need this kind of test to detect when we _pass_ the limit %% - ?rt2("check and maybe incr pending limit", [Direction, Limit, TransId]), + ?rt2("check and maybe incr pending limit", [{direction, Direction}, + {transaction_id, TransId}, + {counter_limit, Limit}]), try megaco_config:get_pending_counter(Direction, TransId) of Val when Val > Limit -> - ?rt2("check and maybe incr - aborted", [Direction, Val, Limit]), + ?rt2("check and maybe incr - aborted", [{counter_value, Val}]), aborted; % Already passed the limit Val -> - ?rt2("check and maybe incr - incr", [Direction, Val, Limit]), + ?rt2("check and maybe incr - incr", [{counter_value, Val}]), megaco_config:incr_pending_counter(Direction, TransId), if Val < Limit -> ok; % Still within the limit true -> ?rt2("check and maybe incr - error", - [Direction, Val, Limit]), + [{counter_value, Val}]), error % Passed the limit end catch _:_ -> %% Has not been created yet (connect). - megaco_config:cre_pending_counter(Direction, TransId, 1), - ok + %% Try create it, but bevare of possible raise condition + try + begin + megaco_config:cre_pending_counter(Direction, TransId, 1), + ok + end + catch + _:_ -> + %% Ouch, raise condition, increment instead... + megaco_config:incr_pending_counter(Direction, TransId), + ok + end end. -%% check_and_maybe_incr_pending_limit(infinity, _, _) -> -%% ok; -%% check_and_maybe_incr_pending_limit(Limit, Direction, TransId) -> -%% %% -%% %% We need this kind of test to detect when we _pass_ the limit -%% %% -%% ?rt2("check and maybe incr pending limit", [Direction, Limit, TransId]), -%% case (catch megaco_config:get_pending_counter(Direction, TransId)) of -%% {'EXIT', _} -> -%% %% Has not been created yet (connect). -%% megaco_config:cre_pending_counter(Direction, TransId, 1), -%% ok; -%% Val when Val > Limit -> -%% ?rt2("check and maybe incr - aborted", [Direction, Val, Limit]), -%% aborted; % Already passed the limit -%% Val -> -%% ?rt2("check and maybe incr - incr", [Direction, Val, Limit]), -%% megaco_config:incr_pending_counter(Direction, TransId), -%% if -%% Val < Limit -> -%% ok; % Still within the limit -%% true -> -%% ?rt2("check and maybe incr - error", -%% [Direction, Val, Limit]), -%% error % Passed the limit -%% end -%% end. - - %% BUGBUG BUGBUG BUGBUG %% %% Do we know that the Rep is still valid? A previous transaction @@ -2648,33 +2607,84 @@ handle_reply( handle_reply(#conn_data{conn_handle = CH} = CD, T, Extra) -> TransId = to_local_trans_id(CD), ?rt2("handle reply", [T, TransId]), - case megaco_monitor:lookup_request(TransId) of - [Req] when (is_record(Req, request) andalso - (CD#conn_data.cancel =:= true)) -> + case {megaco_monitor:request_lockcnt_inc(TransId), + megaco_monitor:lookup_request(TransId)} of + {_Cnt, [Req]} when (is_record(Req, request) andalso + (CD#conn_data.cancel =:= true)) -> ?TC_AWAIT_REPLY_EVENT(true), + ?report_trace(CD, "trans reply - cancel(1)", [T]), do_handle_reply_cancel(CD, Req, T); - [#request{remote_mid = RMid} = Req] when ((RMid =:= preliminary_mid) orelse - (RMid =:= CH#megaco_conn_handle.remote_mid)) -> + {Cnt, [#request{remote_mid = RMid} = Req]} when + ((Cnt =:= 1) andalso + ((RMid =:= preliminary_mid) orelse + (RMid =:= CH#megaco_conn_handle.remote_mid))) -> + ?TC_AWAIT_REPLY_EVENT(false), + %% Just in case conn_data got update after our lookup + %% but before we looked up the request record, we + %% check the cancel field again. + case megaco_config:conn_info(CD, cancel) of + true -> + ?report_trace(CD, "trans reply - cancel(2)", [T]), + megaco_monitor:request_lockcnt_del(TransId), + do_handle_reply_cancel(CD, Req, T); + false -> + ?report_trace(CD, "trans reply", [T]), + do_handle_reply(CD, Req, TransId, T, Extra) + end; + + {Cnt, [#request{remote_mid = RMid} = _Req]} when + (is_integer(Cnt) andalso + ((RMid =:= preliminary_mid) orelse + (RMid =:= CH#megaco_conn_handle.remote_mid))) -> + ?TC_AWAIT_REPLY_EVENT(false), + %% Ok, someone got there before me, now what? + %% This is a plain old raise condition + ?report_important(CD, "trans reply - raise condition", + [T, {request_lockcnt, Cnt}]), + megaco_monitor:request_lockcnt_dec(TransId); + + %% no counter + {_Cnt, [#request{remote_mid = RMid} = Req]} when + ((RMid =:= preliminary_mid) orelse + (RMid =:= CH#megaco_conn_handle.remote_mid)) -> ?TC_AWAIT_REPLY_EVENT(false), + %% The counter does not exist. + %% This can only mean a code upgrade raise condition. + %% That is, this request record was created before + %% this feature (the counters) was instroduced. + %% The simples solution is this is to behave exactly as + %% before, that is pass it along, and leave it to the + %% user to figure out. + %% Just in case conn_data got update after our lookup %% but before we looked up the request record, we %% check the cancel field again. + ?report_verbose(CD, "trans reply - old style", [T]), case megaco_config:conn_info(CD, cancel) of true -> + megaco_monitor:request_lockcnt_del(TransId), do_handle_reply_cancel(CD, Req, T); false -> do_handle_reply(CD, Req, TransId, T, Extra) end; - [#request{user_mod = UserMod, - user_args = UserArgs, - reply_action = Action, - reply_data = UserData, - remote_mid = RMid}] -> + {Cnt, [#request{user_mod = UserMod, + user_args = UserArgs, + reply_action = Action, + reply_data = UserData, + remote_mid = RMid}]} -> ?report_trace(CD, "received trans reply with invalid remote mid", - [T, RMid]), + [{transaction, T}, + {remote_mid, RMid}, + {request_lockcnt, Cnt}]), + if + is_integer(Cnt) -> + megaco_monitor:request_lockcnt_dec(TransId); + true -> + ok + end, WrongMid = CH#megaco_conn_handle.remote_mid, T2 = transform_transaction_reply_enc(CD#conn_data.protocol_version, T), @@ -2685,7 +2695,15 @@ handle_reply(#conn_data{conn_handle = CH} = CD, T, Extra) -> reply_data = UserData}, return_reply(CD2, TransId, UserReply, Extra); - [] -> + {Cnt, []} when is_integer(Cnt) -> + ?TC_AWAIT_REPLY_EVENT(undefined), + ?report_trace(CD, "trans reply (no receiver)", + [T, {request_lockcnt, Cnt}]), + megaco_monitor:request_lockcnt_dec(TransId), + return_unexpected_trans(CD, T, Extra); + + %% No counter + {_Cnt, []} -> ?TC_AWAIT_REPLY_EVENT(undefined), ?report_trace(CD, "trans reply (no receiver)", [T]), return_unexpected_trans(CD, T, Extra) @@ -2716,6 +2734,7 @@ do_handle_reply(CD, %% This is the first reply (maybe of many) megaco_monitor:delete_request(TransId), + megaco_monitor:request_lockcnt_del(TransId), megaco_monitor:cancel_apply_after(Ref), % OTP-4843 megaco_config:del_pending_counter(recv, TransId), % OTP-7189 @@ -3739,6 +3758,11 @@ insert_requests(ConnData, ConnHandle, insert_request(ConnData, ConnHandle, TransId, Action, Data, InitTimer, LongTimer) -> + %% We dont check the result of the lock-counter creation because + %% the only way it could already exist is if the transaction-id + %% range has wrapped and an old counter was not deleted. + megaco_monitor:request_lockcnt_cre(TransId), + #megaco_conn_handle{remote_mid = RemoteMid} = ConnHandle, #conn_data{protocol_version = Version, user_mod = UserMod, @@ -4323,6 +4347,7 @@ cancel_request(ConnData, Req, Reason) -> cancel_request2(ConnData, TransId, UserReply) -> megaco_monitor:delete_request(TransId), + megaco_monitor:request_lockcnt_del(TransId), megaco_config:del_pending_counter(recv, TransId), % OTP-7189 Serial = TransId#trans_id.serial, ConnData2 = ConnData#conn_data{serial = Serial}, @@ -4380,29 +4405,67 @@ receive_reply_remote(ConnData, UserReply) -> receive_reply_remote(ConnData, UserReply, Extra) -> TransId = to_local_trans_id(ConnData), - case (catch megaco_monitor:lookup_request(TransId)) of - [#request{timer_ref = {_Type, Ref}} = Req] -> %% OTP-4843 + case {megaco_monitor:request_lockcnt_inc(TransId), + (catch megaco_monitor:lookup_request(TransId))} of + {Cnt, [Req]} when (Cnt =:= 1) andalso is_record(Req, request) -> %% Don't care about Req and Rep version diff - megaco_monitor:delete_request(TransId), - megaco_monitor:cancel_apply_after(Ref), % OTP-4843 - megaco_config:del_pending_counter(recv, TransId), % OTP-7189 - - UserMod = Req#request.user_mod, - UserArgs = Req#request.user_args, - Action = Req#request.reply_action, - UserData = Req#request.reply_data, - ConnData2 = ConnData#conn_data{user_mod = UserMod, - user_args = UserArgs, - reply_action = Action, - reply_data = UserData}, - return_reply(ConnData2, TransId, UserReply, Extra); - + do_receive_reply_remote(ConnData, TransId, Req, UserReply, Extra); + + {Cnt, [Req]} when is_integer(Cnt) andalso is_record(Req, request) -> + %% Another process is accessing, handle as unexpected + %% (so it has a possibillity to get logged). + ?report_important(ConnData, "trans reply (no receiver)", + [{user_reply, UserReply}, + {request_lockcnt, Cnt}]), + megaco_monitor:request_lockcnt_dec(TransId), + return_unexpected_trans_reply(ConnData, TransId, UserReply, Extra); + + %% no counter + {_Cnt, [Req]} when is_record(Req, request) -> + %% The counter does not exist. + %% This can only mean a code upgrade raise condition. + %% That is, this request record was created before + %% this feature (the counters) was instroduced. + %% The simples solution to this is to behave exactly as + %% before, that is, pass it along, and leave it to the + %% user to figure out. + ?report_trace(ConnData, + "remote reply - " + "code upgrade raise condition", + [{user_reply, UserReply}]), + do_receive_reply_remote(ConnData, TransId, Req, UserReply, Extra); + + {Cnt, _} when is_integer(Cnt) -> + ?report_trace(ConnData, "trans reply (no receiver)", + [{user_reply, UserReply}, {request_lockcnt, Cnt}]), + megaco_monitor:request_lockcnt_dec(TransId), + return_unexpected_trans_reply(ConnData, TransId, UserReply, Extra); + _ -> ?report_trace(ConnData, "remote reply (no receiver)", - [UserReply]), + [{user_reply, UserReply}]), return_unexpected_trans_reply(ConnData, TransId, UserReply, Extra) end. +do_receive_reply_remote(ConnData, TransId, + #request{timer_ref = {_Type, Ref}, + user_mod = UserMod, + user_args = UserArgs, + reply_action = Action, + reply_data = UserData} = _Req, + UserReply, Extra) -> + megaco_monitor:delete_request(TransId), + megaco_monitor:request_lockcnt_del(TransId), + megaco_monitor:cancel_apply_after(Ref), % OTP-4843 + megaco_config:del_pending_counter(recv, TransId), % OTP-7189 + + ConnData2 = ConnData#conn_data{user_mod = UserMod, + user_args = UserArgs, + reply_action = Action, + reply_data = UserData}, + return_reply(ConnData2, TransId, UserReply, Extra). + + cancel_reply(ConnData, #reply{state = waiting_for_ack, user_mod = UserMod, user_args = UserArgs} = Rep, Reason) -> diff --git a/lib/megaco/src/engine/megaco_monitor.erl b/lib/megaco/src/engine/megaco_monitor.erl index f95a20cf58..29275371be 100644 --- a/lib/megaco/src/engine/megaco_monitor.erl +++ b/lib/megaco/src/engine/megaco_monitor.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2000-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2000-2010. 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 %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -51,6 +51,11 @@ update_request_field/3, update_request_fields/2, delete_request/1, + request_lockcnt_cre/1, + request_lockcnt_del/1, + request_lockcnt_inc/1, + request_lockcnt_dec/1, + lookup_reply/1, lookup_reply_field/2, match_replies/1, @@ -115,6 +120,24 @@ update_request_fields(Key, NewFields) when is_list(NewFields) -> delete_request(Key) -> ets:delete(megaco_requests, Key). + +request_lockcnt_cre(TransId) -> + Key = {TransId, lockcnt}, + ets:insert_new(megaco_requests, {Key, 1}). + +request_lockcnt_del(TransId) -> + Key = {TransId, lockcnt}, + ets:delete(megaco_requests, Key). + +request_lockcnt_inc(TransId) -> + Key = {TransId, lockcnt}, + (catch ets:update_counter(megaco_requests, Key, 1)). + +request_lockcnt_dec(TransId) -> + Key = {TransId, lockcnt}, + (catch ets:update_counter(megaco_requests, Key, -1)). + + lookup_reply(Key) -> ets:lookup(megaco_replies, Key). diff --git a/lib/megaco/src/flex/Makefile.in b/lib/megaco/src/flex/Makefile.in index 6ce9b34617..5af651d89b 100644 --- a/lib/megaco/src/flex/Makefile.in +++ b/lib/megaco/src/flex/Makefile.in @@ -280,7 +280,7 @@ release_spec: opt $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin ifeq ($(ENABLE_MEGACO_FLEX_SCANNER),true) $(INSTALL_DATA) $(FLEX_FILES) $(C_TARGETS) $(RELSYSDIR)/src/flex - $(INSTALL_DATA) $(SOLIBS) $(RELSYSDIR)/priv/lib + $(INSTALL_PROGRAM) $(SOLIBS) $(RELSYSDIR)/priv/lib endif |