diff options
Diffstat (limited to 'lib/mnesia/src/mnesia_tm.erl')
-rw-r--r-- | lib/mnesia/src/mnesia_tm.erl | 106 |
1 files changed, 70 insertions, 36 deletions
diff --git a/lib/mnesia/src/mnesia_tm.erl b/lib/mnesia/src/mnesia_tm.erl index 5a070cf0cd..9827ef97ad 100644 --- a/lib/mnesia/src/mnesia_tm.erl +++ b/lib/mnesia/src/mnesia_tm.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2022. All Rights Reserved. +%% Copyright Ericsson AB 1996-2023. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -42,6 +42,7 @@ put_activity_id/2, block_tab/1, unblock_tab/1, + sync/0, fixtable/3, new_cr_format/1 ]). @@ -181,7 +182,7 @@ tmpid(Pid) -> %% Returns a list of participant transaction Tid's mnesia_down(Node) -> - %% Syncronously call needed in order to avoid + %% Synchronously call needed in order to avoid %% race with mnesia_tm's coordinator processes %% that may restart and acquire new locks. %% mnesia_monitor takes care of the sync @@ -205,6 +206,17 @@ block_tab(Tab) -> unblock_tab(Tab) -> req({unblock_tab, Tab}). +fixtable(Tab, Lock, Me) -> + case req({fixtable, [Tab,Lock,Me]}) of + error -> + exit({no_exists, Tab}); + Else -> + Else + end. + +sync() -> + req(sync). + doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor=Sup}=State) -> receive {_From, {async_dirty, Tid, Commit, Tab}} -> @@ -250,25 +262,30 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor= [{tid, Tid}, {prot, Protocol}]), mnesia_checkpoint:tm_enter_pending(Tid, DiscNs, RamNs), Commit = new_cr_format(Commit0), - Pid = - if - node(Tid#tid.pid) =:= node() -> - error({internal_error, local_node}); - Protocol =:= asym_trans orelse Protocol =:= sync_asym_trans -> - Args = [Protocol, tmpid(From), Tid, Commit, DiscNs, RamNs], - spawn_link(?MODULE, commit_participant, Args); - true -> %% *_sym_trans - reply(From, {vote_yes, Tid}), - nopid - end, - P = #participant{tid = Tid, - pid = Pid, - commit = Commit, - disc_nodes = DiscNs, - ram_nodes = RamNs, - protocol = Protocol}, - State2 = State#state{participants = gb_trees:insert(Tid,P,Participants)}, - doit_loop(State2); + case is_blocked(State#state.blocked_tabs, Commit) of + false -> + Pid = + if + node(Tid#tid.pid) =:= node() -> + error({internal_error, local_node}); + Protocol =:= asym_trans orelse Protocol =:= sync_asym_trans -> + Args = [Protocol, tmpid(From), Tid, Commit, DiscNs, RamNs], + spawn_link(?MODULE, commit_participant, Args); + true -> %% *_sym_trans + reply(From, {vote_yes, Tid}), + nopid + end, + P = #participant{tid = Tid, + pid = Pid, + commit = Commit, + disc_nodes = DiscNs, + ram_nodes = RamNs, + protocol = Protocol}, + State2 = State#state{participants = gb_trees:insert(Tid,P,Participants)}, + doit_loop(State2); + true -> + reply(From, {vote_no, Tid, {bad_commit, node()}}, State) + end; {Tid, do_commit} -> case gb_trees:lookup(Tid, Participants) of @@ -449,6 +466,9 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor= reply(From, ok, State2) end; + {From, sync} -> + reply(From, ok, State); + {From, {prepare_checkpoint, Cp}} -> Res = mnesia_checkpoint:tm_prepare(Cp), case Res of @@ -478,6 +498,28 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor= doit_loop(State) end. +is_blocked([], _Commit) -> + false; +is_blocked([Tab|Tabs], #commit{ram_copies=RCs, disc_copies=DCs, + disc_only_copies=DOs, ext=Exts} = Commit) -> + is_blocked_tab(RCs, Tab) orelse + is_blocked_tab(DCs, Tab) orelse + is_blocked_tab(DOs, Tab) orelse + is_blocked_ext_tab(Exts, Tab) orelse + is_blocked(Tabs, Commit). + +is_blocked_tab([{{Tab,_},_,_}|_Ops], Tab) -> true; +is_blocked_tab([_|Ops], Tab) -> is_blocked_tab(Ops, Tab); +is_blocked_tab([],_) -> false. + +is_blocked_ext_tab([], _Tab) -> + false; +is_blocked_ext_tab(Exts, Tab) -> + case lists:keyfind(ext_copies, 1, Exts) of + false -> false; + {_, ExtOps} -> is_blocked_tab([Op || {_, Op} <- ExtOps], Tab) + end. + do_sync_dirty(From, Tid, Commit, _Tab) -> ?eval_debug_fun({?MODULE, sync_dirty, pre}, [{tid, Tid}]), Res = do_dirty(Tid, Commit), @@ -598,7 +640,7 @@ recover_coordinator(Tid, Etabs) -> recover_coordinator(Tid, Protocol, Outcome, Local, DiscNs, RamNs), ?eval_debug_fun({?MODULE, recover_coordinator, post}, [{tid, Tid}, {outcome, Outcome}, {prot, Protocol}]); - false -> %% When killed before store havn't been copied to + false -> %% When killed before store haven't been copied to ok %% to the new nested trans store. end catch _:Reason:Stacktrace -> @@ -881,7 +923,7 @@ try_again(_) -> no. %% We can only restart toplevel transactions. %% If a deadlock situation occurs in a nested transaction %% The whole thing including all nested transactions need to be -%% restarted. The stack is thus popped by a consequtive series of +%% restarted. The stack is thus popped by a consecutive series of %% exit({aborted, #cyclic{}}) calls restart(Mod, Tid, Ts, Fun, Args, Factor0, Retries0, Type, Why) -> @@ -1070,7 +1112,7 @@ dirty(Protocol, Item) -> async_dirty -> %% Send commit records to the other involved nodes, %% but do only wait for one node to complete. - %% Preferrably, the local node if possible. + %% Preferably, the local node if possible. ReadNode = val({Tab, where_to_read}), {WaitFor, FirstRes} = async_send_dirty(Tid, CR, Tab, ReadNode), @@ -1088,7 +1130,7 @@ dirty(Protocol, Item) -> %% This is the commit function, The first thing it does, %% is to find out which nodes that have been participating %% in this particular transaction, all of the mnesia_locker:lock* -%% functions insert the names of the nodes where it aquires locks +%% functions insert the names of the nodes where it acquires locks %% into the local shadow Store %% This function exacutes in the context of the user process t_commit(Type) -> @@ -1379,7 +1421,7 @@ multi_commit(read_only, _Maj = [], Tid, CR, _Store) -> multi_commit(sym_trans, _Maj = [], Tid, CR, Store) -> %% This lightweight commit protocol is used when all - %% the involved tables are replicated symetrically. + %% the involved tables are replicated symmetrically. %% Their storage types must match on each node. %% %% 1 Ask the other involved nodes if they want to commit @@ -1431,7 +1473,7 @@ multi_commit(sym_trans, _Maj = [], Tid, CR, Store) -> multi_commit(sync_sym_trans, _Maj = [], Tid, CR, Store) -> %% This protocol is the same as sym_trans except that it - %% uses syncronized calls to disk_log and syncronized commits + %% uses synchronized calls to disk_log and synchronized commits %% when several nodes are involved. {DiscNs, RamNs} = commit_nodes(CR, [], []), @@ -1754,7 +1796,7 @@ commit_participant(Protocol, Coord, Tid, Bin, C0, DiscNs, _RamNs) -> do_abort(Tid, Bin) when is_binary(Bin) -> %% Possible optimization: - %% If we want we could pass arround a flag + %% If we want we could pass around a flag %% that tells us whether the binary contains %% schema ops or not. Only if the binary %% contains schema ops there are meningful @@ -2326,14 +2368,6 @@ do_stop(#state{coordinators = Coordinators}) -> mnesia_log:stop(), exit(shutdown). -fixtable(Tab, Lock, Me) -> - case req({fixtable, [Tab,Lock,Me]}) of - error -> - exit({no_exists, Tab}); - Else -> - Else - end. - %%%%%%%%%%%%%%%%%%%%%%%%%%% %% System upgrade |