aboutsummaryrefslogtreecommitdiffstats
path: root/lib/mnesia
diff options
context:
space:
mode:
authorUlf Wiger <[email protected]>2010-12-09 18:14:15 +0100
committerHenrik Nord <[email protected]>2011-05-16 11:00:28 +0200
commit38eef7af0f8bc1d2d152cefb8df1e1303ddcac45 (patch)
treed9c59098037eafa221a08efaa085933e8915c127 /lib/mnesia
parent6d446fc5d08d56174a79ab546d5aa2e79277af06 (diff)
downloadotp-38eef7af0f8bc1d2d152cefb8df1e1303ddcac45.tar.gz
otp-38eef7af0f8bc1d2d152cefb8df1e1303ddcac45.tar.bz2
otp-38eef7af0f8bc1d2d152cefb8df1e1303ddcac45.zip
Write locks now check majority when needed.
Since the table loader also sets (table) write locks, a special lock type, 'load', was needed. Unfortunately, this affects mnesia activity callbacks that redefine the lock operation.
Diffstat (limited to 'lib/mnesia')
-rw-r--r--lib/mnesia/src/mnesia.erl6
-rw-r--r--lib/mnesia/src/mnesia_lib.erl10
-rw-r--r--lib/mnesia/src/mnesia_loader.erl2
-rw-r--r--lib/mnesia/src/mnesia_locker.erl33
-rw-r--r--lib/mnesia/src/mnesia_schema.erl1
-rw-r--r--lib/mnesia/src/mnesia_tm.erl12
6 files changed, 52 insertions, 12 deletions
diff --git a/lib/mnesia/src/mnesia.erl b/lib/mnesia/src/mnesia.erl
index 025b32f506..43953f9ad4 100644
--- a/lib/mnesia/src/mnesia.erl
+++ b/lib/mnesia/src/mnesia.erl
@@ -39,6 +39,7 @@
%% Access within an activity - Lock acquisition
lock/2, lock/4,
+ lock_table/2,
read_lock_table/1,
write_lock_table/1,
@@ -415,6 +416,9 @@ lock(LockItem, LockKind) ->
abort(no_transaction)
end.
+lock_table(Tab, LockKind) ->
+ lock({table, Tab}, LockKind).
+
lock(Tid, Ts, LockItem, LockKind) ->
case element(1, Tid) of
tid ->
@@ -467,6 +471,8 @@ lock_table(Tid, Ts, Tab, LockKind) when is_atom(Tab) ->
mnesia_locker:rlock_table(Tid, Store, Tab);
write ->
mnesia_locker:wlock_table(Tid, Store, Tab);
+ load ->
+ mnesia_locker:load_lock_table(Tid, Store, Tab);
sticky_write ->
mnesia_locker:sticky_wlock_table(Tid, Store, Tab);
none ->
diff --git a/lib/mnesia/src/mnesia_lib.erl b/lib/mnesia/src/mnesia_lib.erl
index 36bcfe8de9..7e926a6258 100644
--- a/lib/mnesia/src/mnesia_lib.erl
+++ b/lib/mnesia/src/mnesia_lib.erl
@@ -96,6 +96,8 @@
exists/1,
fatal/2,
get_node_number/0,
+ have_majority/2,
+ have_majority/3,
fix_error/1,
important/2,
incr_counter/1,
@@ -660,6 +662,14 @@ proc_info(_) -> false.
get_node_number() ->
{node(), self()}.
+have_majority(Tab, HaveNodes) ->
+ have_majority(Tab, val({Tab, all_nodes}), HaveNodes).
+
+have_majority(_Tab, AllNodes, HaveNodes) ->
+ Missing = AllNodes -- HaveNodes,
+ Present = AllNodes -- Missing,
+ length(Present) > length(Missing).
+
read_log_files() ->
[{F, catch file:read_file(F)} || F <- mnesia_log:log_files()].
diff --git a/lib/mnesia/src/mnesia_loader.erl b/lib/mnesia/src/mnesia_loader.erl
index 3de329503e..e785b795d1 100644
--- a/lib/mnesia/src/mnesia_loader.erl
+++ b/lib/mnesia/src/mnesia_loader.erl
@@ -702,7 +702,7 @@ send_table(Pid, Tab, RemoteS) ->
prepare_copy(Pid, Tab, Storage) ->
Trans =
fun() ->
- mnesia:write_lock_table(Tab),
+ mnesia:lock_table(Tab, load),
mnesia_subscr:subscribe(Pid, {table, Tab}),
update_where_to_write(Tab, node(Pid)),
mnesia_lib:db_fixtable(Storage, Tab, true),
diff --git a/lib/mnesia/src/mnesia_locker.erl b/lib/mnesia/src/mnesia_locker.erl
index ca0cc79c45..9822dfd116 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
@@ -657,6 +658,7 @@ rwlock(Tid, Store, Oid) ->
case need_lock(Store, Tab, Key, Lock) of
yes ->
Ns = w_nodes(Tab),
+ check_majority(Tab, Ns),
Res = get_rwlocks_on_nodes(Ns, rwlock, Node, Store, Tid, Oid),
?ets_insert(Store, {{locks, Tab, Key}, Lock}),
Res;
@@ -683,6 +685,28 @@ w_nodes(Tab) ->
_ -> 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.
@@ -773,10 +797,14 @@ 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),
+ check_majority(CheckMajority, Tab, Ns),
Op = {self(), {write, Tid, Oid}},
?ets_insert(Store, {{locks, Tab, Key}, write}),
get_wlocks_on_nodes(Ns, Ns, Store, Op, Oid);
@@ -789,6 +817,9 @@ wlock(Tid, Store, Oid) ->
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) ->
diff --git a/lib/mnesia/src/mnesia_schema.erl b/lib/mnesia/src/mnesia_schema.erl
index a6c8ffec01..b3f06322d9 100644
--- a/lib/mnesia/src/mnesia_schema.erl
+++ b/lib/mnesia/src/mnesia_schema.erl
@@ -179,6 +179,7 @@ do_set_schema(Tab, Cs) ->
set({Tab, load_order}, Cs#cstruct.load_order),
set({Tab, access_mode}, Cs#cstruct.access_mode),
set({Tab, majority}, Cs#cstruct.majority),
+ set({Tab, all_nodes}, mnesia_lib:cs_to_nodes(Cs)),
set({Tab, snmp}, Cs#cstruct.snmp),
set({Tab, user_properties}, Cs#cstruct.user_properties),
[set({Tab, user_property, element(1, P)}, P) || P <- Cs#cstruct.user_properties],
diff --git a/lib/mnesia/src/mnesia_tm.erl b/lib/mnesia/src/mnesia_tm.erl
index c7a0c28589..0b87c40add 100644
--- a/lib/mnesia/src/mnesia_tm.erl
+++ b/lib/mnesia/src/mnesia_tm.erl
@@ -1259,23 +1259,15 @@ needs_majority(Tab, #prep{majority = M}) ->
false ->
[{Tab, []} | M];
true ->
- CopyHolders = all_copy_holders(Tab),
+ CopyHolders = val({Tab, all_nodes}),
[{Tab, CopyHolders} | M]
end
end.
-all_copy_holders(Tab) ->
- DC = val({Tab, disc_copies}),
- DO = val({Tab, disc_only_copies}),
- RC = val({Tab, ram_copies}),
- DC ++ DO ++ RC.
-
have_majority([], _) ->
ok;
have_majority([{Tab, AllNodes} | Rest], Nodes) ->
- Missing = AllNodes -- Nodes,
- Present = AllNodes -- Missing,
- case length(Present) > length(Missing) of
+ case mnesia_lib:have_majority(Tab, AllNodes, Nodes) of
true ->
have_majority(Rest, Nodes);
false ->