aboutsummaryrefslogtreecommitdiffstats
path: root/lib/mnesia/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/mnesia/src')
-rw-r--r--lib/mnesia/src/mnesia.app.src3
-rw-r--r--lib/mnesia/src/mnesia.erl6
-rw-r--r--lib/mnesia/src/mnesia.hrl4
-rw-r--r--lib/mnesia/src/mnesia_controller.erl24
-rw-r--r--lib/mnesia/src/mnesia_frag.erl2
-rw-r--r--lib/mnesia/src/mnesia_index.erl6
-rw-r--r--lib/mnesia/src/mnesia_lib.erl13
-rw-r--r--lib/mnesia/src/mnesia_loader.erl3
-rw-r--r--lib/mnesia/src/mnesia_locker.erl32
-rw-r--r--lib/mnesia/src/mnesia_recover.erl37
-rw-r--r--lib/mnesia/src/mnesia_snmp_hook.erl8
-rw-r--r--lib/mnesia/src/mnesia_subscr.erl2
12 files changed, 100 insertions, 40 deletions
diff --git a/lib/mnesia/src/mnesia.app.src b/lib/mnesia/src/mnesia.app.src
index 3715488ec2..e755864792 100644
--- a/lib/mnesia/src/mnesia.app.src
+++ b/lib/mnesia/src/mnesia.app.src
@@ -47,6 +47,7 @@
mnesia_tm
]},
{applications, [kernel, stdlib]},
- {mod, {mnesia_sup, []}}]}.
+ {mod, {mnesia_sup, []}},
+ {runtime_dependencies, ["stdlib-2.0","kernel-3.0","erts-6.0"]}]}.
diff --git a/lib/mnesia/src/mnesia.erl b/lib/mnesia/src/mnesia.erl
index b7d80c1370..8f14831ad3 100644
--- a/lib/mnesia/src/mnesia.erl
+++ b/lib/mnesia/src/mnesia.erl
@@ -1140,10 +1140,12 @@ match_object(_Tid, _Ts, Tab, Pat, _LockKind) ->
add_written_match(S, Pat, Tab, Objs) ->
Ops = find_ops(S, Tab, Pat),
- add_match(Ops, Objs, val({Tab, setorbag})).
+ FixedRes = add_match(Ops, Objs, val({Tab, setorbag})),
+ MS = ets:match_spec_compile([{Pat, [], ['$_']}]),
+ ets:match_spec_run(FixedRes, MS).
find_ops(S, Tab, Pat) ->
- GetWritten = [{{{Tab, '_'}, Pat, write}, [], ['$_']},
+ GetWritten = [{{{Tab, '_'}, '_', write}, [], ['$_']},
{{{Tab, '_'}, '_', delete}, [], ['$_']},
{{{Tab, '_'}, Pat, delete_object}, [], ['$_']}],
ets:select(S, GetWritten).
diff --git a/lib/mnesia/src/mnesia.hrl b/lib/mnesia/src/mnesia.hrl
index 2855792646..c8010d5466 100644
--- a/lib/mnesia/src/mnesia.hrl
+++ b/lib/mnesia/src/mnesia.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. 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
@@ -35,7 +35,7 @@
-define(ets_last(Tab), ets:last(Tab)).
-define(ets_prev(Tab, Key), ets:prev(Tab, Key)).
-define(ets_slot(Tab, Pos), ets:slot(Tab, Pos)).
--define(ets_new_table(Tab, Props), ets:new(Tab, Props)).
+-define(ets_new_table(Tab, Props), _ = ets:new(Tab, Props)).
-define(ets_delete_table(Tab), ets:delete(Tab)).
-define(ets_fixtable(Tab, Bool), ets:fixtable(Tab, Bool)).
diff --git a/lib/mnesia/src/mnesia_controller.erl b/lib/mnesia/src/mnesia_controller.erl
index a83e55ac62..5a9bae54da 100644
--- a/lib/mnesia/src/mnesia_controller.erl
+++ b/lib/mnesia/src/mnesia_controller.erl
@@ -300,8 +300,13 @@ mnesia_down(Node) ->
end.
wait_for_schema_commit_lock() ->
- link(whereis(?SERVER_NAME)),
- unsafe_call(wait_for_schema_commit_lock).
+ try
+ Pid = whereis(?SERVER_NAME),
+ link(Pid), %% Keep the link until release_schema_commit_lock
+ gen_server:call(Pid, wait_for_schema_commit_lock, infinity)
+ catch _:_ ->
+ mnesia:abort({node_not_running, node()})
+ end.
block_controller() ->
call(block_controller).
@@ -557,12 +562,6 @@ cast(Msg) ->
abcast(Nodes, Msg) ->
gen_server:abcast(Nodes, ?SERVER_NAME, Msg).
-unsafe_call(Msg) ->
- case whereis(?SERVER_NAME) of
- undefined -> {error, {node_not_running, node()}};
- Pid -> gen_server:call(Pid, Msg, infinity)
- end.
-
call(Msg) ->
case whereis(?SERVER_NAME) of
undefined ->
@@ -1208,7 +1207,14 @@ handle_info(Done = #loader_done{worker_pid=WPid, table_name=Tab}, State0) ->
{value,{_,Worker}} = lists:keysearch(WPid,1,get_loaders(State0)),
add_loader(Tab,Worker,State1);
_ ->
- State1
+ DelState = State1#state{late_loader_queue=gb_trees:delete_any(Tab, LateQueue0)},
+ case ?catch_val({Tab, storage_type}) of
+ ram_copies ->
+ cast({disc_load, Tab, ram_only}),
+ DelState;
+ _ ->
+ DelState
+ end
end
end,
State3 = opt_start_worker(State2),
diff --git a/lib/mnesia/src/mnesia_frag.erl b/lib/mnesia/src/mnesia_frag.erl
index 4a1616e054..66fc20913c 100644
--- a/lib/mnesia/src/mnesia_frag.erl
+++ b/lib/mnesia/src/mnesia_frag.erl
@@ -939,7 +939,7 @@ do_split(_FH, _OldN, _FragNames, [], Ops) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Delete a fragment from a fragmented table
-%% and merge its records with an other fragment
+%% and merge its records with another fragment
make_multi_del_frag(Tab) ->
verify_multi(Tab),
diff --git a/lib/mnesia/src/mnesia_index.erl b/lib/mnesia/src/mnesia_index.erl
index 8fef611a48..87cb58dae1 100644
--- a/lib/mnesia/src/mnesia_index.erl
+++ b/lib/mnesia/src/mnesia_index.erl
@@ -52,7 +52,11 @@
val(Var) ->
case ?catch_val(Var) of
- {'EXIT', _ReASoN_} -> mnesia_lib:other_val(Var, _ReASoN_);
+ {'EXIT', _ReASoN_} ->
+ case mnesia_lib:other_val(Var) of
+ error -> mnesia_lib:pr_other(Var, _ReASoN_);
+ Val -> Val
+ end;
_VaLuE_ -> _VaLuE_
end.
diff --git a/lib/mnesia/src/mnesia_lib.erl b/lib/mnesia/src/mnesia_lib.erl
index 109e924971..a32c69c59e 100644
--- a/lib/mnesia/src/mnesia_lib.erl
+++ b/lib/mnesia/src/mnesia_lib.erl
@@ -115,6 +115,8 @@
mkcore/1,
not_active_here/1,
other_val/2,
+ other_val/1,
+ pr_other/2,
overload_read/0,
overload_read/1,
overload_set/2,
@@ -389,16 +391,19 @@ unset(Var) ->
?ets_delete(mnesia_gvar, Var).
other_val(Var, Other) ->
+ case other_val(Var) of
+ error -> pr_other(Var, Other);
+ Val -> Val
+ end.
+
+other_val(Var) ->
case Var of
{_, where_to_read} -> nowhere;
{_, where_to_write} -> [];
{_, active_replicas} -> [];
- _ ->
- pr_other(Var, Other)
+ _ -> error
end.
--spec pr_other(_,_) -> no_return().
-
pr_other(Var, Other) ->
Why =
case is_running() of
diff --git a/lib/mnesia/src/mnesia_loader.erl b/lib/mnesia/src/mnesia_loader.erl
index 4afbea1cc2..530317bcdd 100644
--- a/lib/mnesia/src/mnesia_loader.erl
+++ b/lib/mnesia/src/mnesia_loader.erl
@@ -208,7 +208,8 @@ do_get_network_copy(Tab, Reason, Ns, Storage, Cs) ->
set({Tab, load_node}, Node),
set({Tab, load_reason}, Reason),
mnesia_controller:i_have_tab(Tab),
- dbg_out("Table ~p copied from ~p to ~p~n", [Tab, Node, node()]),
+ dbg_out("Table ~p copied from ~p to ~p (~b entries)~n",
+ [Tab, Node, node(), mnesia:table_info(Tab, size)]),
{loaded, ok};
Err = {error, _} when element(1, Reason) == dumper ->
{not_loaded,Err};
diff --git a/lib/mnesia/src/mnesia_locker.erl b/lib/mnesia/src/mnesia_locker.erl
index 32cea903c9..e27396731f 100644
--- a/lib/mnesia/src/mnesia_locker.erl
+++ b/lib/mnesia/src/mnesia_locker.erl
@@ -84,7 +84,7 @@ init(Parent) ->
register(?MODULE, self()),
process_flag(trap_exit, true),
?ets_new_table(mnesia_held_locks, [ordered_set, private, named_table]),
- ?ets_new_table(mnesia_tid_locks, [bag, private, named_table]),
+ ?ets_new_table(mnesia_tid_locks, [ordered_set, private, named_table]),
?ets_new_table(mnesia_sticky_locks, [set, private, named_table]),
?ets_new_table(mnesia_lock_queue, [bag, private, named_table, {keypos, 2}]),
@@ -131,9 +131,14 @@ send_release_tid(Nodes, Tid) ->
receive_release_tid_acc([Node | Nodes], Tid) ->
receive
{?MODULE, Node, {tid_released, Tid}} ->
- receive_release_tid_acc(Nodes, Tid);
- {mnesia_down, Node} ->
receive_release_tid_acc(Nodes, Tid)
+ after 0 ->
+ receive
+ {?MODULE, Node, {tid_released, Tid}} ->
+ receive_release_tid_acc(Nodes, Tid);
+ {mnesia_down, Node} ->
+ receive_release_tid_acc(Nodes, Tid)
+ end
end;
receive_release_tid_acc([], _Tid) ->
ok.
@@ -248,13 +253,13 @@ loop(State) ->
end.
set_lock(Tid, Oid, Op, []) ->
- ?ets_insert(mnesia_tid_locks, {Tid, Oid, Op}),
+ ?ets_insert(mnesia_tid_locks, {{Tid, Oid, Op}}),
?ets_insert(mnesia_held_locks, {Oid, Op, [{Op, Tid}]});
set_lock(Tid, Oid, read, [{Oid, Prev, Items}]) ->
- ?ets_insert(mnesia_tid_locks, {Tid, Oid, read}),
+ ?ets_insert(mnesia_tid_locks, {{Tid, Oid, read}}),
?ets_insert(mnesia_held_locks, {Oid, Prev, [{read, Tid}|Items]});
set_lock(Tid, Oid, write, [{Oid, _Prev, Items}]) ->
- ?ets_insert(mnesia_tid_locks, {Tid, Oid, write}),
+ ?ets_insert(mnesia_tid_locks, {{Tid, Oid, write}}),
?ets_insert(mnesia_held_locks, {Oid, write, [{write, Tid}|Items]});
set_lock(Tid, Oid, Op, undefined) ->
set_lock(Tid, Oid, Op, ?ets_lookup(mnesia_held_locks, Oid)).
@@ -270,7 +275,8 @@ try_sticky_lock(Tid, Op, Pid, {Tab, _} = Oid) ->
try_lock(Tid, Op, Pid, Oid);
[{_,N}] ->
Req = {Pid, {Op, Tid, Oid}},
- Pid ! {?MODULE, node(), {switch, N, Req}}
+ Pid ! {?MODULE, node(), {switch, N, Req}},
+ true
end.
try_lock(Tid, read_write, Pid, Oid) ->
@@ -293,7 +299,7 @@ try_lock(Tid, Op, SimpleOp, Lock, Pid, Oid) ->
?ets_insert(mnesia_lock_queue,
#queue{oid = Oid, tid = Tid, op = Op,
pid = Pid, lucky = Lucky}),
- ?ets_insert(mnesia_tid_locks, {Tid, Oid, {queued, Op}})
+ ?ets_insert(mnesia_tid_locks, {{Tid, Oid, {queued, Op}}})
end.
grant_lock(Tid, read, Lock, Oid = {Tab, Key}, Default)
@@ -492,7 +498,7 @@ set_read_lock_on_all_keys(Tid, From, Tab, IxKey, Pos) ->
?ets_insert(mnesia_lock_queue,
#queue{oid = Oid, tid = Tid, op = Op,
pid = From, lucky = Lucky}),
- ?ets_insert(mnesia_tid_locks, {Tid, Oid, {queued, Op}})
+ ?ets_insert(mnesia_tid_locks, {{Tid, Oid, {queued, Op}}})
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -508,7 +514,8 @@ release_remote_non_pending(Node, Pending) ->
%% running at the failed node and also simply remove all
%% queue'd requests back to the failed node
- AllTids = ?ets_match(mnesia_tid_locks, {'$1', '_', '_'}),
+ AllTids0 = ?ets_match(mnesia_tid_locks, {{'$1', '_', '_'}}),
+ AllTids = lists:usort(AllTids0),
Tids = [T || [T] <- AllTids, Node == node(T#tid.pid), not lists:member(T, Pending)],
do_release_tids(Tids).
@@ -519,9 +526,10 @@ do_release_tids([]) ->
ok.
do_release_tid(Tid) ->
- Locks = ?ets_lookup(mnesia_tid_locks, Tid),
+ Objects = ets:select(mnesia_tid_locks, [{{{Tid, '_', '_'}}, [], ['$_']}]),
+ Locks = lists:map(fun({L}) -> L end, Objects),
?dbg("Release ~p ~p ~n", [Tid, Locks]),
- ?ets_delete(mnesia_tid_locks, Tid),
+ [?ets_delete(mnesia_tid_locks, L) || L <- Locks],
release_locks(Locks),
%% Removed queued locks which has had locks
UniqueLocks = keyunique(lists:sort(Locks),[]),
diff --git a/lib/mnesia/src/mnesia_recover.erl b/lib/mnesia/src/mnesia_recover.erl
index 0548a25ebf..eeb4fa0ced 100644
--- a/lib/mnesia/src/mnesia_recover.erl
+++ b/lib/mnesia/src/mnesia_recover.erl
@@ -178,7 +178,11 @@ log_decision(D) ->
val(Var) ->
case ?catch_val(Var) of
- {'EXIT', Reason} -> mnesia_lib:other_val(Var, Reason);
+ {'EXIT', Reason} ->
+ case mnesia_lib:other_val(Var) of
+ error -> mnesia_lib:pr_other(Var, Reason);
+ Val -> Val
+ end;
Value -> Value
end.
@@ -685,12 +689,29 @@ handle_call({connect_nodes, Ns}, From, State) ->
%% called from handle_info
gen_server:reply(From, {[], AlreadyConnected}),
{noreply, State};
- GoodNodes ->
+ ProbablyGoodNodes ->
%% Now we have agreed upon a protocol with some new nodes
- %% and we may use them when we recover transactions
+ %% and we may use them when we recover transactions.
+ %%
+ %% Just in case Mnesia was stopped on some of those nodes
+ %% between the protocol negotiation and now, we check one
+ %% more time the state of Mnesia.
+ %%
+ %% Of course, there is still a chance that mnesia_down
+ %% events occur during this check and we miss them. To
+ %% prevent it, handle_cast({mnesia_down, ...}, ...) removes
+ %% the down node again, in addition to mnesia_down/1.
+ %%
+ %% See a comment in handle_cast({mnesia_down, ...}, ...).
+ Verify = fun(N) ->
+ Run = mnesia_lib:is_running(N),
+ Run =:= yes orelse Run =:= starting
+ end,
+ GoodNodes = [N || N <- ProbablyGoodNodes, Verify(N)],
+
mnesia_lib:add_list(recover_nodes, GoodNodes),
cast({announce_all, GoodNodes}),
- case get_master_nodes(schema) of
+ case get_master_nodes(schema) of
[] ->
Context = starting_partitioned_network,
mnesia_monitor:detect_inconcistency(GoodNodes, Context);
@@ -838,6 +859,14 @@ handle_cast({what_decision, Node, OtherD}, State) ->
{noreply, State};
handle_cast({mnesia_down, Node}, State) ->
+ %% The node was already removed from recover_nodes in mnesia_down/1,
+ %% but we do it again here in the mnesia_recover process, in case
+ %% another event incorrectly added it back. This can happen during
+ %% Mnesia startup which takes time betweenthe connection, the
+ %% protocol negotiation and the merge of the schema.
+ %%
+ %% See a comment in handle_call({connect_nodes, ...), ...).
+ mnesia_lib:del(recover_nodes, Node),
case State#state.unclear_decision of
undefined ->
{noreply, State};
diff --git a/lib/mnesia/src/mnesia_snmp_hook.erl b/lib/mnesia/src/mnesia_snmp_hook.erl
index 893b39f3c0..256f83b029 100644
--- a/lib/mnesia/src/mnesia_snmp_hook.erl
+++ b/lib/mnesia/src/mnesia_snmp_hook.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. 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
@@ -32,7 +32,11 @@
val(Var) ->
case ?catch_val(Var) of
- {'EXIT', _ReASoN_} -> mnesia_lib:other_val(Var, _ReASoN_);
+ {'EXIT', _ReASoN_} ->
+ case mnesia_lib:other_val(Var) of
+ error -> mnesia_lib:pr_other(Var, _ReASoN_);
+ Val -> Val
+ end;
_VaLuE_ -> _VaLuE_
end.
diff --git a/lib/mnesia/src/mnesia_subscr.erl b/lib/mnesia/src/mnesia_subscr.erl
index 9272211ad2..866a57e370 100644
--- a/lib/mnesia/src/mnesia_subscr.erl
+++ b/lib/mnesia/src/mnesia_subscr.erl
@@ -225,7 +225,7 @@ call(Msg) ->
Res = gen_server:call(Pid, Msg, infinity),
%% We get an exit signal if server dies
receive
- {'EXIT', _Pid, _Reason} ->
+ {'EXIT', Pid, _Reason} ->
{error, {node_not_running, node()}}
after 0 ->
Res