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 + -
显示快捷键?