aboutsummaryrefslogtreecommitdiffstats
path: root/lib/mnesia/src/mnesia_locker.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/mnesia/src/mnesia_locker.erl')
-rw-r--r--lib/mnesia/src/mnesia_locker.erl69
1 files changed, 58 insertions, 11 deletions
diff --git a/lib/mnesia/src/mnesia_locker.erl b/lib/mnesia/src/mnesia_locker.erl
index ca0cc79c45..0492d794f3 100644
--- a/lib/mnesia/src/mnesia_locker.erl
+++ b/lib/mnesia/src/mnesia_locker.erl
@@ -40,7 +40,8 @@
sticky_wlock_table/3,
wlock/3,
wlock_no_exist/4,
- wlock_table/3
+ wlock_table/3,
+ load_lock_table/3
]).
%% sys callback functions
@@ -656,16 +657,17 @@ rwlock(Tid, Store, Oid) ->
Lock = write,
case need_lock(Store, Tab, Key, Lock) of
yes ->
- Ns = w_nodes(Tab),
+ {Ns, Majority} = w_nodes(Tab),
+ check_majority(Majority, Tab, Ns),
Res = get_rwlocks_on_nodes(Ns, rwlock, Node, Store, Tid, Oid),
?ets_insert(Store, {{locks, Tab, Key}, Lock}),
Res;
no ->
if
Key == ?ALL ->
- w_nodes(Tab);
+ element(2, w_nodes(Tab));
Tab == ?GLOBAL ->
- w_nodes(Tab);
+ element(2, w_nodes(Tab));
true ->
dirty_rpc(Node, Tab, Key, Lock)
end
@@ -677,12 +679,34 @@ rwlock(Tid, Store, Oid) ->
%% in the local store under the key == nodes
w_nodes(Tab) ->
- Nodes = ?catch_val({Tab, where_to_write}),
- case Nodes of
- [_ | _] -> Nodes;
+ case ?catch_val({Tab, where_to_wlock}) of
+ {[_ | _], _} = Where -> Where;
_ -> mnesia:abort({no_exists, Tab})
end.
+%% If the table has the 'majority' flag set, we can
+%% only take a write lock if we see a majority of the
+%% nodes.
+
+
+check_majority(true, Tab, HaveNs) ->
+ check_majority(Tab, HaveNs);
+check_majority(false, _, _) ->
+ ok.
+
+check_majority(Tab, HaveNs) ->
+ case ?catch_val({Tab, majority}) of
+ true ->
+ case mnesia_lib:have_majority(Tab, HaveNs) of
+ true ->
+ ok;
+ false ->
+ mnesia:abort({no_majority, Tab})
+ end;
+ _ ->
+ ok
+ end.
+
%% aquire a sticky wlock, a sticky lock is a lock
%% which remains at this node after the termination of the
%% transaction.
@@ -708,12 +732,14 @@ sticky_lock(Tid, Store, {Tab, Key} = Oid, Lock) ->
end.
do_sticky_lock(Tid, Store, {Tab, Key} = Oid, Lock) ->
+ {WNodes, Majority} = w_nodes(Tab),
+ sticky_check_majority(Lock, Tab, Majority, WNodes),
?MODULE ! {self(), {test_set_sticky, Tid, Oid, Lock}},
N = node(),
receive
{?MODULE, N, granted} ->
?ets_insert(Store, {{locks, Tab, Key}, write}),
- [?ets_insert(Store, {nodes, Node}) || Node <- w_nodes(Tab)],
+ [?ets_insert(Store, {nodes, Node}) || Node <- WNodes],
granted;
{?MODULE, N, {granted, Val}} -> %% for rwlocks
case opt_lookup_in_client(Val, Oid, write) of
@@ -721,7 +747,7 @@ do_sticky_lock(Tid, Store, {Tab, Key} = Oid, Lock) ->
exit({aborted, C});
Val2 ->
?ets_insert(Store, {{locks, Tab, Key}, write}),
- [?ets_insert(Store, {nodes, Node}) || Node <- w_nodes(Tab)],
+ [?ets_insert(Store, {nodes, Node}) || Node <- WNodes],
Val2
end;
{?MODULE, N, {not_granted, Reason}} ->
@@ -737,6 +763,16 @@ do_sticky_lock(Tid, Store, {Tab, Key} = Oid, Lock) ->
dirty_sticky_lock(Tab, Key, [N], Lock)
end.
+sticky_check_majority(W, Tab, true, WNodes) when W==write; W==read_write ->
+ case mnesia_lib:have_majority(Tab, WNodes) of
+ true ->
+ ok;
+ false ->
+ mnesia:abort({no_majority, Tab})
+ end;
+sticky_check_majority(_, _, _, _) ->
+ ok.
+
not_stuck(Tid, Store, Tab, _Key, Oid, _Lock, N) ->
rlock(Tid, Store, {Tab, ?ALL}), %% needed?
wlock(Tid, Store, Oid), %% perfect sync
@@ -773,22 +809,33 @@ sticky_wlock_table(Tid, Store, Tab) ->
%% local store when we have aquired the lock.
%%
wlock(Tid, Store, Oid) ->
+ wlock(Tid, Store, Oid, _CheckMajority = true).
+
+wlock(Tid, Store, Oid, CheckMajority) ->
{Tab, Key} = Oid,
case need_lock(Store, Tab, Key, write) of
yes ->
- Ns = w_nodes(Tab),
+ {Ns, Majority} = w_nodes(Tab),
+ if CheckMajority ->
+ check_majority(Majority, Tab, Ns);
+ true ->
+ ignore
+ end,
Op = {self(), {write, Tid, Oid}},
?ets_insert(Store, {{locks, Tab, Key}, write}),
get_wlocks_on_nodes(Ns, Ns, Store, Op, Oid);
no when Key /= ?ALL, Tab /= ?GLOBAL ->
[];
no ->
- w_nodes(Tab)
+ element(2, w_nodes(Tab))
end.
wlock_table(Tid, Store, Tab) ->
wlock(Tid, Store, {Tab, ?ALL}).
+load_lock_table(Tid, Store, Tab) ->
+ wlock(Tid, Store, {Tab, ?ALL}, _CheckMajority = false).
+
%% Write lock even if the table does not exist
wlock_no_exist(Tid, Store, Tab, Ns) ->