diff options
Diffstat (limited to 'lib/mnesia')
-rw-r--r-- | lib/mnesia/doc/src/notes.xml | 26 | ||||
-rw-r--r-- | lib/mnesia/src/mnesia.appup.src | 14 | ||||
-rw-r--r-- | lib/mnesia/src/mnesia_locker.erl | 32 | ||||
-rw-r--r-- | lib/mnesia/src/mnesia_monitor.erl | 89 | ||||
-rw-r--r-- | lib/mnesia/src/mnesia_subscr.erl | 4 | ||||
-rw-r--r-- | lib/mnesia/src/mnesia_tm.erl | 6 | ||||
-rw-r--r-- | lib/mnesia/test/mnesia_dirty_access_test.erl | 7 | ||||
-rw-r--r-- | lib/mnesia/test/mnesia_evil_coverage_test.erl | 25 | ||||
-rw-r--r-- | lib/mnesia/vsn.mk | 2 |
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 |