mnesia_dumper.erl

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

ERL
1,214
字号
		    mnesia_lib:del({schema, local_tables}, Tab),		    mnesia_lib:set({Tab, storage_type}, unknown),		    insert_cstruct(Tid, Cs, true, InPlace, InitBy),		    disc_delete_table(Tab, Storage),		    disc_delete_indecies(Tab, Cs, Storage),		    mnesia_schema:ram_delete_table(Tab, Storage),		    mnesia_checkpoint:tm_del_copy(Tab, Node);		true ->		    case val({Tab, where_to_read}) of			Node ->			    mnesia_lib:set_remote_where_to_read(Tab);			_  ->			    ignore		    end,		    insert_cstruct(Tid, Cs, true, InPlace, InitBy)	    end    end;insert_op(Tid, _, {op, add_table_copy, _Storage, _Node, TabDef}, InPlace, InitBy) ->    %% During prepare commit, the files was created    %% and the replica was announced    Cs = mnesia_schema:list2cs(TabDef),    insert_cstruct(Tid, Cs, true, InPlace, InitBy);insert_op(Tid, _, {op, add_snmp, _Us, TabDef}, InPlace, InitBy) ->    Cs = mnesia_schema:list2cs(TabDef),    insert_cstruct(Tid, Cs, true, InPlace, InitBy);insert_op(Tid, _, {op, del_snmp, TabDef}, InPlace, InitBy) ->    Cs = mnesia_schema:list2cs(TabDef),    Tab = Cs#cstruct.name,    Storage = mnesia_lib:cs_to_storage_type(node(), Cs),    if	InitBy /= startup,	Storage /= unknown ->	    case ?catch_val({Tab, {index, snmp}}) of		{'EXIT', _} -> 		    ignore;		Stab -> 		    mnesia_snmp_hook:delete_table(Tab, Stab),		    mnesia_lib:unset({Tab, {index, snmp}})	    end;	true ->	    ignore    end,    insert_cstruct(Tid, Cs, true, InPlace, InitBy);insert_op(Tid, _, {op, add_index, Pos, TabDef}, InPlace, InitBy) ->    Cs = mnesia_schema:list2cs(TabDef),    Tab = insert_cstruct(Tid, Cs, true, InPlace, InitBy),    Storage = mnesia_lib:cs_to_storage_type(node(), Cs),    case InitBy of	startup when Storage == disc_only_copies ->	    true = open_files(Tab, Storage, InPlace, InitBy),	    mnesia_index:init_indecies(Tab, Storage, [Pos]);	startup ->	    ignore; 	_  ->	    mnesia_index:init_indecies(Tab, Storage, [Pos])    end;insert_op(Tid, _, {op, del_index, Pos, TabDef}, InPlace, InitBy) ->    Cs = mnesia_schema:list2cs(TabDef),    Tab = Cs#cstruct.name,    Storage = mnesia_lib:cs_to_storage_type(node(), Cs),    case InitBy of	startup when Storage == disc_only_copies ->	    mnesia_index:del_index_table(Tab, Storage, Pos);	startup -> 	    ignore;	_ ->	    mnesia_index:del_index_table(Tab, Storage, Pos)    end,    insert_cstruct(Tid, Cs, true, InPlace, InitBy);insert_op(Tid, _, {op, change_table_access_mode,TabDef, _OldAccess, _Access}, InPlace, InitBy) ->    Cs = mnesia_schema:list2cs(TabDef),    case InitBy of	startup -> ignore;	_ -> mnesia_controller:change_table_access_mode(Cs)    end,    insert_cstruct(Tid, Cs, true, InPlace, InitBy);insert_op(Tid, _, {op, change_table_load_order, TabDef, _OldLevel, _Level}, InPlace, InitBy) ->    Cs = mnesia_schema:list2cs(TabDef),    insert_cstruct(Tid, Cs, true, InPlace, InitBy);insert_op(Tid, _, {op, delete_property, TabDef, PropKey}, InPlace, InitBy) ->    Cs = mnesia_schema:list2cs(TabDef),    Tab = Cs#cstruct.name,    mnesia_lib:unset({Tab, user_property, PropKey}),    insert_cstruct(Tid, Cs, true, InPlace, InitBy);insert_op(Tid, _, {op, write_property, TabDef, _Prop}, InPlace, InitBy) ->    Cs = mnesia_schema:list2cs(TabDef),    insert_cstruct(Tid, Cs, true, InPlace, InitBy);insert_op(Tid, _, {op, change_table_frag, _Change, TabDef}, InPlace, InitBy) ->    Cs = mnesia_schema:list2cs(TabDef),    insert_cstruct(Tid, Cs, true, InPlace, InitBy).open_files(Tab, Storage, UpdateInPlace, InitBy)  when Storage /= unknown, Storage /= ram_copies ->    case get({?MODULE, Tab}) of	undefined ->	    case ?catch_val({Tab, setorbag}) of		{'EXIT', _} ->		    false;		Type ->		    case Storage of 			disc_copies when Tab /= schema ->			    Bool = open_disc_copies(Tab, InitBy),			    Bool;			_ ->			    Fname = prepare_open(Tab, UpdateInPlace),			    Args = [{file, Fname},				    {keypos, 2},				    {repair, mnesia_monitor:get_env(auto_repair)},				    {type, mnesia_lib:disk_type(Tab, Type)}],			    {ok, _} = mnesia_monitor:open_dets(Tab, Args),			    put({?MODULE, Tab}, {opened_dumper, dat}),			    true		    end	    end;	already_dumped ->	    false;	{opened_dumper, _} ->	    true    end;open_files(_Tab, _Storage, _UpdateInPlace, _InitBy) ->    false.open_disc_copies(Tab, InitBy) ->    DclF = mnesia_lib:tab2dcl(Tab),    DumpEts = 	case file:read_file_info(DclF) of	    {error, enoent} ->		false;	    {ok, DclInfo} ->		DcdF =  mnesia_lib:tab2dcd(Tab),		case file:read_file_info(DcdF) of		    {error, Reason} ->			mnesia_lib:dbg_out("File ~p info_error ~p ~n",					   [DcdF, Reason]),			true;		    {ok, DcdInfo} -> 			Mul = case ?catch_val(dc_dump_limit) of				  {'EXIT', _} -> ?DumpToEtsMultiplier;				  Val -> Val			      end,			DcdInfo#file_info.size =< (DclInfo#file_info.size * Mul)		end	end,    if 	DumpEts == false; InitBy == startup ->	    	    mnesia_log:open_log({?MODULE,Tab}, 				mnesia_log:dcl_log_header(), 				DclF, 				mnesia_lib:exists(DclF), 				mnesia_monitor:get_env(auto_repair),				read_write),	    put({?MODULE, Tab}, {opened_dumper, dcl}),	    true;	true ->	    mnesia_log:ets2dcd(Tab),	    put({?MODULE, Tab}, already_dumped),	    false    end. %% Always opens the dcl file for writing overriding already_dumped %% mechanismen, used for schema transactions.open_dcl(Tab) ->    case get({?MODULE, Tab}) of    	{opened_dumper, _} ->	    true;	_ -> %% undefined or already_dumped	    DclF = mnesia_lib:tab2dcl(Tab),	    mnesia_log:open_log({?MODULE,Tab}, 				mnesia_log:dcl_log_header(), 				DclF, 				mnesia_lib:exists(DclF), 				mnesia_monitor:get_env(auto_repair),				read_write),	    put({?MODULE, Tab}, {opened_dumper, dcl}),	    true    end.prepare_open(Tab, UpdateInPlace) ->    Dat =  mnesia_lib:tab2dat(Tab),    case UpdateInPlace of	true ->	    Dat;	false ->	    Tmp = mnesia_lib:tab2tmp(Tab),	    case catch mnesia_lib:copy_file(Dat, Tmp) of		ok ->		    Tmp;		Error ->		    fatal("Cannot copy dets file ~p to ~p: ~p~n",			  [Dat, Tmp, Error])	    end	end.del_opened_tab(Tab) ->    erase({?MODULE, Tab}).close_files(UpdateInPlace, Outcome, InitBy) -> % Update in place    close_files(UpdateInPlace, Outcome, InitBy, get()).close_files(InPlace, Outcome, InitBy, [{{?MODULE, Tab}, already_dumped} | Tail]) ->    erase({?MODULE, Tab}),    close_files(InPlace, Outcome, InitBy, Tail);close_files(InPlace, Outcome, InitBy, [{{?MODULE, Tab}, {opened_dumper, Type}} | Tail]) ->    erase({?MODULE, Tab}),    case val({Tab, storage_type}) of	disc_only_copies when InitBy /= startup ->	    ignore;	disc_copies when Tab /= schema -> 	    mnesia_log:close_log({?MODULE,Tab});	Storage ->	    do_close(InPlace, Outcome, Tab, Type, Storage)    end,    close_files(InPlace, Outcome, InitBy, Tail);close_files(InPlace, Outcome, InitBy, [_ | Tail]) ->    close_files(InPlace, Outcome, InitBy, Tail);close_files(_, _, _InitBy, []) ->    ok.%% If storage is unknown during close clean up files, this can happen if timing%% is right and dirty_write conflicts with schema operations.do_close(_, _, Tab, dcl, unknown) ->    mnesia_log:close_log({?MODULE,Tab}),    file:delete(mnesia_lib:tab2dcl(Tab));do_close(_, _, Tab, dcl, _) ->  %% To be safe, can it happen?    mnesia_log:close_log({?MODULE,Tab});do_close(InPlace, Outcome, Tab, dat, Storage) ->    mnesia_monitor:close_dets(Tab),    if	Storage == unknown, InPlace == true  ->	    file:delete(mnesia_lib:tab2dat(Tab));	InPlace == true ->	    %% Update in place	    ok;	Outcome == ok, Storage /= unknown ->	    %% Success: swap tmp files with dat files	    TabDat = mnesia_lib:tab2dat(Tab),	    ok = file:rename(mnesia_lib:tab2tmp(Tab), TabDat);	true ->	    file:delete(mnesia_lib:tab2tmp(Tab))    end.    ensure_rename(From, To) ->    case mnesia_lib:exists(From) of	true ->	    file:rename(From, To);	false ->	    case mnesia_lib:exists(To) of		true ->		    ok;		false ->		    {error, {rename_failed, From, To}}	    end    end.    insert_cstruct(Tid, Cs, KeepWhereabouts, InPlace, InitBy) ->    Val = mnesia_schema:insert_cstruct(Tid, Cs, KeepWhereabouts),    {schema, Tab, _} = Val,    S = val({schema, storage_type}),    disc_insert(Tid, S, schema, Tab, Val, write, InPlace, InitBy),    Tab.delete_cstruct(Tid, Cs, InPlace, InitBy) ->    Val = mnesia_schema:delete_cstruct(Tid, Cs),    {schema, Tab, _} = Val,    S = val({schema, storage_type}),    disc_insert(Tid, S, schema, Tab, Val, delete, InPlace, InitBy),    Tab.temp_set_master_nodes() ->    Tabs = val({schema, local_tables}),    Masters = [{Tab, (val({Tab, disc_copies}) ++ 		      val({Tab, ram_copies}) ++ 		      val({Tab, disc_only_copies})) -- [node()]} 	       || Tab <- Tabs],    %% UseDir = false since we don't want to remember these    %% masternodes and we are running (really soon anyway) since we want this    %% to be known during table loading.    mnesia_recover:log_master_nodes(Masters, false, yes),    ok.    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Raw dump of table. Dumper must have unique access to the ets table.raw_named_dump_table(Tab, Ftype) ->    case mnesia_monitor:use_dir() of	true ->	    mnesia_lib:lock_table(Tab),	    TmpFname = mnesia_lib:tab2tmp(Tab),	    Fname =		case Ftype of		    dat -> mnesia_lib:tab2dat(Tab);		    dmp -> mnesia_lib:tab2dmp(Tab)		end,	    file:delete(TmpFname),	    file:delete(Fname),	    TabSize = ?ets_info(Tab, size),	    TabRef = Tab,	    DiskType = mnesia_lib:disk_type(Tab),	    Args = [{file, TmpFname},		    {keypos, 2},		    %%		    {ram_file, true},		    {estimated_no_objects, TabSize + 256},		    {repair, mnesia_monitor:get_env(auto_repair)},		    {type, DiskType}],	    case mnesia_lib:dets_sync_open(TabRef, Args) of		{ok, TabRef} ->		    Storage = ram_copies,		    mnesia_lib:db_fixtable(Storage, Tab, true),		    		    case catch raw_dump_table(TabRef, Tab) of			{'EXIT', Reason} ->			    mnesia_lib:db_fixtable(Storage, Tab, false),			    mnesia_lib:dets_sync_close(Tab),			    file:delete(TmpFname),			    mnesia_lib:unlock_table(Tab),			    exit({"Dump of table to disc failed", Reason});			ok ->			    mnesia_lib:db_fixtable(Storage, Tab, false),			    mnesia_lib:dets_sync_close(Tab),			    mnesia_lib:unlock_table(Tab),			    ok = file:rename(TmpFname, Fname)		    end;		{error, Reason} ->		    mnesia_lib:unlock_table(Tab),		    exit({"Open of file before dump to disc failed", Reason})	    end;	false ->	    exit({has_no_disc, node()})    end.raw_dump_table(DetsRef, EtsRef) ->    dets:from_ets(DetsRef, EtsRef).%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Load regulator%% %% This is a poor mans substitute for a fair scheduler algorithm %% in the Erlang emulator. The mnesia_dumper process performs many %% costly BIF invokations and must pay for this. But since the %% Emulator does not handle this properly we must compensate for %% this with some form of load regulation of ourselves in order to%% not steal all computation power in the Erlang Emulator ans make%% other processes starve. Hopefully this is a temporary solution.start_regulator() ->    case mnesia_monitor:get_env(dump_log_load_regulation) of	false ->	    nopid;	true ->	    N = ?REGULATOR_NAME,	    case mnesia_monitor:start_proc(N, ?MODULE, regulator_init, [self()]) of		{ok, Pid} ->		    Pid;		{error, Reason} ->		    fatal("Failed to start ~n: ~p~n", [N, Reason])	    end    end.regulator_init(Parent) ->    %% No need for trapping exits.    %% Using low priority causes the regulation    process_flag(priority, low),    register(?REGULATOR_NAME, self()),    proc_lib:init_ack(Parent, {ok, self()}),    regulator_loop().regulator_loop() ->    receive	{regulate, From} ->	    From ! {regulated, self()},	    regulator_loop();	{stop, From} ->	    From ! {stopped, self()},	    exit(normal)    end.regulate(nopid) ->    ok;regulate(RegulatorPid) ->    RegulatorPid ! {regulate, self()},    receive	{regulated, RegulatorPid} -> ok    end.val(Var) ->    case ?catch_val(Var) of	{'EXIT', Reason} -> mnesia_lib:other_val(Var, Reason); 	Value -> Value     end.

⌨️ 快捷键说明

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