mnesia_log.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,023 行 · 第 1/2 页

ERL
1,023
字号
confirm_decision_log_dump() ->    case mnesia_monitor:close_log(previous_decision_log) of	ok ->	    file:delete(previous_decision_log_file());	{error, Reason} ->	    fatal("Cannot confirm decision log dump: ~p~n",		  [Reason])    end.save_decision_tab(Decisions) ->    Log = decision_tab,    Tmp = mnesia_lib:dir("DECISION_TAB.TMP"),    file:delete(Tmp),    open_log(Log, decision_tab_header(), Tmp),    append(Log, Decisions),    close_log(Log),    TabFile = decision_tab_file(),    ok = file:rename(Tmp, TabFile).open_decision_tab() ->    TabFile = decision_tab_file(),    open_log(decision_tab, decision_tab_header(), TabFile),    start.close_decision_tab() ->    close_log(decision_tab).chunk_decision_tab(Cont) ->    %% dbg_out("chunk tab ~p~n", [Cont]),    chunk_log(decision_tab, Cont).close_decision_log() ->    close_log(decision_log).log_decision(Decision) ->    append(decision_log, Decision).%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Debug functionsview() ->    lists:foreach(fun(F) -> view(F) end, log_files()).view(File) ->    mnesia_lib:show("*****  ~p ***** ~n", [File]),    case exists(File) of	false ->	    nolog;	true ->	    N = view_only,	    Args = [{file, File}, {name, N}, {mode, read_only}],	    case disk_log:open(Args) of		{ok, N} ->		    view_file(start, N);		{repaired, _, _, _} ->		    view_file(start, N);		{error, Reason} ->		    error("Cannot open log ~p: ~p~n", [File, Reason])	    end    end.view_file(C, Log) ->    case disk_log:chunk(Log, C) of	{error, Reason} ->	    error("** Possibly truncated FILE ~p~n", [Reason]),	    error;	eof ->	    disk_log:close(Log),	    eof;	{C2, Terms, _BadBytes} ->	    dbg_out("Lost ~p bytes in ~p ~n", [_BadBytes, Log]),	    lists:foreach(fun(X) -> mnesia_lib:show("~p~n", [X]) end, 			  Terms),	    view_file(C2, Log);	{C2, Terms} ->	    lists:foreach(fun(X) -> mnesia_lib:show("~p~n", [X]) end, 			  Terms),	    view_file(C2, Log)    end.%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Backup-record(backup_args, {name, module, opaque, scope, prev_name, tables, cookie}).backup(Opaque) ->    backup(Opaque, []).backup(Opaque, Mod) when atom(Mod) ->    backup(Opaque, [{module, Mod}]);backup(Opaque, Args) when list(Args) ->    %% Backup all tables with max redundancy    CpArgs = [{ram_overrides_dump, false}, {max, val({schema, tables})}],    case mnesia_checkpoint:activate(CpArgs) of	{ok, Name, _Nodes} ->	    Res = backup_checkpoint(Name, Opaque, Args),	    mnesia_checkpoint:deactivate(Name),	    Res;	{error, Reason} ->	    {error, Reason}    end.backup_checkpoint(Name, Opaque) ->    backup_checkpoint(Name, Opaque, []).backup_checkpoint(Name, Opaque, Mod) when atom(Mod) ->    backup_checkpoint(Name, Opaque, [{module, Mod}]);backup_checkpoint(Name, Opaque, Args) when list(Args) ->    DefaultMod = mnesia_monitor:get_env(backup_module),    B = #backup_args{name = Name,		     module = DefaultMod,		     opaque = Opaque,		     scope = global,		     tables = all,		     prev_name = Name},    case check_backup_args(Args, B) of	{ok, B2} ->	    %% Decentralized backup	    %% Incremental	    Self = self(),	    Pid = spawn_link(?MODULE, backup_master, [Self, B2]),	    receive		{Pid, Self, Res} -> Res	    end;	{error, Reason} ->	    {error, Reason}    end.check_backup_args([Arg | Tail], B) ->    case catch check_backup_arg_type(Arg, B) of	{'EXIT', _Reason} ->	    {error, {badarg, Arg}};	B2 ->	    check_backup_args(Tail, B2)    end;check_backup_args([], B) ->    {ok, B}.check_backup_arg_type(Arg, B) ->        case Arg of	{scope, global} ->	    B#backup_args{scope = global};	{scope, local} ->	    B#backup_args{scope = local};	{module, Mod} ->	    Mod2 = mnesia_monitor:do_check_type(backup_module, Mod),	    B#backup_args{module = Mod2};	{incremental, Name} ->	    B#backup_args{prev_name = Name};	{tables, Tabs} when list(Tabs) ->	    B#backup_args{tables = Tabs}    end.backup_master(ClientPid, B) ->    process_flag(trap_exit, true),    case catch do_backup_master(B) of	{'EXIT', Reason} ->	    ClientPid ! {self(), ClientPid, {error, {'EXIT', Reason}}};	Res ->	    ClientPid ! {self(), ClientPid, Res}    end,    unlink(ClientPid),    exit(normal).do_backup_master(B) ->    Name = B#backup_args.name,    B2 = safe_apply(B, open_write, [B#backup_args.opaque]),    B3 = safe_write(B2, [backup_log_header()]),    case mnesia_checkpoint:tables_and_cookie(Name) of	{ok, AllTabs, Cookie} ->	    Tabs = select_tables(AllTabs, B3),	    B4 = B3#backup_args{cookie = Cookie},	    %% Always put schema first in backup file	    B5 = backup_schema(B4, Tabs),	    B6 = lists:foldl(fun backup_tab/2, B5, Tabs -- [schema]),	    safe_apply(B6, commit_write, [B6#backup_args.opaque]),	    ok;	{error, Reason} ->	    abort_write(B3, {?MODULE, backup_master}, [B], {error, Reason})    end.select_tables(AllTabs, B) ->    Tabs =	case B#backup_args.tables of	    all -> AllTabs;	    SomeTabs when list(SomeTabs) -> SomeTabs	end,    case B#backup_args.scope of	global ->	    Tabs;	local ->	    Name = B#backup_args.name,	    [T || T <- Tabs, mnesia_checkpoint:most_local_node(Name, T) == node()]    end.safe_write(B, []) ->    B;safe_write(B, Recs) ->	    safe_apply(B, write, [B#backup_args.opaque, Recs]).backup_schema(B, Tabs) ->    case lists:member(schema, Tabs) of	true ->	    backup_tab(schema, B);	false ->	    Defs = [{schema, T, mnesia_schema:get_create_list(T)} || T <- Tabs],	    safe_write(B, Defs)    end.safe_apply(B, write, [_, Items]) when Items == [] ->    B;safe_apply(B, What, Args) ->    Abort = fun(R) -> abort_write(B, What, Args, R) end,    receive	{'EXIT', Pid, R} -> Abort({'EXIT', Pid, R})    after 0 ->	    Mod = B#backup_args.module,	    case catch apply(Mod, What, Args) of		{ok, Opaque} -> B#backup_args{opaque=Opaque};		{error, R} -> Abort(R);		R -> Abort(R)	    end    end.abort_write(B, What, Args, Reason) ->    Mod = B#backup_args.module,    Opaque = B#backup_args.opaque,    dbg_out("Failed to perform backup. M=~p:F=~p:A=~p -> ~p~n",	    [Mod, What, Args, Reason]),    case catch apply(Mod, abort_write, [Opaque]) of	{ok, _Res} ->	    throw({error, Reason});	Other ->	    error("Failed to abort backup. ~p:~p~p -> ~p~n",		  [Mod, abort_write, [Opaque], Other]),	    throw({error, Reason})    end.	backup_tab(Tab, B) ->    Name = B#backup_args.name,    case mnesia_checkpoint:most_local_node(Name, Tab) of	{ok, Node} when Node == node() ->	    tab_copier(self(), B, Tab);	{ok, Node} ->	    RemoteB = B,	    Pid = spawn_link(Node, ?MODULE, tab_copier, [self(), RemoteB, Tab]),	    RecName = val({Tab, record_name}),	    tab_receiver(Pid, B, Tab, RecName, 0);	{error, Reason} ->	    abort_write(B, {?MODULE, backup_tab}, [Tab, B], {error, Reason})    end.    tab_copier(Pid, B, Tab) when record(B, backup_args) ->    %% Intentional crash at exit    Name = B#backup_args.name,    PrevName = B#backup_args.prev_name,    {FirstName, FirstSource} = select_source(Tab, Name, PrevName),    ?eval_debug_fun({?MODULE, tab_copier, pre}, [{name, Name}, {tab, Tab}]),    Res = handle_more(Pid, B, Tab, FirstName, FirstSource, Name),    ?eval_debug_fun({?MODULE, tab_copier, post}, [{name, Name}, {tab, Tab}]),    handle_last(Pid, Res).select_source(Tab, Name, PrevName) ->    if	Tab == schema ->	    %% Always full backup of schema	    {Name, table};	Name == PrevName ->	    %% Full backup	    {Name, table};	true ->	    %% Wants incremental backup	    case mnesia_checkpoint:most_local_node(PrevName, Tab) of		{ok, Node} when Node == node() ->		    %% Accept incremental backup		    {PrevName, retainer};		_ ->		    %% Do a full backup anyway		    dbg_out("Incremental backup escalated to full backup: ~p~n", [Tab]),		    {Name, table}	    end    end.handle_more(Pid, B, Tab, FirstName, FirstSource, Name) ->    Acc = {0, B},    case {mnesia_checkpoint:really_retain(Name, Tab),	  mnesia_checkpoint:really_retain(FirstName, Tab)} of	{true, true} ->	    Acc2 = iterate(B, FirstName, Tab, Pid, FirstSource, latest, first, Acc),	    iterate(B, Name, Tab, Pid, retainer, checkpoint, last, Acc2);	{false, false}->	    %% Put the dumped file in the backup	    %% instead of the ram table. Does	    %% only apply to ram_copies.	    iterate(B, Name, Tab, Pid, retainer, checkpoint, last, Acc);	Bad ->	    Reason = {"Checkpoints for incremental backup must have same "		      "setting of ram_overrides_dump",		      Tab, Name, FirstName, Bad},	    abort_write(B, {?MODULE, backup_tab}, [Tab, B], {error, Reason})    end.handle_last(Pid, {_Count, B}) when Pid == self() ->    B;handle_last(Pid, _Acc) ->    unlink(Pid),    Pid ! {self(), {last, {ok, dummy}}},    exit(normal).iterate(B, Name, Tab, Pid, Source, Age, Pass, Acc) ->    Fun = 	if	    Pid == self() ->		RecName = val({Tab, record_name}),		fun(Recs, A) -> copy_records(RecName, Tab, Recs, A) end;	    true ->		fun(Recs, A) -> send_records(Pid, Tab, Recs, Pass, A) end	end,    case mnesia_checkpoint:iterate(Name, Tab, Fun, Acc, Source, Age) of	{ok, Acc2} ->	    Acc2;	{error, Reason} ->	    R = {error, {"Tab copier iteration failed", Reason}},	    abort_write(B, {?MODULE, iterate}, [self(), B, Tab], R)    end.copy_records(_RecName, _Tab, [], Acc) ->    Acc;copy_records(RecName, Tab, Recs, {Count, B}) ->    Recs2 = rec_filter(B, Tab, RecName, Recs),    B2 = safe_write(B, Recs2),    {Count + 1, B2}.send_records(Pid, Tab, Recs, Pass, {Count, B}) ->    receive	{Pid, more, Count} ->	    if		Pass == last, Recs == [] ->		    {Count, B};		true ->		    Next = Count + 1,		    Pid ! {self(), {more, Next, Recs}},		    {Next, B}	    end;	Msg ->	    exit({send_records_unexpected_msg, Tab, Msg})    end.tab_receiver(Pid, B, Tab, RecName, Slot) ->    Pid ! {self(), more, Slot},    receive	{Pid, {more, Next, Recs}} ->	    Recs2 = rec_filter(B, Tab, RecName, Recs),	    B2 = safe_write(B, Recs2),	    tab_receiver(Pid, B2, Tab, RecName, Next);		{Pid, {last, {ok,_}}} ->	    B;	{'EXIT', Pid, {error, R}} ->	    Reason = {error, {"Tab copier crashed", R}},	    abort_write(B, {?MODULE, remote_tab_sender}, [self(), B, Tab], Reason);	{'EXIT', Pid, R} ->	    Reason = {error, {"Tab copier crashed", {'EXIT', R}}},	    abort_write(B, {?MODULE, remote_tab_sender}, [self(), B, Tab], Reason);	Msg ->	    R = {error, {"Tab receiver got unexpected msg", Msg}}, 	    abort_write(B, {?MODULE, remote_tab_sender}, [self(), B, Tab], R)    end.rec_filter(B, schema, _RecName, Recs) ->    case catch mnesia_bup:refresh_cookie(Recs, B#backup_args.cookie) of	Recs2 when list(Recs2) ->	    Recs2;	{error, _Reason} ->	    %% No schema table cookie	    Recs    end;rec_filter(_B, Tab, Tab, Recs) ->    Recs;rec_filter(_B, Tab, _RecName, Recs) ->    [setelement(1, Rec, Tab) || Rec <- Recs].ets2dcd(Tab) ->    ets2dcd(Tab, dcd).ets2dcd(Tab, Ftype) ->    Fname =	case Ftype of	    dcd -> mnesia_lib:tab2dcd(Tab);	    dmp -> mnesia_lib:tab2dmp(Tab)	end,        TmpF = mnesia_lib:tab2tmp(Tab),    file:delete(TmpF),        Log  = open_log({Tab, ets2dcd}, dcd_log_header(), TmpF, false),    mnesia_lib:db_fixtable(ram_copies, Tab, true),    ok   = ets2dcd(mnesia_lib:db_init_chunk(ram_copies, Tab, 1000), Tab, Log),    mnesia_lib:db_fixtable(ram_copies, Tab, false),    close_log(Log),    ok = file:rename(TmpF, Fname),    %% Remove old log data which is now in the new dcd.    %% No one else should be accessing this file!    file:delete(mnesia_lib:tab2dcl(Tab)),    ok.ets2dcd('$end_of_table', _Tab, _Log) ->    ok;ets2dcd({Recs, Cont}, Tab, Log) ->     ok = disk_log:alog_terms(Log, Recs),         ets2dcd(mnesia_lib:db_chunk(ram_copies, Cont), Tab, Log).dcd2ets(Tab) ->    dcd2ets(Tab, mnesia_monitor:get_env(auto_repair)).dcd2ets(Tab, Rep) ->    Dcd = mnesia_lib:tab2dcd(Tab),    case mnesia_lib:exists(Dcd) of	true ->	    Log = open_log({Tab, dcd2ets}, dcd_log_header(), Dcd, 			   true, Rep, read_only),	    Data = chunk_log(Log, start),	    ok = insert_dcdchunk(Data, Log, Tab),	    close_log(Log),	    load_dcl(Tab, Rep); 	false -> %% Handle old dets files, and conversion from disc_only to disc.	    Fname = mnesia_lib:tab2dat(Tab),	    Type = val({Tab, setorbag}),	    case mnesia_lib:dets_to_ets(Tab, Tab, Fname, Type, Rep, yes) of		loaded ->		    ets2dcd(Tab),		    file:delete(Fname),		    0;		{error, Error} ->		    erlang:fault({"Failed to load table from disc", [Tab, Error]})	    end    end.insert_dcdchunk({Cont, [LogH | Rest]}, Log, Tab)   when record(LogH, log_header),         LogH#log_header.log_kind == dcd_log,        LogH#log_header.log_version >= "1.0" ->        insert_dcdchunk({Cont, Rest}, Log, Tab);   insert_dcdchunk({Cont, Recs}, Log, Tab) ->         true = ets:insert(Tab, Recs),    insert_dcdchunk(chunk_log(Log, Cont), Log, Tab);insert_dcdchunk(eof, _Log, _Tab) ->    ok.load_dcl(Tab, Rep) ->    FName = mnesia_lib:tab2dcl(Tab),    case mnesia_lib:exists(FName) of	true -> 	    	    Name = {load_dcl,Tab},	    open_log(Name, 		     dcl_log_header(), 		     FName, 		     true,		     Rep, 		     read_only),	    FirstChunk = chunk_log(Name, start),            N = insert_logchunk(FirstChunk, Name, 0),	    close_log(Name),	    N;	false ->	    0    end.insert_logchunk({C2, Recs}, Tab, C) ->    N = add_recs(Recs, C),    insert_logchunk(chunk_log(Tab, C2), Tab, C+N);insert_logchunk(eof, _Tab, C) ->    C.add_recs([{{Tab, _Key}, Val, write} | Rest], N) ->    true = ets:insert(Tab, Val),    add_recs(Rest, N+1);add_recs([{{Tab, Key}, _Val, delete} | Rest], N) ->    true = ets:delete(Tab, Key),    add_recs(Rest, N+1);add_recs([{{Tab, _Key}, Val, delete_object} | Rest], N) ->    true = ets:match_delete(Tab, Val),    add_recs(Rest, N+1);add_recs([{{Tab, Key}, Val, update_counter} | Rest], N) ->    {RecName, Incr} = Val,    case catch ets:update_counter(Tab, Key, Incr) of	CounterVal when integer(CounterVal) ->	    ok;	_ when Incr < 0 ->	    Zero = {RecName, Key, 0},	    true = ets:insert(Tab, Zero);	_ ->	    Zero = {RecName, Key, Incr},	    true = ets:insert(Tab, Zero)    end,    add_recs(Rest, N+1);add_recs([LogH|Rest], N)   when record(LogH, log_header),         LogH#log_header.log_kind == dcl_log,        LogH#log_header.log_version >= "1.0" ->        add_recs(Rest, N);add_recs([{{Tab, _Key}, _Val, clear_table} | Rest], N) ->    true = ets:match_delete(Tab, '_'),    add_recs(Rest, N+ets:info(Tab, size));  add_recs([], N) ->    N.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?