aboutsummaryrefslogtreecommitdiffstats
path: root/lib/megaco/src
diff options
context:
space:
mode:
authorMicael Karlberg <[email protected]>2010-06-07 12:00:00 +0200
committerBjörn Gustavsson <[email protected]>2010-08-20 08:57:11 +0200
commit61b1feed86ccf574613b913c5eea57d138eeb178 (patch)
treef4e25826fff8e222c95741ff401c5a112a912456 /lib/megaco/src
parent6769f83da0f193052a30ff8933a014e9cf3b0cdf (diff)
downloadotp-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.src23
-rw-r--r--lib/megaco/src/app/megaco_internal.hrl26
-rw-r--r--lib/megaco/src/engine/megaco_config.erl427
-rw-r--r--lib/megaco/src/engine/megaco_messenger.erl239
-rw-r--r--lib/megaco/src/engine/megaco_monitor.erl33
-rw-r--r--lib/megaco/src/flex/Makefile.in2
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