aboutsummaryrefslogtreecommitdiffstats
path: root/lib/mnesia/src/mnesia_schema.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/mnesia/src/mnesia_schema.erl')
-rw-r--r--lib/mnesia/src/mnesia_schema.erl99
1 files changed, 87 insertions, 12 deletions
diff --git a/lib/mnesia/src/mnesia_schema.erl b/lib/mnesia/src/mnesia_schema.erl
index 354431a296..fef72ad39c 100644
--- a/lib/mnesia/src/mnesia_schema.erl
+++ b/lib/mnesia/src/mnesia_schema.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1996-2011. 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
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
@@ -37,6 +37,7 @@
change_table_copy_type/3,
change_table_access_mode/2,
change_table_load_order/2,
+ change_table_majority/2,
change_table_frag/2,
clear_table/1,
create_table/1,
@@ -62,6 +63,7 @@
list2cs/1,
lock_schema/0,
merge_schema/0,
+ merge_schema/1,
move_table/3,
opt_create_dir/2,
prepare_commit/3,
@@ -177,6 +179,8 @@ do_set_schema(Tab, Cs) ->
set({Tab, disc_only_copies}, Cs#cstruct.disc_only_copies),
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],
@@ -650,6 +654,7 @@ list2cs(List) when is_list(List) ->
Snmp = pick(Name, snmp, List, []),
LoadOrder = pick(Name, load_order, List, 0),
AccessMode = pick(Name, access_mode, List, read_write),
+ Majority = pick(Name, majority, List, false),
UserProps = pick(Name, user_properties, List, []),
verify({alt, [nil, list]}, mnesia_lib:etype(UserProps),
{bad_type, Name, {user_properties, UserProps}}),
@@ -675,6 +680,7 @@ list2cs(List) when is_list(List) ->
snmp = Snmp,
load_order = LoadOrder,
access_mode = AccessMode,
+ majority = Majority,
local_content = LC,
record_name = RecName,
attributes = Attrs,
@@ -808,7 +814,16 @@ verify_cstruct(Cs) when is_record(Cs, cstruct) ->
Access = Cs#cstruct.access_mode,
verify({alt, [read_write, read_only]}, Access,
{bad_type, Tab, {access_mode, Access}}),
-
+ Majority = Cs#cstruct.majority,
+ verify({alt, [true, false]}, Majority,
+ {bad_type, Tab, {majority, Majority}}),
+ case Majority of
+ true ->
+ verify(false, LC,
+ {combine_error, Tab, [{local_content,true},{majority,true}]});
+ false ->
+ ok
+ end,
Snmp = Cs#cstruct.snmp,
verify(true, mnesia_snmp_hook:check_ustruct(Snmp),
{badarg, Tab, {snmp, Snmp}}),
@@ -1494,6 +1509,43 @@ make_change_table_load_order(Tab, LoadOrder) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+change_table_majority(Tab, Majority) when is_boolean(Majority) ->
+ schema_transaction(fun() -> do_change_table_majority(Tab, Majority) end).
+
+do_change_table_majority(schema, _Majority) ->
+ mnesia:abort({bad_type, schema});
+do_change_table_majority(Tab, Majority) ->
+ TidTs = get_tid_ts_and_lock(schema, write),
+ get_tid_ts_and_lock(Tab, none),
+ insert_schema_ops(TidTs, make_change_table_majority(Tab, Majority)).
+
+make_change_table_majority(Tab, Majority) ->
+ ensure_writable(schema),
+ Cs = incr_version(val({Tab, cstruct})),
+ ensure_active(Cs),
+ OldMajority = Cs#cstruct.majority,
+ Cs2 = Cs#cstruct{majority = Majority},
+ FragOps = case lists:keyfind(base_table, 1, Cs#cstruct.frag_properties) of
+ {_, Tab} ->
+ FragNames = mnesia_frag:frag_names(Tab) -- [Tab],
+ lists:map(
+ fun(T) ->
+ get_tid_ts_and_lock(Tab, none),
+ CsT = incr_version(val({T, cstruct})),
+ ensure_active(CsT),
+ CsT2 = CsT#cstruct{majority = Majority},
+ verify_cstruct(CsT2),
+ {op, change_table_majority, cs2list(CsT2),
+ OldMajority, Majority}
+ end, FragNames);
+ false -> [];
+ {_, _} -> mnesia:abort({bad_type, Tab})
+ end,
+ verify_cstruct(Cs2),
+ [{op, change_table_majority, cs2list(Cs2), OldMajority, Majority} | FragOps].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
write_table_property(Tab, Prop) when is_tuple(Prop), size(Prop) >= 1 ->
schema_transaction(fun() -> do_write_table_property(Tab, Prop) end);
write_table_property(Tab, Prop) ->
@@ -1733,7 +1785,10 @@ prepare_op(_Tid, {op, announce_im_running, Node, SchemaDef, Running, RemoteRunni
Node == node() -> %% Announce has already run on local node
ignore; %% from do_merge_schema
true ->
- NewNodes = mnesia_lib:uniq(Running++RemoteRunning) -- val({current,db_nodes}),
+ %% If a node has restarted it may still linger in db_nodes,
+ %% but have been removed from recover_nodes
+ Current = mnesia_lib:intersect(val({current,db_nodes}), [node()|val(recover_nodes)]),
+ NewNodes = mnesia_lib:uniq(Running++RemoteRunning) -- Current,
mnesia_lib:set(prepare_op, {announce_im_running,NewNodes}),
announce_im_running(NewNodes, SchemaCs)
end,
@@ -2650,10 +2705,16 @@ make_dump_tables([]) ->
%% Merge the local schema with the schema on other nodes
merge_schema() ->
- schema_transaction(fun() -> do_merge_schema() end).
+ schema_transaction(fun() -> do_merge_schema([]) end).
+
+merge_schema(UserFun) ->
+ schema_transaction(fun() -> UserFun(fun(Arg) -> do_merge_schema(Arg) end) end).
+
-do_merge_schema() ->
+do_merge_schema(LockTabs0) ->
{_Mod, Tid, Ts} = get_tid_ts_and_lock(schema, write),
+ LockTabs = [{T, tab_to_nodes(T)} || T <- LockTabs0],
+ [get_tid_ts_and_lock(T,write) || {T,_} <- LockTabs],
Connected = val(recover_nodes),
Running = val({current, db_nodes}),
Store = Ts#tidstore.store,
@@ -2665,9 +2726,12 @@ do_merge_schema() ->
mnesia:abort({bad_commit, {missing_lock, Miss}})
end,
case Connected -- Running of
- [Node | _] ->
+ [Node | _] = OtherNodes ->
%% Time for a schema merging party!
mnesia_locker:wlock_no_exist(Tid, Store, schema, [Node]),
+ [mnesia_locker:wlock_no_exist(
+ Tid, Store, T, mnesia_lib:intersect(Ns, OtherNodes))
+ || {T,Ns} <- LockTabs],
case rpc:call(Node, mnesia_controller, get_cstructs, []) of
{cstructs, Cstructs, RemoteRunning1} ->
LockedAlready = Running ++ [Node],
@@ -2676,11 +2740,15 @@ do_merge_schema() ->
if
RemoteRunning /= RemoteRunning1 ->
mnesia_lib:error("Mnesia on ~p could not connect to node(s) ~p~n",
- [node(), RemoteRunning1 -- RemoteRunning]);
+ [node(), RemoteRunning1 -- RemoteRunning]),
+ mnesia:abort({node_not_running, RemoteRunning1 -- RemoteRunning});
true -> ok
end,
NeedsLock = RemoteRunning -- LockedAlready,
mnesia_locker:wlock_no_exist(Tid, Store, schema, NeedsLock),
+ [mnesia_locker:wlock_no_exist(Tid, Store, T,
+ mnesia_lib:intersect(Ns,NeedsLock))
+ || {T,Ns} <- LockTabs],
{value, SchemaCs} =
lists:keysearch(schema, #cstruct.name, Cstructs),
@@ -2714,6 +2782,10 @@ do_merge_schema() ->
not_merged
end.
+tab_to_nodes(Tab) when is_atom(Tab) ->
+ Cs = val({Tab, cstruct}),
+ mnesia_lib:cs_to_nodes(Cs).
+
make_merge_schema(Node, [Cs | Cstructs]) ->
Ops = do_make_merge_schema(Node, Cs),
Ops ++ make_merge_schema(Node, Cstructs);
@@ -2953,6 +3025,7 @@ merge_versions(AnythingNew, Cs, RemoteCs, Force) ->
Cs#cstruct.index == RemoteCs#cstruct.index,
Cs#cstruct.snmp == RemoteCs#cstruct.snmp,
Cs#cstruct.access_mode == RemoteCs#cstruct.access_mode,
+ Cs#cstruct.majority == RemoteCs#cstruct.majority,
Cs#cstruct.load_order == RemoteCs#cstruct.load_order,
Cs#cstruct.user_properties == RemoteCs#cstruct.user_properties ->
do_merge_versions(AnythingNew, Cs, RemoteCs);
@@ -3012,7 +3085,9 @@ announce_im_running([N | Ns], SchemaCs) ->
mnesia_lib:add({current, db_nodes}, N),
mnesia_controller:add_active_replica(schema, N, SchemaCs);
false ->
- ignore
+ mnesia_lib:error("Mnesia on ~p could not connect to node ~p~n",
+ [node(), N]),
+ mnesia:abort({node_not_running, N})
end,
announce_im_running(Ns, SchemaCs);
announce_im_running([], _) ->