aboutsummaryrefslogtreecommitdiffstats
path: root/lib/mnesia
diff options
context:
space:
mode:
Diffstat (limited to 'lib/mnesia')
-rw-r--r--lib/mnesia/doc/src/notes.xml26
-rw-r--r--lib/mnesia/src/mnesia.appup.src14
-rw-r--r--lib/mnesia/src/mnesia_locker.erl32
-rw-r--r--lib/mnesia/src/mnesia_monitor.erl89
-rw-r--r--lib/mnesia/src/mnesia_subscr.erl4
-rw-r--r--lib/mnesia/src/mnesia_tm.erl6
-rw-r--r--lib/mnesia/test/mnesia_dirty_access_test.erl7
-rw-r--r--lib/mnesia/test/mnesia_evil_coverage_test.erl25
-rw-r--r--lib/mnesia/vsn.mk2
9 files changed, 139 insertions, 66 deletions
diff --git a/lib/mnesia/doc/src/notes.xml b/lib/mnesia/doc/src/notes.xml
index da66a647f5..0e9131190d 100644
--- a/lib/mnesia/doc/src/notes.xml
+++ b/lib/mnesia/doc/src/notes.xml
@@ -38,7 +38,31 @@
thus constitutes one section in this document. The title of each
section is the version number of Mnesia.</p>
- <section><title>Mnesia 4.10</title>
+ <section><title>Mnesia 4.11</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed a race in mnesia which could cause hanging
+ transaction when sticky locks had been used. Thanks
+ janchochol.</p>
+ <p>
+ Own Id: OTP-11375</p>
+ </item>
+ <item>
+ <p>
+ Fixed dirty_update_counter which could return ok, thanks
+ Anton Ryabkov.</p>
+ <p>
+ Own Id: OTP-11485</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Mnesia 4.10</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/mnesia/src/mnesia.appup.src b/lib/mnesia/src/mnesia.appup.src
index 355aafb215..c245299740 100644
--- a/lib/mnesia/src/mnesia.appup.src
+++ b/lib/mnesia/src/mnesia.appup.src
@@ -1,22 +1,16 @@
%% -*- erlang -*-
{"%VSN%",
[
- {"4.7.1", [{restart_application, mnesia}]},
- {"4.7", [{restart_application, mnesia}]},
- {"4.6", [{restart_application, mnesia}]},
- {"4.5.1", [{restart_application, mnesia}]},
- {"4.5", [{restart_application, mnesia}]},
+ {<<"4\\.1[0-9].*">>, [{restart_application, mnesia}]},
+ {<<"4\\.[5-9].*">>, [{restart_application, mnesia}]},
{"4.4.19", [{restart_application, mnesia}]},
{"4.4.18", [{restart_application, mnesia}]},
{"4.4.17", [{restart_application, mnesia}]},
{"4.4.16", [{restart_application, mnesia}]}
],
[
- {"4.7.1", [{restart_application, mnesia}]},
- {"4.7", [{restart_application, mnesia}]},
- {"4.6", [{restart_application, mnesia}]},
- {"4.5.1", [{restart_application, mnesia}]},
- {"4.5", [{restart_application, mnesia}]},
+ {<<"4\\.1[0-9].*">>, [{restart_application, mnesia}]},
+ {<<"4\\.[5-9].*">>, [{restart_application, mnesia}]},
{"4.4.19", [{restart_application, mnesia}]},
{"4.4.18", [{restart_application, mnesia}]},
{"4.4.17", [{restart_application, mnesia}]},
diff --git a/lib/mnesia/src/mnesia_locker.erl b/lib/mnesia/src/mnesia_locker.erl
index 14011003d3..c4fe370ec1 100644
--- a/lib/mnesia/src/mnesia_locker.erl
+++ b/lib/mnesia/src/mnesia_locker.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. 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
@@ -26,8 +26,8 @@
global_lock/5,
ixrlock/5,
init/1,
- mnesia_down/2,
release_tid/1,
+ mnesia_down/2,
async_release_tid/2,
send_release_tid/2,
receive_release_tid_acc/2,
@@ -137,6 +137,17 @@ receive_release_tid_acc([Node | Nodes], Tid) ->
receive_release_tid_acc([], _Tid) ->
ok.
+mnesia_down(Node, Pending) ->
+ case whereis(?MODULE) of
+ undefined -> {error, node_not_running};
+ Pid ->
+ Ref = make_ref(),
+ Pid ! {{self(), Ref}, {release_remote_non_pending, Node, Pending}},
+ receive %% No need to wait for anything else if process dies we die soon
+ {Ref,ok} -> ok
+ end
+ end.
+
loop(State) ->
receive
{From, {write, Tid, Oid}} ->
@@ -213,9 +224,9 @@ loop(State) ->
reply(From, {tid_released, Tid}),
loop(State);
- {release_remote_non_pending, Node, Pending} ->
+ {{From, Ref},{release_remote_non_pending, Node, Pending}} ->
release_remote_non_pending(Node, Pending),
- mnesia_monitor:mnesia_down(?MODULE, Node),
+ From ! {Ref, ok},
loop(State);
{'EXIT', Pid, _} when Pid == State#state.supervisor ->
@@ -653,19 +664,6 @@ ix_read_res(Tab,IxKey,Pos) ->
%% ********************* end server code ********************
%% The following code executes at the client side of a transactions
-mnesia_down(N, Pending) ->
- case whereis(?MODULE) of
- undefined ->
- %% Takes care of mnesia_down's in early startup
- mnesia_monitor:mnesia_down(?MODULE, N);
- Pid ->
- %% Syncronously call needed in order to avoid
- %% race with mnesia_tm's coordinator processes
- %% that may restart and acquire new locks.
- %% mnesia_monitor ensures the sync.
- Pid ! {release_remote_non_pending, N, Pending}
- end.
-
%% Aquire a write lock, but do a read, used by
%% mnesia:wread/1
diff --git a/lib/mnesia/src/mnesia_monitor.erl b/lib/mnesia/src/mnesia_monitor.erl
index 7a788238fc..c7b905a1bf 100644
--- a/lib/mnesia/src/mnesia_monitor.erl
+++ b/lib/mnesia/src/mnesia_monitor.erl
@@ -78,7 +78,7 @@
-record(state, {supervisor, pending_negotiators = [],
going_down = [], tm_started = false, early_connects = [],
- connecting, mq = []}).
+ connecting, mq = [], remote_node_status = []}).
-define(current_protocol_version, {8,1}).
@@ -482,27 +482,24 @@ handle_cast({mnesia_down, mnesia_controller, Node}, State) ->
mnesia_tm:mnesia_down(Node),
{noreply, State};
-handle_cast({mnesia_down, mnesia_tm, {Node, Pending}}, State) ->
- mnesia_locker:mnesia_down(Node, Pending),
- {noreply, State};
-
-handle_cast({mnesia_down, mnesia_locker, Node}, State) ->
+handle_cast({mnesia_down, mnesia_tm, Node}, State) ->
Down = {mnesia_down, Node},
mnesia_lib:report_system_event(Down),
GoingDown = lists:delete(Node, State#state.going_down),
State2 = State#state{going_down = GoingDown},
Pending = State#state.pending_negotiators,
+ State3 = check_raise_conditon_nodeup(Node, State2),
case lists:keysearch(Node, 1, Pending) of
{value, {Node, Mon, ReplyTo, Reply}} ->
%% Late reply to remote monitor
link(Mon), %% link to remote Monitor
gen_server:reply(ReplyTo, Reply),
P2 = lists:keydelete(Node, 1,Pending),
- State3 = State2#state{pending_negotiators = P2},
- process_q(State3);
+ State4 = State3#state{pending_negotiators = P2},
+ process_q(State4);
false ->
%% No pending remote monitors
- process_q(State2)
+ process_q(State3)
end;
handle_cast({disconnect, Node}, State) ->
@@ -568,27 +565,18 @@ handle_info({protocol_negotiated, From,Res}, State) ->
gen_server:reply(From, Res),
process_q(State#state{connecting = undefined});
-handle_info({nodeup, Node}, State) ->
- %% Ok, we are connected to yet another Erlang node
- %% Let's check if Mnesia is running there in order
- %% to detect if the network has been partitioned
- %% due to communication failure.
-
- HasDown = mnesia_recover:has_mnesia_down(Node),
- ImRunning = mnesia_lib:is_running(),
+handle_info({check_nodeup, Node}, State) ->
+ State2 = check_mnesia_down(Node, State),
+ {noreply, State2};
- if
- %% If I'm not running the test will be made later.
- HasDown == true, ImRunning == yes ->
- spawn_link(?MODULE, detect_partitioned_network, [self(), Node]);
- true ->
- ignore
- end,
- {noreply, State};
+handle_info({nodeup, Node}, State) ->
+ State2 = remote_node_status(Node, up, State),
+ State3 = check_mnesia_down(Node, State2),
+ {noreply, State3};
-handle_info({nodedown, _Node}, State) ->
- %% Ignore, we are only caring about nodeup's
- {noreply, State};
+handle_info({nodedown, Node}, State) ->
+ State2 = remote_node_status(Node, down, State),
+ {noreply, State2};
handle_info({disk_log, _Node, Log, Info}, State) ->
case Info of
@@ -830,3 +818,48 @@ report_inconsistency([{badrpc, _Reason} | Replies], Context, Status) ->
report_inconsistency(Replies, Context, Status);
report_inconsistency([], _Context, Status) ->
Status.
+
+remote_node_status(Node, Status, State) ->
+ {ok, Nodes} = mnesia_schema:read_nodes(),
+ case lists:member(Node, Nodes) of
+ true ->
+ update_node_status({Node, Status}, State);
+ _ ->
+ State
+ end.
+
+update_node_status({Node, down}, State = #state{remote_node_status = RNodeS}) ->
+ RNodeS2 = lists:ukeymerge(1, [{Node, down}], RNodeS),
+ State#state{remote_node_status = RNodeS2};
+update_node_status({Node, up}, State = #state{remote_node_status = RNodeS}) ->
+ case lists:keyfind(Node, 1, RNodeS) of
+ {Node, down} ->
+ RNodeS2 = lists:ukeymerge(1, [{Node, up}], RNodeS),
+ State#state{remote_node_status = RNodeS2};
+ _ ->
+ State
+ end.
+
+check_raise_conditon_nodeup(Node, State = #state{remote_node_status = RNodeS}) ->
+ case lists:keyfind(Node, 1, RNodeS) of
+ {Node, up} ->
+ self() ! {check_nodeup, Node};
+ _ ->
+ ignore
+ end,
+ State#state{remote_node_status = lists:keydelete(Node, 1, RNodeS)}.
+
+check_mnesia_down(Node, State = #state{remote_node_status = RNodeS}) ->
+ %% Check if the network has been partitioned
+ %% due to communication failure.
+
+ HasDown = mnesia_recover:has_mnesia_down(Node),
+ ImRunning = mnesia_lib:is_running(),
+ if
+ %% If I'm not running the test will be made later.
+ HasDown == true, ImRunning == yes ->
+ spawn_link(?MODULE, detect_partitioned_network, [self(), Node]),
+ State#state{remote_node_status = lists:keydelete(Node, 1, RNodeS)};
+ true ->
+ State
+ end.
diff --git a/lib/mnesia/src/mnesia_subscr.erl b/lib/mnesia/src/mnesia_subscr.erl
index 8f78dc55e8..9272211ad2 100644
--- a/lib/mnesia/src/mnesia_subscr.erl
+++ b/lib/mnesia/src/mnesia_subscr.erl
@@ -204,7 +204,9 @@ what(Tab, Tid, Obj, write, undefined) ->
{mnesia_table_event, {write, Tab, Obj, Old, Tid}};
{'EXIT', _} ->
ignore
- end.
+ end;
+what(Tab, Tid, Obj, write, Old) ->
+ {mnesia_table_event, {write, Tab, Obj, Old, Tid}}.
deliver(_, ignore) ->
ok;
diff --git a/lib/mnesia/src/mnesia_tm.erl b/lib/mnesia/src/mnesia_tm.erl
index e54e5c4e88..17af0cad44 100644
--- a/lib/mnesia/src/mnesia_tm.erl
+++ b/lib/mnesia/src/mnesia_tm.erl
@@ -181,7 +181,7 @@ mnesia_down(Node) ->
%% mnesia_monitor takes care of the sync
case whereis(?MODULE) of
undefined ->
- mnesia_monitor:mnesia_down(?MODULE, {Node, []});
+ mnesia_monitor:mnesia_down(?MODULE, Node);
Pid ->
Pid ! {mnesia_down, Node}
end.
@@ -403,7 +403,9 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor=
Tids = gb_trees:keys(Participants),
reconfigure_participants(N, gb_trees:values(Participants)),
NewState = clear_fixtable(N, State),
- mnesia_monitor:mnesia_down(?MODULE, {N, Tids}),
+
+ mnesia_locker:mnesia_down(N, Tids),
+ mnesia_monitor:mnesia_down(?MODULE, N),
doit_loop(NewState);
{From, {unblock_me, Tab}} ->
diff --git a/lib/mnesia/test/mnesia_dirty_access_test.erl b/lib/mnesia/test/mnesia_dirty_access_test.erl
index 6017092095..519b4bb052 100644
--- a/lib/mnesia/test/mnesia_dirty_access_test.erl
+++ b/lib/mnesia/test/mnesia_dirty_access_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. 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
@@ -198,6 +198,11 @@ dirty_update_counter(Config, Storage) ->
?match(1, mnesia:dirty_update_counter({Tab, foo}, 1)),
?match([{Tab, foo,1}], mnesia:dirty_read({Tab,foo})),
+ ?match({ok,_}, mnesia:subscribe({table, Tab, detailed})),
+
+ ?match(2, mnesia:dirty_update_counter({Tab, foo}, 1)),
+ ?match([{Tab, foo,2}], mnesia:dirty_read({Tab,foo})),
+
?verify_mnesia(Nodes, []).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/mnesia/test/mnesia_evil_coverage_test.erl b/lib/mnesia/test/mnesia_evil_coverage_test.erl
index db23a39943..91820238e5 100644
--- a/lib/mnesia/test/mnesia_evil_coverage_test.erl
+++ b/lib/mnesia/test/mnesia_evil_coverage_test.erl
@@ -1869,14 +1869,19 @@ subscribe_extended(Config) when is_list(Config) ->
{attributes, record_info(fields, tab)}],
?match({atomic, ok}, mnesia:create_table(Tab2, Def2)),
+ Tab3 = ctab,
+ Def3 = [{Storage, [N1, N2]}],
+ ?match({atomic, ok}, mnesia:create_table(Tab3, Def3)),
+
?match({ok, N1}, mnesia:subscribe({table, Tab1, detailed})),
?match({ok, N1}, mnesia:subscribe({table, Tab2, detailed})),
+ ?match({ok, N1}, mnesia:subscribe({table, Tab3, detailed})),
?match({error, {already_exists, _}}, mnesia:subscribe({table, Tab1, simple})),
?match({error, {badarg, {table, Tab1, bad}}}, mnesia:subscribe({table, Tab1, bad})),
?match({ok, N1}, mnesia:subscribe(activity)),
- test_ext_sub(Tab1, Tab2),
+ test_ext_sub(Tab1, Tab2, Tab3),
?match({ok, N1}, mnesia:unsubscribe(activity)),
?match({ok, N1}, mnesia:subscribe({table, Tab1, detailed})),
@@ -1895,11 +1900,11 @@ subscribe_extended(Config) when is_list(Config) ->
{max, [Tab1, Tab2]}]),
?match({ok, N1}, mnesia:subscribe({table, Tab2, detailed})),
?match({ok, N1}, mnesia:subscribe(activity)),
- test_ext_sub(Tab1, Tab2),
+ test_ext_sub(Tab1, Tab2, Tab3),
?verify_mnesia(Nodes, []).
-test_ext_sub(Tab1, Tab2) ->
+test_ext_sub(Tab1, Tab2, Tab3) ->
%% The basics
Rec1 = {Tab1, 1, 0, 0},
Rec2 = {Tab1, 1, 1, 0},
@@ -1940,7 +1945,6 @@ test_ext_sub(Tab1, Tab2) ->
?match({atomic, ok}, Delete(Tab1, 1)),
?match({mnesia_table_event, {delete, Tab1, {Tab1, 1}, [], {tid,_,S}}}, recv_event()),
?match({mnesia_activity_event, {complete, {tid,_,S}}}, recv_event()),
-
?match({ok, _N1}, mnesia:unsubscribe({table, Tab1, detailed})),
%% BAG
@@ -1969,6 +1973,17 @@ test_ext_sub(Tab1, Tab2) ->
?match({atomic, ok}, Delete(Tab2, 2)),
?match({mnesia_table_event, {delete, Tab2, {Tab2, 2}, [Rec4, Rec3], {tid,_,S}}}, recv_event()),
?match({mnesia_activity_event, {complete, {tid,_,S}}}, recv_event()),
+
+ %% COUNTERS
+
+ Rec5 = {Tab3, counter, 0},
+ ?match(ok, mnesia:dirty_write(Rec5)),
+ ?match({mnesia_table_event, {write, Tab3, Rec5, [], D}}, recv_event()),
+ ?match(1, mnesia:dirty_update_counter({Tab3, counter}, 1)),
+ ?match({mnesia_table_event, {write, Tab3, {Tab3,counter,1}, [Rec5], D}}, recv_event()),
+ ?match(ok, mnesia:dirty_delete({Tab3, counter})),
+ ?match({mnesia_table_event, {delete, Tab3, {Tab3,counter},
+ [{Tab3,counter,1}], D}}, recv_event()),
ok.
@@ -1987,7 +2002,7 @@ subscribe_standard(Config) when is_list(Config)->
%% Check system events
?match({error, {badarg, foo}}, mnesia:unsubscribe(foo)),
?match({error, badarg}, mnesia:unsubscribe({table, foo})),
- ?match(_, mnesia:unsubscribe(activity)),
+ mnesia:unsubscribe(activity),
?match({ok, N1}, mnesia:subscribe(system)),
?match({ok, N1}, mnesia:subscribe(activity)),
diff --git a/lib/mnesia/vsn.mk b/lib/mnesia/vsn.mk
index c8187013be..064ba43791 100644
--- a/lib/mnesia/vsn.mk
+++ b/lib/mnesia/vsn.mk
@@ -1 +1 @@
-MNESIA_VSN = 4.10
+MNESIA_VSN = 4.11