aboutsummaryrefslogtreecommitdiffstats
path: root/lib/mnesia/src/mnesia_bup.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/mnesia/src/mnesia_bup.erl')
-rw-r--r--lib/mnesia/src/mnesia_bup.erl526
1 files changed, 296 insertions, 230 deletions
diff --git a/lib/mnesia/src/mnesia_bup.erl b/lib/mnesia/src/mnesia_bup.erl
index 3b084e7371..3e55deb958 100644
--- a/lib/mnesia/src/mnesia_bup.erl
+++ b/lib/mnesia/src/mnesia_bup.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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/.
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
%%
-%% 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.
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
%%
%% %CopyrightEnd%
%%
@@ -27,6 +28,7 @@
fallback_exists/0,
tm_fallback_start/1,
create_schema/1,
+ create_schema/2,
install_fallback/1,
install_fallback/2,
uninstall_fallback/0,
@@ -45,7 +47,7 @@
uninstall_fallback_master/2,
local_uninstall_fallback/2,
do_traverse_backup/7,
- trav_apply/4
+ trav_apply/5
]).
-include("mnesia.hrl").
@@ -78,45 +80,58 @@
%% BunchOfRecords will be [] when the iteration is done.
iterate(Mod, Fun, Opaque, Acc) ->
R = #restore{bup_module = Mod, bup_data = Opaque},
- case catch read_schema_section(R) of
- {error, Reason} ->
- {error, Reason};
- {R2, {Header, Schema, Rest}} ->
- case catch iter(R2, Header, Schema, Fun, Acc, Rest) of
- {ok, R3, Res} ->
- catch safe_apply(R3, close_read, [R3#restore.bup_data]),
- {ok, Res};
- {error, Reason} ->
- catch safe_apply(R2, close_read, [R2#restore.bup_data]),
- {error, Reason};
- {'EXIT', Pid, Reason} ->
- catch safe_apply(R2, close_read, [R2#restore.bup_data]),
- {error, {'EXIT', Pid, Reason}};
- {'EXIT', Reason} ->
- catch safe_apply(R2, close_read, [R2#restore.bup_data]),
- {error, {'EXIT', Reason}}
- end
+ try read_schema_section(R) of
+ {R2, {Header, Schema, Rest}} ->
+ Ext = get_ext_types(Schema),
+ try iter(R2, Header, Schema, Ext, Fun, Acc, Rest) of
+ {ok, R3, Res} ->
+ close_read(R3),
+ {ok, Res}
+ catch throw:Err ->
+ close_read(R2),
+ Err;
+ _:Reason ->
+ close_read(R2),
+ {error, {Reason, erlang:get_stacktrace()}}
+ end
+ catch throw:{error,_} = Err ->
+ Err
end.
-iter(R, Header, Schema, Fun, Acc, []) ->
+get_ext_types(Schema) ->
+ try
+ List = lookup_schema(schema, Schema),
+ case lists:keyfind(user_properties, 1, List) of
+ {_, Props} ->
+ proplists:get_value(
+ mnesia_backend_types, Props, []);
+ false ->
+ []
+ end
+ catch
+ throw:{error, {"Cannot lookup",_}} ->
+ []
+ end.
+
+iter(R, Header, Schema, Ext, Fun, Acc, []) ->
case safe_apply(R, read, [R#restore.bup_data]) of
{R2, []} ->
- Res = Fun([], Header, Schema, Acc),
+ Res = Fun([], Header, Schema, Ext, Acc),
{ok, R2, Res};
{R2, BupItems} ->
- iter(R2, Header, Schema, Fun, Acc, BupItems)
+ iter(R2, Header, Schema, Ext, Fun, Acc, BupItems)
end;
-iter(R, Header, Schema, Fun, Acc, BupItems) ->
- Acc2 = Fun(BupItems, Header, Schema, Acc),
- iter(R, Header, Schema, Fun, Acc2, []).
+iter(R, Header, Schema, Ext, Fun, Acc, BupItems) ->
+ Acc2 = Fun(BupItems, Header, Schema, Ext, Acc),
+ iter(R, Header, Schema, Ext, Fun, Acc2, []).
-spec safe_apply(#restore{}, atom(), list()) -> tuple().
safe_apply(R, write, [_, Items]) when Items =:= [] ->
R;
safe_apply(R, What, Args) ->
- Abort = fun(Re) -> abort_restore(R, What, Args, Re) end,
+ Abort = abort_restore_fun(R, What, Args),
Mod = R#restore.bup_module,
- case catch apply(Mod, What, Args) of
+ try apply(Mod, What, Args) of
{ok, Opaque, Items} when What =:= read ->
{R#restore{bup_data = Opaque}, Items};
{ok, Opaque} when What =/= read->
@@ -125,16 +140,23 @@ safe_apply(R, What, Args) ->
Abort(Re);
Re ->
Abort(Re)
+ catch _:Re ->
+ Abort(Re)
end.
-abort_restore(R, What, Args, Reason) ->
- Mod = R#restore.bup_module,
- Opaque = R#restore.bup_data,
+-spec abort_restore_fun(_, _, _) -> fun((_) -> no_return()).
+abort_restore_fun(R, What, Args) ->
+ fun(Re) -> abort_restore(R, What, Args, Re) end.
+
+abort_restore(R = #restore{bup_module=Mod}, What, Args, Reason) ->
dbg_out("Restore aborted. ~p:~p~p -> ~p~n",
[Mod, What, Args, Reason]),
- catch apply(Mod, close_read, [Opaque]),
+ close_read(R),
throw({error, Reason}).
+close_read(#restore{bup_module=Mod, bup_data=Opaque}) ->
+ ?SAFE(Mod:close_read(Opaque)).
+
fallback_to_schema() ->
Fname = fallback_bup(),
fallback_to_schema(Fname).
@@ -145,45 +167,41 @@ fallback_to_schema(Fname) ->
{error, Reason} ->
{error, Reason};
Schema ->
- case catch lookup_schema(schema, Schema) of
- {error, _} ->
- {error, "No schema in fallback"};
- List ->
- {ok, fallback, List}
+ try lookup_schema(schema, Schema) of
+ List -> {ok, fallback, List}
+ catch throw:_ ->
+ {error, "No schema in fallback"}
end
end.
%% Opens Opaque reads schema and then close
read_schema(Mod, Opaque) ->
R = #restore{bup_module = Mod, bup_data = Opaque},
- case catch read_schema_section(R) of
- {error, Reason} ->
- {error, Reason};
+ try read_schema_section(R) of
{R2, {_Header, Schema, _}} ->
- catch safe_apply(R2, close_read, [R2#restore.bup_data]),
- Schema
+ close_read(R2),
+ Schema
+ catch throw:{error,_} = Error ->
+ Error
end.
%% Open backup media and extract schema
%% rewind backup media and leave it open
%% Returns {R, {Header, Schema}}
read_schema_section(R) ->
- case catch do_read_schema_section(R) of
- {'EXIT', Reason} ->
- catch safe_apply(R, close_read, [R#restore.bup_data]),
- {error, {'EXIT', Reason}};
- {error, Reason} ->
- catch safe_apply(R, close_read, [R#restore.bup_data]),
- {error, Reason};
- {R2, {H, Schema, Rest}} ->
- Schema2 = convert_schema(H#log_header.log_version, Schema),
- {R2, {H, Schema2, Rest}}
- end.
+ {R2, {H, Schema, Rest}} = do_read_schema_section(R),
+ Schema2 = convert_schema(H#log_header.log_version, Schema),
+ {R2, {H, Schema2, Rest}}.
do_read_schema_section(R) ->
R2 = safe_apply(R, open_read, [R#restore.bup_data]),
- {R3, RawSchema} = safe_apply(R2, read, [R2#restore.bup_data]),
- do_read_schema_section(R3, verify_header(RawSchema), []).
+ try
+ {R3, RawSchema} = safe_apply(R2, read, [R2#restore.bup_data]),
+ do_read_schema_section(R3, verify_header(RawSchema), [])
+ catch T:E ->
+ close_read(R2),
+ erlang:raise(T,E,erlang:get_stacktrace())
+ end.
do_read_schema_section(R, {ok, B, C, []}, Acc) ->
case safe_apply(R, read, [R#restore.bup_data]) of
@@ -201,7 +219,7 @@ do_read_schema_section(R, {ok, B, _C, Rest}, Acc) ->
{R, {B, Acc, Rest}};
do_read_schema_section(_R, {error, Reason}, _Acc) ->
- {error, Reason}.
+ throw({error, Reason}).
verify_header([H | RawSchema]) when is_record(H, log_header) ->
Current = mnesia_log:backup_log_header(),
@@ -218,7 +236,7 @@ verify_header([H | RawSchema]) when is_record(H, log_header) ->
{error, {"Bad kind of header. Cannot be used as backup.", H}}
end;
verify_header(RawSchema) ->
- {error, {"Missing header. Cannot be used as backup.", catch hd(RawSchema)}}.
+ {error, {"Missing header. Cannot be used as backup.", ?CATCH(hd(RawSchema))}}.
refresh_cookie(Schema, NewCookie) ->
case lists:keysearch(schema, 2, Schema) of
@@ -261,7 +279,7 @@ convert_0_1(Schema) ->
Cs = mnesia_schema:list2cs(List),
convert_0_1(Schema2, [], Cs);
false ->
- List = mnesia_schema:get_initial_schema(disc_copies, [node()]),
+ List = mnesia_schema:get_initial_schema(disc_copies, [node()], []),
Cs = mnesia_schema:list2cs(List),
convert_0_1(Schema, [], Cs)
end.
@@ -309,16 +327,19 @@ schema2bup({schema, Tab, TableDef}) ->
%% Create schema on the given nodes
%% Requires that old schemas has been deleted
%% Returns ok | {error, Reason}
-create_schema([]) ->
- create_schema([node()]);
-create_schema(Ns) when is_list(Ns) ->
+create_schema(Nodes) ->
+ create_schema(Nodes, []).
+
+create_schema([], Props) ->
+ create_schema([node()], Props);
+create_schema(Ns, Props) when is_list(Ns), is_list(Props) ->
case is_set(Ns) of
true ->
- create_schema(Ns, mnesia_schema:ensure_no_schema(Ns));
+ create_schema(Ns, mnesia_schema:ensure_no_schema(Ns), Props);
false ->
{error, {combine_error, Ns}}
end;
-create_schema(Ns) ->
+create_schema(Ns, _Props) ->
{error, {badarg, Ns}}.
is_set(List) when is_list(List) ->
@@ -326,7 +347,7 @@ is_set(List) when is_list(List) ->
is_set(_) ->
false.
-create_schema(Ns, ok) ->
+create_schema(Ns, ok, Props) ->
%% Ensure that we access the intended Mnesia
%% directory. This function may not be called
%% during startup since it will cause the
@@ -345,7 +366,7 @@ create_schema(Ns, ok) ->
Str = mk_str(),
File = mnesia_lib:dir(Str),
file:delete(File),
- case catch make_initial_backup(Ns, File, Mod) of
+ try make_initial_backup(Ns, File, Mod, Props) of
{ok, _Res} ->
case do_install_fallback(File, Mod) of
ok ->
@@ -353,8 +374,8 @@ create_schema(Ns, ok) ->
ok;
{error, Reason} ->
{error, Reason}
- end;
- {error, Reason} ->
+ end
+ catch throw:{error, Reason} ->
{error, Reason}
end
end
@@ -362,17 +383,20 @@ create_schema(Ns, ok) ->
{error, Reason} ->
{error, Reason}
end;
-create_schema(_Ns, {error, Reason}) ->
+create_schema(_Ns, {error, Reason}, _) ->
{error, Reason};
-create_schema(_Ns, Reason) ->
+create_schema(_Ns, Reason, _) ->
{error, Reason}.
mk_str() ->
- Now = [integer_to_list(I) || I <- tuple_to_list(now())],
+ Now = integer_to_list(erlang:unique_integer([positive])),
lists:concat([node()] ++ Now ++ ".TMP").
make_initial_backup(Ns, Opaque, Mod) ->
- Orig = mnesia_schema:get_initial_schema(disc_copies, Ns),
+ make_initial_backup(Ns, Opaque, Mod, []).
+
+make_initial_backup(Ns, Opaque, Mod, Props) ->
+ Orig = mnesia_schema:get_initial_schema(disc_copies, Ns, Props),
Modded = proplists:delete(storage_properties, proplists:delete(majority, Orig)),
Schema = [{schema, schema, Modded}],
O2 = do_apply(Mod, open_write, [Opaque], Opaque),
@@ -384,10 +408,11 @@ make_initial_backup(Ns, Opaque, Mod) ->
do_apply(_, write, [_, Items], Opaque) when Items =:= [] ->
Opaque;
do_apply(Mod, What, Args, _Opaque) ->
- case catch apply(Mod, What, Args) of
+ try apply(Mod, What, Args) of
{ok, Opaque2} -> Opaque2;
- {error, Reason} -> throw({error, Reason});
- {'EXIT', Reason} -> throw({error, {'EXIT', Reason}})
+ {error, Reason} -> throw({error, Reason})
+ catch _:Reason ->
+ throw({error, {'EXIT', Reason}})
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -425,11 +450,11 @@ do_install_fallback(_Opaque, Args) ->
{error, {badarg, Args}}.
check_fallback_args([Arg | Tail], FA) ->
- case catch check_fallback_arg_type(Arg, FA) of
- {'EXIT', _Reason} ->
- {error, {badarg, Arg}};
+ try check_fallback_arg_type(Arg, FA) of
FA2 ->
check_fallback_args(Tail, FA2)
+ catch error:_ ->
+ {error, {badarg, Arg}}
end;
check_fallback_args([], FA) ->
{ok, FA}.
@@ -484,38 +509,38 @@ install_fallback_master(ClientPid, FA) ->
State = {start, FA},
Opaque = FA#fallback_args.opaque,
Mod = FA#fallback_args.module,
- Res = (catch iterate(Mod, fun restore_recs/4, Opaque, State)),
+ Res = iterate(Mod, fun restore_recs/5, Opaque, State),
unlink(ClientPid),
ClientPid ! {self(), Res},
exit(shutdown).
-restore_recs(_, _, _, stop) ->
+restore_recs(_, _, _, _, stop) ->
throw({error, "restore_recs already stopped"});
-restore_recs(Recs, Header, Schema, {start, FA}) ->
+restore_recs(Recs, Header, Schema, Ext, {start, FA}) ->
%% No records in backup
Schema2 = convert_schema(Header#log_header.log_version, Schema),
CreateList = lookup_schema(schema, Schema2),
- case catch mnesia_schema:list2cs(CreateList) of
- {'EXIT', Reason} ->
- throw({error, {"Bad schema in restore_recs", Reason}});
+ try mnesia_schema:list2cs(CreateList) of
Cs ->
Ns = get_fallback_nodes(FA, Cs#cstruct.disc_copies),
global:set_lock({{mnesia_table_lock, schema}, self()}, Ns, infinity),
Args = [self(), FA],
Pids = [spawn_link(N, ?MODULE, fallback_receiver, Args) || N <- Ns],
send_fallback(Pids, {start, Header, Schema2}),
- Res = restore_recs(Recs, Header, Schema2, Pids),
+ Res = restore_recs(Recs, Header, Schema2, Ext, Pids),
global:del_lock({{mnesia_table_lock, schema}, self()}, Ns),
Res
+ catch _:Reason ->
+ throw({error, {"Bad schema in restore_recs", Reason}})
end;
-restore_recs([], _Header, _Schema, Pids) ->
+restore_recs([], _Header, _Schema, _Ext, Pids) ->
send_fallback(Pids, swap),
send_fallback(Pids, stop),
stop;
-restore_recs(Recs, _, _, Pids) ->
+restore_recs(Recs, _, _, _, Pids) ->
send_fallback(Pids, {records, Recs}),
Pids.
@@ -579,45 +604,46 @@ fallback_tmp_name() -> "FALLBACK.TMP".
fallback_receiver(Master, FA) ->
process_flag(trap_exit, true),
- case catch register(mnesia_fallback, self()) of
- {'EXIT', _} ->
- Reason = {already_exists, node()},
- local_fallback_error(Master, Reason);
- true ->
- FA2 = check_fallback_dir(Master, FA),
- Bup = FA2#fallback_args.fallback_bup,
- case mnesia_lib:exists(Bup) of
- true ->
- Reason2 = {already_exists, node()},
- local_fallback_error(Master, Reason2);
- false ->
- Mod = mnesia_backup,
- Tmp = FA2#fallback_args.fallback_tmp,
- R = #restore{mode = replace,
- bup_module = Mod,
- bup_data = Tmp},
- file:delete(Tmp),
- case catch fallback_receiver_loop(Master, R, FA2, schema) of
- {error, Reason} ->
- local_fallback_error(Master, Reason);
- Other ->
- exit(Other)
- end
- end
- end.
+ Res = try
+ register(mnesia_fallback, self()),
+ FA2 = check_fallback_dir(FA),
+ Bup = FA2#fallback_args.fallback_bup,
+ false = mnesia_lib:exists(Bup),
+ Mod = mnesia_backup,
+ Tmp = FA2#fallback_args.fallback_tmp,
+ R = #restore{mode = replace,
+ bup_module = Mod,
+ bup_data = Tmp},
+ file:delete(Tmp),
+ fallback_receiver_loop(Master, R, FA2, schema)
+ catch
+ error:_ ->
+ Reason = {already_exists, node()},
+ local_fallback_error(Master, Reason);
+ throw:{error, Reason} ->
+ local_fallback_error(Master, Reason)
+ end,
+ exit(Res).
local_fallback_error(Master, Reason) ->
Master ! {self(), {error, Reason}},
unlink(Master),
exit(Reason).
+
check_fallback_dir(Master, FA) ->
+ try check_fallback_dir(FA)
+ catch throw:{error,Reason} ->
+ local_fallback_error(Master, Reason)
+ end.
+
+check_fallback_dir(FA) ->
case mnesia:system_info(schema_location) of
ram ->
Reason = {has_no_disc, node()},
- local_fallback_error(Master, Reason);
+ throw({error, Reason});
_ ->
- Dir = check_fallback_dir_arg(Master, FA),
+ Dir = check_fallback_dir_arg(FA),
Bup = filename:join([Dir, fallback_name()]),
Tmp = filename:join([Dir, fallback_tmp_name()]),
FA#fallback_args{fallback_bup = Bup,
@@ -625,22 +651,20 @@ check_fallback_dir(Master, FA) ->
mnesia_dir = Dir}
end.
-check_fallback_dir_arg(Master, FA) ->
+check_fallback_dir_arg(FA) ->
case FA#fallback_args.use_default_dir of
true ->
mnesia_lib:dir();
false when FA#fallback_args.scope =:= local ->
Dir = FA#fallback_args.mnesia_dir,
- case catch mnesia_monitor:do_check_type(dir, Dir) of
- {'EXIT', _R} ->
+ try mnesia_monitor:do_check_type(dir, Dir)
+ catch _:_ ->
Reason = {badarg, {dir, Dir}, node()},
- local_fallback_error(Master, Reason);
- AbsDir->
- AbsDir
- end;
+ throw({error, Reason})
+ end;
false when FA#fallback_args.scope =:= global ->
Reason = {combine_error, global, dir, node()},
- local_fallback_error(Master, Reason)
+ throw({error, Reason})
end.
fallback_receiver_loop(Master, R, FA, State) ->
@@ -666,7 +690,7 @@ fallback_receiver_loop(Master, R, FA, State) ->
Bup = FA#fallback_args.fallback_bup,
Tmp = FA#fallback_args.fallback_tmp,
throw_bad_res(ok, file:rename(Tmp, Bup)),
- catch mnesia_lib:set(active_fallback, true),
+ ?SAFE(mnesia_lib:set(active_fallback, true)),
?eval_debug_fun({?MODULE, fallback_receiver_loop, post_swap}, []),
Master ! {self(), ok},
fallback_receiver_loop(Master, R, FA, stop);
@@ -697,7 +721,7 @@ throw_bad_res(_Expected, Actual) -> throw({error, Actual}).
tm_fallback_start(IgnoreFallback) ->
mnesia_schema:lock_schema(),
Res = do_fallback_start(fallback_exists(), IgnoreFallback),
- mnesia_schema: unlock_schema(),
+ mnesia_schema:unlock_schema(),
case Res of
ok -> ok;
{error, Reason} -> exit(Reason)
@@ -715,9 +739,9 @@ do_fallback_start(true, false) ->
BupFile = fallback_bup(),
Mod = mnesia_backup,
LocalTabs = ?ets_new_table(mnesia_local_tables, [set, public, {keypos, 2}]),
- case catch iterate(Mod, fun restore_tables/4, BupFile, {start, LocalTabs}) of
+ case iterate(Mod, fun restore_tables/5, BupFile, {start, LocalTabs}) of
{ok, _Res} ->
- catch dets:close(schema),
+ ?SAFE(dets:close(schema)),
TmpSchema = mnesia_lib:tab2tmp(schema),
DatSchema = mnesia_lib:tab2dat(schema),
AllLT = ?ets_match_object(LocalTabs, '_'),
@@ -733,28 +757,27 @@ do_fallback_start(true, false) ->
{error, {"Cannot start from fallback. Rename error.", Reason}}
end;
{error, Reason} ->
- {error, {"Cannot start from fallback", Reason}};
- {'EXIT', Reason} ->
{error, {"Cannot start from fallback", Reason}}
end.
-restore_tables(All=[Rec | Recs], Header, Schema, State={local, LocalTabs, LT}) ->
+restore_tables(All=[Rec | Recs], Header, Schema, Ext,
+ State={local, LocalTabs, LT}) ->
Tab = element(1, Rec),
if
Tab =:= LT#local_tab.name ->
Key = element(2, Rec),
(LT#local_tab.add)(Tab, Key, Rec, LT),
- restore_tables(Recs, Header, Schema, State);
+ restore_tables(Recs, Header, Schema, Ext, State);
true ->
NewState = {new, LocalTabs},
- restore_tables(All, Header, Schema, NewState)
+ restore_tables(All, Header, Schema, Ext, NewState)
end;
-restore_tables(All=[Rec | Recs], Header, Schema, {new, LocalTabs}) ->
+restore_tables(All=[Rec | Recs], Header, Schema, Ext, {new, LocalTabs}) ->
Tab = element(1, Rec),
case ?ets_lookup(LocalTabs, Tab) of
[] ->
State = {not_local, LocalTabs, Tab},
- restore_tables(Recs, Header, Schema, State);
+ restore_tables(Recs, Header, Schema, Ext, State);
[LT] when is_record(LT, local_tab) ->
State = {local, LocalTabs, LT},
case LT#local_tab.opened of
@@ -763,38 +786,39 @@ restore_tables(All=[Rec | Recs], Header, Schema, {new, LocalTabs}) ->
(LT#local_tab.open)(Tab, LT),
?ets_insert(LocalTabs,LT#local_tab{opened=true})
end,
- restore_tables(All, Header, Schema, State)
+ restore_tables(All, Header, Schema, Ext, State)
end;
-restore_tables(All=[Rec | Recs], Header, Schema, S = {not_local, LocalTabs, PrevTab}) ->
+restore_tables(All=[Rec | Recs], Header, Schema, Ext,
+ S = {not_local, LocalTabs, PrevTab}) ->
Tab = element(1, Rec),
if
Tab =:= PrevTab ->
- restore_tables(Recs, Header, Schema, S);
+ restore_tables(Recs, Header, Schema, Ext, S);
true ->
State = {new, LocalTabs},
- restore_tables(All, Header, Schema, State)
+ restore_tables(All, Header, Schema, Ext, State)
end;
-restore_tables(Recs, Header, Schema, {start, LocalTabs}) ->
+restore_tables(Recs, Header, Schema, Ext, {start, LocalTabs}) ->
Dir = mnesia_lib:dir(),
OldDir = filename:join([Dir, "OLD_DIR"]),
mnesia_schema:purge_dir(OldDir, []),
mnesia_schema:purge_dir(Dir, [fallback_name()]),
- init_dat_files(Schema, LocalTabs),
+ init_dat_files(Schema, Ext, LocalTabs),
State = {new, LocalTabs},
- restore_tables(Recs, Header, Schema, State);
-restore_tables([], _Header, _Schema, State) ->
+ restore_tables(Recs, Header, Schema, Ext, State);
+restore_tables([], _Header, _Schema, _Ext, State) ->
State.
%% Creates all neccessary dat files and inserts
%% the table definitions in the schema table
%%
%% Returns a list of local_tab tuples for all local tables
-init_dat_files(Schema, LocalTabs) ->
+init_dat_files(Schema, Ext, LocalTabs) ->
TmpFile = mnesia_lib:tab2tmp(schema),
Args = [{file, TmpFile}, {keypos, 2}, {type, set}],
case dets:open_file(schema, Args) of % Assume schema lock
{ok, _} ->
- create_dat_files(Schema, LocalTabs),
+ create_dat_files(Schema, Ext, LocalTabs),
ok = dets:close(schema),
LocalTab = #local_tab{name = schema,
storage_type = disc_copies,
@@ -809,10 +833,10 @@ init_dat_files(Schema, LocalTabs) ->
throw({error, {"Cannot open file", schema, Args, Reason}})
end.
-create_dat_files([{schema, schema, TabDef} | Tail], LocalTabs) ->
+create_dat_files([{schema, schema, TabDef} | Tail], Ext, LocalTabs) ->
ok = dets:insert(schema, {schema, schema, TabDef}),
- create_dat_files(Tail, LocalTabs);
-create_dat_files([{schema, Tab, TabDef} | Tail], LocalTabs) ->
+ create_dat_files(Tail, Ext, LocalTabs);
+create_dat_files([{schema, Tab, TabDef} | Tail], Ext, LocalTabs) ->
TmpFile = mnesia_lib:tab2tmp(Tab),
DatFile = mnesia_lib:tab2dat(Tab),
DclFile = mnesia_lib:tab2dcl(Tab),
@@ -825,56 +849,21 @@ create_dat_files([{schema, Tab, TabDef} | Tail], LocalTabs) ->
mnesia_lib:dets_sync_close(Tab),
file:delete(TmpFile),
- Cs = mnesia_schema:list2cs(TabDef),
+ Cs = mnesia_schema:list2cs(TabDef, Ext),
ok = dets:insert(schema, {schema, Tab, TabDef}),
RecName = Cs#cstruct.record_name,
Storage = mnesia_lib:cs_to_storage_type(node(), Cs),
+ delete_ext(Storage, Tab),
+ Semantics = mnesia_lib:semantics(Storage, storage),
if
- Storage =:= unknown ->
+ Semantics =:= undefined ->
ok = dets:delete(schema, {schema, Tab}),
- create_dat_files(Tail, LocalTabs);
- Storage =:= disc_only_copies ->
- Args = [{file, TmpFile}, {keypos, 2},
- {type, mnesia_lib:disk_type(Tab, Cs#cstruct.type)}],
- Open = fun(T, LT) when T =:= LT#local_tab.name ->
- case mnesia_lib:dets_sync_open(T, Args) of
- {ok, _} ->
- ok;
- {error, Reason} ->
- throw({error, {"Cannot open file", T, Args, Reason}})
- end
- end,
- Add = fun(T, Key, Rec, LT) when T =:= LT#local_tab.name ->
- case Rec of
- {_T, Key} ->
- ok = dets:delete(T, Key);
- (Rec) when T =:= RecName ->
- ok = dets:insert(Tab, Rec);
- (Rec) ->
- Rec2 = setelement(1, Rec, RecName),
- ok = dets:insert(T, Rec2)
- end
- end,
- Close = fun(T, LT) when T =:= LT#local_tab.name ->
- mnesia_lib:dets_sync_close(T)
- end,
- Swap = fun(T, LT) when T =:= LT#local_tab.name ->
- Expunge(),
- case LT#local_tab.opened of
- true ->
- Close(T,LT);
- false ->
- Open(T,LT),
- Close(T,LT)
- end,
- case file:rename(TmpFile, DatFile) of
- ok ->
- ok;
- {error, Reason} ->
- mnesia_lib:fatal("Cannot rename file ~p -> ~p: ~p~n",
- [TmpFile, DatFile, Reason])
- end
- end,
+ create_dat_files(Tail, Ext, LocalTabs);
+ Semantics =:= disc_only_copies ->
+ Open = disc_only_open_fun(Storage, Cs),
+ Add = disc_only_add_fun(Storage, Cs),
+ Close = disc_only_close_fun(Storage),
+ Swap = disc_only_swap_fun(Storage, Expunge, Open, Close),
LocalTab = #local_tab{name = Tab,
storage_type = Storage,
open = Open,
@@ -884,8 +873,8 @@ create_dat_files([{schema, Tab, TabDef} | Tail], LocalTabs) ->
record_name = RecName,
opened = false},
?ets_insert(LocalTabs, LocalTab),
- create_dat_files(Tail, LocalTabs);
- Storage =:= ram_copies; Storage =:= disc_copies ->
+ create_dat_files(Tail, Ext, LocalTabs);
+ Semantics =:= ram_copies; Storage =:= disc_copies ->
Open = fun(T, LT) when T =:= LT#local_tab.name ->
mnesia_log:open_log({?MODULE, T},
mnesia_log:dcl_log_header(),
@@ -946,18 +935,97 @@ create_dat_files([{schema, Tab, TabDef} | Tail], LocalTabs) ->
opened = false
},
?ets_insert(LocalTabs, LocalTab),
- create_dat_files(Tail, LocalTabs)
+ create_dat_files(Tail, Ext, LocalTabs);
+ true ->
+ error({unknown_semantics, [{semantics, Semantics},
+ {tabdef, TabDef},
+ {ext, Ext}]})
end;
-create_dat_files([{schema, Tab} | Tail], LocalTabs) ->
+create_dat_files([{schema, Tab} | Tail], Ext, LocalTabs) ->
?ets_delete(LocalTabs, Tab),
ok = dets:delete(schema, {schema, Tab}),
TmpFile = mnesia_lib:tab2tmp(Tab),
mnesia_lib:dets_sync_close(Tab),
file:delete(TmpFile),
- create_dat_files(Tail, LocalTabs);
-create_dat_files([], _LocalTabs) ->
+ create_dat_files(Tail, Ext, LocalTabs);
+create_dat_files([], _Ext, _LocalTabs) ->
ok.
+delete_ext({ext, Alias, Mod}, Tab) ->
+ Mod:close_table(Alias, Tab),
+ Mod:delete_table(Alias, Tab),
+ ok;
+delete_ext(_, _) ->
+ ok.
+
+
+disc_only_open_fun(disc_only_copies, #cstruct{name = Tab} =Cs) ->
+ TmpFile = mnesia_lib:tab2tmp(Tab),
+ Args = [{file, TmpFile}, {keypos, 2},
+ {type, mnesia_lib:disk_type(Tab, Cs#cstruct.type)}],
+ fun(T, LT) when T =:= LT#local_tab.name ->
+ case mnesia_lib:dets_sync_open(T, Args) of
+ {ok, _} ->
+ ok;
+ {error, Reason} ->
+ throw({error, {"Cannot open file", T, Args, Reason}})
+ end
+ end;
+disc_only_open_fun({ext,Alias,Mod}, Cs) ->
+ fun(T, LT) when T =:= LT#local_tab.name ->
+ ok = Mod:load_table(Alias, T, restore, mnesia_schema:cs2list(Cs))
+ end.
+
+disc_only_add_fun(Storage, #cstruct{name = Tab,
+ record_name = RecName}) ->
+ fun(T, Key, Rec, #local_tab{name = T}) when T =:= Tab->
+ case Rec of
+ {_T, Key} ->
+ ok = mnesia_lib:db_erase(Storage, T, Key);
+ (Rec) when T =:= RecName ->
+ ok = mnesia_lib:db_put(Storage, T, Rec);
+ (Rec) ->
+ ok = mnesia_lib:db_put(Storage, T,
+ setelement(1, Rec, RecName))
+ end
+ end.
+
+disc_only_close_fun(disc_only_copies) ->
+ fun(T, LT) when T =:= LT#local_tab.name ->
+ mnesia_lib:dets_sync_close(T)
+ end;
+disc_only_close_fun({ext, Alias, Mod}) ->
+ fun(T, _LT) ->
+ Mod:sync_close_table(Alias, T)
+ end.
+
+
+disc_only_swap_fun(disc_only_copies, Expunge, Open, Close) ->
+ fun(T, LT) when T =:= LT#local_tab.name ->
+ TmpFile = mnesia_lib:tab2tmp(T),
+ DatFile = mnesia_lib:tab2dat(T),
+ Expunge(),
+ case LT#local_tab.opened of
+ true ->
+ Close(T,LT);
+ false ->
+ Open(T,LT),
+ Close(T,LT)
+ end,
+ case file:rename(TmpFile, DatFile) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ mnesia_lib:fatal("Cannot rename file ~p -> ~p: ~p~n",
+ [TmpFile, DatFile, Reason])
+ end
+ end;
+disc_only_swap_fun({ext, _Alias, _Mod}, _Expunge, _Open, Close) ->
+ fun(T, #local_tab{name = T} = LT) ->
+ Close(T, LT)
+ end.
+
+
uninstall_fallback() ->
uninstall_fallback([{scope, global}]).
@@ -996,10 +1064,10 @@ uninstall_fallback_master(ClientPid, FA) ->
case fallback_to_schema(Bup) of
{ok, fallback, List} ->
Cs = mnesia_schema:list2cs(List),
- case catch get_fallback_nodes(FA, Cs#cstruct.disc_copies) of
+ try get_fallback_nodes(FA, Cs#cstruct.disc_copies) of
Ns when is_list(Ns) ->
- do_uninstall(ClientPid, Ns, FA);
- {error, Reason} ->
+ do_uninstall(ClientPid, Ns, FA)
+ catch throw:{error, Reason} ->
local_fallback_error(ClientPid, Reason)
end;
{error, Reason} ->
@@ -1042,13 +1110,13 @@ local_uninstall_fallback(Master, FA) ->
%% Don't trap exit
register(mnesia_fallback, self()), % May exit
- FA2 = check_fallback_dir(Master, FA), % May exit
+ FA2 = check_fallback_dir(Master, FA), % May exit
Master ! {self(), started},
receive
{Master, do_uninstall} ->
?eval_debug_fun({?MODULE, uninstall_fallback2, pre_delete}, []),
- catch mnesia_lib:set(active_fallback, false),
+ ?SAFE(mnesia_lib:set(active_fallback, false)),
Tmp = FA2#fallback_args.fallback_tmp,
Bup = FA2#fallback_args.fallback_bup,
file:delete(Tmp),
@@ -1071,10 +1139,8 @@ rec_uninstall(ClientPid, [Pid | Pids], AccRes) ->
{Pid, BadRes} ->
rec_uninstall(ClientPid, Pids, BadRes)
end;
-rec_uninstall(ClientPid, [], Res) ->
- ClientPid ! {self(), Res},
- unlink(ClientPid),
- exit(normal).
+rec_uninstall(_, [], Res) ->
+ Res.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Backup traversal
@@ -1125,30 +1191,29 @@ do_traverse_backup(ClientPid, Source, SourceMod, Target, TargetMod, Fun, Acc) ->
Iter =
if
TargetMod =/= read_only ->
- case catch do_apply(TargetMod, open_write, [Target], Target) of
- {error, Error} ->
+ try do_apply(TargetMod, open_write, [Target], Target)
+ catch throw:{error, Error} ->
unlink(ClientPid),
ClientPid ! {iter_done, self(), {error, Error}},
- exit(Error);
- Else -> Else
+ exit(Error)
end;
true ->
ignore
end,
A = {start, Fun, Acc, TargetMod, Iter},
Res =
- case iterate(SourceMod, fun trav_apply/4, Source, A) of
+ case iterate(SourceMod, fun trav_apply/5, Source, A) of
{ok, {iter, _, Acc2, _, Iter2}} when TargetMod =/= read_only ->
- case catch do_apply(TargetMod, commit_write, [Iter2], Iter2) of
- {error, Reason} ->
- {error, Reason};
- _ ->
- {ok, Acc2}
+ try
+ do_apply(TargetMod, commit_write, [Iter2], Iter2),
+ {ok, Acc2}
+ catch throw:{error, Reason} ->
+ {error, Reason}
end;
{ok, {iter, _, Acc2, _, _}} ->
{ok, Acc2};
{error, Reason} when TargetMod =/= read_only->
- catch do_apply(TargetMod, abort_write, [Iter], Iter),
+ ?CATCH(do_apply(TargetMod, abort_write, [Iter], Iter)),
{error, {"Backup traversal failed", Reason}};
{error, Reason} ->
{error, {"Backup traversal failed", Reason}}
@@ -1156,7 +1221,7 @@ do_traverse_backup(ClientPid, Source, SourceMod, Target, TargetMod, Fun, Acc) ->
unlink(ClientPid),
ClientPid ! {iter_done, self(), Res}.
-trav_apply(Recs, _Header, _Schema, {iter, Fun, Acc, Mod, Iter}) ->
+trav_apply(Recs, _Header, _Schema, _Ext, {iter, Fun, Acc, Mod, Iter}) ->
{NewRecs, Acc2} = filter_foldl(Fun, Acc, Recs),
if
Mod =/= read_only, NewRecs =/= [] ->
@@ -1165,7 +1230,7 @@ trav_apply(Recs, _Header, _Schema, {iter, Fun, Acc, Mod, Iter}) ->
true ->
{iter, Fun, Acc2, Mod, Iter}
end;
-trav_apply(Recs, Header, Schema, {start, Fun, Acc, Mod, Iter}) ->
+trav_apply(Recs, Header, Schema, Ext, {start, Fun, Acc, Mod, Iter}) ->
Iter2 =
if
Mod =/= read_only ->
@@ -1173,8 +1238,9 @@ trav_apply(Recs, Header, Schema, {start, Fun, Acc, Mod, Iter}) ->
true ->
Iter
end,
- TravAcc = trav_apply(Schema, Header, Schema, {iter, Fun, Acc, Mod, Iter2}),
- trav_apply(Recs, Header, Schema, TravAcc).
+ TravAcc = trav_apply(Schema, Header, Schema, Ext,
+ {iter, Fun, Acc, Mod, Iter2}),
+ trav_apply(Recs, Header, Schema, Ext, TravAcc).
filter_foldl(Fun, Acc, [Head|Tail]) ->
case Fun(Head, Acc) of