aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/diameter/doc/src/diameter.xml21
-rw-r--r--lib/diameter/doc/src/diameter_dict.xml2
-rw-r--r--lib/diameter/include/diameter_gen.hrl2
-rw-r--r--lib/diameter/src/base/diameter.erl5
-rw-r--r--lib/diameter/src/base/diameter_config.erl14
-rw-r--r--lib/diameter/src/base/diameter_peer_fsm.erl18
-rw-r--r--lib/diameter/src/base/diameter_service.erl6
-rw-r--r--lib/diameter/src/base/diameter_traffic.erl15
-rw-r--r--lib/diameter/src/base/diameter_types.erl29
-rw-r--r--lib/diameter/test/diameter_codec_test.erl10
-rw-r--r--lib/diameter/test/diameter_config_SUITE.erl9
-rw-r--r--lib/diameter/test/diameter_traffic_SUITE.erl9
-rw-r--r--lib/mnesia/src/mnesia.erl50
-rw-r--r--lib/mnesia/src/mnesia.hrl7
-rw-r--r--lib/mnesia/src/mnesia_bup.erl227
-rw-r--r--lib/mnesia/src/mnesia_checkpoint.erl36
-rw-r--r--lib/mnesia/src/mnesia_controller.erl48
-rw-r--r--lib/mnesia/src/mnesia_dumper.erl97
-rw-r--r--lib/mnesia/src/mnesia_frag.erl59
-rw-r--r--lib/mnesia/src/mnesia_index.erl12
-rw-r--r--lib/mnesia/src/mnesia_late_loader.erl6
-rw-r--r--lib/mnesia/src/mnesia_lib.erl131
-rw-r--r--lib/mnesia/src/mnesia_loader.erl64
-rw-r--r--lib/mnesia/src/mnesia_locker.erl19
-rw-r--r--lib/mnesia/src/mnesia_log.erl44
-rw-r--r--lib/mnesia/src/mnesia_monitor.erl38
-rw-r--r--lib/mnesia/src/mnesia_recover.erl36
-rw-r--r--lib/mnesia/src/mnesia_schema.erl47
-rw-r--r--lib/mnesia/src/mnesia_snmp_hook.erl17
-rw-r--r--lib/mnesia/src/mnesia_subscr.erl33
-rw-r--r--lib/mnesia/src/mnesia_text.erl22
-rw-r--r--lib/mnesia/src/mnesia_tm.erl196
-rw-r--r--lib/mnesia/test/mnesia_config_backup.erl3
-rw-r--r--lib/mnesia/test/mnesia_config_test.erl22
-rw-r--r--lib/mnesia/test/mnesia_evil_backup.erl19
-rw-r--r--lib/observer/src/Makefile1
-rw-r--r--lib/observer/src/observer.app.src1
-rw-r--r--lib/observer/src/observer_alloc_wx.erl256
-rw-r--r--lib/observer/src/observer_lib.erl7
-rw-r--r--lib/observer/src/observer_perf_wx.erl273
-rw-r--r--lib/observer/src/observer_sys_wx.erl87
-rw-r--r--lib/observer/src/observer_wx.erl19
-rw-r--r--lib/stdlib/src/stdlib.appup.src4
-rw-r--r--lib/wx/api_gen/wx_gen_cpp.erl7
-rw-r--r--lib/wx/api_gen/wxapi.conf5
-rw-r--r--lib/wx/c_src/gen/wxe_events.cpp10
-rw-r--r--lib/wx/c_src/gen/wxe_init.cpp10
-rw-r--r--lib/wx/configure.in21
-rw-r--r--lib/wx/examples/demo/demo.erl10
-rw-r--r--lib/wx/include/wx.hrl8
50 files changed, 1184 insertions, 908 deletions
diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml
index 37e67d8630..6e41b01c44 100644
--- a/lib/diameter/doc/src/diameter.xml
+++ b/lib/diameter/doc/src/diameter.xml
@@ -783,6 +783,27 @@ be matched by corresponding &capability; configuration, of
</item>
+<marker id="incoming_maxlen"/>
+<tag><c>{incoming_maxlen, 0..16777215}</c></tag>
+<item>
+<p>
+Bound on the expected size of incoming Diameter messages.
+Messages larger than the specified number of bytes are discarded.</p>
+
+<p>
+Defaults to <c>16777215</c>, the maximum value of the 24-bit Message
+Length field in a Diameter Header.</p>
+
+<warning>
+<p>
+This option should be set to as low a value as is sufficient for the
+Diameter applications and peers in question, since decoding incoming
+messages from a malicious peer can otherwise generate significant
+load.</p>
+</warning>
+
+</item>
+
<tag><c>{restrict_connections, false
| node
| nodes
diff --git a/lib/diameter/doc/src/diameter_dict.xml b/lib/diameter/doc/src/diameter_dict.xml
index 9db9bcffde..5cf1b174a0 100644
--- a/lib/diameter/doc/src/diameter_dict.xml
+++ b/lib/diameter/doc/src/diameter_dict.xml
@@ -529,7 +529,7 @@ answer record and passed to a &app_handle_request;
callback upon reception of an incoming request.</p>
<p>
-In cases in which there is a choice between list() and binary() types
+In cases in which there is a choice between string() and binary() types
for OctetString() and derived types, the representation is determined
by the value of &mod_string_decode;.</p>
diff --git a/lib/diameter/include/diameter_gen.hrl b/lib/diameter/include/diameter_gen.hrl
index 8272904856..0eef218a07 100644
--- a/lib/diameter/include/diameter_gen.hrl
+++ b/lib/diameter/include/diameter_gen.hrl
@@ -395,7 +395,7 @@ d(false, Reason, Name, Avp, {Avps, Acc}) ->
diameter_lib:log(decode_error,
?MODULE,
?LINE,
- {Reason, Name, Avp#diameter_avp.name, Stack}),
+ {Name, Avp#diameter_avp.name, Stack}),
{Rec, Failed} = Acc,
{[Avp|Avps], {Rec, [rc(Reason, Avp) | Failed]}}.
diff --git a/lib/diameter/src/base/diameter.erl b/lib/diameter/src/base/diameter.erl
index 67dfc7bdbf..010f977b97 100644
--- a/lib/diameter/src/base/diameter.erl
+++ b/lib/diameter/src/base/diameter.erl
@@ -45,6 +45,7 @@
-export_type([evaluable/0,
restriction/0,
+ message_length/0,
remotes/0,
sequence/0,
app_alias/0,
@@ -298,6 +299,9 @@ call(SvcName, App, Message) ->
| [node()]
| evaluable().
+-type message_length()
+ :: 0..16#FFFFFF.
+
%% Options passed to start_service/2
-type service_opt()
@@ -307,6 +311,7 @@ call(SvcName, App, Message) ->
| {sequence, sequence() | evaluable()}
| {share_peers, remotes()}
| {string_decode, boolean()}
+ | {incoming_maxlen, message_length()}
| {use_shared_peers, remotes()}
| {spawn_opt, list()}.
diff --git a/lib/diameter/src/base/diameter_config.erl b/lib/diameter/src/base/diameter_config.erl
index 0d0304bf33..8ac3b9d6ca 100644
--- a/lib/diameter/src/base/diameter_config.erl
+++ b/lib/diameter/src/base/diameter_config.erl
@@ -159,7 +159,8 @@ stop_service(SvcName) ->
%% # add_transport/2
%% --------------------------------------------------------------------------
--spec add_transport(diameter:service_name(), {connect|listen, [diameter:transport_opt()]})
+-spec add_transport(diameter:service_name(),
+ {connect|listen, [diameter:transport_opt()]})
-> {ok, diameter:transport_ref()}
| {error, term()}.
@@ -645,6 +646,7 @@ make_config(SvcName, Opts) ->
{false, monitor},
{?NOMASK, sequence},
{nodes, restrict_connections},
+ {16#FFFFFF, incoming_maxlen},
{true, string_decode},
{[], spawn_opt}]),
@@ -670,12 +672,20 @@ make_opts(Opts, Defs) ->
[{K, opt(K,V)} || {K,V} <- Known].
+opt(incoming_maxlen, N)
+ when 0 =< N, N < 1 bsl 24 ->
+ N;
+
opt(spawn_opt, L)
when is_list(L) ->
L;
opt(K, false = B)
- when K /= sequence ->
+ when K == share_peers;
+ K == use_shared_peers;
+ K == monitor;
+ K == restrict_connections;
+ K == string_decode ->
B;
opt(K, true = B)
diff --git a/lib/diameter/src/base/diameter_peer_fsm.erl b/lib/diameter/src/base/diameter_peer_fsm.erl
index aac2685514..2255d0a76b 100644
--- a/lib/diameter/src/base/diameter_peer_fsm.erl
+++ b/lib/diameter/src/base/diameter_peer_fsm.erl
@@ -125,7 +125,8 @@
%% outgoing DPR; boolean says whether or not
%% the request was sent explicitly with
%% diameter:call/4.
- length_errors :: exit | handle | discard}).
+ length_errors :: exit | handle | discard,
+ incoming_maxlen :: integer() | infinity}).
%% There are non-3588 states possible as a consequence of 5.6.1 of the
%% standard and the corresponding problem for incoming CEA's: we don't
@@ -203,6 +204,7 @@ i({Ack, WPid, {M, Ref} = T, Opts, {SvcOpts, Nodes, Dict0, Svc}}) ->
diameter_stats:reg(Ref),
diameter_codec:setopts([{common_dictionary, Dict0} | SvcOpts]),
{_,_} = Mask = proplists:get_value(sequence, SvcOpts),
+ Maxlen = proplists:get_value(incoming_maxlen, SvcOpts, 16#FFFFFF),
{[Cs,Ds], Rest} = proplists:split(Opts, [capabilities_cb, disconnect_cb]),
putr(?CB_KEY, {Ref, [F || {_,F} <- Cs]}),
putr(?DPR_KEY, [F || {_, F} <- Ds]),
@@ -223,7 +225,8 @@ i({Ack, WPid, {M, Ref} = T, Opts, {SvcOpts, Nodes, Dict0, Svc}}) ->
dictionary = Dict0,
mode = M,
service = svc(Svc, Addrs),
- length_errors = OnLengthErr}.
+ length_errors = OnLengthErr,
+ incoming_maxlen = Maxlen}.
%% The transport returns its local ip addresses so that different
%% transports on the same service can use different local addresses.
%% The local addresses are put into Host-IP-Address avps here when
@@ -326,11 +329,14 @@ handle_info(T, #state{} = State) ->
{?MODULE, Tag, Reason} ->
?LOG(stop, Tag),
{stop, {shutdown, Reason}, State}
- end.
+ end;
%% The form of the throw caught here is historical. It's
%% significant that it's not a 2-tuple, as in ?FAILURE(Reason),
%% since these are caught elsewhere.
+handle_info(T, S) -> %% started in old code
+ handle_info(T, #state{} = erlang:append_element(S, infinity)).
+
%% Note that there's no guarantee that the service and transport
%% capabilities are good enough to build a CER/CEA that can be
%% succesfully encoded. It's not checked at diameter:add_transport/2
@@ -561,6 +567,12 @@ recv(Bin, S) ->
%% recv1/3
+recv1(_,
+ #diameter_packet{header = H, bin = Bin},
+ #state{incoming_maxlen = M})
+ when M < size(Bin) ->
+ invalid(false, incoming_maxlen_exceeded, {size(Bin), H});
+
%% Incoming request after outgoing DPR: discard. Don't discard DPR, so
%% both ends don't do so when sending simultaneously.
recv1(Name,
diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl
index a01bcdd4e7..86e744dfbe 100644
--- a/lib/diameter/src/base/diameter_service.erl
+++ b/lib/diameter/src/base/diameter_service.erl
@@ -131,7 +131,8 @@
| {share_peers, diameter:remotes()} %% broadcast to
| {use_shared_peers, diameter:remotes()} %% use from
| {restrict_connections, diameter:restriction()}
- | {string_decode, boolean()}]}).
+ | {string_decode, boolean()}
+ | {incoming_maxlen, diameter:message_length()}]}).
%% shared_peers reflects the peers broadcast from remote nodes.
%% Record representing an RFC 3539 watchdog process implemented by
@@ -698,7 +699,8 @@ service_options(Opts) ->
Opts,
?RESTRICT)},
{spawn_opt, proplists:get_value(spawn_opt, Opts, [])},
- {string_decode, proplists:get_value(string_decode, Opts, true)}].
+ {string_decode, proplists:get_value(string_decode, Opts, true)},
+ {incoming_maxlen, proplists:get_value(incoming_maxlen, Opts, 16#FFFFFF)}].
%% The order of options is significant since we match against the list.
mref(false = No) ->
diff --git a/lib/diameter/src/base/diameter_traffic.erl b/lib/diameter/src/base/diameter_traffic.erl
index 784f9ca08f..538ebeeeba 100644
--- a/lib/diameter/src/base/diameter_traffic.erl
+++ b/lib/diameter/src/base/diameter_traffic.erl
@@ -78,7 +78,11 @@
service_name :: diameter:service_name(),
apps :: [#diameter_app{}],
sequence :: diameter:sequence(),
- codec :: list()}).
+ codec :: [{string_decode, boolean()}
+ | {incoming_maxlen, diameter:message_length()}]}).
+%% Note that incoming_maxlen is currently handled in diameter_peer_fsm,
+%% so that any message exceeding the maximum is discarded. Retain the
+%% option in case we want to extend the values and semantics.
%% Record stored in diameter_request for each outgoing request.
-record(request,
@@ -102,7 +106,9 @@ make_recvdata([SvcName, PeerT, Apps, SvcOpts | _]) ->
peerT = PeerT,
apps = Apps,
sequence = Mask,
- codec = [T || {K,_} = T <- SvcOpts, K == string_decode]}.
+ codec = [T || {K,_} = T <- SvcOpts,
+ lists:member(K, [string_decode,
+ incoming_maxlen])]}.
%% ---------------------------------------------------------------------------
%% peer_up/1
@@ -233,6 +239,8 @@ receive_message(TPid, Pkt, Dict0, RecvData)
Dict0,
RecvData).
+%% recv/6
+
%% Incoming request ...
recv(true, false, TPid, Pkt, Dict0, T) ->
spawn_request(TPid, Pkt, Dict0, T);
@@ -240,6 +248,7 @@ recv(true, false, TPid, Pkt, Dict0, T) ->
%% ... answer to known request ...
recv(false, #request{ref = Ref, handler = Pid} = Req, _, Pkt, Dict0, _) ->
Pid ! {answer, Ref, Req, Dict0, Pkt};
+
%% Note that failover could have happened prior to this message being
%% received and triggering failback. That is, both a failover message
%% and answer may be on their way to the handler process. In the worst
@@ -1693,6 +1702,8 @@ send({TPid, Pkt, #request{handler = Pid} = Req0, SvcName, Timeout, TRef}) ->
end.
%% recv/4
+%%
+%% Relay an answer from a remote node.
recv(TPid, Pid, TRef, Ref) ->
receive
diff --git a/lib/diameter/src/base/diameter_types.erl b/lib/diameter/src/base/diameter_types.erl
index fe7613541c..87a0f0663d 100644
--- a/lib/diameter/src/base/diameter_types.erl
+++ b/lib/diameter/src/base/diameter_types.erl
@@ -93,7 +93,7 @@
case diameter_codec:getopt(string_decode) of
true ->
binary_to_list(Bin);
- _ ->
+ false ->
Bin
end;
@@ -565,18 +565,29 @@ msb(false) -> ?TIME_2036.
scan_uri(Bin) ->
RE = "^(aaas?)://"
- "([-a-zA-Z0-9.]+)"
- "(:([0-9]+))?"
+ "([-a-zA-Z0-9.]{1,255})"
+ "(:0{0,5}([0-9]{1,5}))?"
"(;transport=(tcp|sctp|udp))?"
"(;protocol=(diameter|radius|tacacs\\+))?$",
+ %% A port number is 16-bit, so an arbitrary number of digits is
+ %% just a vulnerability, but provide a little slack with leading
+ %% zeros in a port number just because the regexp was previously
+ %% [0-9]+ and it's not inconceivable that a value might be padded.
+ %% Don't fantasize about this padding being more than the number
+ %% of digits in the port number proper.
+ %%
+ %% Similarly, a FQDN can't be arbitrarily long: at most 255
+ %% octets.
{match, [A, DN, PN, T, P]} = re:run(Bin,
RE,
[{capture, [1,2,4,6,8], binary}]),
Type = to_atom(A),
{PN0, T0} = defaults(diameter_codec:getopt(rfc), Type),
+ PortNr = to_int(PN, PN0),
+ 0 = PortNr bsr 16, %% assert
#diameter_uri{type = Type,
- fqdn = from_bin(DN),
- port = to_int(PN, PN0),
+ fqdn = 'OctetString'(decode, DN),
+ port = PortNr,
transport = to_atom(T, T0),
protocol = to_atom(P, diameter)}.
@@ -588,14 +599,6 @@ defaults(6733, aaa) ->
defaults(6733, aaas) ->
{5658, tcp}.
-from_bin(B) ->
- case diameter_codec:getopt(string_decode) of
- true ->
- binary_to_list(B);
- false ->
- B
- end.
-
to_int(<<>>, N) ->
N;
to_int(B, _) ->
diff --git a/lib/diameter/test/diameter_codec_test.erl b/lib/diameter/test/diameter_codec_test.erl
index 854b71ba93..5f1dbfbd61 100644
--- a/lib/diameter/test/diameter_codec_test.erl
+++ b/lib/diameter/test/diameter_codec_test.erl
@@ -352,15 +352,19 @@ values('DiameterURI') ->
{[],
["aaa" ++ S ++ "://diameter.se" ++ P ++ Tr ++ Pr
|| S <- ["", "s"],
- P <- ["", ":1234"],
+ P <- ["", ":1234", ":0", ":65535"],
Tr <- ["" | [";transport=" ++ X
|| X <- ["tcp", "sctp", "udp"]]],
Pr <- ["" | [";protocol=" ++ X
|| X <- ["diameter","radius","tacacs+"]]],
Tr /= ";transport=udp"
- orelse (Pr /= ";protocol=diameter" andalso Pr /= "")],
- ["aaa://diameter.se;transport=udp;protocol=diameter",
+ orelse (Pr /= ";protocol=diameter" andalso Pr /= "")]
+ ++ ["aaa://" ++ lists:duplicate(255, $x)],
+ ["aaa://diameter.se:65536",
+ "aaa://diameter.se:-1",
+ "aaa://diameter.se;transport=udp;protocol=diameter",
"aaa://diameter.se;transport=udp",
+ "aaa://" ++ lists:duplicate(256, $x),
"aaa://:3868",
"aaax://diameter.se",
"aaa://diameter.se;transport=tcpx",
diff --git a/lib/diameter/test/diameter_config_SUITE.erl b/lib/diameter/test/diameter_config_SUITE.erl
index 77f7aace1b..bbdf672291 100644
--- a/lib/diameter/test/diameter_config_SUITE.erl
+++ b/lib/diameter/test/diameter_config_SUITE.erl
@@ -85,6 +85,12 @@
{string_decode,
[[true], [false]],
[[0], [x]]},
+ {incoming_maxlen,
+ [[0], [65536], [16#FFFFFF]],
+ [[-1], [1 bsl 24], [infinity], [false]]},
+ {spawn_opt,
+ [[[]], [[monitor, link]]],
+ [[false]]},
{invalid_option, %% invalid service options are rejected
[],
[[x],
@@ -186,6 +192,9 @@
{private,
[[x]],
[]},
+ {spawn_opt,
+ [[[]], [[monitor, link]]],
+ [[false]]},
{invalid_option, %% invalid transport options are silently ignored
[[x],
[x,x]],
diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl
index 10c58ab6e7..7dd9f39f85 100644
--- a/lib/diameter/test/diameter_traffic_SUITE.erl
+++ b/lib/diameter/test/diameter_traffic_SUITE.erl
@@ -59,6 +59,7 @@
send_unexpected_mandatory_decode/1,
send_unexpected_mandatory/1,
send_long/1,
+ send_maxlen/1,
send_nopeer/1,
send_noapp/1,
send_discard/1,
@@ -182,6 +183,7 @@
{'Acct-Application-Id', [?DIAMETER_APP_ID_ACCOUNTING]},
{restrict_connections, false},
{string_decode, Decode},
+ {incoming_maxlen, 1 bsl 21},
{spawn_opt, [{min_heap_size, 5000}]}
| [{application, [{dictionary, D},
{module, ?MODULE},
@@ -317,6 +319,7 @@ tc() ->
send_unexpected_mandatory_decode,
send_unexpected_mandatory,
send_long,
+ send_maxlen,
send_nopeer,
send_noapp,
send_discard,
@@ -635,6 +638,12 @@ send_long(Config) ->
['STA', _SessionId, {'Result-Code', ?SUCCESS} | _]
= call(Config, Req).
+%% Send something longer than the configure incoming_maxlen.
+send_maxlen(Config) ->
+ Req = ['STR', {'Termination-Cause', ?LOGOUT},
+ {'User-Name', [lists:duplicate(1 bsl 21, $X)]}],
+ {timeout, _} = call(Config, Req).
+
%% Send something for which pick_peer finds no suitable peer.
send_nopeer(Config) ->
Req = ['STR', {'Termination-Cause', ?LOGOUT}],
diff --git a/lib/mnesia/src/mnesia.erl b/lib/mnesia/src/mnesia.erl
index 792b6c4a73..f501a4485b 100644
--- a/lib/mnesia/src/mnesia.erl
+++ b/lib/mnesia/src/mnesia.erl
@@ -145,7 +145,7 @@
%% Local function in order to avoid external function call
val(Var) ->
case ?catch_val(Var) of
- {'EXIT', Reason} -> mnesia_lib:other_val(Var, Reason);
+ {'EXIT', _} -> mnesia_lib:other_val(Var);
Value -> Value
end.
@@ -807,7 +807,7 @@ next(Tid,Ts,Tab,Key)
tid ->
lock_table(Tid, Ts, Tab, read),
do_fixtable(Tab,Ts),
- New = (catch dirty_next(Tab,Key)),
+ New = ?CATCH(dirty_next(Tab,Key)),
stored_keys(Tab,New,Key,Ts,next,
val({Tab, setorbag}));
_Protocol ->
@@ -833,7 +833,7 @@ prev(Tid,Ts,Tab,Key)
tid ->
lock_table(Tid, Ts, Tab, read),
do_fixtable(Tab,Ts),
- New = (catch dirty_prev(Tab,Key)),
+ New = ?CATCH(dirty_prev(Tab,Key)),
stored_keys(Tab,New,Key,Ts,prev,
val({Tab, setorbag}));
_Protocol ->
@@ -965,7 +965,7 @@ foldl(Fun, Acc, Tab, LockKind) when is_function(Fun) ->
foldl(ActivityId, Opaque, Fun, Acc, Tab, LockKind) ->
{Type, Prev} = init_iteration(ActivityId, Opaque, Tab, LockKind),
- Res = (catch do_foldl(ActivityId, Opaque, Tab, dirty_first(Tab), Fun, Acc, Type, Prev)),
+ Res = ?CATCH(do_foldl(ActivityId, Opaque, Tab, dirty_first(Tab), Fun, Acc, Type, Prev)),
close_iteration(Res, Tab).
do_foldl(A, O, Tab, '$end_of_table', Fun, RAcc, _Type, Stored) ->
@@ -1011,7 +1011,7 @@ foldr(ActivityId, Opaque, Fun, Acc, Tab, LockKind) ->
true -> %% Order doesn't matter for set and bag
TempPrev %% Keep the order so we can use ordsets:del_element
end,
- Res = (catch do_foldr(ActivityId, Opaque, Tab, dirty_last(Tab), Fun, Acc, Type, Prev)),
+ Res = ?CATCH(do_foldr(ActivityId, Opaque, Tab, dirty_last(Tab), Fun, Acc, Type, Prev)),
close_iteration(Res, Tab).
do_foldr(A, O, Tab, '$end_of_table', Fun, RAcc, _Type, Stored) ->
@@ -1905,21 +1905,21 @@ any_table_info(Tab, _Item) ->
abort({bad_type, Tab}).
raw_table_info(Tab, Item) ->
- case ?catch_val({Tab, storage_type}) of
- ram_copies ->
- info_reply(catch ?ets_info(Tab, Item), Tab, Item);
- disc_copies ->
- info_reply(catch ?ets_info(Tab, Item), Tab, Item);
- disc_only_copies ->
- info_reply(catch dets:info(Tab, Item), Tab, Item);
- unknown ->
- bad_info_reply(Tab, Item);
- {'EXIT', _} ->
+ try
+ case ?ets_lookup_element(mnesia_gvar, {Tab, storage_type}, 2) of
+ ram_copies ->
+ info_reply(?ets_info(Tab, Item), Tab, Item);
+ disc_copies ->
+ info_reply(?ets_info(Tab, Item), Tab, Item);
+ disc_only_copies ->
+ info_reply(dets:info(Tab, Item), Tab, Item);
+ unknown ->
+ bad_info_reply(Tab, Item)
+ end
+ catch error:_ ->
bad_info_reply(Tab, Item)
end.
-info_reply({'EXIT', _Reason}, Tab, Item) ->
- bad_info_reply(Tab, Item);
info_reply({error, _Reason}, Tab, Item) ->
bad_info_reply(Tab, Item);
info_reply(Val, _Tab, _Item) ->
@@ -2063,9 +2063,8 @@ storage_count(T, {U, R, D, DO}) ->
end.
system_info(Item) ->
- case catch system_info2(Item) of
- {'EXIT',Error} -> abort(Error);
- Other -> Other
+ try system_info2(Item)
+ catch _:Error -> abort(Error)
end.
system_info2(all) ->
@@ -2381,11 +2380,10 @@ del_table_index(Tab, Ix) ->
mnesia_schema:del_table_index(Tab, Ix).
transform_table(Tab, Fun, NewA) ->
- case catch val({Tab, record_name}) of
- {'EXIT', Reason} ->
- mnesia:abort(Reason);
- OldRN ->
- mnesia_schema:transform_table(Tab, Fun, NewA, OldRN)
+ try val({Tab, record_name}) of
+ OldRN -> mnesia_schema:transform_table(Tab, Fun, NewA, OldRN)
+ catch exit:Reason ->
+ mnesia:abort(Reason)
end.
transform_table(Tab, Fun, NewA, NewRN) ->
@@ -2796,7 +2794,7 @@ pre_qlc(Opts, Tab) ->
end.
post_qlc(Tab) ->
- case catch get(mnesia_activity_state) of
+ case get(mnesia_activity_state) of
{_,#tid{},_} -> ok;
_ ->
case ?catch_val({Tab, setorbag}) of
diff --git a/lib/mnesia/src/mnesia.hrl b/lib/mnesia/src/mnesia.hrl
index 9a58ea581a..86b6fd908f 100644
--- a/lib/mnesia/src/mnesia.hrl
+++ b/lib/mnesia/src/mnesia.hrl
@@ -39,7 +39,12 @@
-define(ets_delete_table(Tab), ets:delete(Tab)).
-define(ets_fixtable(Tab, Bool), ets:fixtable(Tab, Bool)).
--define(catch_val(Var), (catch ?ets_lookup_element(mnesia_gvar, Var, 2))).
+
+-define(SAFE(OP), try (OP) catch error:_ -> ok end).
+-define(CATCH(OP), try (OP) catch _:_Reason -> {'EXIT', _Reason} end).
+
+-define(catch_val(Var), (try ?ets_lookup_element(mnesia_gvar, Var, 2)
+ catch error:_ -> {'EXIT', {badarg, []}} end)).
%% It's important that counter is first, since we compare tid's
diff --git a/lib/mnesia/src/mnesia_bup.erl b/lib/mnesia/src/mnesia_bup.erl
index 71e610bd63..3fee952d77 100644
--- a/lib/mnesia/src/mnesia_bup.erl
+++ b/lib/mnesia/src/mnesia_bup.erl
@@ -78,24 +78,21 @@
%% BunchOfRecords will be [] when the iteration is done.
iterate(Mod, Fun, Opaque, Acc) ->
R = #restore{bup_module = Mod, bup_data = Opaque},
- case catch read_schema_section(R) of
- {error, Reason} ->
- {error, Reason};
- {R2, {Header, Schema, Rest}} ->
- case catch iter(R2, Header, Schema, Fun, Acc, Rest) of
- {ok, R3, Res} ->
- catch safe_apply(R3, close_read, [R3#restore.bup_data]),
- {ok, Res};
- {error, Reason} ->
- catch safe_apply(R2, close_read, [R2#restore.bup_data]),
- {error, Reason};
- {'EXIT', Pid, Reason} ->
- catch safe_apply(R2, close_read, [R2#restore.bup_data]),
- {error, {'EXIT', Pid, Reason}};
- {'EXIT', Reason} ->
- catch safe_apply(R2, close_read, [R2#restore.bup_data]),
- {error, {'EXIT', Reason}}
- end
+ try read_schema_section(R) of
+ {R2, {Header, Schema, Rest}} ->
+ try iter(R2, Header, Schema, Fun, Acc, Rest) of
+ {ok, R3, Res} ->
+ close_read(R3),
+ {ok, Res}
+ catch throw:Err ->
+ close_read(R2),
+ Err;
+ _:Reason ->
+ close_read(R2),
+ {error, {Reason, erlang:get_stacktrace()}}
+ end
+ catch throw:{error,_} = Err ->
+ Err
end.
iter(R, Header, Schema, Fun, Acc, []) ->
@@ -116,7 +113,7 @@ safe_apply(R, write, [_, Items]) when Items =:= [] ->
safe_apply(R, What, Args) ->
Abort = fun(Re) -> abort_restore(R, What, Args, Re) end,
Mod = R#restore.bup_module,
- case catch apply(Mod, What, Args) of
+ try apply(Mod, What, Args) of
{ok, Opaque, Items} when What =:= read ->
{R#restore{bup_data = Opaque}, Items};
{ok, Opaque} when What =/= read->
@@ -125,16 +122,19 @@ safe_apply(R, What, Args) ->
Abort(Re);
Re ->
Abort(Re)
+ catch _:Re ->
+ Abort(Re)
end.
-abort_restore(R, What, Args, Reason) ->
- Mod = R#restore.bup_module,
- Opaque = R#restore.bup_data,
+abort_restore(R = #restore{bup_module=Mod}, What, Args, Reason) ->
dbg_out("Restore aborted. ~p:~p~p -> ~p~n",
[Mod, What, Args, Reason]),
- catch apply(Mod, close_read, [Opaque]),
+ close_read(R),
throw({error, Reason}).
+close_read(#restore{bup_module=Mod, bup_data=Opaque}) ->
+ ?SAFE(Mod:close_read(Opaque)).
+
fallback_to_schema() ->
Fname = fallback_bup(),
fallback_to_schema(Fname).
@@ -145,40 +145,30 @@ fallback_to_schema(Fname) ->
{error, Reason} ->
{error, Reason};
Schema ->
- case catch lookup_schema(schema, Schema) of
- {error, _} ->
- {error, "No schema in fallback"};
- List ->
- {ok, fallback, List}
+ try lookup_schema(schema, Schema) of
+ List -> {ok, fallback, List}
+ catch throw:_ ->
+ {error, "No schema in fallback"}
end
end.
%% Opens Opaque reads schema and then close
read_schema(Mod, Opaque) ->
R = #restore{bup_module = Mod, bup_data = Opaque},
- case catch read_schema_section(R) of
- {error, Reason} ->
- {error, Reason};
- {R2, {_Header, Schema, _}} ->
- catch safe_apply(R2, close_read, [R2#restore.bup_data]),
- Schema
+ try read_schema_section(R) of
+ {_, {_Header, Schema, _}} -> Schema
+ catch throw:{error,_} = Error ->
+ Error
+ after close_read(R)
end.
%% Open backup media and extract schema
%% rewind backup media and leave it open
%% Returns {R, {Header, Schema}}
read_schema_section(R) ->
- case catch do_read_schema_section(R) of
- {'EXIT', Reason} ->
- catch safe_apply(R, close_read, [R#restore.bup_data]),
- {error, {'EXIT', Reason}};
- {error, Reason} ->
- catch safe_apply(R, close_read, [R#restore.bup_data]),
- {error, Reason};
- {R2, {H, Schema, Rest}} ->
- Schema2 = convert_schema(H#log_header.log_version, Schema),
- {R2, {H, Schema2, Rest}}
- end.
+ {R2, {H, Schema, Rest}} = do_read_schema_section(R),
+ Schema2 = convert_schema(H#log_header.log_version, Schema),
+ {R2, {H, Schema2, Rest}}.
do_read_schema_section(R) ->
R2 = safe_apply(R, open_read, [R#restore.bup_data]),
@@ -201,7 +191,7 @@ do_read_schema_section(R, {ok, B, _C, Rest}, Acc) ->
{R, {B, Acc, Rest}};
do_read_schema_section(_R, {error, Reason}, _Acc) ->
- {error, Reason}.
+ throw({error, Reason}).
verify_header([H | RawSchema]) when is_record(H, log_header) ->
Current = mnesia_log:backup_log_header(),
@@ -218,7 +208,7 @@ verify_header([H | RawSchema]) when is_record(H, log_header) ->
{error, {"Bad kind of header. Cannot be used as backup.", H}}
end;
verify_header(RawSchema) ->
- {error, {"Missing header. Cannot be used as backup.", catch hd(RawSchema)}}.
+ {error, {"Missing header. Cannot be used as backup.", ?CATCH(hd(RawSchema))}}.
refresh_cookie(Schema, NewCookie) ->
case lists:keysearch(schema, 2, Schema) of
@@ -345,7 +335,7 @@ create_schema(Ns, ok) ->
Str = mk_str(),
File = mnesia_lib:dir(Str),
file:delete(File),
- case catch make_initial_backup(Ns, File, Mod) of
+ try make_initial_backup(Ns, File, Mod) of
{ok, _Res} ->
case do_install_fallback(File, Mod) of
ok ->
@@ -353,8 +343,8 @@ create_schema(Ns, ok) ->
ok;
{error, Reason} ->
{error, Reason}
- end;
- {error, Reason} ->
+ end
+ catch throw:{error, Reason} ->
{error, Reason}
end
end
@@ -384,10 +374,11 @@ make_initial_backup(Ns, Opaque, Mod) ->
do_apply(_, write, [_, Items], Opaque) when Items =:= [] ->
Opaque;
do_apply(Mod, What, Args, _Opaque) ->
- case catch apply(Mod, What, Args) of
+ try apply(Mod, What, Args) of
{ok, Opaque2} -> Opaque2;
- {error, Reason} -> throw({error, Reason});
- {'EXIT', Reason} -> throw({error, {'EXIT', Reason}})
+ {error, Reason} -> throw({error, Reason})
+ catch _:Reason ->
+ throw({error, {'EXIT', Reason}})
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -425,11 +416,11 @@ do_install_fallback(_Opaque, Args) ->
{error, {badarg, Args}}.
check_fallback_args([Arg | Tail], FA) ->
- case catch check_fallback_arg_type(Arg, FA) of
- {'EXIT', _Reason} ->
- {error, {badarg, Arg}};
+ try check_fallback_arg_type(Arg, FA) of
FA2 ->
check_fallback_args(Tail, FA2)
+ catch error:_ ->
+ {error, {badarg, Arg}}
end;
check_fallback_args([], FA) ->
{ok, FA}.
@@ -484,7 +475,7 @@ install_fallback_master(ClientPid, FA) ->
State = {start, FA},
Opaque = FA#fallback_args.opaque,
Mod = FA#fallback_args.module,
- Res = (catch iterate(Mod, fun restore_recs/4, Opaque, State)),
+ Res = iterate(Mod, fun restore_recs/4, Opaque, State),
unlink(ClientPid),
ClientPid ! {self(), Res},
exit(shutdown).
@@ -496,9 +487,7 @@ restore_recs(Recs, Header, Schema, {start, FA}) ->
%% No records in backup
Schema2 = convert_schema(Header#log_header.log_version, Schema),
CreateList = lookup_schema(schema, Schema2),
- case catch mnesia_schema:list2cs(CreateList) of
- {'EXIT', Reason} ->
- throw({error, {"Bad schema in restore_recs", Reason}});
+ try mnesia_schema:list2cs(CreateList) of
Cs ->
Ns = get_fallback_nodes(FA, Cs#cstruct.disc_copies),
global:set_lock({{mnesia_table_lock, schema}, self()}, Ns, infinity),
@@ -508,6 +497,8 @@ restore_recs(Recs, Header, Schema, {start, FA}) ->
Res = restore_recs(Recs, Header, Schema2, Pids),
global:del_lock({{mnesia_table_lock, schema}, self()}, Ns),
Res
+ catch _:Reason ->
+ throw({error, {"Bad schema in restore_recs", Reason}})
end;
restore_recs([], _Header, _Schema, Pids) ->
@@ -579,45 +570,46 @@ fallback_tmp_name() -> "FALLBACK.TMP".
fallback_receiver(Master, FA) ->
process_flag(trap_exit, true),
- case catch register(mnesia_fallback, self()) of
- {'EXIT', _} ->
- Reason = {already_exists, node()},
- local_fallback_error(Master, Reason);
- true ->
- FA2 = check_fallback_dir(Master, FA),
- Bup = FA2#fallback_args.fallback_bup,
- case mnesia_lib:exists(Bup) of
- true ->
- Reason2 = {already_exists, node()},
- local_fallback_error(Master, Reason2);
- false ->
- Mod = mnesia_backup,
- Tmp = FA2#fallback_args.fallback_tmp,
- R = #restore{mode = replace,
- bup_module = Mod,
- bup_data = Tmp},
- file:delete(Tmp),
- case catch fallback_receiver_loop(Master, R, FA2, schema) of
- {error, Reason} ->
- local_fallback_error(Master, Reason);
- Other ->
- exit(Other)
- end
- end
- end.
+ Res = try
+ register(mnesia_fallback, self()),
+ FA2 = check_fallback_dir(FA),
+ Bup = FA2#fallback_args.fallback_bup,
+ false = mnesia_lib:exists(Bup),
+ Mod = mnesia_backup,
+ Tmp = FA2#fallback_args.fallback_tmp,
+ R = #restore{mode = replace,
+ bup_module = Mod,
+ bup_data = Tmp},
+ file:delete(Tmp),
+ fallback_receiver_loop(Master, R, FA2, schema)
+ catch
+ error:_ ->
+ Reason = {already_exists, node()},
+ local_fallback_error(Master, Reason);
+ throw:{error, Reason} ->
+ local_fallback_error(Master, Reason)
+ end,
+ exit(Res).
local_fallback_error(Master, Reason) ->
Master ! {self(), {error, Reason}},
unlink(Master),
exit(Reason).
+
check_fallback_dir(Master, FA) ->
+ try check_fallback_dir(FA)
+ catch throw:{error,Reason} ->
+ local_fallback_error(Master, Reason)
+ end.
+
+check_fallback_dir(FA) ->
case mnesia:system_info(schema_location) of
ram ->
Reason = {has_no_disc, node()},
- local_fallback_error(Master, Reason);
+ throw({error, Reason});
_ ->
- Dir = check_fallback_dir_arg(Master, FA),
+ Dir = check_fallback_dir_arg(FA),
Bup = filename:join([Dir, fallback_name()]),
Tmp = filename:join([Dir, fallback_tmp_name()]),
FA#fallback_args{fallback_bup = Bup,
@@ -625,22 +617,20 @@ check_fallback_dir(Master, FA) ->
mnesia_dir = Dir}
end.
-check_fallback_dir_arg(Master, FA) ->
+check_fallback_dir_arg(FA) ->
case FA#fallback_args.use_default_dir of
true ->
mnesia_lib:dir();
false when FA#fallback_args.scope =:= local ->
Dir = FA#fallback_args.mnesia_dir,
- case catch mnesia_monitor:do_check_type(dir, Dir) of
- {'EXIT', _R} ->
+ try mnesia_monitor:do_check_type(dir, Dir)
+ catch _:_ ->
Reason = {badarg, {dir, Dir}, node()},
- local_fallback_error(Master, Reason);
- AbsDir->
- AbsDir
- end;
+ throw({error, Reason})
+ end;
false when FA#fallback_args.scope =:= global ->
Reason = {combine_error, global, dir, node()},
- local_fallback_error(Master, Reason)
+ throw({error, Reason})
end.
fallback_receiver_loop(Master, R, FA, State) ->
@@ -666,7 +656,7 @@ fallback_receiver_loop(Master, R, FA, State) ->
Bup = FA#fallback_args.fallback_bup,
Tmp = FA#fallback_args.fallback_tmp,
throw_bad_res(ok, file:rename(Tmp, Bup)),
- catch mnesia_lib:set(active_fallback, true),
+ ?SAFE(mnesia_lib:set(active_fallback, true)),
?eval_debug_fun({?MODULE, fallback_receiver_loop, post_swap}, []),
Master ! {self(), ok},
fallback_receiver_loop(Master, R, FA, stop);
@@ -697,7 +687,7 @@ throw_bad_res(_Expected, Actual) -> throw({error, Actual}).
tm_fallback_start(IgnoreFallback) ->
mnesia_schema:lock_schema(),
Res = do_fallback_start(fallback_exists(), IgnoreFallback),
- mnesia_schema: unlock_schema(),
+ mnesia_schema:unlock_schema(),
case Res of
ok -> ok;
{error, Reason} -> exit(Reason)
@@ -715,9 +705,9 @@ do_fallback_start(true, false) ->
BupFile = fallback_bup(),
Mod = mnesia_backup,
LocalTabs = ?ets_new_table(mnesia_local_tables, [set, public, {keypos, 2}]),
- case catch iterate(Mod, fun restore_tables/4, BupFile, {start, LocalTabs}) of
+ case iterate(Mod, fun restore_tables/4, BupFile, {start, LocalTabs}) of
{ok, _Res} ->
- catch dets:close(schema),
+ ?SAFE(dets:close(schema)),
TmpSchema = mnesia_lib:tab2tmp(schema),
DatSchema = mnesia_lib:tab2dat(schema),
AllLT = ?ets_match_object(LocalTabs, '_'),
@@ -733,8 +723,6 @@ do_fallback_start(true, false) ->
{error, {"Cannot start from fallback. Rename error.", Reason}}
end;
{error, Reason} ->
- {error, {"Cannot start from fallback", Reason}};
- {'EXIT', Reason} ->
{error, {"Cannot start from fallback", Reason}}
end.
@@ -996,10 +984,10 @@ uninstall_fallback_master(ClientPid, FA) ->
case fallback_to_schema(Bup) of
{ok, fallback, List} ->
Cs = mnesia_schema:list2cs(List),
- case catch get_fallback_nodes(FA, Cs#cstruct.disc_copies) of
+ try get_fallback_nodes(FA, Cs#cstruct.disc_copies) of
Ns when is_list(Ns) ->
- do_uninstall(ClientPid, Ns, FA);
- {error, Reason} ->
+ do_uninstall(ClientPid, Ns, FA)
+ catch throw:{error, Reason} ->
local_fallback_error(ClientPid, Reason)
end;
{error, Reason} ->
@@ -1042,13 +1030,13 @@ local_uninstall_fallback(Master, FA) ->
%% Don't trap exit
register(mnesia_fallback, self()), % May exit
- FA2 = check_fallback_dir(Master, FA), % May exit
+ FA2 = check_fallback_dir(Master, FA), % May exit
Master ! {self(), started},
receive
{Master, do_uninstall} ->
?eval_debug_fun({?MODULE, uninstall_fallback2, pre_delete}, []),
- catch mnesia_lib:set(active_fallback, false),
+ ?SAFE(mnesia_lib:set(active_fallback, false)),
Tmp = FA2#fallback_args.fallback_tmp,
Bup = FA2#fallback_args.fallback_bup,
file:delete(Tmp),
@@ -1071,10 +1059,8 @@ rec_uninstall(ClientPid, [Pid | Pids], AccRes) ->
{Pid, BadRes} ->
rec_uninstall(ClientPid, Pids, BadRes)
end;
-rec_uninstall(ClientPid, [], Res) ->
- ClientPid ! {self(), Res},
- unlink(ClientPid),
- exit(normal).
+rec_uninstall(_, [], Res) ->
+ Res.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Backup traversal
@@ -1125,12 +1111,11 @@ do_traverse_backup(ClientPid, Source, SourceMod, Target, TargetMod, Fun, Acc) ->
Iter =
if
TargetMod =/= read_only ->
- case catch do_apply(TargetMod, open_write, [Target], Target) of
- {error, Error} ->
+ try do_apply(TargetMod, open_write, [Target], Target)
+ catch throw:{error, Error} ->
unlink(ClientPid),
ClientPid ! {iter_done, self(), {error, Error}},
- exit(Error);
- Else -> Else
+ exit(Error)
end;
true ->
ignore
@@ -1139,16 +1124,16 @@ do_traverse_backup(ClientPid, Source, SourceMod, Target, TargetMod, Fun, Acc) ->
Res =
case iterate(SourceMod, fun trav_apply/4, Source, A) of
{ok, {iter, _, Acc2, _, Iter2}} when TargetMod =/= read_only ->
- case catch do_apply(TargetMod, commit_write, [Iter2], Iter2) of
- {error, Reason} ->
- {error, Reason};
- _ ->
- {ok, Acc2}
+ try
+ do_apply(TargetMod, commit_write, [Iter2], Iter2),
+ {ok, Acc2}
+ catch throw:{error, Reason} ->
+ {error, Reason}
end;
{ok, {iter, _, Acc2, _, _}} ->
{ok, Acc2};
{error, Reason} when TargetMod =/= read_only->
- catch do_apply(TargetMod, abort_write, [Iter], Iter),
+ ?CATCH(do_apply(TargetMod, abort_write, [Iter], Iter)),
{error, {"Backup traversal failed", Reason}};
{error, Reason} ->
{error, {"Backup traversal failed", Reason}}
diff --git a/lib/mnesia/src/mnesia_checkpoint.erl b/lib/mnesia/src/mnesia_checkpoint.erl
index 442e68a13d..0a3ea8d769 100644
--- a/lib/mnesia/src/mnesia_checkpoint.erl
+++ b/lib/mnesia/src/mnesia_checkpoint.erl
@@ -128,7 +128,7 @@ tm_enter_pending([], Pending) ->
Pending;
tm_enter_pending([Tab | Tabs], Pending) ->
%% io:format("Add ~p ~p ~p~n",[Tab, Pending, hd(tl(element(2, process_info(self(), current_stacktrace))))]),
- catch ?ets_insert(Tab, Pending),
+ ?SAFE(?ets_insert(Tab, Pending)),
tm_enter_pending(Tabs, Pending).
tm_exit_pending(Tid) ->
@@ -427,22 +427,22 @@ check_tables(Cp) ->
arrange_retainers(Cp, Overriders, AllTabs) ->
R = #retainer{cp_name = Cp#checkpoint_args.name},
- case catch [R#retainer{tab_name = Tab,
- writers = select_writers(Cp, Tab)}
- || Tab <- AllTabs] of
- {'EXIT', Reason} ->
- {error, Reason};
+ try [R#retainer{tab_name = Tab,
+ writers = select_writers(Cp, Tab)}
+ || Tab <- AllTabs] of
Retainers ->
{ok, Cp#checkpoint_args{ram_overrides_dump = Overriders,
- retainers = Retainers,
- nodes = writers(Retainers)}}
+ retainers = Retainers,
+ nodes = writers(Retainers)}}
+ catch throw:Reason ->
+ {error, Reason}
end.
select_writers(Cp, Tab) ->
case filter_remote(Cp, val({Tab, active_replicas})) of
[] ->
- exit({"Cannot prepare checkpoint (replica not available)",
- [Tab, Cp#checkpoint_args.name]});
+ throw({"Cannot prepare checkpoint (replica not available)",
+ [Tab, Cp#checkpoint_args.name]});
Writers ->
This = node(),
case {lists:member(Tab, Cp#checkpoint_args.max),
@@ -492,12 +492,12 @@ check_prep([], Name, Nodes, IgnoreNew) ->
collect_pending(Name, Nodes, IgnoreNew) ->
case rpc:multicall(Nodes, ?MODULE, call, [Name, collect_pending]) of
{Replies, []} ->
- case catch ?ets_new_table(mnesia_union, [bag]) of
- {'EXIT', Reason} -> %% system limit
+ try
+ UnionTab = ?ets_new_table(mnesia_union, [bag]),
+ compute_union(Replies, Nodes, Name, UnionTab, IgnoreNew)
+ catch error:Reason -> %% system limit
Msg = "Cannot create an ets table pending union",
- {error, {system_limit, Msg, Reason}};
- UnionTab ->
- compute_union(Replies, Nodes, Name, UnionTab, IgnoreNew)
+ {error, {system_limit, Msg, Reason}}
end;
{_, BadNodes} ->
deactivate(Nodes, Name),
@@ -1170,7 +1170,7 @@ iterate(Name, Tab, Fun, Acc, Source, Val) ->
{error, Reason};
{ok, Iter, Pid} ->
link(Pid), % We don't want any pending fixtable's
- Res = (catch iter(Fun, Acc, Iter)),
+ Res = ?CATCH(iter(Fun, Acc, Iter)),
unlink(Pid),
call(Name, {iter_end, Iter}),
case Res of
@@ -1246,7 +1246,7 @@ system_code_change(Cp, _Module, _OldVsn, _Extra) ->
val(Var) ->
case ?catch_val(Var) of
- {'EXIT', _ReASoN_} -> mnesia_lib:other_val(Var, _ReASoN_);
- _VaLuE_ -> _VaLuE_
+ {'EXIT', _} -> mnesia_lib:other_val(Var);
+ _VaLuE_ -> _VaLuE_
end.
diff --git a/lib/mnesia/src/mnesia_controller.erl b/lib/mnesia/src/mnesia_controller.erl
index aa72de7594..b9d3779e9a 100644
--- a/lib/mnesia/src/mnesia_controller.erl
+++ b/lib/mnesia/src/mnesia_controller.erl
@@ -186,7 +186,7 @@ max_loaders() ->
val(Var) ->
case ?catch_val(Var) of
- {'EXIT', Reason} -> mnesia_lib:other_val(Var, Reason);
+ {'EXIT', _} -> mnesia_lib:other_val(Var);
Value -> Value
end.
@@ -241,9 +241,7 @@ do_wait_for_tables(Tabs, Timeout) ->
end.
reply_wait(Tabs) ->
- case catch mnesia_lib:active_tables() of
- {'EXIT', _} ->
- {error, {node_not_running, node()}};
+ try mnesia_lib:active_tables() of
Active when is_list(Active) ->
case Tabs -- Active of
[] ->
@@ -251,6 +249,7 @@ reply_wait(Tabs) ->
BadTabs ->
{timeout, BadTabs}
end
+ catch exit:_ -> {error, {node_not_running, node()}}
end.
wait_for_tables_init(From, Tabs) ->
@@ -261,13 +260,12 @@ wait_for_tables_init(From, Tabs) ->
exit(normal).
wait_for_init(From, Tabs, Init) ->
- case catch link(Init) of
- {'EXIT', _} ->
- %% Mnesia is not started
- {error, {node_not_running, node()}};
+ try link(Init) of
true when is_pid(Init) ->
cast({sync_tabs, Tabs, self()}),
rec_tabs(Tabs, Tabs, From, Init)
+ catch error:_ -> %% Mnesia is not started
+ {error, {node_not_running, node()}}
end.
sync_reply(Waiter, Tab) ->
@@ -343,7 +341,7 @@ get_network_copy(Tab, Cs) ->
%% might be solved by using monitor in subscr instead.
process_flag(trap_exit, true),
Load = load_table_fun(Work),
- Res = (catch Load()),
+ Res = ?CATCH(Load()),
process_flag(trap_exit, false),
call({del_other, self()}),
case Res of
@@ -592,11 +590,8 @@ call(Msg) ->
end.
remote_call(Node, Func, Args) ->
- case catch gen_server:call({?MODULE, Node}, {Func, Args, self()}, infinity) of
- {'EXIT', Error} ->
- {error, Error};
- Else ->
- Else
+ try gen_server:call({?MODULE, Node}, {Func, Args, self()}, infinity)
+ catch exit:Error -> {error, Error}
end.
multicall(Nodes, Msg) ->
@@ -677,7 +672,7 @@ handle_call(block_controller, From, State) ->
noreply(State2);
handle_call({update,Fun}, From, State) ->
- Res = (catch Fun()),
+ Res = ?CATCH(Fun()),
reply(From, Res),
noreply(State);
@@ -1256,7 +1251,7 @@ handle_info(#sender_done{worker_pid=Pid, worker_res=Res}, State) ->
end;
handle_info({'EXIT', Pid, R}, State) when Pid == State#state.supervisor ->
- catch set(mnesia_status, stopping),
+ ?SAFE(set(mnesia_status, stopping)),
case State#state.dumper_pid of
undefined ->
dbg_out("~p was ~p~n", [?SERVER_NAME, R]),
@@ -1480,9 +1475,9 @@ orphan_tables([], _, _, LocalOrphans, RemoteMasters) ->
node_has_tabs([Tab | Tabs], Node, State) when Node /= node() ->
State2 =
- case catch update_whereabouts(Tab, Node, State) of
- State1 = #state{} -> State1;
- {'EXIT', R} -> %% Tab was just deleted?
+ try update_whereabouts(Tab, Node, State) of
+ State1 = #state{} -> State1
+ catch exit:R -> %% Tab was just deleted?
case ?catch_val({Tab, cstruct}) of
{'EXIT', _} -> State; % yes
_ -> erlang:error(R)
@@ -1768,22 +1763,17 @@ change_table_majority(Cs) ->
update_where_to_wlock(Tab) ->
WNodes = val({Tab, where_to_write}),
- Majority = case catch val({Tab, majority}) of
- true -> true;
- _ -> false
- end,
+ Majority = ?catch_val({Tab, majority}) == true,
set({Tab, where_to_wlock}, {WNodes, Majority}).
%% node To now has tab loaded, but this must be undone
%% This code is rpc:call'ed from the tab_copier process
%% when it has *not* released it's table lock
unannounce_add_table_copy(Tab, To) ->
- catch del_active_replica(Tab, To),
- case catch val({Tab , where_to_read}) of
- To ->
- mnesia_lib:set_remote_where_to_read(Tab);
- _ ->
- ignore
+ ?SAFE(del_active_replica(Tab, To)),
+ try To = val({Tab , where_to_read}),
+ mnesia_lib:set_remote_where_to_read(Tab)
+ catch _:_ -> ignore
end.
user_sync_tab(Tab) ->
diff --git a/lib/mnesia/src/mnesia_dumper.erl b/lib/mnesia/src/mnesia_dumper.erl
index 509b765dee..693f20dbc2 100644
--- a/lib/mnesia/src/mnesia_dumper.erl
+++ b/lib/mnesia/src/mnesia_dumper.erl
@@ -137,7 +137,7 @@ perform_dump(InitBy, Regulator) ->
U = mnesia_monitor:get_env(dump_log_update_in_place),
Cont = mnesia_log:init_log_dump(),
mnesia_recover:sync(),
- case catch do_perform_dump(Cont, U, InitBy, Regulator, undefined) of
+ try do_perform_dump(Cont, U, InitBy, Regulator, undefined) of
ok ->
?eval_debug_fun({?MODULE, post_dump}, [InitBy]),
case mnesia_monitor:use_dir() of
@@ -148,17 +148,15 @@ perform_dump(InitBy, Regulator) ->
end,
mnesia_recover:allow_garb(),
%% And now to the crucial point...
- mnesia_log:confirm_log_dump(Diff);
- {error, Reason} ->
- {error, Reason};
- {'EXIT', {Desc, Reason}} ->
+ mnesia_log:confirm_log_dump(Diff)
+ catch exit:Reason when Reason =/= fatal ->
case mnesia_monitor:get_env(auto_repair) of
true ->
- mnesia_lib:important(Desc, Reason),
+ mnesia_lib:important(error, Reason),
%% Ignore rest of the log
mnesia_log:confirm_log_dump(Diff);
false ->
- fatal(Desc, Reason)
+ fatal(error, Reason)
end
end;
{error, Reason} ->
@@ -176,24 +174,25 @@ scan_decisions(Fname, InitBy, Regulator) ->
mnesia_log:open_log(Name, Header, Fname, Exists,
mnesia_monitor:get_env(auto_repair), read_only),
Cont = start,
- Res = (catch do_perform_dump(Cont, false, InitBy, Regulator, undefined)),
- mnesia_log:close_log(Name),
- case Res of
- ok -> ok;
- {'EXIT', Reason} -> {error, Reason}
+ try
+ do_perform_dump(Cont, false, InitBy, Regulator, undefined)
+ catch exit:Reason when Reason =/= fatal ->
+ {error, Reason}
+ after mnesia_log:close_log(Name)
end
end.
do_perform_dump(Cont, InPlace, InitBy, Regulator, OldVersion) ->
case mnesia_log:chunk_log(Cont) of
{C2, Recs} ->
- case catch insert_recs(Recs, InPlace, InitBy, Regulator, OldVersion) of
- {'EXIT', R} ->
- Reason = {"Transaction log dump error: ~p~n", [R]},
- close_files(InPlace, {error, Reason}, InitBy),
- exit(Reason);
+ try insert_recs(Recs, InPlace, InitBy, Regulator, OldVersion) of
Version ->
do_perform_dump(C2, InPlace, InitBy, Regulator, Version)
+ catch _:R when R =/= fatal ->
+ ST = erlang:get_stacktrace(),
+ Reason = {"Transaction log dump error: ~p~n", [{R, ST}]},
+ close_files(InPlace, {error, Reason}, InitBy),
+ exit(Reason)
end;
eof ->
close_files(InPlace, ok, InitBy),
@@ -303,17 +302,16 @@ perform_update(Tid, SchemaOps, _DumperMode, _UseDir) ->
InitBy = fast_schema_update,
InPlace = mnesia_monitor:get_env(dump_log_update_in_place),
- ?eval_debug_fun({?MODULE, dump_schema_op}, [InitBy]),
- case catch insert_ops(Tid, schema_ops, SchemaOps, InPlace, InitBy,
- mnesia_log:version()) of
- {'EXIT', Reason} ->
- Error = {error, {"Schema update error", Reason}},
+ try insert_ops(Tid, schema_ops, SchemaOps, InPlace, InitBy,
+ mnesia_log:version()),
+ ?eval_debug_fun({?MODULE, post_dump}, [InitBy]),
+ close_files(InPlace, ok, InitBy),
+ ok
+ catch _:Reason when Reason =/= fatal ->
+ ST = erlang:get_stacktrace(),
+ Error = {error, {"Schema update error", {Reason, ST}}},
close_files(InPlace, Error, InitBy),
- fatal("Schema update error ~p ~p", [Reason, SchemaOps]);
- _ ->
- ?eval_debug_fun({?MODULE, post_dump}, [InitBy]),
- close_files(InPlace, ok, InitBy),
- ok
+ fatal("Schema update error ~p ~p", [{Reason,ST}, SchemaOps])
end.
insert_ops(_Tid, _Storage, [], _InPlace, _InitBy, _) -> ok;
@@ -362,13 +360,11 @@ dets_insert(Op,Tab,Key,Val) ->
case dets_incr_counter(Tab,Key) of
true ->
{RecName, Incr} = Val,
- case catch dets:update_counter(Tab, Key, Incr) of
- CounterVal when is_integer(CounterVal) ->
- ok;
- _ when Incr < 0 ->
+ try _ = dets:update_counter(Tab, Key, Incr)
+ catch error:_ when Incr < 0 ->
Zero = {RecName, Key, 0},
ok = dets:insert(Tab, Zero);
- _ ->
+ error:_ ->
Init = {RecName, Key, Incr},
ok = dets:insert(Tab, Init)
end;
@@ -786,7 +782,7 @@ insert_op(Tid, _, {op, clear_table, TabDef}, InPlace, InitBy) ->
end,
%% Need to catch this, it crashes on ram_copies if
%% the op comes before table is loaded at startup.
- catch insert(Tid, Storage, Tab, '_', Oid, clear_table, InPlace, InitBy)
+ ?CATCH(insert(Tid, Storage, Tab, '_', Oid, clear_table, InPlace, InitBy))
end;
insert_op(Tid, _, {op, merge_schema, TabDef}, InPlace, InitBy) ->
@@ -1060,14 +1056,13 @@ prepare_open(Tab, UpdateInPlace) ->
Dat;
false ->
Tmp = mnesia_lib:tab2tmp(Tab),
- case catch mnesia_lib:copy_file(Dat, Tmp) of
- ok ->
- Tmp;
- Error ->
+ try ok = mnesia_lib:copy_file(Dat, Tmp)
+ catch error:Error ->
fatal("Cannot copy dets file ~p to ~p: ~p~n",
[Dat, Tmp, Error])
- end
- end.
+ end,
+ Tmp
+ end.
del_opened_tab(Tab) ->
erase({?MODULE, Tab}).
@@ -1189,18 +1184,16 @@ raw_named_dump_table(Tab, Ftype) ->
Storage = ram_copies,
mnesia_lib:db_fixtable(Storage, Tab, true),
- case catch raw_dump_table(TabRef, Tab) of
- {'EXIT', Reason} ->
- mnesia_lib:db_fixtable(Storage, Tab, false),
- mnesia_lib:dets_sync_close(Tab),
- file:delete(TmpFname),
- mnesia_lib:unlock_table(Tab),
- exit({"Dump of table to disc failed", Reason});
- ok ->
- mnesia_lib:db_fixtable(Storage, Tab, false),
- mnesia_lib:dets_sync_close(Tab),
- mnesia_lib:unlock_table(Tab),
- ok = file:rename(TmpFname, Fname)
+ try
+ ok = raw_dump_table(TabRef, Tab),
+ ok = file:rename(TmpFname, Fname)
+ catch _:Reason ->
+ ?SAFE(file:delete(TmpFname)),
+ exit({"Dump of table to disc failed", Reason})
+ after
+ mnesia_lib:db_fixtable(Storage, Tab, false),
+ mnesia_lib:dets_sync_close(Tab),
+ mnesia_lib:unlock_table(Tab)
end;
{error, Reason} ->
mnesia_lib:unlock_table(Tab),
@@ -1266,6 +1259,6 @@ regulate(RegulatorPid) ->
val(Var) ->
case ?catch_val(Var) of
- {'EXIT', Reason} -> mnesia_lib:other_val(Var, Reason);
+ {'EXIT', _} -> mnesia_lib:other_val(Var);
Value -> Value
end.
diff --git a/lib/mnesia/src/mnesia_frag.erl b/lib/mnesia/src/mnesia_frag.erl
index 66fc20913c..6036ac4e8f 100644
--- a/lib/mnesia/src/mnesia_frag.erl
+++ b/lib/mnesia/src/mnesia_frag.erl
@@ -406,10 +406,11 @@ verify_numbers(FH,MatchSpec) ->
VerifyFun = fun(F) when is_integer(F), F >= 1, F =< N -> false;
(_F) -> true
end,
- case catch lists:filter(VerifyFun, FragNumbers) of
- [] ->
- FragNumbers;
- BadFrags ->
+ try
+ Frags = lists:filter(VerifyFun, FragNumbers),
+ Frags == [] orelse error(Frags),
+ FragNumbers
+ catch error:BadFrags ->
mnesia:abort({"match_spec_to_frag_numbers: Fragment numbers out of range",
BadFrags, {range, 1, N}})
end.
@@ -437,7 +438,7 @@ remote_select(ReplyTo, Ref, NameNodes, MatchSpec) ->
do_remote_select(ReplyTo, Ref, [{Name, Node} | NameNodes], MatchSpec) ->
if
Node == node() ->
- Res = (catch {ok, mnesia:dirty_select(Name, MatchSpec)}),
+ Res = ?CATCH({ok, mnesia:dirty_select(Name, MatchSpec)}),
ReplyTo ! {remote_select, Ref, Node, Res},
do_remote_select(ReplyTo, Ref, NameNodes, MatchSpec);
true ->
@@ -886,17 +887,19 @@ adjust_before_split(FH) ->
HashMod:add_frag(HashState)
end,
N = FH#frag_state.n_fragments + 1,
- FromFrags2 = (catch lists:sort(FromFrags)),
- UnionFrags = (catch lists:merge(FromFrags2, lists:sort(AdditionalWriteFrags))),
VerifyFun = fun(F) when is_integer(F), F >= 1, F =< N -> false;
(_F) -> true
end,
- case catch lists:filter(VerifyFun, UnionFrags) of
- [] ->
- FH2 = FH#frag_state{n_fragments = N,
- hash_state = HashState2},
- {FH2, FromFrags2, UnionFrags};
- BadFrags ->
+ try
+ FromFrags2 = lists:sort(FromFrags),
+ UnionFrags = lists:merge(FromFrags2, lists:sort(AdditionalWriteFrags)),
+
+ Frags = lists:filter(VerifyFun, UnionFrags),
+ Frags == [] orelse error(Frags),
+ FH2 = FH#frag_state{n_fragments = N,
+ hash_state = HashState2},
+ {FH2, FromFrags2, UnionFrags}
+ catch error:BadFrags ->
mnesia:abort({"add_frag: Fragment numbers out of range",
BadFrags, {range, 1, N}})
end.
@@ -981,22 +984,24 @@ adjust_before_merge(FH) ->
HashMod:del_frag(HashState)
end,
N = FH#frag_state.n_fragments,
- FromFrags2 = (catch lists:sort(FromFrags)),
- UnionFrags = (catch lists:merge(FromFrags2, lists:sort(AdditionalWriteFrags))),
VerifyFun = fun(F) when is_integer(F), F >= 1, F =< N -> false;
(_F) -> true
end,
- case catch lists:filter(VerifyFun, UnionFrags) of
- [] ->
- case lists:member(N, FromFrags2) of
- true ->
- FH2 = FH#frag_state{n_fragments = N - 1,
- hash_state = HashState2},
- {FH2, FromFrags2, UnionFrags};
+ try
+ FromFrags2 = lists:sort(FromFrags),
+ UnionFrags = lists:merge(FromFrags2, lists:sort(AdditionalWriteFrags)),
+
+ Frags = lists:filter(VerifyFun, UnionFrags),
+ [] == Frags orelse error(Frags),
+ case lists:member(N, FromFrags2) of
+ true ->
+ FH2 = FH#frag_state{n_fragments = N - 1,
+ hash_state = HashState2},
+ {FH2, FromFrags2, UnionFrags};
false ->
- mnesia:abort({"del_frag: Last fragment number not included", N})
- end;
- BadFrags ->
+ mnesia:abort({"del_frag: Last fragment number not included", N})
+ end
+ catch error:BadFrags ->
mnesia:abort({"del_frag: Fragment numbers out of range",
BadFrags, {range, 1, N}})
end.
@@ -1141,8 +1146,8 @@ remove_node(Node, Cs) ->
val(Var) ->
case ?catch_val(Var) of
- {'EXIT', Reason} -> mnesia_lib:other_val(Var, Reason);
- Value -> Value
+ {'EXIT', _} -> mnesia_lib:other_val(Var);
+ Value -> Value
end.
set_frag_hash(Tab, Props) ->
diff --git a/lib/mnesia/src/mnesia_index.erl b/lib/mnesia/src/mnesia_index.erl
index 87cb58dae1..6a7c964fce 100644
--- a/lib/mnesia/src/mnesia_index.erl
+++ b/lib/mnesia/src/mnesia_index.erl
@@ -45,21 +45,11 @@
del_transient/3,
del_index_table/3]).
--import(mnesia_lib, [verbose/2]).
+-import(mnesia_lib, [val/1, verbose/2]).
-include("mnesia.hrl").
-record(index, {setorbag, pos_list}).
-val(Var) ->
- case ?catch_val(Var) of
- {'EXIT', _ReASoN_} ->
- case mnesia_lib:other_val(Var) of
- error -> mnesia_lib:pr_other(Var, _ReASoN_);
- Val -> Val
- end;
- _VaLuE_ -> _VaLuE_
- end.
-
%% read an object list throuh its index table
%% we assume that table Tab has index on attribute number Pos
diff --git a/lib/mnesia/src/mnesia_late_loader.erl b/lib/mnesia/src/mnesia_late_loader.erl
index d09de3ca66..9a113c6306 100644
--- a/lib/mnesia/src/mnesia_late_loader.erl
+++ b/lib/mnesia/src/mnesia_late_loader.erl
@@ -36,17 +36,19 @@
-define(SERVER_NAME, ?MODULE).
+-include("mnesia.hrl").
+
-record(state, {supervisor}).
async_late_disc_load(_, [], _) -> ok;
async_late_disc_load(Node, Tabs, Reason) ->
Msg = {async_late_disc_load, Tabs, Reason},
- catch ({?SERVER_NAME, Node} ! {self(), Msg}).
+ ?SAFE({?SERVER_NAME, Node} ! {self(), Msg}).
maybe_async_late_disc_load(_, [], _) -> ok;
maybe_async_late_disc_load(Node, Tabs, Reason) ->
Msg = {maybe_async_late_disc_load, Tabs, Reason},
- catch ({?SERVER_NAME, Node} ! {self(), Msg}).
+ ?SAFE({?SERVER_NAME, Node} ! {self(), Msg}).
start() ->
mnesia_monitor:start_proc(?SERVER_NAME, ?MODULE, init, [self()]).
diff --git a/lib/mnesia/src/mnesia_lib.erl b/lib/mnesia/src/mnesia_lib.erl
index fc41cbedcb..7bd207f816 100644
--- a/lib/mnesia/src/mnesia_lib.erl
+++ b/lib/mnesia/src/mnesia_lib.erl
@@ -114,9 +114,7 @@
lock_table/1,
mkcore/1,
not_active_here/1,
- other_val/2,
other_val/1,
- pr_other/2,
overload_read/0,
overload_read/1,
overload_set/2,
@@ -380,8 +378,8 @@ search_key(_Key, []) ->
val(Var) ->
case ?catch_val(Var) of
- {'EXIT', _ReASoN_} -> mnesia_lib:other_val(Var, _ReASoN_);
- _VaLuE_ -> _VaLuE_
+ {'EXIT', _} -> other_val(Var);
+ _VaLuE_ -> _VaLuE_
end.
set(Var, Val) ->
@@ -390,13 +388,13 @@ set(Var, Val) ->
unset(Var) ->
?ets_delete(mnesia_gvar, Var).
-other_val(Var, Other) ->
- case other_val(Var) of
- error -> pr_other(Var, Other);
+other_val(Var) ->
+ case other_val_1(Var) of
+ error -> pr_other(Var);
Val -> Val
end.
-other_val(Var) ->
+other_val_1(Var) ->
case Var of
{_, where_to_read} -> nowhere;
{_, where_to_write} -> [];
@@ -404,21 +402,16 @@ other_val(Var) ->
_ -> error
end.
-pr_other(Var, Other) ->
- Why =
+pr_other(Var) ->
+ Why =
case is_running() of
no -> {node_not_running, node()};
_ -> {no_exists, Var}
end,
- verbose("~p (~p) val(mnesia_gvar, ~w) -> ~p ~p ~n",
+ verbose("~p (~p) val(mnesia_gvar, ~w) -> ~p ~n",
[self(), process_info(self(), registered_name),
- Var, Other, Why]),
- case Other of
- {badarg, [{ets, lookup_element, _, _}|_]} ->
- exit(Why);
- _ ->
- erlang:error(Why)
- end.
+ Var, Why]),
+ exit(Why).
%% Some functions for list valued variables
add(Var, Val) ->
@@ -905,7 +898,7 @@ dirty_rpc_error_tag(Reason) ->
end.
fatal(Format, Args) ->
- catch set(mnesia_status, stopping),
+ ?SAFE(catch set(mnesia_status, stopping)),
Core = mkcore({crashinfo, {Format, Args}}),
report_fatal(Format, Args, Core),
timer:sleep(10000), % Enough to write the core dump to disc?
@@ -917,7 +910,7 @@ report_fatal(Format, Args) ->
report_fatal(Format, Args, Core) ->
report_system_event({mnesia_fatal, Format, Args, Core}),
- catch exit(whereis(mnesia_monitor), fatal).
+ ?SAFE(exit(whereis(mnesia_monitor), fatal)).
%% We sleep longer and longer the more we try
%% Made some testing and came up with the following constants
@@ -1014,7 +1007,7 @@ dbg_out(Format, Args) ->
%% Keep the last 10 debug print outs
save(DbgInfo) ->
- catch save2(DbgInfo).
+ ?SAFE(save2(DbgInfo)).
save2(DbgInfo) ->
Key = {'$$$_report', current_pos},
@@ -1090,35 +1083,29 @@ db_match_object(Tab, Pat) ->
db_match_object(val({Tab, storage_type}), Tab, Pat).
db_match_object(Storage, Tab, Pat) ->
db_fixtable(Storage, Tab, true),
- Res = catch_match_object(Storage, Tab, Pat),
- db_fixtable(Storage, Tab, false),
- case Res of
- {'EXIT', Reason} -> exit(Reason);
- _ -> Res
+ try
+ case Storage of
+ disc_only_copies -> dets:match_object(Tab, Pat);
+ _ -> ets:match_object(Tab, Pat)
+ end
+ after
+ db_fixtable(Storage, Tab, false)
end.
-catch_match_object(disc_only_copies, Tab, Pat) ->
- catch dets:match_object(Tab, Pat);
-catch_match_object(_, Tab, Pat) ->
- catch ets:match_object(Tab, Pat).
-
db_select(Tab, Pat) ->
db_select(val({Tab, storage_type}), Tab, Pat).
db_select(Storage, Tab, Pat) ->
db_fixtable(Storage, Tab, true),
- Res = catch_select(Storage, Tab, Pat),
- db_fixtable(Storage, Tab, false),
- case Res of
- {'EXIT', Reason} -> exit(Reason);
- _ -> Res
+ try
+ case Storage of
+ disc_only_copies -> dets:select(Tab, Pat);
+ _ -> ets:select(Tab, Pat)
+ end
+ after
+ db_fixtable(Storage, Tab, false)
end.
-catch_select(disc_only_copies, Tab, Pat) ->
- catch dets:select(Tab, Pat);
-catch_select(_, Tab, Pat) ->
- catch ets:select(Tab, Pat).
-
db_select_init(disc_only_copies, Tab, Pat, Limit) ->
dets:select(Tab, Pat, Limit);
db_select_init(_, Tab, Pat, Limit) ->
@@ -1262,7 +1249,7 @@ dets_sync_open(Tab, Args) ->
end.
dets_sync_close(Tab) ->
- catch dets:close(Tab),
+ ?SAFE(dets:close(Tab)),
unlock_table(Tab),
ok.
@@ -1298,7 +1285,7 @@ readable_indecies(Tab) ->
scratch_debug_fun() ->
dbg_out("scratch_debug_fun(): ~p~n", [?DEBUG_TAB]),
- (catch ?ets_delete_table(?DEBUG_TAB)),
+ ?SAFE(?ets_delete_table(?DEBUG_TAB)),
?ets_new_table(?DEBUG_TAB, [set, public, named_table, {keypos, 2}]).
activate_debug_fun(FunId, Fun, InitialContext, File, Line) ->
@@ -1311,43 +1298,45 @@ activate_debug_fun(FunId, Fun, InitialContext, File, Line) ->
update_debug_info(Info).
update_debug_info(Info) ->
- case catch ?ets_insert(?DEBUG_TAB, Info) of
- {'EXIT', _} ->
+ try ?ets_insert(?DEBUG_TAB, Info),
+ ok
+ catch error:_ ->
scratch_debug_fun(),
- ?ets_insert(?DEBUG_TAB, Info);
- _ ->
- ok
+ ?ets_insert(?DEBUG_TAB, Info)
end,
dbg_out("update_debug_info(~p)~n", [Info]),
ok.
deactivate_debug_fun(FunId, _File, _Line) ->
- catch ?ets_delete(?DEBUG_TAB, FunId),
+ ?SAFE(?ets_delete(?DEBUG_TAB, FunId)),
ok.
eval_debug_fun(FunId, EvalContext, EvalFile, EvalLine) ->
- case catch ?ets_lookup(?DEBUG_TAB, FunId) of
- [] ->
- ok;
- [Info] ->
- OldContext = Info#debug_info.context,
- dbg_out("~s(~p): ~w "
- "activated in ~s(~p)~n "
- "eval_debug_fun(~w, ~w)~n",
- [filename:basename(EvalFile), EvalLine, Info#debug_info.id,
- filename:basename(Info#debug_info.file), Info#debug_info.line,
- OldContext, EvalContext]),
- Fun = Info#debug_info.function,
- NewContext = Fun(OldContext, EvalContext),
-
- case catch ?ets_lookup(?DEBUG_TAB, FunId) of
- [Info] when NewContext /= OldContext ->
- NewInfo = Info#debug_info{context = NewContext},
- update_debug_info(NewInfo);
- _ ->
- ok
- end;
- {'EXIT', _} -> ok
+ try
+ case ?ets_lookup(?DEBUG_TAB, FunId) of
+ [] ->
+ ok;
+ [Info] ->
+ OldContext = Info#debug_info.context,
+ dbg_out("~s(~p): ~w "
+ "activated in ~s(~p)~n "
+ "eval_debug_fun(~w, ~w)~n",
+ [filename:basename(EvalFile), EvalLine, Info#debug_info.id,
+ filename:basename(Info#debug_info.file), Info#debug_info.line,
+ OldContext, EvalContext]),
+ Fun = Info#debug_info.function,
+ NewContext = Fun(OldContext, EvalContext),
+
+ case ?ets_lookup(?DEBUG_TAB, FunId) of
+ [Info] when NewContext /= OldContext ->
+ NewInfo = Info#debug_info{context = NewContext},
+ update_debug_info(NewInfo);
+ _ ->
+ ok
+ end
+ end
+ catch error ->
+ ok
end.
-ifdef(debug).
diff --git a/lib/mnesia/src/mnesia_loader.erl b/lib/mnesia/src/mnesia_loader.erl
index cbb3d7e430..65ea743fd3 100644
--- a/lib/mnesia/src/mnesia_loader.erl
+++ b/lib/mnesia/src/mnesia_loader.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2014. 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
@@ -35,7 +35,7 @@
val(Var) ->
case ?catch_val(Var) of
- {'EXIT', Reason} -> mnesia_lib:other_val(Var, Reason);
+ {'EXIT', _} -> mnesia_lib:other_val(Var);
Value -> Value
end.
@@ -332,7 +332,7 @@ wait_on_load_complete(Pid) ->
{Pid, Res} ->
Res;
{'EXIT', Pid, Reason} ->
- exit(Reason);
+ error(Reason);
Else ->
Pid ! Else,
wait_on_load_complete(Pid)
@@ -442,18 +442,18 @@ init_table(Tab, disc_only_copies, Fun, DetsInfo,Sender) ->
ErtsVer = erlang:system_info(version),
case DetsInfo of
{ErtsVer, DetsData} ->
- Res = (catch dets:is_compatible_bchunk_format(Tab, DetsData)),
- case Res of
- {'EXIT',{undef,[{dets,_,_,_}|_]}} ->
- Sender ! {self(), {old_protocol, Tab}},
- dets:init_table(Tab, Fun); %% Old dets version
- {'EXIT', What} ->
- exit(What);
+ try dets:is_compatible_bchunk_format(Tab, DetsData) of
false ->
Sender ! {self(), {old_protocol, Tab}},
dets:init_table(Tab, Fun); %% Old dets version
true ->
dets:init_table(Tab, Fun, [{format, bchunk}])
+ catch
+ error:{undef,[{dets,_,_,_}|_]} ->
+ Sender ! {self(), {old_protocol, Tab}},
+ dets:init_table(Tab, Fun); %% Old dets version
+ error:What ->
+ What
end;
Old when Old /= false ->
Sender ! {self(), {old_protocol, Tab}},
@@ -462,10 +462,10 @@ init_table(Tab, disc_only_copies, Fun, DetsInfo,Sender) ->
dets:init_table(Tab, Fun)
end;
init_table(Tab, _, Fun, _DetsInfo,_) ->
- case catch ets:init_table(Tab, Fun) of
- true ->
- ok;
- {'EXIT', Else} -> Else
+ try
+ true = ets:init_table(Tab, Fun),
+ ok
+ catch _:Else -> {Else, erlang:get_stacktrace()}
end.
@@ -572,9 +572,9 @@ handle_last({ram_copies, Tab}, _Type, DatBin) ->
down(Tab, Storage) ->
case Storage of
ram_copies ->
- catch ?ets_delete_table(Tab);
+ ?SAFE(?ets_delete_table(Tab));
disc_copies ->
- catch ?ets_delete_table(Tab);
+ ?SAFE(?ets_delete_table(Tab));
disc_only_copies ->
TmpFile = mnesia_lib:tab2tmp(Tab),
mnesia_lib:dets_sync_close(Tab),
@@ -658,26 +658,23 @@ send_table(Pid, Tab, RemoteS) ->
{Init, Chunk} = reader_funcs(UseDetsChunk, Tab, Storage, KeysPerTransfer),
SendIt = fun() ->
- prepare_copy(Pid, Tab, Storage),
+ {atomic, ok} = prepare_copy(Pid, Tab, Storage),
send_more(Pid, 1, Chunk, Init(), Tab),
finish_copy(Pid, Tab, Storage, RemoteS)
end,
- case catch SendIt() of
- receiver_died ->
+ try SendIt() of
+ {_, receiver_died} -> ok;
+ {atomic, no_more} -> ok
+ catch
+ throw:receiver_died ->
cleanup_tab_copier(Pid, Storage, Tab),
- unlink(whereis(mnesia_tm)),
ok;
- {_, receiver_died} ->
- unlink(whereis(mnesia_tm)),
- ok;
- {atomic, no_more} ->
- unlink(whereis(mnesia_tm)),
- ok;
- Reason ->
+ error:Reason -> %% Prepare failed
cleanup_tab_copier(Pid, Storage, Tab),
- unlink(whereis(mnesia_tm)),
- {error, Reason}
+ {error, {tab_copier, Tab, {Reason, erlang:get_stacktrace()}}}
+ after
+ unlink(whereis(mnesia_tm))
end
end.
@@ -690,12 +687,7 @@ prepare_copy(Pid, Tab, Storage) ->
mnesia_lib:db_fixtable(Storage, Tab, true),
ok
end,
- case mnesia:transaction(Trans) of
- {atomic, ok} ->
- ok;
- {aborted, Reason} ->
- exit({tab_copier_prepare, Tab, Reason})
- end.
+ mnesia:transaction(Trans).
update_where_to_write(Tab, Node) ->
case val({Tab, access_mode}) of
@@ -828,6 +820,6 @@ dat2bin(_Tab, _LocalS, _RemoteS) ->
nobin.
handle_exit(Pid, Reason) when node(Pid) == node() ->
- exit(Reason);
+ error(Reason);
handle_exit(_Pid, _Reason) -> %% Not from our node, this will be handled by
ignore. %% mnesia_down soon.
diff --git a/lib/mnesia/src/mnesia_locker.erl b/lib/mnesia/src/mnesia_locker.erl
index 1efb939e00..6658dbeacb 100644
--- a/lib/mnesia/src/mnesia_locker.erl
+++ b/lib/mnesia/src/mnesia_locker.erl
@@ -98,7 +98,7 @@ init(Parent) ->
val(Var) ->
case ?catch_val(Var) of
- {'EXIT', _ReASoN_} -> mnesia_lib:other_val(Var, _ReASoN_);
+ {'EXIT', _} -> mnesia_lib:other_val(Var);
_VaLuE_ -> _VaLuE_
end.
@@ -1001,13 +1001,11 @@ flush_remaining(Ns=[Node | Tail], SkipNode, Res) ->
opt_lookup_in_client(lookup_in_client, Oid, Lock) ->
{Tab, Key} = Oid,
- case catch mnesia_lib:db_get(Tab, Key) of
- {'EXIT', _} ->
+ try mnesia_lib:db_get(Tab, Key)
+ catch error:_ ->
%% Table has been deleted from this node,
%% restart the transaction.
- #cyclic{op = read, lock = Lock, oid = Oid, lucky = nowhere};
- Val ->
- Val
+ #cyclic{op = read, lock = Lock, oid = Oid, lucky = nowhere}
end;
opt_lookup_in_client(Val, _Oid, _Lock) ->
Val.
@@ -1139,11 +1137,10 @@ send_requests([], _X) ->
rec_requests([Node | Nodes], Oid, Store) ->
Res = l_req_rec(Node, Store),
- case catch rlock_get_reply(Node, Store, Oid, Res) of
- {'EXIT', Reason} ->
- flush_remaining(Nodes, Node, Reason);
- _ ->
- rec_requests(Nodes, Oid, Store)
+ try rlock_get_reply(Node, Store, Oid, Res) of
+ _ -> rec_requests(Nodes, Oid, Store)
+ catch _:Reason ->
+ flush_remaining(Nodes, Node, Reason)
end;
rec_requests([], _Oid, _Store) ->
ok.
diff --git a/lib/mnesia/src/mnesia_log.erl b/lib/mnesia/src/mnesia_log.erl
index 6206a8bdb9..21ad0ffdb6 100644
--- a/lib/mnesia/src/mnesia_log.erl
+++ b/lib/mnesia/src/mnesia_log.erl
@@ -462,7 +462,7 @@ chunk_log(Cont) ->
chunk_log(_Log, eof) ->
eof;
chunk_log(Log, Cont) ->
- case catch disk_log:chunk(Log, Cont) of
+ case disk_log:chunk(Log, Cont) of
{error, Reason} ->
fatal("Possibly truncated ~p file: ~p~n",
[Log, Reason]);
@@ -647,11 +647,11 @@ backup_checkpoint(Name, Opaque, Args) when is_list(Args) ->
end.
check_backup_args([Arg | Tail], B) ->
- case catch check_backup_arg_type(Arg, B) of
- {'EXIT', _Reason} ->
- {error, {badarg, Arg}};
+ try check_backup_arg_type(Arg, B) of
B2 ->
check_backup_args(Tail, B2)
+ catch error:_ ->
+ {error, {badarg, Arg}}
end;
check_backup_args([], B) ->
@@ -674,11 +674,11 @@ check_backup_arg_type(Arg, B) ->
backup_master(ClientPid, B) ->
process_flag(trap_exit, true),
- case catch do_backup_master(B) of
- {'EXIT', Reason} ->
- ClientPid ! {self(), ClientPid, {error, {'EXIT', Reason}}};
+ try do_backup_master(B) of
Res ->
ClientPid ! {self(), ClientPid, Res}
+ catch _:Reason ->
+ ClientPid ! {self(), ClientPid, {error, {'EXIT', Reason}}}
end,
unlink(ClientPid),
exit(normal).
@@ -736,10 +736,10 @@ safe_apply(B, What, Args) ->
{'EXIT', Pid, R} -> Abort({'EXIT', Pid, R})
after 0 ->
Mod = B#backup_args.module,
- case catch apply(Mod, What, Args) of
+ try apply(Mod, What, Args) of
{ok, Opaque} -> B#backup_args{opaque=Opaque};
- {error, R} -> Abort(R);
- R -> Abort(R)
+ {error, R} -> Abort(R)
+ catch _:R -> Abort(R)
end
end.
@@ -748,10 +748,9 @@ abort_write(B, What, Args, Reason) ->
Opaque = B#backup_args.opaque,
dbg_out("Failed to perform backup. M=~p:F=~p:A=~p -> ~p~n",
[Mod, What, Args, Reason]),
- case catch apply(Mod, abort_write, [Opaque]) of
- {ok, _Res} ->
- throw({error, Reason});
- Other ->
+ try apply(Mod, abort_write, [Opaque]) of
+ {ok, _Res} -> throw({error, Reason})
+ catch _:Other ->
error("Failed to abort backup. ~p:~p~p -> ~p~n",
[Mod, abort_write, [Opaque], Other]),
throw({error, Reason})
@@ -892,10 +891,8 @@ tab_receiver(Pid, B, Tab, RecName, Slot) ->
end.
rec_filter(B, schema, _RecName, Recs) ->
- case catch mnesia_bup:refresh_cookie(Recs, B#backup_args.cookie) of
- Recs2 when is_list(Recs2) ->
- Recs2;
- {error, _Reason} ->
+ try mnesia_bup:refresh_cookie(Recs, B#backup_args.cookie)
+ catch throw:{error, _Reason} ->
%% No schema table cookie
Recs
end;
@@ -1006,13 +1003,14 @@ add_recs([{{Tab, _Key}, Val, delete_object} | Rest], N) ->
add_recs(Rest, N+1);
add_recs([{{Tab, Key}, Val, update_counter} | Rest], N) ->
{RecName, Incr} = Val,
- case catch ets:update_counter(Tab, Key, Incr) of
- CounterVal when is_integer(CounterVal) ->
- ok;
- _ when Incr < 0 ->
+ try
+ CounterVal = ets:update_counter(Tab, Key, Incr),
+ true = (CounterVal >= 0)
+ catch
+ error:_ when Incr < 0 ->
Zero = {RecName, Key, 0},
true = ets:insert(Tab, Zero);
- _ ->
+ error:_ ->
Zero = {RecName, Key, Incr},
true = ets:insert(Tab, Zero)
end,
diff --git a/lib/mnesia/src/mnesia_monitor.erl b/lib/mnesia/src/mnesia_monitor.erl
index a0e0e630ec..14b1ab5c1a 100644
--- a/lib/mnesia/src/mnesia_monitor.erl
+++ b/lib/mnesia/src/mnesia_monitor.erl
@@ -268,7 +268,7 @@ init([Parent]) ->
set(version, Version),
dbg_out("Version: ~p~n", [Version]),
- case catch process_config_args(env()) of
+ try process_config_args(env()) of
ok ->
mnesia_lib:set({'$$$_report', current_pos}, 0),
Level = mnesia_lib:val(debug),
@@ -288,8 +288,8 @@ init([Parent]) ->
set(pending_checkpoints, []),
set(pending_checkpoint_pids, []),
- {ok, #state{supervisor = Parent}};
- {'EXIT', Reason} ->
+ {ok, #state{supervisor = Parent}}
+ catch _:Reason ->
mnesia_lib:report_fatal("Bad configuration: ~p~n", [Reason]),
{stop, {bad_config, Reason}}
end.
@@ -323,25 +323,24 @@ non_empty_dir() ->
%%----------------------------------------------------------------------
handle_call({mktab, Tab, Args}, _From, State) ->
- case catch ?ets_new_table(Tab, Args) of
- {'EXIT', ExitReason} ->
+ try ?ets_new_table(Tab, Args) of
+ Reply ->
+ {reply, Reply, State}
+ catch error:ExitReason ->
Msg = "Cannot create ets table",
Reason = {system_limit, Msg, Tab, Args, ExitReason},
fatal("~p~n", [Reason]),
- {noreply, State};
- Reply ->
- {reply, Reply, State}
+ {noreply, State}
end;
handle_call({unsafe_mktab, Tab, Args}, _From, State) ->
- case catch ?ets_new_table(Tab, Args) of
- {'EXIT', ExitReason} ->
- {reply, {error, ExitReason}, State};
+ try ?ets_new_table(Tab, Args) of
Reply ->
{reply, Reply, State}
+ catch error:ExitReason ->
+ {reply, {error, ExitReason}, State}
end;
-
handle_call({open_dets, Tab, Args}, _From, State) ->
case mnesia_lib:dets_sync_open(Tab, Args) of
{ok, Tab} ->
@@ -546,7 +545,7 @@ handle_info({'EXIT', Pid, fatal}, State) when node(Pid) == node() ->
%% is in progress
%% exit(State#state.supervisor, shutdown),
%% It is better to kill an innocent process
- catch exit(whereis(mnesia_locker), kill),
+ ?SAFE(exit(whereis(mnesia_locker), kill)),
{noreply, State};
handle_info(Msg = {'EXIT',Pid,_}, State) ->
@@ -727,11 +726,8 @@ default_env(send_compressed) ->
0.
check_type(Env, Val) ->
- case catch do_check_type(Env, Val) of
- {'EXIT', _Reason} ->
- exit({bad_config, Env, Val});
- NewVal ->
- NewVal
+ try do_check_type(Env, Val)
+ catch error:_ -> exit({bad_config, Env, Val})
end.
do_check_type(access_module, A) when is_atom(A) -> A;
@@ -781,12 +777,12 @@ media(opt_disc) -> opt_disc;
media(ram) -> ram.
patch_env(Env, Val) ->
- case catch do_check_type(Env, Val) of
- {'EXIT', _Reason} ->
- {error, {bad_type, Env, Val}};
+ try do_check_type(Env, Val) of
NewVal ->
application_controller:set_env(mnesia, Env, NewVal),
NewVal
+ catch error:_ ->
+ {error, {bad_type, Env, Val}}
end.
detect_partitioned_network(Mon, Node) ->
diff --git a/lib/mnesia/src/mnesia_recover.erl b/lib/mnesia/src/mnesia_recover.erl
index eeb4fa0ced..aa567a23cb 100644
--- a/lib/mnesia/src/mnesia_recover.erl
+++ b/lib/mnesia/src/mnesia_recover.erl
@@ -178,11 +178,8 @@ log_decision(D) ->
val(Var) ->
case ?catch_val(Var) of
- {'EXIT', Reason} ->
- case mnesia_lib:other_val(Var) of
- error -> mnesia_lib:pr_other(Var, Reason);
- Val -> Val
- end;
+ {'EXIT', _Reason} ->
+ mnesia_lib:other_val(Var);
Value -> Value
end.
@@ -373,11 +370,8 @@ log_master_nodes2([], _UseDir, IsRunning, WorstRes) ->
get_master_node_info() ->
Tab = mnesia_decision,
Pat = {master_nodes, '_', '_'},
- case catch mnesia_lib:db_match_object(ram_copies,Tab, Pat) of
- {'EXIT', _} ->
- [];
- Masters ->
- Masters
+ try mnesia_lib:db_match_object(ram_copies,Tab, Pat)
+ catch error:_ -> []
end.
get_master_node_tables() ->
@@ -385,9 +379,8 @@ get_master_node_tables() ->
[Tab || {master_nodes, Tab, _Nodes} <- Masters].
get_master_nodes(Tab) ->
- case catch ?ets_lookup_element(mnesia_decision, Tab, 3) of
- {'EXIT', _} -> [];
- Nodes -> Nodes
+ try ?ets_lookup_element(mnesia_decision, Tab, 3)
+ catch error:_ -> []
end.
%% Determine what has happened to the transaction
@@ -485,8 +478,6 @@ load_decision_tab() ->
load_decision_tab(Cont, load_decision_tab),
mnesia_log:close_decision_tab().
-load_decision_tab(eof, _InitBy) ->
- ok;
load_decision_tab(Cont, InitBy) ->
case mnesia_log:chunk_decision_tab(Cont) of
{Cont2, Decisions} ->
@@ -519,8 +510,6 @@ dump_decision_log(InitBy) ->
Cont = mnesia_log:prepare_decision_log_dump(),
perform_dump_decision_log(Cont, InitBy).
-perform_dump_decision_log(eof, _InitBy) ->
- confirm_decision_log_dump();
perform_dump_decision_log(Cont, InitBy) when InitBy == startup ->
case mnesia_log:chunk_decision_log(Cont) of
{Cont2, Decisions} ->
@@ -1024,7 +1013,7 @@ decision(Tid) ->
decision(Tid, tabs()).
decision(Tid, [Tab | Tabs]) ->
- case catch ?ets_lookup(Tab, Tid) of
+ try ?ets_lookup(Tab, Tid) of
[D] when is_record(D, decision) ->
D;
[C] when is_record(C, transient_decision) ->
@@ -1034,8 +1023,8 @@ decision(Tid, [Tab | Tabs]) ->
ram_nodes = []
};
[] ->
- decision(Tid, Tabs);
- {'EXIT', _} ->
+ decision(Tid, Tabs)
+ catch error:_ ->
%% Recently switched transient decision table
decision(Tid, Tabs)
end;
@@ -1046,11 +1035,8 @@ outcome(Tid, Default) ->
outcome(Tid, Default, tabs()).
outcome(Tid, Default, [Tab | Tabs]) ->
- case catch ?ets_lookup_element(Tab, Tid, 3) of
- {'EXIT', _} ->
- outcome(Tid, Default, Tabs);
- Val ->
- Val
+ try ?ets_lookup_element(Tab, Tid, 3)
+ catch error:_ -> outcome(Tid, Default, Tabs)
end;
outcome(_Tid, Default, []) ->
Default.
diff --git a/lib/mnesia/src/mnesia_schema.erl b/lib/mnesia/src/mnesia_schema.erl
index 52180cfcf5..4c8234bbc7 100644
--- a/lib/mnesia/src/mnesia_schema.erl
+++ b/lib/mnesia/src/mnesia_schema.erl
@@ -151,7 +151,7 @@ exit_on_error(GoodRes) ->
val(Var) ->
case ?catch_val(Var) of
- {'EXIT', Reason} -> mnesia_lib:other_val(Var, Reason);
+ {'EXIT', _} -> mnesia_lib:other_val(Var);
Value -> Value
end.
@@ -2151,14 +2151,14 @@ prepare_op(_Tid, {op, transform, Fun, TabDef}, _WaitFor) ->
mnesia_lib:db_fixtable(Storage, Tab, true),
Key = mnesia_lib:db_first(Tab),
Op = {op, transform, Fun, TabDef},
- case catch transform_objs(Fun, Tab, RecName,
- Key, NewArity, Storage, Type, [Op]) of
- {'EXIT', Reason} ->
- mnesia_lib:db_fixtable(Storage, Tab, false),
- exit({"Bad transform function", Tab, Fun, node(), Reason});
+ try transform_objs(Fun, Tab, RecName, Key,
+ NewArity, Storage, Type, [Op]) of
Objs ->
mnesia_lib:db_fixtable(Storage, Tab, false),
{true, Objs, mandatory}
+ catch _:Reason ->
+ mnesia_lib:db_fixtable(Storage, Tab, false),
+ exit({"Bad transform function", Tab, Fun, node(), Reason})
end
end;
@@ -2342,7 +2342,7 @@ undo_prepare_commit(Tid, Commit) ->
ignore;
Ops ->
%% Catch to allow failure mnesia_controller may not be started
- catch mnesia_controller:release_schema_commit_lock(),
+ ?SAFE(mnesia_controller:release_schema_commit_lock()),
undo_prepare_ops(Tid, Ops)
end,
Commit.
@@ -2489,14 +2489,14 @@ ram_delete_table(Tab, Storage) ->
%% delete possible index files and data .....
%% Got to catch this since if no info has been set in the
%% mnesia_gvar it will crash
- catch mnesia_index:del_transient(Tab, Storage),
+ ?CATCH(mnesia_index:del_transient(Tab, Storage)),
case ?catch_val({Tab, {index, snmp}}) of
{'EXIT', _} ->
ignore;
Etab ->
- catch mnesia_snmp_hook:delete_table(Tab, Etab)
+ ?SAFE(mnesia_snmp_hook:delete_table(Tab, Etab))
end,
- catch ?ets_delete_table(Tab)
+ ?SAFE(?ets_delete_table(Tab))
end.
purge_dir(Dir, KeepFiles) ->
@@ -2584,10 +2584,7 @@ info2(_, []) ->
io:format("~n", []).
get_table_properties(Tab) ->
- case catch mnesia_lib:db_match_object(ram_copies,
- mnesia_gvar, {{Tab, '_'}, '_'}) of
- {'EXIT', _} ->
- mnesia:abort({no_exists, Tab, all});
+ try mnesia_lib:db_match_object(ram_copies, mnesia_gvar, {{Tab, '_'}, '_'}) of
RawGvar ->
case [{Item, Val} || {{_Tab, Item}, Val} <- RawGvar] of
[] ->
@@ -2598,6 +2595,8 @@ get_table_properties(Tab) ->
Master = {master_nodes, mnesia:table_info(Tab, master_nodes)},
lists:sort([Size, Memory, Master | Gvar])
end
+ catch error:_ ->
+ mnesia:abort({no_exists, Tab, all})
end.
%%%%%%%%%%% RESTORE %%%%%%%%%%%
@@ -2620,15 +2619,15 @@ restore(_Opaque, BadArg) ->
{aborted, {badarg, BadArg}}.
restore(Opaque, Args, Module) when is_list(Args), is_atom(Module) ->
InitR = #r{opaque = Opaque, module = Module},
- case catch lists:foldl(fun check_restore_arg/2, InitR, Args) of
+ try lists:foldl(fun check_restore_arg/2, InitR, Args) of
R when is_record(R, r) ->
case mnesia_bup:read_schema(R#r.module, Opaque) of
{error, Reason} ->
{aborted, Reason};
BupSchema ->
schema_transaction(fun() -> do_restore(R, BupSchema) end)
- end;
- {'EXIT', Reason} ->
+ end
+ catch exit:Reason ->
{aborted, Reason}
end;
restore(_Opaque, Args, Module) ->
@@ -3073,15 +3072,13 @@ do_make_merge_schema(Node, NeedsConv, RemoteCs = #cstruct{}) ->
%% Returns a new cstruct or issues a fatal error
merge_cstructs(Cs, RemoteCs, Force) ->
verify_cstruct(Cs),
- case catch do_merge_cstructs(Cs, RemoteCs, Force) of
- {'EXIT', {aborted, _Reason}} when Force == true ->
- Cs;
- {'EXIT', Reason} ->
- exit(Reason);
+ try do_merge_cstructs(Cs, RemoteCs, Force) of
MergedCs when is_record(MergedCs, cstruct) ->
- MergedCs;
- Other ->
- throw(Other)
+ MergedCs
+ catch exit:{aborted, _Reason} when Force == true ->
+ Cs;
+ exit:Reason -> exit(Reason);
+ error:Reason -> exit(Reason)
end.
do_merge_cstructs(Cs, RemoteCs, Force) ->
diff --git a/lib/mnesia/src/mnesia_snmp_hook.erl b/lib/mnesia/src/mnesia_snmp_hook.erl
index 256f83b029..c76cf89ebb 100644
--- a/lib/mnesia/src/mnesia_snmp_hook.erl
+++ b/lib/mnesia/src/mnesia_snmp_hook.erl
@@ -30,15 +30,6 @@
-include("mnesia.hrl").
-val(Var) ->
- case ?catch_val(Var) of
- {'EXIT', _ReASoN_} ->
- case mnesia_lib:other_val(Var) of
- error -> mnesia_lib:pr_other(Var, _ReASoN_);
- Val -> Val
- end;
- _VaLuE_ -> _VaLuE_
- end.
check_ustruct([]) ->
true; %% default value, not SNMP'ified
@@ -85,12 +76,12 @@ delete_table(_MnesiaTab, Tree) ->
%%-----------------------------------------------------------------
update({clear_table, MnesiaTab}) ->
- Tree = val({MnesiaTab, {index, snmp}}),
+ Tree = mnesia_lib:val({MnesiaTab, {index, snmp}}),
b_clear(Tree),
ok;
update({Op, MnesiaTab, MnesiaKey, SnmpKey}) ->
- Tree = val({MnesiaTab, {index, snmp}}),
+ Tree = mnesia_lib:val({MnesiaTab, {index, snmp}}),
update(Op, Tree, MnesiaKey, SnmpKey).
update(Op, Tree, MnesiaKey, SnmpKey) ->
@@ -120,7 +111,7 @@ update(Op, Tree, MnesiaKey, SnmpKey) ->
%%-----------------------------------------------------------------
key_to_oid(Tab,Key) ->
- Types = val({Tab,snmp}),
+ Types = mnesia_lib:val({Tab,snmp}),
key_to_oid(Tab, Key, Types).
key_to_oid(Tab, Key, [{key, Types}]) ->
@@ -144,7 +135,7 @@ keys_to_oid(N, Key, Oid, Types) ->
%% This can be lookup up in tree but that might be on a remote node.
%% It's probably faster to look it up, but use when it migth be remote
oid_to_key(Oid, Tab) ->
- [{key, Types}] = val({Tab,snmp}),
+ [{key, Types}] = mnesia_lib:val({Tab,snmp}),
oid_to_key_1(Types, Oid).
oid_to_key_1(integer, [Key]) -> Key;
diff --git a/lib/mnesia/src/mnesia_subscr.erl b/lib/mnesia/src/mnesia_subscr.erl
index 866a57e370..c39edea9e3 100644
--- a/lib/mnesia/src/mnesia_subscr.erl
+++ b/lib/mnesia/src/mnesia_subscr.erl
@@ -186,11 +186,11 @@ patch_record(Tab, Obj) ->
end.
what(Tab, Tid, {RecName, Key}, delete, undefined) ->
- case catch mnesia_lib:db_get(Tab, Key) of
- Old when is_list(Old) -> %% Op only allowed for set table.
- {mnesia_table_event, {delete, Tab, {RecName, Key}, Old, Tid}};
- _ ->
- %% Record just deleted by a dirty_op or
+ try mnesia_lib:db_get(Tab, Key) of
+ Old -> %% Op only allowed for set table.
+ {mnesia_table_event, {delete, Tab, {RecName, Key}, Old, Tid}}
+ catch error:_ ->
+ %% Record just deleted by a dirty_op or
%% the whole table has been deleted
ignore
end;
@@ -199,10 +199,10 @@ what(Tab, Tid, Obj, delete, Old) ->
what(Tab, Tid, Obj, delete_object, _Old) ->
{mnesia_table_event, {delete, Tab, Obj, [Obj], Tid}};
what(Tab, Tid, Obj, write, undefined) ->
- case catch mnesia_lib:db_get(Tab, element(2, Obj)) of
- Old when is_list(Old) ->
- {mnesia_table_event, {write, Tab, Obj, Old, Tid}};
- {'EXIT', _} ->
+ try mnesia_lib:db_get(Tab, element(2, Obj)) of
+ Old ->
+ {mnesia_table_event, {write, Tab, Obj, Old, Tid}}
+ catch error:_ ->
ignore
end;
what(Tab, Tid, Obj, write, Old) ->
@@ -386,12 +386,12 @@ activate(ClientPid, What, Var, OldSubscribers, SubscrTab) ->
case lists:member(ClientPid, Old) of
false ->
%% Don't care about checking old links
- case catch link(ClientPid) of
+ try link(ClientPid) of
true ->
?ets_insert(SubscrTab, {ClientPid, What}),
add_subscr(Var, What, ClientPid),
- {ok, node()};
- {'EXIT', _Reason} ->
+ {ok, node()}
+ catch error:_ ->
{error, {no_exists, ClientPid}}
end;
true ->
@@ -443,11 +443,10 @@ add_subscr({Tab, commit_work}, What, Pid) ->
deactivate(ClientPid, What, Var, SubscrTab) ->
?ets_match_delete(SubscrTab, {ClientPid, What}),
- case catch ?ets_lookup_element(SubscrTab, ClientPid, 1) of
- List when is_list(List) ->
- ignore;
- {'EXIT', _} ->
- unlink(ClientPid)
+ try
+ ?ets_lookup_element(SubscrTab, ClientPid, 1),
+ ignore
+ catch error:_ -> unlink(ClientPid)
end,
try
del_subscr(Var, What, ClientPid),
diff --git a/lib/mnesia/src/mnesia_text.erl b/lib/mnesia/src/mnesia_text.erl
index 0906d18da9..794e633238 100644
--- a/lib/mnesia/src/mnesia_text.erl
+++ b/lib/mnesia/src/mnesia_text.erl
@@ -84,8 +84,12 @@ validate_tab({Tabname, RecName, List}) ->
validate_tab(_) -> error(badtab).
make_tabs([{Tab, Def} | Tail]) ->
- case catch mnesia:table_info(Tab, where_to_read) of
- {'EXIT', _} -> %% non-existing table
+ try mnesia:table_info(Tab, where_to_read) of
+ Node ->
+ io:format("** Table ~w already exists on ~p, just entering data~n",
+ [Tab, Node]),
+ make_tabs(Tail)
+ catch exit:_ -> %% non-existing table
case mnesia:create_table(Tab, Def) of
{aborted, Reason} ->
io:format("** Failed to create table ~w ~n"
@@ -95,11 +99,7 @@ make_tabs([{Tab, Def} | Tail]) ->
_ ->
io:format("New table ~w~n", [Tab]),
make_tabs(Tail)
- end;
- Node ->
- io:format("** Table ~w already exists on ~p, just entering data~n",
- [Tab, Node]),
- make_tabs(Tail)
+ end
end;
make_tabs([]) ->
@@ -118,11 +118,9 @@ load_data(L) ->
parse(File) ->
case file(File) of
{ok, Terms} ->
- case catch collect(Terms) of
- {error, X} ->
- {error, X};
- Other ->
- {ok, Other}
+ try collect(Terms) of
+ Other -> {ok, Other}
+ catch throw:Error -> Error
end;
Other ->
Other
diff --git a/lib/mnesia/src/mnesia_tm.erl b/lib/mnesia/src/mnesia_tm.erl
index af658150da..b4b46228e9 100644
--- a/lib/mnesia/src/mnesia_tm.erl
+++ b/lib/mnesia/src/mnesia_tm.erl
@@ -51,6 +51,7 @@
]).
-include("mnesia.hrl").
+
-import(mnesia_lib, [set/2]).
-import(mnesia_lib, [fatal/2, verbose/2, dbg_out/2]).
@@ -119,7 +120,7 @@ init(Parent) ->
val(Var) ->
case ?catch_val(Var) of
- {'EXIT', _ReASoN_} -> mnesia_lib:other_val(Var, _ReASoN_);
+ {'EXIT', _} -> mnesia_lib:other_val(Var);
_VaLuE_ -> _VaLuE_
end.
@@ -224,11 +225,7 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor=
end;
{From, start_outer} -> %% Create and associate ets_tab with Tid
- case catch ?ets_new_table(mnesia_trans_store, [bag, public]) of
- {'EXIT', Reason} -> %% system limit
- Msg = "Cannot create an ets table for the "
- "local transaction store",
- reply(From, {error, {system_limit, Msg, Reason}}, State);
+ try ?ets_new_table(mnesia_trans_store, [bag, public]) of
Etab ->
tmlink(From),
C = mnesia_recover:incr_trans_tid_serial(),
@@ -237,6 +234,10 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor=
A2 = gb_trees:insert(Tid,[Etab],Coordinators),
S2 = State#state{coordinators = A2},
reply(From, {new_tid, Tid, Etab}, S2)
+ catch error:Reason -> %% system limit
+ Msg = "Cannot create an ets table for the "
+ "local transaction store",
+ reply(From, {error, {system_limit, Msg, Reason}}, State)
end;
{From, {ask_commit, Protocol, Tid, Commit, DiscNs, RamNs}} ->
@@ -339,15 +340,15 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor=
end;
{From, {add_store, Tid}} -> %% new store for nested transaction
- case catch ?ets_new_table(mnesia_trans_store, [bag, public]) of
- {'EXIT', Reason} -> %% system limit
- Msg = "Cannot create an ets table for a nested "
- "local transaction store",
- reply(From, {error, {system_limit, Msg, Reason}}, State);
+ try ?ets_new_table(mnesia_trans_store, [bag, public]) of
Etab ->
A2 = add_coord_store(Coordinators, Tid, Etab),
reply(From, {new_store, Etab},
State#state{coordinators = A2})
+ catch error:Reason -> %% system limit
+ Msg = "Cannot create an ets table for a nested "
+ "local transaction store",
+ reply(From, {error, {system_limit, Msg, Reason}}, State)
end;
{From, {del_store, Tid, Current, Obsolete, PropagateStore}} ->
@@ -471,13 +472,13 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor=
do_sync_dirty(From, Tid, Commit, _Tab) ->
?eval_debug_fun({?MODULE, sync_dirty, pre}, [{tid, Tid}]),
- Res = (catch do_dirty(Tid, Commit)),
+ Res = do_dirty(Tid, Commit),
?eval_debug_fun({?MODULE, sync_dirty, post}, [{tid, Tid}]),
From ! {?MODULE, node(), {dirty_res, Res}}.
do_async_dirty(Tid, Commit, _Tab) ->
?eval_debug_fun({?MODULE, async_dirty, pre}, [{tid, Tid}]),
- catch do_dirty(Tid, Commit),
+ do_dirty(Tid, Commit),
?eval_debug_fun({?MODULE, async_dirty, post}, [{tid, Tid}]).
@@ -501,7 +502,7 @@ process_dirty_queue(_Tab, []) ->
[].
prepare_pending_coordinators([{Tid, [Store | _Etabs]} | Coords], IgnoreNew) ->
- case catch ?ets_lookup(Store, pending) of
+ try ?ets_lookup(Store, pending) of
[] ->
prepare_pending_coordinators(Coords, IgnoreNew);
[Pending] ->
@@ -511,8 +512,8 @@ prepare_pending_coordinators([{Tid, [Store | _Etabs]} | Coords], IgnoreNew) ->
true ->
ignore
end,
- prepare_pending_coordinators(Coords, IgnoreNew);
- {'EXIT', _} ->
+ prepare_pending_coordinators(Coords, IgnoreNew)
+ catch error:_ ->
prepare_pending_coordinators(Coords, IgnoreNew)
end;
prepare_pending_coordinators([], _IgnoreNew) ->
@@ -573,11 +574,7 @@ recover_coordinator(Tid, Etabs) ->
Store = hd(Etabs),
CheckNodes = get_elements(nodes,Store),
TellNodes = CheckNodes -- [node()],
- case catch arrange(Tid, Store, async) of
- {'EXIT', Reason} ->
- dbg_out("Recovery of coordinator ~p failed:~n", [Tid, Reason]),
- Protocol = asym_trans,
- tell_outcome(Tid, Protocol, node(), CheckNodes, TellNodes);
+ try arrange(Tid, Store, async) of
{_N, Prep} ->
%% Tell the participants about the outcome
Protocol = Prep#prep.protocol,
@@ -596,6 +593,11 @@ recover_coordinator(Tid, Etabs) ->
false -> %% When killed before store havn't been copied to
ok %% to the new nested trans store.
end
+ catch _:Reason ->
+ dbg_out("Recovery of coordinator ~p failed:~n",
+ [Tid, {Reason, erlang:get_stacktrace()}]),
+ Protocol = asym_trans,
+ tell_outcome(Tid, Protocol, node(), CheckNodes, TellNodes)
end,
erase_ets_tabs(Etabs),
transaction_terminated(Tid),
@@ -724,33 +726,25 @@ non_transaction(OldState={_,_,Trans}, Fun, Args, ActivityKind, Mod)
_ -> async
end,
case transaction(OldState, Fun, Args, infinity, Mod, Kind) of
- {atomic, Res} ->
- Res;
- {aborted,Res} ->
- exit(Res)
+ {atomic, Res} -> Res;
+ {aborted,Res} -> exit(Res)
end;
non_transaction(OldState, Fun, Args, ActivityKind, Mod) ->
Id = {ActivityKind, self()},
NewState = {Mod, Id, non_transaction},
put(mnesia_activity_state, NewState),
- %% I Want something uniqe here, references are expensive
- Ref = mNeSia_nOn_TrAnSacTioN,
- RefRes = (catch {Ref, apply(Fun, Args)}),
- case OldState of
- undefined -> erase(mnesia_activity_state);
- _ -> put(mnesia_activity_state, OldState)
- end,
- case RefRes of
- {Ref, Res} ->
- case Res of
- {'EXIT', Reason} -> exit(Reason);
- {aborted, Reason} -> mnesia:abort(Reason);
- _ -> Res
- end;
- {'EXIT', Reason} ->
- exit(Reason);
- Throw ->
- throw(Throw)
+ try apply(Fun, Args) of
+ {'EXIT', Reason} -> exit(Reason);
+ {aborted, Reason} -> mnesia:abort(Reason);
+ Res -> Res
+ catch
+ throw:Throw -> throw(Throw);
+ _:Reason -> exit(Reason)
+ after
+ case OldState of
+ undefined -> erase(mnesia_activity_state);
+ _ -> put(mnesia_activity_state, OldState)
+ end
end.
transaction(OldTidTs, Fun, Args, Retries, Mod, Type) ->
@@ -810,23 +804,28 @@ insert_objs([], _Tab) ->
ok.
execute_transaction(Fun, Args, Factor, Retries, Type) ->
- case catch apply_fun(Fun, Args, Type) of
- {'EXIT', Reason} ->
- check_exit(Fun, Args, Factor, Retries, Reason, Type);
+ try apply_fun(Fun, Args, Type) of
{atomic, Value} ->
mnesia_lib:incr_counter(trans_commits),
erase(mnesia_activity_state),
%% no need to clear locks, already done by commit ...
%% Flush any un processed mnesia_down messages we might have
flush_downs(),
- catch unlink(whereis(?MODULE)),
+ ?SAFE(unlink(whereis(?MODULE))),
{atomic, Value};
+ {do_abort, Reason} ->
+ check_exit(Fun, Args, Factor, Retries, {aborted, Reason}, Type);
{nested_atomic, Value} ->
mnesia_lib:incr_counter(trans_commits),
- {atomic, Value};
- Value -> %% User called throw
+ {atomic, Value}
+ catch throw:Value -> %% User called throw
Reason = {aborted, {throw, Value}},
- return_abort(Fun, Args, Reason)
+ return_abort(Fun, Args, Reason);
+ error:Reason ->
+ ST = erlang:get_stacktrace(),
+ check_exit(Fun, Args, Factor, Retries, {Reason,ST}, Type);
+ _:Reason ->
+ check_exit(Fun, Args, Factor, Retries, Reason, Type)
end.
apply_fun(Fun, Args, Type) ->
@@ -836,10 +835,10 @@ apply_fun(Fun, Args, Type) ->
{atomic, Result};
do_commit_nested ->
{nested_atomic, Result};
- {do_abort, {aborted, Reason}} ->
- {'EXIT', {aborted, Reason}};
- {do_abort, Reason} ->
- {'EXIT', {aborted, Reason}}
+ {do_abort, {aborted, Reason}} ->
+ {do_abort, Reason};
+ {do_abort, _} = Abort ->
+ Abort
end.
check_exit(Fun, Args, Factor, Retries, Reason, Type) ->
@@ -943,7 +942,7 @@ return_abort(Fun, Args, Reason) ->
OldStore = Ts#tidstore.store,
Nodes = get_elements(nodes, OldStore),
intercept_friends(Tid, Ts),
- catch mnesia_lib:incr_counter(trans_failures),
+ ?SAFE(mnesia_lib:incr_counter(trans_failures)),
Level = Ts#tidstore.level,
if
Level == 1 ->
@@ -951,7 +950,7 @@ return_abort(Fun, Args, Reason) ->
?MODULE ! {delete_transaction, Tid},
erase(mnesia_activity_state),
flush_downs(),
- catch unlink(whereis(?MODULE)),
+ ?SAFE(unlink(whereis(?MODULE))),
{aborted, mnesia_lib:fix_error(Reason)};
true ->
%% Nested transaction
@@ -1005,11 +1004,11 @@ erase_activity_id() ->
erase(mnesia_activity_state).
get_elements(Type,Store) ->
- case catch ?ets_lookup(Store, Type) of
+ try ?ets_lookup(Store, Type) of
[] -> [];
[{_,Val}] -> [Val];
- {'EXIT', _} -> [];
Vals -> [Val|| {_,Val} <- Vals]
+ catch error:_ -> []
end.
opt_propagate_store(_Current, _Obsolete, false) ->
@@ -1032,7 +1031,7 @@ intercept_friends(_Tid, Ts) ->
intercept_best_friend([],_) -> ok;
intercept_best_friend([{stop,Fun} | R],Ignore) ->
- catch Fun(),
+ ?CATCH(Fun()),
intercept_best_friend(R,Ignore);
intercept_best_friend([Pid | R],false) ->
Pid ! {activity_ended, undefined, self()},
@@ -1046,25 +1045,12 @@ wait_for_best_friend(Pid, Timeout) ->
{'EXIT', Pid, _} -> ok;
{activity_ended, _, Pid} -> ok
after Timeout ->
- case my_process_is_alive(Pid) of
+ case erlang:is_process_alive(Pid) of
true -> wait_for_best_friend(Pid, 1000);
false -> ok
end
end.
-my_process_is_alive(Pid) ->
- case catch erlang:is_process_alive(Pid) of % New BIF in R5
- true ->
- true;
- false ->
- false;
- {'EXIT', _} -> % Pre R5 backward compatibility
- case process_info(Pid, message_queue_len) of
- undefined -> false;
- _ -> true
- end
- end.
-
dirty(Protocol, Item) ->
{{Tab, Key}, _Val, _Op} = Item,
Tid = {dirty, self()},
@@ -1144,18 +1130,8 @@ arrange(Tid, Store, Type) ->
async -> #prep{protocol = sym_trans, records = Recs};
sync -> #prep{protocol = sync_sym_trans, records = Recs}
end,
- case catch do_arrange(Tid, Store, Key, Prep, N) of
- {'EXIT', Reason} ->
- dbg_out("do_arrange failed ~p ~p~n", [Reason, Tid]),
- case Reason of
- {aborted, R} ->
- mnesia:abort(R);
- _ ->
- mnesia:abort(Reason)
- end;
- {New, Prepared} ->
- {New, Prepared#prep{records = reverse(Prepared#prep.records)}}
- end.
+ {New, Prepared} = do_arrange(Tid, Store, Key, Prep, N),
+ {New, Prepared#prep{records = reverse(Prepared#prep.records)}}.
reverse([]) ->
[];
@@ -1522,7 +1498,7 @@ multi_commit(asym_trans, Majority, Tid, CR, Store) ->
Pending = mnesia_checkpoint:tm_enter_pending(Tid, DiscNs, RamNs),
?ets_insert(Store, Pending),
{WaitFor, Local} = ask_commit(asym_trans, Tid, CR2, DiscNs, RamNs),
- SchemaPrep = (catch mnesia_schema:prepare_commit(Tid, Local, {coord, WaitFor})),
+ SchemaPrep = ?CATCH(mnesia_schema:prepare_commit(Tid, Local, {coord, WaitFor})),
{Votes, Pids} = rec_all(WaitFor, Tid, do_commit, []),
?eval_debug_fun({?MODULE, multi_commit_asym_got_votes},
@@ -1589,7 +1565,7 @@ rec_acc_pre_commit([Pid | Tail], Tid, Store, Commit, Res, DumperMode,
GoodPids, SchemaAckPids);
{mnesia_down, Node} when Node == node(Pid) ->
AbortRes = {do_abort, {bad_commit, Node}},
- catch Pid ! {Tid, AbortRes}, %% Tell him that he has died
+ ?SAFE(Pid ! {Tid, AbortRes}), %% Tell him that he has died
rec_acc_pre_commit(Tail, Tid, Store, Commit, AbortRes, DumperMode,
GoodPids, SchemaAckPids)
end;
@@ -1666,7 +1642,7 @@ commit_participant(Coord, Tid, C = #commit{}, DiscNs, RamNs) ->
commit_participant(Coord, Tid, Bin, C0, DiscNs, _RamNs) ->
?eval_debug_fun({?MODULE, commit_participant, pre}, [{tid, Tid}]),
- case catch mnesia_schema:prepare_commit(Tid, C0, {part, Coord}) of
+ try mnesia_schema:prepare_commit(Tid, C0, {part, Coord}) of
{Modified, C = #commit{}, DumperMode} ->
%% If we can not find any local unclear decision
%% we should presume abort at startup recovery
@@ -1742,9 +1718,8 @@ commit_participant(Coord, Tid, Bin, C0, DiscNs, _RamNs) ->
reply(Coord, {do_abort, Tid, self(), {bad_commit,internal}}),
verbose("** ERROR ** commit_participant ~p, got unexpected msg: ~p~n",
[Tid, Msg])
- end;
-
- {'EXIT', Reason} ->
+ end
+ catch _:Reason ->
?eval_debug_fun({?MODULE, commit_participant, vote_no},
[{tid, Tid}]),
reply(Coord, {vote_no, Tid, Reason}),
@@ -1790,22 +1765,20 @@ do_commit(Tid, C, DumperMode) ->
%% Update the items
do_update(Tid, Storage, [Op | Ops], OldRes) ->
- case catch do_update_op(Tid, Storage, Op) of
- ok ->
- do_update(Tid, Storage, Ops, OldRes);
- {'EXIT', Reason} ->
+ try do_update_op(Tid, Storage, Op) of
+ ok -> do_update(Tid, Storage, Ops, OldRes);
+ NewRes -> do_update(Tid, Storage, Ops, NewRes)
+ catch _:Reason ->
%% This may only happen when we recently have
%% deleted our local replica, changed storage_type
%% or transformed table
%% BUGBUG: Updates may be lost if storage_type is changed.
%% Determine actual storage type and try again.
%% BUGBUG: Updates may be lost if table is transformed.
-
+ ST = erlang:get_stacktrace(),
verbose("do_update in ~w failed: ~p -> {'EXIT', ~p}~n",
- [Tid, Op, Reason]),
- do_update(Tid, Storage, Ops, OldRes);
- NewRes ->
- do_update(Tid, Storage, Ops, NewRes)
+ [Tid, Op, {Reason, ST}]),
+ do_update(Tid, Storage, Ops, OldRes)
end;
do_update(_Tid, _Storage, [], Res) ->
Res.
@@ -1821,14 +1794,15 @@ do_update_op(Tid, Storage, {{Tab, K}, Val, delete}) ->
do_update_op(Tid, Storage, {{Tab, K}, {RecName, Incr}, update_counter}) ->
{NewObj, OldObjs} =
- case catch mnesia_lib:db_update_counter(Storage, Tab, K, Incr) of
- NewVal when is_integer(NewVal), NewVal >= 0 ->
- {{RecName, K, NewVal}, [{RecName, K, NewVal - Incr}]};
- _ when Incr > 0 ->
+ try
+ NewVal = mnesia_lib:db_update_counter(Storage, Tab, K, Incr),
+ true = is_integer(NewVal) andalso (NewVal >= 0),
+ {{RecName, K, NewVal}, [{RecName, K, NewVal - Incr}]}
+ catch error:_ when Incr > 0 ->
New = {RecName, K, Incr},
mnesia_lib:db_put(Storage, Tab, New),
{New, []};
- _ ->
+ error:_ ->
Zero = {RecName, K, 0},
mnesia_lib:db_put(Storage, Tab, Zero),
{Zero, []}
@@ -1913,16 +1887,14 @@ commit_clear([H|R], Tid, Tab, K, Obj)
do_snmp(_, []) -> ok;
do_snmp(Tid, [Head | Tail]) ->
- case catch mnesia_snmp_hook:update(Head) of
- {'EXIT', Reason} ->
+ try mnesia_snmp_hook:update(Head)
+ catch _:Reason ->
%% This should only happen when we recently have
%% deleted our local replica or recently deattached
%% the snmp table
-
+ ST = erlang:get_stacktrace(),
verbose("do_snmp in ~w failed: ~p -> {'EXIT', ~p}~n",
- [Tid, Head, Reason]);
- ok ->
- ignore
+ [Tid, Head, {Reason, ST}])
end,
do_snmp(Tid, Tail).
@@ -2093,7 +2065,7 @@ rec_all([Node | Tail], Tid, Res, Pids) ->
%% Make sure that mnesia_tm knows it has died
%% it may have been restarted
Abort = {do_abort, {bad_commit, Node}},
- catch {?MODULE, Node} ! {Tid, Abort},
+ ?SAFE({?MODULE, Node} ! {Tid, Abort}),
rec_all(Tail, Tid, Abort, Pids)
end;
rec_all([], _Tid, Res, Pids) ->
diff --git a/lib/mnesia/test/mnesia_config_backup.erl b/lib/mnesia/test/mnesia_config_backup.erl
index 0916e255e2..a7d8c04a45 100644
--- a/lib/mnesia/test/mnesia_config_backup.erl
+++ b/lib/mnesia/test/mnesia_config_backup.erl
@@ -90,7 +90,8 @@ open_read(Name) ->
List = lists:reverse(ReverseList),
{ok, #backup{name = Name, mode = read, items = List}};
{error, Reason} ->
- {error, {open_read, Reason}}
+ %% {error, {open_read, Reason}}
+ {Reason, error} %% Testing error handling in mnesia
end.
read(Opaque) when Opaque#backup.mode == read ->
diff --git a/lib/mnesia/test/mnesia_config_test.erl b/lib/mnesia/test/mnesia_config_test.erl
index c495bce63f..a8fb93b28e 100644
--- a/lib/mnesia/test/mnesia_config_test.erl
+++ b/lib/mnesia/test/mnesia_config_test.erl
@@ -37,7 +37,6 @@
dump_log_update_in_place/1,
event_module/1,
- ignore_fallback_at_startup/1,
inconsistent_database/1,
max_wait_for_decision/1,
send_compressed/1,
@@ -104,7 +103,7 @@ all() ->
[access_module, auto_repair, backup_module, debug, dir,
dump_log_load_regulation, {group, dump_log_thresholds},
dump_log_update_in_place,
- event_module, ignore_fallback_at_startup,
+ event_module,
inconsistent_database, max_wait_for_decision,
send_compressed, app_test, {group, schema_config},
unknown_config].
@@ -317,11 +316,17 @@ backup_module(Config) when is_list(Config) ->
?match([], mnesia_test_lib:start_mnesia(Nodes, [test_table, test_table2])),
%% Now check newly started tables
- ?match({atomic, [1,2]},
+ ?match({atomic, [1,2]},
mnesia:transaction(fun() -> lists:sort(mnesia:all_keys(test_table)) end)),
- ?match({atomic, [3,4]},
+ ?match({atomic, [3,4]},
mnesia:transaction(fun() -> lists:sort(mnesia:all_keys(test_table2)) end)),
-
+
+ %% Test some error cases
+ mnesia:set_debug_level(debug),
+ ?match({error, _}, mnesia:install_fallback("NonExisting.FILE")),
+ ?match({error, _}, mnesia:install_fallback(filename:join(mnesia_lib:dir(), "LATEST.LOG"))),
+
+ %% Cleanup
file:delete(File),
?verify_mnesia(Nodes, []),
?cleanup(1, Config),
@@ -609,13 +614,6 @@ dump_log_load_regulation(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-ignore_fallback_at_startup(doc) ->
- ["Start Mnesia without rollback of the database to the fallback. ",
- "Once Mnesia has been (re)started the installed fallback should",
- "be handled as a normal active fallback.",
- "Install a customized event module which disables the termination",
- "of Mnesia when mnesia_down occurrs with an active fallback."].
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
max_wait_for_decision(doc) ->
diff --git a/lib/mnesia/test/mnesia_evil_backup.erl b/lib/mnesia/test/mnesia_evil_backup.erl
index 9e0a8db1ae..68efa3f6ea 100644
--- a/lib/mnesia/test/mnesia_evil_backup.erl
+++ b/lib/mnesia/test/mnesia_evil_backup.erl
@@ -142,6 +142,9 @@ restore_errors(Config) when is_list(Config) ->
?match({aborted, {badarg, _}}, mnesia:restore(notAfile, [{skip_tables, xxx}])),
?match({aborted, {badarg, _}}, mnesia:restore(notAfile, [{recreate_tables, [schema]}])),
?match({aborted, {badarg, _}}, mnesia:restore(notAfile, [{default_op, asdklasd}])),
+ MnesiaDir = mnesia_lib:dir(),
+ ?match({aborted, {not_a_log_file, _}}, mnesia:restore(filename:join(MnesiaDir, "schema.DAT"), [])),
+ ?match({aborted, _}, mnesia:restore(filename:join(MnesiaDir, "LATEST.LOG"), [])),
ok.
restore_clear(suite) -> [];
@@ -488,6 +491,14 @@ install_fallback(Config) when is_list(Config) ->
mnesia_test_lib:kill_mnesia([Node1, Node2]),
timer:sleep(timer:seconds(1)), % Let it die!
+ ok = mnesia:start([{ignore_fallback_at_startup, true}]),
+ ok = mnesia:wait_for_tables([Tab, Tab2, Tab3], 10000),
+ ?match([{Tab, 6, test_nok}], mnesia:dirty_read({Tab, 6})),
+ mnesia_test_lib:kill_mnesia([Node1]),
+ application:set_env(mnesia, ignore_fallback_at_startup, false),
+
+ timer:sleep(timer:seconds(1)), % Let it die!
+
?match([], mnesia_test_lib:start_mnesia([Node1, Node2], [Tab, Tab2, Tab3])),
% Verify
@@ -510,6 +521,13 @@ install_fallback(Config) when is_list(Config) ->
file:delete(File3),
?match({error, _}, mnesia:install_fallback(File3)),
?match({error, _}, mnesia:install_fallback(File2, mnesia_badmod)),
+ ?match({error, _}, mnesia:install_fallback(File2, {foo, foo})),
+ ?match({error, _}, mnesia:install_fallback(File2, [{foo, foo}])),
+ ?match({error, {badarg, {skip_tables, _}}},
+ mnesia:install_fallback(File2, [{default_op, skip_tables},
+ {default_op, keep_tables},
+ {keep_tables, [Tab, Tab2, Tab3]},
+ {skip_tables, [foo,{asd}]}])),
?match(ok, mnesia:install_fallback(File2, mnesia_backup)),
?match(ok, file:delete(File)),
?match(ok, file:delete(File2)),
@@ -535,6 +553,7 @@ uninstall_fallback(Config) when is_list(Config) ->
?match(ok, mnesia:install_fallback(File2)),
?match(ok, file:delete(File)),
?match(ok, file:delete(File2)),
+ ?match({error, _}, mnesia:uninstall_fallback([foobar])),
?match(ok, mnesia:uninstall_fallback()),
mnesia_test_lib:kill_mnesia([Node1, Node2]),
diff --git a/lib/observer/src/Makefile b/lib/observer/src/Makefile
index c120865213..a42967644a 100644
--- a/lib/observer/src/Makefile
+++ b/lib/observer/src/Makefile
@@ -61,6 +61,7 @@ MODULES= \
etop_txt \
observer \
observer_app_wx \
+ observer_alloc_wx \
observer_html_lib \
observer_lib \
observer_perf_wx \
diff --git a/lib/observer/src/observer.app.src b/lib/observer/src/observer.app.src
index 197d0a2a95..e293990d64 100644
--- a/lib/observer/src/observer.app.src
+++ b/lib/observer/src/observer.app.src
@@ -44,6 +44,7 @@
etop_tr,
etop_txt,
observer,
+ observer_alloc_wx,
observer_app_wx,
observer_html_lib,
observer_lib,
diff --git a/lib/observer/src/observer_alloc_wx.erl b/lib/observer/src/observer_alloc_wx.erl
new file mode 100644
index 0000000000..0c4bc9ee4b
--- /dev/null
+++ b/lib/observer/src/observer_alloc_wx.erl
@@ -0,0 +1,256 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2015. 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%
+-module(observer_alloc_wx).
+
+-export([start_link/2]).
+
+%% wx_object callbacks
+-export([init/1, handle_info/2, terminate/2, code_change/3, handle_call/3,
+ handle_event/2, handle_sync_event/3, handle_cast/2]).
+
+-behaviour(wx_object).
+-include_lib("wx/include/wx.hrl").
+-include("observer_defs.hrl").
+
+-record(state,
+ {
+ offset = 0.0,
+ active = false,
+ parent,
+ windows,
+ data = {0, queue:new()},
+ panel,
+ paint,
+ appmon,
+ async
+ }).
+
+-define(ALLOC_W, 1).
+-define(UTIL_W, 2).
+
+start_link(Notebook, Parent) ->
+ wx_object:start_link(?MODULE, [Notebook, Parent], []).
+
+init([Notebook, Parent]) ->
+ try
+ Panel = wxPanel:new(Notebook),
+ Main = wxBoxSizer:new(?wxVERTICAL),
+ Style = ?wxFULL_REPAINT_ON_RESIZE bor ?wxCLIP_CHILDREN,
+ Carrier = wxPanel:new(Panel, [{winid, ?ALLOC_W}, {style,Style}]),
+ Utilz = wxPanel:new(Panel, [{winid, ?UTIL_W}, {style,Style}]),
+ BorderFlags = ?wxLEFT bor ?wxRIGHT,
+ wxSizer:add(Main, Carrier, [{flag, ?wxEXPAND bor BorderFlags bor ?wxTOP},
+ {proportion, 1}, {border, 5}]),
+
+ wxSizer:add(Main, Utilz, [{flag, ?wxEXPAND bor BorderFlags},
+ {proportion, 1}, {border, 5}]),
+
+ MemWin = {MemPanel,_} = create_mem_info(Panel),
+ wxSizer:add(Main, MemPanel, [{flag, ?wxEXPAND bor BorderFlags bor ?wxBOTTOM},
+ {proportion, 1}, {border, 5}]),
+ wxWindow:setSizer(Panel, Main),
+
+ PaintInfo = observer_perf_wx:setup_graph_drawing([Carrier, Utilz]),
+ {Panel, #state{parent=Parent,
+ panel =Panel,
+ windows = {Carrier, Utilz, MemWin},
+ paint=PaintInfo}
+ }
+ catch _:Err ->
+ io:format("~p crashed ~p: ~p~n",[?MODULE, Err, erlang:get_stacktrace()]),
+ {stop, Err}
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+handle_event(#wx{event=#wxCommand{type=command_menu_selected}},
+ State = #state{}) ->
+ {noreply, State};
+
+handle_event(Event, _State) ->
+ error({unhandled_event, Event}).
+
+%%%%%%%%%%
+handle_sync_event(#wx{obj=Panel, event = #wxPaint{}},_,
+ #state{active=Active, offset=Offset, paint=Paint,
+ windows=Windows, data=Data}) ->
+ %% Sigh workaround bug on MacOSX (Id in paint event is always 0)
+ Id = if Panel =:= element(?ALLOC_W, Windows) -> alloc;
+ Panel =:= element(?UTIL_W, Windows) -> utilz
+ end,
+ observer_perf_wx:refresh_panel(Panel, Id, Offset, Data, Active, Paint),
+ ok.
+%%%%%%%%%%
+handle_call(Event, From, _State) ->
+ error({unhandled_call, Event, From}).
+
+handle_cast(Event, _State) ->
+ error({unhandled_cast, Event}).
+%%%%%%%%%%
+
+handle_info({Key, {promise_reply, {badrpc, _}}}, #state{async=Key} = State) ->
+ {noreply, State#state{active=false, appmon=undefined}};
+
+handle_info({Key, {promise_reply, SysInfo}}, #state{async=Key, data=Data} = State) ->
+ Info = alloc_info(SysInfo),
+ update_alloc(State, Info),
+ {noreply, State#state{offset=0.0, data = add_data(Info, Data), async=undefined}};
+
+handle_info({refresh, Seq, Freq, Node}, #state{panel=Panel, appmon=Node, async=Key} = State) ->
+ wxWindow:refresh(Panel),
+ Next = Seq+1,
+ if
+ Next > Freq, Key =:= undefined ->
+ erlang:send_after(trunc(1000 / Freq), self(), {refresh, 1, Freq, Node}),
+ Req = rpc:async_call(Node, observer_backend, sys_info, []),
+ {noreply, State#state{offset=Seq/Freq, async=Req}};
+ true ->
+ erlang:send_after(trunc(1000 / Freq), self(), {refresh, Next, Freq, Node}),
+ {noreply, State#state{offset=Seq/Freq}}
+ end;
+handle_info({refresh, _Seq, _Freq, _Node}, State) ->
+ {noreply, State};
+
+handle_info({active, Node}, State = #state{parent=Parent, panel=Panel, appmon=Old}) ->
+ create_menus(Parent, []),
+ try
+ Node = Old,
+ wxWindow:refresh(Panel),
+ {noreply, State#state{active=true}}
+ catch _:_ ->
+ SysInfo = observer_wx:try_rpc(Node, observer_backend, sys_info, []),
+ Info = alloc_info(SysInfo),
+ Freq = 6,
+ erlang:send_after(trunc(1000 / Freq), self(), {refresh, 1, Freq, Node}),
+ wxWindow:refresh(Panel),
+ {noreply, State#state{active=true, appmon=Node, offset=0.0,
+ data = add_data(Info, {0, queue:new()})}}
+ end;
+
+handle_info(not_active, State = #state{appmon=_Pid}) ->
+ {noreply, State#state{active=false}};
+
+handle_info({'EXIT', Old, _}, State = #state{appmon=Old}) ->
+ {noreply, State#state{active=false, appmon=undefined}};
+
+handle_info(_Event, State) ->
+ %% io:format("~p:~p: ~p~n",[?MODULE,?LINE,_Event]),
+ {noreply, State}.
+
+terminate(_Event, #state{}) ->
+ ok.
+code_change(_, _, State) ->
+ State.
+
+%%%%%%%%%%
+
+add_data(Stats, {N, Q}) when N > 60 ->
+ {N, queue:drop(queue:in(Stats, Q))};
+add_data(Stats, {N, Q}) ->
+ {N+1, queue:in(Stats, Q)}.
+
+update_alloc(#state{windows={_, _, {_, Grid}}}, Fields) ->
+ Max = wxListCtrl:getItemCount(Grid),
+ Update = fun({Name, BS, CS}, Row) ->
+ (Row >= Max) andalso wxListCtrl:insertItem(Grid, Row, ""),
+ wxListCtrl:setItem(Grid, Row, 0, observer_lib:to_str(Name)),
+ wxListCtrl:setItem(Grid, Row, 1, observer_lib:to_str(BS div 1024)),
+ wxListCtrl:setItem(Grid, Row, 2, observer_lib:to_str(CS div 1024)),
+ Row + 1
+ end,
+ lists:foldl(Update, 0, Fields),
+ Fields.
+
+alloc_info(SysInfo) ->
+ AllocInfo = proplists:get_value(alloc_info, SysInfo, []),
+ alloc_info(AllocInfo, [], 0, 0, true).
+
+alloc_info([{Type,Instances}|Allocators],TypeAcc,TotalBS,TotalCS,IncludeTotal) ->
+ {BS,CS,NewTotalBS,NewTotalCS,NewIncludeTotal} =
+ sum_alloc_instances(Instances,0,0,TotalBS,TotalCS),
+ alloc_info(Allocators,[{Type,BS,CS}|TypeAcc],NewTotalBS,NewTotalCS,
+ IncludeTotal andalso NewIncludeTotal);
+alloc_info([],TypeAcc,TotalBS,TotalCS,IncludeTotal) ->
+ Types = [X || X={_,BS,CS} <- TypeAcc, (BS>0 orelse CS>0)],
+ case IncludeTotal of
+ true ->
+ [{total,TotalBS,TotalCS} | lists:reverse(Types)];
+ false ->
+ lists:reverse(Types)
+ end.
+
+sum_alloc_instances(false,BS,CS,TotalBS,TotalCS) ->
+ {BS,CS,TotalBS,TotalCS,false};
+sum_alloc_instances([{_,_,Data}|Instances],BS,CS,TotalBS,TotalCS) ->
+ {NewBS,NewCS,NewTotalBS,NewTotalCS} =
+ sum_alloc_one_instance(Data,BS,CS,TotalBS,TotalCS),
+ sum_alloc_instances(Instances,NewBS,NewCS,NewTotalBS,NewTotalCS);
+sum_alloc_instances([],BS,CS,TotalBS,TotalCS) ->
+ {BS,CS,TotalBS,TotalCS,true}.
+
+sum_alloc_one_instance([{sbmbcs,[{blocks_size,BS,_,_},{carriers_size,CS,_,_}]}|
+ Rest],OldBS,OldCS,TotalBS,TotalCS) ->
+ sum_alloc_one_instance(Rest,OldBS+BS,OldCS+CS,TotalBS,TotalCS);
+sum_alloc_one_instance([{_,[{blocks_size,BS,_,_},{carriers_size,CS,_,_}]}|
+ Rest],OldBS,OldCS,TotalBS,TotalCS) ->
+ sum_alloc_one_instance(Rest,OldBS+BS,OldCS+CS,TotalBS+BS,TotalCS+CS);
+sum_alloc_one_instance([{_,[{blocks_size,BS},{carriers_size,CS}]}|
+ Rest],OldBS,OldCS,TotalBS,TotalCS) ->
+ sum_alloc_one_instance(Rest,OldBS+BS,OldCS+CS,TotalBS+BS,TotalCS+CS);
+sum_alloc_one_instance([_|Rest],BS,CS,TotalBS,TotalCS) ->
+ sum_alloc_one_instance(Rest,BS,CS,TotalBS,TotalCS);
+sum_alloc_one_instance([],BS,CS,TotalBS,TotalCS) ->
+ {BS,CS,TotalBS,TotalCS}.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+create_mem_info(Parent) ->
+ Panel = wxPanel:new(Parent),
+ wxWindow:setBackgroundColour(Panel, {255,255,255}),
+ Style = ?wxLC_REPORT bor ?wxLC_SINGLE_SEL bor ?wxLC_HRULES bor ?wxLC_VRULES,
+ Grid = wxListCtrl:new(Panel, [{style, Style}]),
+ Li = wxListItem:new(),
+ AddListEntry = fun({Name, Align, DefSize}, Col) ->
+ wxListItem:setText(Li, Name),
+ wxListItem:setAlign(Li, Align),
+ wxListCtrl:insertColumn(Grid, Col, Li),
+ wxListCtrl:setColumnWidth(Grid, Col, DefSize),
+ Col + 1
+ end,
+ ListItems = [{"Allocator Type", ?wxLIST_FORMAT_LEFT, 200},
+ {"Block size (kB)", ?wxLIST_FORMAT_RIGHT, 150},
+ {"Carrier size (kB)",?wxLIST_FORMAT_RIGHT, 150}],
+ lists:foldl(AddListEntry, 0, ListItems),
+ wxListItem:destroy(Li),
+
+ Sizer = wxBoxSizer:new(?wxVERTICAL),
+ wxSizer:add(Sizer, Grid, [{flag, ?wxEXPAND bor ?wxLEFT bor ?wxRIGHT},
+ {border, 5}, {proportion, 1}]),
+ wxWindow:setSizerAndFit(Panel, Sizer),
+ {Panel, Grid}.
+
+
+create_menus(Parent, _) ->
+ MenuEntries =
+ [{"File",
+ [
+ ]}
+ ],
+ observer_wx:create_menus(Parent, MenuEntries).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/observer/src/observer_lib.erl b/lib/observer/src/observer_lib.erl
index 34c7b127ff..9592ab5977 100644
--- a/lib/observer/src/observer_lib.erl
+++ b/lib/observer/src/observer_lib.erl
@@ -493,8 +493,11 @@ link_entry2(Panel,{Target,Str},Cursor) ->
wxWindow:setToolTip(TC, ToolTip),
TC.
-to_link(Tuple = {_Target, _Str}) ->
- Tuple;
+to_link(RegName={Name, Node}) when is_atom(Name), is_atom(Node) ->
+ Str = io_lib:format("{~p,~p}", [Name, Node]),
+ {RegName, Str};
+to_link(TI = {_Target, _Identifier}) ->
+ TI;
to_link(Target0) ->
Target=to_str(Target0),
{Target, Target}.
diff --git a/lib/observer/src/observer_perf_wx.erl b/lib/observer/src/observer_perf_wx.erl
index 8173349ed7..4df9218087 100644
--- a/lib/observer/src/observer_perf_wx.erl
+++ b/lib/observer/src/observer_perf_wx.erl
@@ -24,7 +24,8 @@
handle_event/2, handle_sync_event/3, handle_cast/2]).
%% Drawing wrappers for DC and GC areas
--export([haveGC/0,
+-export([setup_graph_drawing/1, refresh_panel/6,
+ haveGC/0,
setPen/2, setFont/3, setBrush/2,
strokeLine/5, strokeLines/2, drawRoundedRectangle/6,
drawText/4, getTextExtent/2]).
@@ -42,13 +43,12 @@
data = {0, queue:new()},
panel,
paint,
- appmon,
- usegc = false
+ appmon
}).
-define(wxGC, wxGraphicsContext).
--record(paint, {font, small, pen, pen2, pens}).
+-record(paint, {font, small, pen, pen2, pens, usegc = false}).
-define(RQ_W, 1).
-define(MEM_W, 2).
@@ -63,14 +63,11 @@ init([Notebook, Parent]) ->
Main = wxBoxSizer:new(?wxVERTICAL),
Style = ?wxFULL_REPAINT_ON_RESIZE bor ?wxCLIP_CHILDREN,
CPU = wxPanel:new(Panel, [{winid, ?RQ_W}, {style,Style}]),
- wxWindow:setBackgroundColour(CPU, ?wxWHITE),
wxSizer:add(Main, CPU, [{flag, ?wxEXPAND bor ?wxALL},
{proportion, 1}, {border, 5}]),
MemIO = wxBoxSizer:new(?wxHORIZONTAL),
MEM = wxPanel:new(Panel, [{winid, ?MEM_W}, {style,Style}]),
- wxWindow:setBackgroundColour(MEM, ?wxWHITE),
IO = wxPanel:new(Panel, [{winid, ?IO_W}, {style,Style}]),
- wxWindow:setBackgroundColour(IO, ?wxWHITE),
wxSizer:add(MemIO, MEM, [{flag, ?wxEXPAND bor ?wxLEFT},
{proportion, 1}, {border, 5}]),
wxSizer:add(MemIO, IO, [{flag, ?wxEXPAND bor ?wxLEFT bor ?wxRIGHT},
@@ -79,53 +76,56 @@ init([Notebook, Parent]) ->
{proportion, 1}, {border, 5}]),
wxWindow:setSizer(Panel, Main),
- wxPanel:connect(CPU, paint, [callback]),
- wxPanel:connect(IO, paint, [callback]),
- wxPanel:connect(MEM, paint, [callback]),
- case os:type() of
- {win32, _} -> %% Ignore erase on windows
- wxPanel:connect(CPU, erase_background, [{callback, fun(_,_) -> ok end}]),
- wxPanel:connect(IO, erase_background, [{callback, fun(_,_) -> ok end}]),
- wxPanel:connect(MEM, erase_background, [{callback, fun(_,_) -> ok end}]);
- _ -> ok
- end,
+ PaintInfo = setup_graph_drawing([CPU, MEM, IO]),
+ process_flag(trap_exit, true),
+ {Panel, #state{parent=Parent,
+ panel =Panel,
+ windows = {CPU, MEM, IO},
+ paint=PaintInfo
+ }}
+ catch _:Err ->
+ io:format("~p crashed ~p: ~p~n",[?MODULE, Err, erlang:get_stacktrace()]),
+ {stop, Err}
+ end.
+
+setup_graph_drawing(Panels) ->
+ IsWindows = element(1, os:type()) =:= win32,
+ IgnoreCB = {callback, fun(_,_) -> ok end},
+ Do = fun(Panel) ->
+ wxWindow:setBackgroundColour(Panel, ?wxWHITE),
+ wxPanel:connect(Panel, paint, [callback]),
+ IsWindows andalso
+ wxPanel:connect(Panel, erase_background, [IgnoreCB])
+ end,
+ _ = [Do(Panel) || Panel <- Panels],
UseGC = haveGC(),
Version28 = ?wxMAJOR_VERSION =:= 2 andalso ?wxMINOR_VERSION =:= 8,
{Font, SmallFont}
- = case os:type() of
- {unix, _} when UseGC, Version28 ->
+ = if UseGC, Version28 ->
%% Def font is really small when using Graphics contexts in 2.8
%% Hardcode it
F = wxFont:new(12,?wxFONTFAMILY_DECORATIVE,?wxFONTSTYLE_NORMAL,?wxFONTWEIGHT_BOLD),
SF = wxFont:new(10, ?wxFONTFAMILY_DECORATIVE, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_NORMAL),
{F, SF};
- _ ->
+ true ->
DefFont = wxSystemSettings:getFont(?wxSYS_DEFAULT_GUI_FONT),
DefSize = wxFont:getPointSize(DefFont),
DefFamily = wxFont:getFamily(DefFont),
- F = wxFont:new(DefSize, DefFamily, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_BOLD),
- SF = wxFont:new(DefSize-1, DefFamily, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_NORMAL),
+ F = wxFont:new(DefSize-1, DefFamily, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_BOLD),
+ SF = wxFont:new(DefSize-2, DefFamily, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_NORMAL),
{F, SF}
end,
BlackPen = wxPen:new({0,0,0}, [{width, 2}]),
- Pens = [wxPen:new(Col, [{width, 2}]) || Col <- tuple_to_list(colors())],
- process_flag(trap_exit, true),
- {Panel, #state{parent=Parent,
- panel =Panel,
- windows = {CPU, MEM, IO},
- usegc=UseGC,
- paint=#paint{font = Font,
- small = SmallFont,
- pen = ?wxGREY_PEN,
- pen2 = BlackPen,
- pens = list_to_tuple(Pens)
- }
- }}
- catch _:Err ->
- io:format("~p crashed ~p: ~p~n",[?MODULE, Err, erlang:get_stacktrace()]),
- {stop, Err}
- end.
+ Pens = [wxPen:new(Col, [{width, 3}]) || Col <- tuple_to_list(colors())],
+ #paint{usegc = UseGC,
+ font = Font,
+ small = SmallFont,
+ pen = ?wxGREY_PEN,
+ pen2 = BlackPen,
+ pens = list_to_tuple(Pens)
+ }.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -139,21 +139,25 @@ handle_event(Event, _State) ->
%%%%%%%%%%
handle_sync_event(#wx{obj=Panel, event = #wxPaint{}},_,
#state{active=Active, offset=Offset, paint=Paint,
- windows=Windows, data=Data, usegc=UseGC}) ->
- %% PaintDC must be created in a callback to work on windows.
+ windows=Windows, data=Data}) ->
%% Sigh workaround bug on MacOSX (Id in paint event is always 0)
%% Panel = element(Id, Windows),
- Id = if Panel =:= element(?RQ_W, Windows) -> ?RQ_W;
- Panel =:= element(?MEM_W, Windows) -> ?MEM_W;
- Panel =:= element(?IO_W, Windows) -> ?IO_W
+ Id = if Panel =:= element(?RQ_W, Windows) -> runq;
+ Panel =:= element(?MEM_W, Windows) -> memory;
+ Panel =:= element(?IO_W, Windows) -> io
end,
- IsWindows = element(1, os:type()) =:= win32,
- DC = if IsWindows ->
+ refresh_panel(Panel, Id, Offset, Data, Active, Paint),
+ ok.
+
+refresh_panel(Panel, Id, Offset, Data, Active, #paint{usegc=UseGC} = Paint) ->
+ %% PaintDC must be created in a callback to work on windows.
+ IsWindows = element(1, os:type()) =:= win32,
+ DC = if IsWindows ->
%% Ugly hack to aviod flickering on windows, works on windows only
%% But the other platforms are doublebuffered by default
wx:typeCast(wxBufferedPaintDC:new(Panel), wxPaintDC);
- true ->
+ true ->
wxPaintDC:new(Panel)
end,
IsWindows andalso wxDC:clear(DC),
@@ -167,8 +171,9 @@ handle_sync_event(#wx{obj=Panel, event = #wxPaint{}},_,
io:format("Internal error ~p ~p~n",[Err, erlang:get_stacktrace()])
end,
UseGC andalso ?wxGC:destroy(GC),
- wxPaintDC:destroy(DC),
- ok.
+ wxPaintDC:destroy(DC).
+
+
%%%%%%%%%%
handle_call(Event, From, _State) ->
error({unhandled_call, Event, From}).
@@ -247,10 +252,10 @@ create_menus(Parent, _) ->
observer_wx:create_menus(Parent, MenuEntries).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-collect_data(?RQ_W, {N, Q}) ->
+collect_data(runq, {N, Q}) ->
case queue:to_list(Q) of
- [] -> {0, 0, []};
- [_] -> {0, 0, []};
+ [] -> {0, 0, [], []};
+ [_] -> {0, 0, [], []};
[{stats, _Ver, Init0, _IO, _Mem}|Data0] ->
Init = lists:sort(Init0),
[_|Data=[First|_]] = lists:foldl(fun({stats, _, T0, _, _}, [Prev|Acc]) ->
@@ -258,25 +263,46 @@ collect_data(?RQ_W, {N, Q}) ->
Delta = calc_delta(TN, Prev),
[TN, list_to_tuple(Delta)|Acc]
end, [Init], Data0),
- {N, lmax(Data), lists:reverse([First|Data])}
+ NoGraphs = tuple_size(First),
+ {N, lmax(Data), lists:reverse([First|Data]), lists:seq(1, NoGraphs)}
end;
-collect_data(?MEM_W, {N, Q}) ->
+collect_data(memory, {N, Q}) ->
MemT = mem_types(),
Data = [list_to_tuple([Value || {Type,Value} <- MemInfo,
lists:member(Type, MemT)])
|| {stats, _Ver, _RQ, _IO, MemInfo} <- queue:to_list(Q)],
- {N, lmax(Data), Data};
-collect_data(?IO_W, {N, Q}) ->
+ {N, lmax(Data), Data, MemT};
+collect_data(io, {N, Q}) ->
case queue:to_list(Q) of
- [] -> {0, 0, []};
- [_] -> {0, 0, []};
+ [] -> {0, 0, [], []};
+ [_] -> {0, 0, [], []};
[{stats, _Ver, _RQ, {{_,In0}, {_,Out0}}, _Mem}|Data0] ->
[_,_|Data=[First|_]] =
lists:foldl(fun({stats, _, _, {{_,In}, {_,Out}}, _}, [PIn,Pout|Acc]) ->
[In,Out,{In-PIn,Out-Pout}|Acc]
end, [In0,Out0], Data0),
- {N, lmax(Data), lists:reverse([First|Data])}
- end.
+ {N, lmax(Data), lists:reverse([First|Data]), [input, output]}
+ end;
+collect_data(alloc, {N, Q}) ->
+ List = queue:to_list(Q),
+ Data = [list_to_tuple([Carrier || {_Type,_Block,Carrier} <- MemInfo])
+ || MemInfo <- List],
+ Info = case List of %% Varies depending on erlang build config/platform
+ [MInfo|_] -> [Type || {Type, _, _} <- MInfo];
+ _ -> []
+ end,
+ {N, lmax(Data), Data, Info};
+
+collect_data(utilz, {N, Q}) ->
+ List = queue:to_list(Q),
+ Data = [list_to_tuple([round(100*Block/Carrier) || {_Type,Block,Carrier} <- MemInfo])
+ || MemInfo <- List],
+ Info = case List of %% Varies depending on erlang build config/platform
+ [MInfo|_] -> [Type || {Type, _, _} <- MInfo];
+ _ -> []
+ end,
+ {N, lmax(Data), Data, Info}.
+
mem_types() ->
[total, processes, atom, binary, code, ets].
@@ -299,14 +325,14 @@ draw(Offset, Id, DC, Panel, Paint=#paint{pens=Pens, small=Small}, Data, Active)
%% This can be optimized a lot by collecting data once
%% and draw to memory and then blit memory and only draw new entries in new memory
%% area. Hmm now rewritten to use ?wxGC I don't now if it is feasable.
- {Len, Max0, Hs} = collect_data(Id, Data),
- Max = calc_max(Max0),
- NoGraphs = try tuple_size(hd(Hs)) catch _:_ -> 0 end,
+ {Len, Max0, Hs, Info} = collect_data(Id, Data),
+ {Max,_,_} = MaxDisp = calc_max(Id, Max0),
Size = wxWindow:getClientSize(Panel),
- {X0,Y0,WS,HS} = draw_borders(Id, NoGraphs, DC, Size, Max, Paint),
+ {X0,Y0,WS,HS, DrawBs} = draw_borders(Id, Info, DC, Size, MaxDisp, Paint),
Last = 60*WS+X0-1,
Start = max(61-Len, 0)*WS+X0 - Offset*WS,
Samples = length(Hs),
+ NoGraphs = try tuple_size(hd(Hs)) catch _:_ -> 0 end,
case Active andalso Samples > 1 andalso NoGraphs > 0 of
true ->
Draw = fun(N) ->
@@ -315,14 +341,16 @@ draw(Offset, Id, DC, Panel, Paint=#paint{pens=Pens, small=Small}, Data, Active)
strokeLines(DC, Lines),
N+1
end,
- [Draw(I) || I <- lists:seq(NoGraphs, 1, -1)];
+ [Draw(I) || I <- lists:seq(NoGraphs, 1, -1)],
+ DrawBs();
false ->
- Info = case Active andalso Samples =< 1 of
- true -> "Waiting on data";
+ DrawBs(),
+ Text = case Active andalso Samples =< 1 of
+ true -> "Waiting for data";
false -> "Information not available"
end,
setFont(DC, Small, {0,0,0}),
- drawText(DC, Info, X0 + 100, element(2,Size) div 2)
+ drawText(DC, Text, X0 + 100, element(2,Size) div 2)
end,
ok.
@@ -397,9 +425,8 @@ spline_tan(Y0, Y1, Y2, Y3) ->
-define(BW, 5).
-define(BH, 5).
-draw_borders(Type, NoGraphs, DC, {W,H}, Max,
+draw_borders(Type, Info, DC, {W,H}, {Max, Unit, MaxUnit},
#paint{pen=Pen, pen2=Pen2, font=Font, small=Small}) ->
- {Unit, MaxUnit} = bytes(Type, Max),
Str1 = observer_lib:to_str(MaxUnit),
Str2 = observer_lib:to_str(MaxUnit div 2),
Str3 = observer_lib:to_str(0),
@@ -410,10 +437,10 @@ draw_borders(Type, NoGraphs, DC, {W,H}, Max,
GraphX0 = ?BW+TW+?BW,
GraphX1 = W-?BW*4,
- TopTextX = ?BW+TW+?BW,
- MaxTextY = ?BH+TH+?BH,
+ TopTextX = ?BW*3+TW,
+ MaxTextY = TH+?BH,
BottomTextY = H-?BH-TH,
- SecondsY = BottomTextY - ?BH - TH,
+ SecondsY = BottomTextY - TH,
GraphY0 = MaxTextY + (TH / 2),
GraphY1 = SecondsY - ?BH,
GraphW = GraphX1-GraphX0-1,
@@ -447,17 +474,7 @@ draw_borders(Type, NoGraphs, DC, {W,H}, Max,
strokeLine(DC, GraphX0-3, GraphY50, GraphX1, GraphY50),
strokeLine(DC, GraphX0-3, GraphY75, GraphX1, GraphY75),
- setPen(DC, Pen2),
- strokeLines(DC, [{GraphX0, GraphY0-1}, {GraphX0, GraphY1+1},
- {GraphX1, GraphY1+1}, {GraphX1, GraphY0-1},
- {GraphX0, GraphY0-1}]),
-
setFont(DC, Font, {0,0,0}),
- case Type of
- ?RQ_W -> drawText(DC, "Scheduler Utilization (%) ", TopTextX,?BH);
- ?MEM_W -> drawText(DC, "Memory Usage " ++ Unit, TopTextX,?BH);
- ?IO_W -> drawText(DC, "IO Usage " ++ Unit, TopTextX,?BH)
- end,
Text = fun(X,Y, Str, PenId) ->
if PenId == 0 ->
@@ -468,32 +485,65 @@ draw_borders(Type, NoGraphs, DC, {W,H}, Max,
end,
drawText(DC, Str, X, Y),
{StrW, _} = getTextExtent(DC, Str),
- StrW + X + SpaceW
+ StrW + X + ?BW*2
end,
+
case Type of
- ?RQ_W ->
- TN0 = Text(?BW, BottomTextY, "Scheduler: ", 0),
+ runq ->
+ drawText(DC, "Scheduler Utilization (%) ", TopTextX, ?BH),
+ TN0 = Text(TopTextX, BottomTextY, "Scheduler: ", 0),
lists:foldl(fun(Id, Pos0) ->
Text(Pos0, BottomTextY, integer_to_list(Id), Id)
- end, TN0, lists:seq(1, NoGraphs));
- ?MEM_W ->
+ end, TN0, Info);
+ memory ->
+ drawText(DC, "Memory Usage " ++ Unit, TopTextX,?BH),
+ lists:foldl(fun(MType, {PenId, Pos0}) ->
+ Str = to_string(MType),
+ Pos = Text(Pos0, BottomTextY, Str, PenId),
+ {PenId+1, Pos}
+ end, {1, TopTextX}, Info);
+ io ->
+ drawText(DC, "IO Usage " ++ Unit, TopTextX,?BH),
+ lists:foldl(fun(MType, {PenId, Pos0}) ->
+ Str = to_string(MType),
+ Pos = Text(Pos0, BottomTextY, Str, PenId),
+ {PenId+1, Pos}
+ end, {1, TopTextX}, Info);
+ alloc ->
+ drawText(DC, "Carrier Size " ++ Unit, TopTextX,?BH);
+ utilz ->
+ drawText(DC, "Carrier Utilization (%)" ++ Unit, TopTextX,?BH),
lists:foldl(fun(MType, {PenId, Pos0}) ->
- Str = uppercase(atom_to_list(MType)),
+ Str = to_string(MType),
Pos = Text(Pos0, BottomTextY, Str, PenId),
{PenId+1, Pos}
- end, {1, ?BW}, mem_types());
- ?IO_W ->
- TN0 = Text(?BW, BottomTextY, "Input", 1),
- Text(TN0, BottomTextY, "Output", 2)
+ end, {1, TopTextX}, Info)
end,
- {GraphX0+1, GraphY1, ScaleW, ScaleH}.
+ DrawBorder = fun() ->
+ setPen(DC, Pen2),
+ strokeLines(DC, [{GraphX0, GraphY0-1}, {GraphX0, GraphY1+1},
+ {GraphX1, GraphY1+1}, {GraphX1, GraphY0-1},
+ {GraphX0, GraphY0-1}])
+ end,
+ {GraphX0+1, GraphY1, ScaleW, ScaleH, DrawBorder}.
+
+to_string(Atom) ->
+ Name = atom_to_list(Atom),
+ case lists:reverse(Name) of
+ "colla_" ++ Rev ->
+ uppercase(lists:reverse(Rev));
+ _ ->
+ uppercase(Name)
+ end.
uppercase([C|Rest]) ->
[C-$a+$A|Rest].
-calc_max(Max) when Max < 10 -> 10;
-calc_max(Max) -> calc_max1(Max).
+calc_max(Type, Max) ->
+ bytes(Type, Max).
+calc_max1(Max) when Max < 10 ->
+ 10;
calc_max1(Max) ->
case Max div 10 of
X when X < 10 ->
@@ -506,23 +556,36 @@ calc_max1(Max) ->
10*calc_max1(X)
end.
-bytes(?RQ_W, Val) -> {"", Val};
+bytes(runq, Val) ->
+ Upper = calc_max1(Val),
+ {Upper, "", Upper};
+bytes(utilz, Val) ->
+ Upper = calc_max1(Val),
+ {Upper, "", Upper};
bytes(_, B) ->
KB = B div 1024,
MB = KB div 1024,
GB = MB div 1024,
if
- GB > 10 -> {"(GB)", GB};
- MB > 10 -> {"(MB)", MB};
- KB > 0 -> {"(KB)", KB};
- true -> {"(B)", B}
+ GB > 10 ->
+ Upper = calc_max1(GB),
+ {Upper*1024*1024*1024, "(GB)", Upper};
+ MB > 10 ->
+ Upper = calc_max1(MB),
+ {Upper*1024*1024, "(MB)", Upper};
+ KB > 0 ->
+ Upper = calc_max1(KB),
+ {Upper*1024, "(KB)", Upper};
+ true ->
+ Upper = calc_max1(B),
+ {Upper, "(B)", Upper}
end.
colors() ->
- {{200, 50, 50}, {50, 200, 50}, {50, 50, 200},
- {255, 110, 0}, {50, 200, 200}, {200, 50, 200},
- {240, 200, 80}, {140, 2, 140},
- {100, 200, 240}, {100, 240, 100}
+ {{240, 100, 100}, {100, 240, 100}, {100, 100, 240},
+ {220, 220, 80}, {100, 240, 240}, {240, 100, 240},
+ {100, 25, 25}, {25, 100, 25}, {25, 25, 100},
+ {120, 120, 0}, {25, 100, 100}, {100, 50, 100}
}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/observer/src/observer_sys_wx.erl b/lib/observer/src/observer_sys_wx.erl
index f989f9cf97..ea89590e84 100644
--- a/lib/observer/src/observer_sys_wx.erl
+++ b/lib/observer/src/observer_sys_wx.erl
@@ -37,7 +37,6 @@
parent_notebook,
panel, sizer,
menubar,
- alloc,
fields,
timer}).
@@ -48,7 +47,6 @@ start_link(Notebook, Parent) ->
init([Notebook, Parent]) ->
SysInfo = observer_backend:sys_info(),
- AllocInfo = proplists:get_value(alloc_info, SysInfo, []),
{Info, Stat} = info_fields(),
Panel = wxPanel:new(Notebook),
Sizer = wxBoxSizer:new(?wxVERTICAL),
@@ -60,16 +58,13 @@ init([Notebook, Parent]) ->
wxSizer:add(TopSizer, FPanel0, [{flag, ?wxEXPAND}, {proportion, 1}]),
wxSizer:add(TopSizer, FPanel1, [{flag, ?wxEXPAND}, {proportion, 1}]),
BorderFlags = ?wxLEFT bor ?wxRIGHT,
- {MemPanel, MemoryInfo} = create_mem_info(Panel, AllocInfo),
wxSizer:add(Sizer, TopSizer, [{flag, ?wxEXPAND bor BorderFlags bor ?wxTOP},
{proportion, 0}, {border, 5}]),
- wxSizer:add(Sizer, MemPanel, [{flag, ?wxEXPAND bor BorderFlags bor ?wxBOTTOM},
- {proportion, 1}, {border, 5}]),
wxPanel:setSizer(Panel, Sizer),
Timer = observer_lib:start_timer(10),
{Panel, #sys_wx_state{parent=Parent,
parent_notebook=Notebook,
- panel=Panel, sizer=Sizer, alloc=MemoryInfo,
+ panel=Panel, sizer=Sizer,
timer=Timer, fields=Fields0 ++ Fields1}}.
create_sys_menu(Parent) ->
@@ -77,91 +72,13 @@ create_sys_menu(Parent) ->
#create_menu{id = ?ID_REFRESH_INTERVAL, text = "Refresh interval"}]},
observer_wx:create_menus(Parent, [View]).
-update_syspage(#sys_wx_state{node = Node, fields=Fields, sizer=Sizer, alloc=AllocCtrl}) ->
+update_syspage(#sys_wx_state{node = Node, fields=Fields, sizer=Sizer}) ->
SysInfo = observer_wx:try_rpc(Node, observer_backend, sys_info, []),
- AllocInfo = proplists:get_value(alloc_info, SysInfo, []),
{Info, Stat} = info_fields(),
observer_lib:update_info(Fields, observer_lib:fill_info(Info, SysInfo) ++
observer_lib:fill_info(Stat, SysInfo)),
- update_alloc(AllocCtrl, AllocInfo),
wxSizer:layout(Sizer).
-create_mem_info(Parent, Fields) ->
- Panel = wxPanel:new(Parent),
- wxWindow:setBackgroundColour(Panel, {255,255,255}),
- Style = ?wxLC_REPORT bor ?wxLC_SINGLE_SEL bor ?wxLC_HRULES bor ?wxLC_VRULES,
- Grid = wxListCtrl:new(Panel, [{style, Style}]),
- Li = wxListItem:new(),
- AddListEntry = fun({Name, Align, DefSize}, Col) ->
- wxListItem:setText(Li, Name),
- wxListItem:setAlign(Li, Align),
- wxListCtrl:insertColumn(Grid, Col, Li),
- wxListCtrl:setColumnWidth(Grid, Col, DefSize),
- Col + 1
- end,
- ListItems = [{"Allocator Type", ?wxLIST_FORMAT_LEFT, 200},
- {"Block size (kB)", ?wxLIST_FORMAT_RIGHT, 150},
- {"Carrier size (kB)",?wxLIST_FORMAT_RIGHT, 150}],
- lists:foldl(AddListEntry, 0, ListItems),
- wxListItem:destroy(Li),
- update_alloc(Grid, Fields),
-
- Sizer = wxBoxSizer:new(?wxVERTICAL),
- wxSizer:add(Sizer, Grid, [{flag, ?wxEXPAND bor ?wxLEFT bor ?wxRIGHT},
- {border, 5}, {proportion, 1}]),
- wxWindow:setSizerAndFit(Panel, Sizer),
- {Panel, Grid}.
-
-update_alloc(Grid, AllocInfo) ->
- Fields = alloc_info(AllocInfo, [], 0, 0, true),
- wxListCtrl:deleteAllItems(Grid),
- Update = fun({Name, BS, CS}, Row) ->
- wxListCtrl:insertItem(Grid, Row, ""),
- wxListCtrl:setItem(Grid, Row, 0, observer_lib:to_str(Name)),
- wxListCtrl:setItem(Grid, Row, 1, observer_lib:to_str(BS div 1024)),
- wxListCtrl:setItem(Grid, Row, 2, observer_lib:to_str(CS div 1024)),
- Row + 1
- end,
- lists:foldl(Update, 0, Fields),
- Fields.
-
-alloc_info([{Type,Instances}|Allocators],TypeAcc,TotalBS,TotalCS,IncludeTotal) ->
- {BS,CS,NewTotalBS,NewTotalCS,NewIncludeTotal} =
- sum_alloc_instances(Instances,0,0,TotalBS,TotalCS),
- alloc_info(Allocators,[{Type,BS,CS}|TypeAcc],NewTotalBS,NewTotalCS,
- IncludeTotal andalso NewIncludeTotal);
-alloc_info([],TypeAcc,TotalBS,TotalCS,IncludeTotal) ->
- Types = [X || X={_,BS,CS} <- TypeAcc, (BS>0 orelse CS>0)],
- case IncludeTotal of
- true ->
- [{total,TotalBS,TotalCS} | lists:reverse(Types)];
- false ->
- lists:reverse(Types)
- end.
-
-sum_alloc_instances(false,BS,CS,TotalBS,TotalCS) ->
- {BS,CS,TotalBS,TotalCS,false};
-sum_alloc_instances([{_,_,Data}|Instances],BS,CS,TotalBS,TotalCS) ->
- {NewBS,NewCS,NewTotalBS,NewTotalCS} =
- sum_alloc_one_instance(Data,BS,CS,TotalBS,TotalCS),
- sum_alloc_instances(Instances,NewBS,NewCS,NewTotalBS,NewTotalCS);
-sum_alloc_instances([],BS,CS,TotalBS,TotalCS) ->
- {BS,CS,TotalBS,TotalCS,true}.
-
-sum_alloc_one_instance([{sbmbcs,[{blocks_size,BS,_,_},{carriers_size,CS,_,_}]}|
- Rest],OldBS,OldCS,TotalBS,TotalCS) ->
- sum_alloc_one_instance(Rest,OldBS+BS,OldCS+CS,TotalBS,TotalCS);
-sum_alloc_one_instance([{_,[{blocks_size,BS,_,_},{carriers_size,CS,_,_}]}|
- Rest],OldBS,OldCS,TotalBS,TotalCS) ->
- sum_alloc_one_instance(Rest,OldBS+BS,OldCS+CS,TotalBS+BS,TotalCS+CS);
-sum_alloc_one_instance([{_,[{blocks_size,BS},{carriers_size,CS}]}|
- Rest],OldBS,OldCS,TotalBS,TotalCS) ->
- sum_alloc_one_instance(Rest,OldBS+BS,OldCS+CS,TotalBS+BS,TotalCS+CS);
-sum_alloc_one_instance([_|Rest],BS,CS,TotalBS,TotalCS) ->
- sum_alloc_one_instance(Rest,BS,CS,TotalBS,TotalCS);
-sum_alloc_one_instance([],BS,CS,TotalBS,TotalCS) ->
- {BS,CS,TotalBS,TotalCS}.
-
info_fields() ->
Info = [{"System and Architecture",
[{"System Version", otp_release},
diff --git a/lib/observer/src/observer_wx.erl b/lib/observer/src/observer_wx.erl
index 54c4092a78..cf602569aa 100644
--- a/lib/observer/src/observer_wx.erl
+++ b/lib/observer/src/observer_wx.erl
@@ -43,6 +43,7 @@
-define(LAST_NODES_MENU_ID, 2000).
-define(TRACE_STR, "Trace Overview").
+-define(ALLOC_STR, "Memory Allocators").
%% Records
-record(state,
@@ -58,6 +59,7 @@
trace_panel,
app_panel,
perf_panel,
+ allc_panel,
active_tab,
node,
nodes,
@@ -149,6 +151,10 @@ setup(#state{frame = Frame} = State) ->
PerfPanel = observer_perf_wx:start_link(Notebook, self()),
wxNotebook:addPage(Notebook, PerfPanel, "Load Charts", []),
+ %% Memory Allocator Viewer Panel
+ AllcPanel = observer_alloc_wx:start_link(Notebook, self()),
+ wxNotebook:addPage(Notebook, AllcPanel, ?ALLOC_STR, []),
+
%% App Viewer Panel
AppPanel = observer_app_wx:start_link(Notebook, self()),
wxNotebook:addPage(Notebook, AppPanel, "Applications", []),
@@ -184,6 +190,7 @@ setup(#state{frame = Frame} = State) ->
trace_panel = TracePanel,
app_panel = AppPanel,
perf_panel = PerfPanel,
+ allc_panel = AllcPanel,
active_tab = SysPid,
node = node(),
nodes = Nodes
@@ -505,7 +512,7 @@ check_page_title(Notebook) ->
get_active_pid(#state{notebook=Notebook, pro_panel=Pro, sys_panel=Sys,
tv_panel=Tv, trace_panel=Trace, app_panel=App,
- perf_panel=Perf
+ perf_panel=Perf, allc_panel=Alloc
}) ->
Panel = case check_page_title(Notebook) of
"Processes" -> Pro;
@@ -513,13 +520,14 @@ get_active_pid(#state{notebook=Notebook, pro_panel=Pro, sys_panel=Sys,
"Table Viewer" -> Tv;
?TRACE_STR -> Trace;
"Load Charts" -> Perf;
- "Applications" -> App
+ "Applications" -> App;
+ ?ALLOC_STR -> Alloc
end,
wx_object:get_pid(Panel).
pid2panel(Pid, #state{pro_panel=Pro, sys_panel=Sys,
tv_panel=Tv, trace_panel=Trace, app_panel=App,
- perf_panel=Perf}) ->
+ perf_panel=Perf, allc_panel=Alloc}) ->
case Pid of
Pro -> "Processes";
Sys -> "System";
@@ -527,6 +535,7 @@ pid2panel(Pid, #state{pro_panel=Pro, sys_panel=Sys,
Trace -> ?TRACE_STR;
Perf -> "Load Charts";
App -> "Applications";
+ Alloc -> ?ALLOC_STR;
_ -> "unknown"
end.
@@ -617,8 +626,8 @@ default_menus(NodesMenuItems) ->
%% automagicly, so just add them to a menu that always exist.
%% But not to the help menu for some reason
- {Tag, Menus} = NodeMenu,
- [{Tag, Menus ++ [Quit,About]}, LogMenu, {"&Help", [Help]}]
+ {Tag, Menus} = FileMenu,
+ [{Tag, Menus ++ [Quit,About]}, NodeMenu, LogMenu, {"&Help", [Help]}]
end.
clean_menus(Menus, MenuBar) ->
diff --git a/lib/stdlib/src/stdlib.appup.src b/lib/stdlib/src/stdlib.appup.src
index 5900fd3ff3..ee87a8ddb2 100644
--- a/lib/stdlib/src/stdlib.appup.src
+++ b/lib/stdlib/src/stdlib.appup.src
@@ -17,9 +17,9 @@
%% %CopyrightEnd%
{"%VSN%",
%% Up from - max one major revision back
- [{<<"2\\.[1-2](\\.[0-9]+)*">>,[restart_new_emulator]}, %% 17.1-17.3
+ [{<<"2\\.[1-3](\\.[0-9]+)*">>,[restart_new_emulator]}, %% 17.1-17.3
{<<"2\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}], %% 17.0
%% Down to - max one major revision back
- [{<<"2\\.[1-2](\\.[0-9]+)*">>,[restart_new_emulator]}, %% 17.1-17.3
+ [{<<"2\\.[1-3](\\.[0-9]+)*">>,[restart_new_emulator]}, %% 17.1-17.3
{<<"2\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}] %% 17.0
}.
diff --git a/lib/wx/api_gen/wx_gen_cpp.erl b/lib/wx/api_gen/wx_gen_cpp.erl
index 107d064f4a..720526b3b9 100644
--- a/lib/wx/api_gen/wx_gen_cpp.erl
+++ b/lib/wx/api_gen/wx_gen_cpp.erl
@@ -975,6 +975,13 @@ build_ret(Name = "ev->m_scanCode",_,#type{base=bool,single=true,by_val=true}) ->
w(" rt.addBool(~s);~n",[Name]),
w("#else~n rt.addBool(false);~n",[]),
w("#endif~n",[]);
+build_ret(Name = "ev->m_metaDown",_,#type{base=bool,single=true,by_val=true}) ->
+ %% Hardcoded workaround for MAC on 2.9 and later
+ w("#if wxCHECK_VERSION(2,9,0) && defined(_MACOSX)~n", []),
+ w(" rt.addBool(ev->m_rawControlDown);~n",[]),
+ w("#else~n rt.addBool(~s);~n",[Name]),
+ w("#endif~n",[]);
+
build_ret(Name,_,#type{base=bool,single=true,by_val=true}) ->
w(" rt.addBool(~s);~n",[Name]);
build_ret(Name,{arg, both},#type{base=int,single=true,mod=M}) ->
diff --git a/lib/wx/api_gen/wxapi.conf b/lib/wx/api_gen/wxapi.conf
index 2e961cce98..09f21af0f3 100644
--- a/lib/wx/api_gen/wxapi.conf
+++ b/lib/wx/api_gen/wxapi.conf
@@ -32,7 +32,10 @@
wxALWAYS_NATIVE_DOUBLE_BUFFER,
wxGAUGE_EMULATE_INDETERMINATE_MODE,
wxTR_DEFAULT_STYLE,
- wxSL_LABELS
+ wxSL_LABELS,
+ wxCURSOR_DEFAULT,
+ wxCURSOR_ARROWWAIT,
+ wxCURSOR_MAX
]}.
{gvars,
diff --git a/lib/wx/c_src/gen/wxe_events.cpp b/lib/wx/c_src/gen/wxe_events.cpp
index 255b36c2fa..ae85931d8d 100644
--- a/lib/wx/c_src/gen/wxe_events.cpp
+++ b/lib/wx/c_src/gen/wxe_events.cpp
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2014. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2015. 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
@@ -394,7 +394,11 @@ case 167: {// wxMouseEvent
rt.addBool(ev->m_controlDown);
rt.addBool(ev->m_shiftDown);
rt.addBool(ev->m_altDown);
+#if wxCHECK_VERSION(2,9,0) && defined(_MACOSX)
+ rt.addBool(ev->m_rawControlDown);
+#else
rt.addBool(ev->m_metaDown);
+#endif
rt.addInt(ev->m_wheelRotation);
rt.addInt(ev->m_wheelDelta);
rt.addInt(ev->m_linesPerAction);
@@ -419,7 +423,11 @@ case 169: {// wxKeyEvent
rt.addBool(ev->m_controlDown);
rt.addBool(ev->m_shiftDown);
rt.addBool(ev->m_altDown);
+#if wxCHECK_VERSION(2,9,0) && defined(_MACOSX)
+ rt.addBool(ev->m_rawControlDown);
+#else
rt.addBool(ev->m_metaDown);
+#endif
#if !wxCHECK_VERSION(2,9,0)
rt.addBool(ev->m_scanCode);
#else
diff --git a/lib/wx/c_src/gen/wxe_init.cpp b/lib/wx/c_src/gen/wxe_init.cpp
index 3a4bced790..1673f2a1b3 100644
--- a/lib/wx/c_src/gen/wxe_init.cpp
+++ b/lib/wx/c_src/gen/wxe_init.cpp
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2014. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2015. 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
@@ -56,6 +56,12 @@ void WxeApp::init_nonconsts(wxeMemEnv *memenv, ErlDrvTermData caller) {
rt.addTupleCount(2);
rt.addAtom("wxMOD_CMD"); rt.addInt(wxMOD_CMD);
rt.addTupleCount(2);
+ rt.addAtom("wxCURSOR_ARROWWAIT"); rt.addInt(wxCURSOR_ARROWWAIT);
+ rt.addTupleCount(2);
+ rt.addAtom("wxCURSOR_DEFAULT"); rt.addInt(wxCURSOR_DEFAULT);
+ rt.addTupleCount(2);
+ rt.addAtom("wxCURSOR_MAX"); rt.addInt(wxCURSOR_MAX);
+ rt.addTupleCount(2);
rt.addAtom("wxBLACK"); rt.add(*(wxBLACK));
rt.addTupleCount(2);
rt.addAtom("wxBLACK_BRUSH"); rt.addRef(getRef((void *)wxBLACK_BRUSH,memenv),"wxBrush");
@@ -138,7 +144,7 @@ void WxeApp::init_nonconsts(wxeMemEnv *memenv, ErlDrvTermData caller) {
rt.addTupleCount(2);
rt.addAtom("wxWHITE_PEN"); rt.addRef(getRef((void *)wxWHITE_PEN,memenv),"wxPen");
rt.addTupleCount(2);
- rt.endList(57);
+ rt.endList(60);
rt.addTupleCount(2);
rt.send();
}
diff --git a/lib/wx/configure.in b/lib/wx/configure.in
index 4c4d4f41a8..fbdddb9220 100644
--- a/lib/wx/configure.in
+++ b/lib/wx/configure.in
@@ -441,19 +441,26 @@ else
else
CWXWIN_PROG=`cygpath -d "$PROGRAMFILES" | cygpath -f - 2>/dev/null`
fi
- CWXWIN3=$CWXWIN_PROG/wxWidgets-?.*.*
- CWXWIN4=$CWXWIN_PROG/wxMSW-?.*.*
- CWX_DOCUMENTED="/opt/local/pgm/wxMSW-?.*.* /opt/local/pgm/wxWidgets-?.*.*"
+
+ CWXWIN3="$CWXWIN_PROG/wxWidgets-3.*.* $CWXWIN_PROG/wxWidgets-2.*.*"
+ CWXWIN4="$CWXWIN_PROG/wxMSW-3.*.* $CWXWIN_PROG/wxMSW-2.*.*"
+
+ DOC_OPT=/opt/local/pgm
+ CWX_DOCUMENTED="$DOC_OPT/wxWidgets-2.*.* $DOC_OPT/wxMSW-2.*.*"
+ CWX_DOCUMENTED="$DOC_OPT/wxWidgets-3.*.* $DOC_OPT/wxMSW-3.*.* $CWX_DOCUMENTED"
+
case $ac_cv_sizeof_void_p in
8)
- CWX_DOCUMENTED="/opt/local64/pgm/wxMSW-?.*.* /opt/local64/pgm/wxWidgets-?.*.* $CWX_DOCUMENTED"
+ DOC_OPT64=/opt/local64/pgm
+ CWX_DOCUMENTED="$DOC_OPT64/wxWidgets-2.*.* $DOC_OPT64/wxMSW-2.*.* $CWX_DOCUMENTED"
+ CWX_DOCUMENTED="$DOC_OPT64/wxWidgets-3.*.* $DOC_OPT64/wxMSW-3.*.* $CWX_DOCUMENTED"
;;
*)
true
;;
- esac
-
- CWXPATH="$CWXWIN0 $CWXWIN1 $CWXWIN2 $CWX_DOCUMENTED $CWXWIN3.* $CWXWIN4.*"
+ esac
+
+ CWXPATH="$CWXWIN0 $CWXWIN1 $CWXWIN2 $CWX_DOCUMENTED $CWXWIN3 $CWXWIN4"
for dir in $CWXPATH; do
AC_MSG_NOTICE(Checking: [$dir])
diff --git a/lib/wx/examples/demo/demo.erl b/lib/wx/examples/demo/demo.erl
index 2f560096f5..65fb05cd94 100644
--- a/lib/wx/examples/demo/demo.erl
+++ b/lib/wx/examples/demo/demo.erl
@@ -256,9 +256,17 @@ handle_event(#wx{id = Id,
wx_misc:launchDefaultBrowser("http://www.erlang.org/doc/apps/wx/part_frame.html"),
{noreply, State};
?wxID_ABOUT ->
+ WxWVer = io_lib:format("~p.~p.~p.~p",
+ [?wxMAJOR_VERSION, ?wxMINOR_VERSION,
+ ?wxRELEASE_NUMBER, ?wxSUBRELEASE_NUMBER]),
+ application:load(wx),
+ {ok, WxVsn} = application:get_key(wx, vsn),
AboutString =
"Demo of various widgets\n"
- "Authors: Olle & Dan",
+ "Authors: Olle & Dan\n\n" ++
+ "Frontend: wx-" ++ WxVsn ++
+ "\nBackend: wxWidgets-" ++ lists:flatten(WxWVer),
+
wxMessageDialog:showModal(wxMessageDialog:new(State#state.win, AboutString,
[{style,
?wxOK bor
diff --git a/lib/wx/include/wx.hrl b/lib/wx/include/wx.hrl
index 348daf64ce..9b913c7c00 100644
--- a/lib/wx/include/wx.hrl
+++ b/lib/wx/include/wx.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2015. 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
@@ -1883,9 +1883,9 @@
-define(wxCURSOR_WAIT, 24).
-define(wxCURSOR_WATCH, 25).
-define(wxCURSOR_BLANK, 26).
--define(wxCURSOR_DEFAULT, 27).
--define(wxCURSOR_ARROWWAIT, 28).
--define(wxCURSOR_MAX, 29).
+-define(wxCURSOR_DEFAULT, wxe_util:get_const(wxCURSOR_DEFAULT)).
+-define(wxCURSOR_ARROWWAIT, wxe_util:get_const(wxCURSOR_ARROWWAIT)).
+-define(wxCURSOR_MAX, wxe_util:get_const(wxCURSOR_MAX)).
% From "generic_2laywin.h"
-define(wxLAYOUT_QUERY, 256).
-define(wxLAYOUT_MRU_LENGTH, 16).