mnesia_lib.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,331 行 · 第 1/3 页
ERL
1,331 行
%% This function is needed due to the fact%% that the application_controller enters%% a deadlock now and then. ac is implemented%% as a rather naive server.ensure_loaded(Appl) -> case application_controller:get_loaded(Appl) of {true, _} -> ok; false -> case application:load(Appl) of ok -> ok; {error, {already_loaded, Appl}} -> ok; {error, Reason} -> {error, {application_load_error, Reason}} end end.local_active_tables() -> Tabs = val({schema, local_tables}), lists:zf(fun(Tab) -> active_here(Tab) end, Tabs).active_tables() -> Tabs = val({schema, tables}), F = fun(Tab) -> case val({Tab, where_to_read}) of nowhere -> false; _ -> {true, Tab} end end, lists:zf(F, Tabs).etype(X) when integer(X) -> integer;etype([]) -> nil;etype(X) when list(X) -> list;etype(X) when tuple(X) -> tuple;etype(X) when atom(X) -> atom;etype(_) -> othertype.remote_copy_holders(Cs) -> copy_holders(Cs) -- [node()].copy_holders(Cs) when Cs#cstruct.local_content == false -> cs_to_nodes(Cs);copy_holders(Cs) when Cs#cstruct.local_content == true -> case lists:member(node(), cs_to_nodes(Cs)) of true -> [node()]; false -> [] end.set_remote_where_to_read(Tab) -> set_remote_where_to_read(Tab, []).set_remote_where_to_read(Tab, Ignore) -> Active = val({Tab, active_replicas}), Valid = case mnesia_recover:get_master_nodes(Tab) of [] -> Active; Masters -> mnesia_lib:intersect(Masters, Active) end, Available = mnesia_lib:intersect(val({current, db_nodes}), Valid -- Ignore), DiscOnlyC = val({Tab, disc_only_copies}), Prefered = Available -- DiscOnlyC, if Prefered /= [] -> set({Tab, where_to_read}, hd(Prefered)); Available /= [] -> set({Tab, where_to_read}, hd(Available)); true -> set({Tab, where_to_read}, nowhere) end.%%% Local onlyset_local_content_whereabouts(Tab) -> add({schema, local_tables}, Tab), add({Tab, active_replicas}, node()), set({Tab, where_to_write}, [node()]), set({Tab, where_to_read}, node()).%%% counter routinescreate_counter(Name) -> set_counter(Name, 0).set_counter(Name, Val) -> ?ets_insert(mnesia_gvar, {Name, Val}).incr_counter(Name) -> ?ets_update_counter(mnesia_gvar, Name, 1).incr_counter(Name, I) -> ?ets_update_counter(mnesia_gvar, Name, I).update_counter(Name, Val) -> ?ets_update_counter(mnesia_gvar, Name, Val).read_counter(Name) -> ?ets_lookup_element(mnesia_gvar, Name, 2).cs_to_nodes(Cs) -> Cs#cstruct.disc_only_copies ++ Cs#cstruct.disc_copies ++ Cs#cstruct.ram_copies. dist_coredump() -> dist_coredump(all_nodes()).dist_coredump(Ns) -> {Replies, _} = rpc:multicall(Ns, ?MODULE, coredump, []), Replies.coredump() -> coredump({crashinfo, {"user initiated~n", []}}).coredump(CrashInfo) -> Core = mkcore(CrashInfo), Out = core_file(), important("Writing Mnesia core to file: ~p...~p~n", [Out, CrashInfo]), file:write_file(Out, Core), Out.core_file() -> Integers = tuple_to_list(date()) ++ tuple_to_list(time()), Fun = fun(I) when I < 10 -> ["_0", I]; (I) -> ["_", I] end, List = lists:append([Fun(I) || I <- Integers]), case mnesia_monitor:get_env(core_dir) of Dir when list(Dir) -> filename:absname(lists:concat(["MnesiaCore.", node()] ++ List), Dir); _ -> filename:absname(lists:concat(["MnesiaCore.", node()] ++ List)) end. mkcore(CrashInfo) ->% dbg_out("Making a Mnesia core dump...~p~n", [CrashInfo]), Nodes = [node() |nodes()], TidLocks = (catch ets:tab2list(mnesia_tid_locks)), Core = [ CrashInfo, {time, {date(), time()}}, {self, catch process_info(self())}, {nodes, catch rpc:multicall(Nodes, ?MODULE, get_node_number, [])}, {applications, catch lists:sort(application:loaded_applications())}, {flags, catch init:get_arguments()}, {code_path, catch code:get_path()}, {code_loaded, catch lists:sort(code:all_loaded())}, {etsinfo, catch ets_info(ets:all())}, {version, catch mnesia:system_info(version)}, {schema, catch ets:tab2list(schema)}, {gvar, catch ets:tab2list(mnesia_gvar)}, {master_nodes, catch mnesia_recover:get_master_node_info()}, {processes, catch procs()}, {relatives, catch relatives()}, {workers, catch workers(mnesia_controller:get_workers(2000))}, {locking_procs, catch locking_procs(TidLocks)}, {held_locks, catch mnesia:system_info(held_locks)}, {tid_locks, TidLocks}, {lock_queue, catch mnesia:system_info(lock_queue)}, {load_info, catch mnesia_controller:get_info(2000)}, {trans_info, catch mnesia_tm:get_info(2000)}, {schema_file, catch file:read_file(tab2dat(schema))}, {dir_info, catch dir_info()}, {logfile, catch {ok, read_log_files()}} ], term_to_binary(Core).procs() -> Fun = fun(P) -> {P, (catch lists:zf(fun proc_info/1, process_info(P)))} end, lists:map(Fun, processes()).proc_info({registered_name, Val}) -> {true, Val};proc_info({message_queue_len, Val}) -> {true, Val};proc_info({status, Val}) -> {true, Val};proc_info({current_function, Val}) -> {true, Val};proc_info(_) -> false.get_node_number() -> {node(), self()}.read_log_files() -> [{F, catch file:read_file(F)} || F <- mnesia_log:log_files()].dir_info() -> {ok, Cwd} = file:get_cwd(), Dir = dir(), [{cwd, Cwd, file:read_file_info(Cwd)}, {mnesia_dir, Dir, file:read_file_info(Dir)}] ++ case file:list_dir(Dir) of {ok, Files} -> [{mnesia_file, F, catch file:read_file_info(dir(F))} || F <- Files]; Other -> [Other] end.ets_info([H|T]) -> [{table, H, mk_info_tuple(ets:info(H))} | ets_info(T)];ets_info([]) -> [].mk_info_tuple(T) when is_list(T) -> list_to_tuple(T);mk_info_tuple(T) -> T.relatives() -> Info = fun(Name) -> case whereis(Name) of undefined -> false; Pid -> {true, {Name, Pid, catch process_info(Pid)}} end end, lists:zf(Info, mnesia:ms()).workers({workers, Loaders, Senders, Dumper}) -> Info = fun({Pid, {send_table, Tab, _Receiver, _St}}) -> case Pid of undefined -> false; Pid -> {true, {Pid, Tab, catch process_info(Pid)}} end; ({Pid, What}) when is_pid(Pid) -> {true, {Pid, What, catch process_info(Pid)}}; ({Name, Pid}) -> case Pid of undefined -> false; Pid -> {true, {Name, Pid, catch process_info(Pid)}} end end, SInfo = lists:zf(Info, Senders), Linfo = lists:zf(Info, Loaders), [{senders, SInfo},{loader, Linfo}|lists:zf(Info, [{dumper, Dumper}])].locking_procs(LockList) when list(LockList) -> Tids = [element(1, Lock) || Lock <- LockList], UT = uniq(Tids), Info = fun(Tid) -> Pid = Tid#tid.pid, case node(Pid) == node() of true -> {true, {Pid, catch process_info(Pid)}}; _ -> false end end, lists:zf(Info, UT).view() -> Bin = mkcore({crashinfo, {"view only~n", []}}), vcore(Bin).%% Displays a Mnesia file on the tty. The file may be repaired.view(File) -> case suffix([".DAT", ".RET", ".DMP", ".TMP"], File) of true -> view(File, dat); false -> case suffix([".LOG", ".BUP", ".ETS"], File) of true -> view(File, log); false -> case lists:prefix("MnesiaCore.", File) of true -> view(File, core); false -> {error, "Unknown file name"} end end end.view(File, dat) -> dets:view(File);view(File, log) -> mnesia_log:view(File);view(File, core) -> vcore(File).suffix(Suffixes, File) -> Fun = fun(S) -> lists:suffix(S, File) end, lists:any(Fun, Suffixes).%% View a core filevcore() -> Prefix = lists:concat(["MnesiaCore.", node()]), Filter = fun(F) -> lists:prefix(Prefix, F) end, {ok, Cwd} = file:get_cwd(), case file:list_dir(Cwd) of {ok, Files}-> CoreFiles = lists:sort(lists:zf(Filter, Files)), show("Mnesia core files: ~p~n", [CoreFiles]), vcore(lists:last(CoreFiles)); Error -> Error end.vcore(Bin) when binary(Bin) -> Core = binary_to_term(Bin), Fun = fun({Item, Info}) -> show("***** ~p *****~n", [Item]), case catch vcore_elem({Item, Info}) of {'EXIT', Reason} -> show("{'EXIT', ~p}~n", [Reason]); _ -> ok end end, lists:foreach(Fun, Core); vcore(File) -> show("~n***** Mnesia core: ~p *****~n", [File]), case file:read_file(File) of {ok, Bin} -> vcore(Bin); _ -> nocore end.vcore_elem({schema_file, {ok, B}}) -> Fname = "/tmp/schema.DAT", file:write_file(Fname, B), dets:view(Fname), file:delete(Fname);vcore_elem({logfile, {ok, BinList}}) -> Fun = fun({F, Info}) -> show("----- logfile: ~p -----~n", [F]), case Info of {ok, B} -> Fname = "/tmp/mnesia_vcore_elem.TMP", file:write_file(Fname, B), mnesia_log:view(Fname), file:delete(Fname); _ -> show("~p~n", [Info]) end end, lists:foreach(Fun, BinList);vcore_elem({crashinfo, {Format, Args}}) -> show(Format, Args);vcore_elem({gvar, L}) -> show("~p~n", [lists:sort(L)]);vcore_elem({transactions, Info}) -> mnesia_tm:display_info(user, Info);vcore_elem({_Item, Info}) -> show("~p~n", [Info]).fix_error(X) -> set(last_error, X), %% for debugabililty case X of {aborted, Reason} -> Reason; {abort, Reason} -> Reason; Y when atom(Y) -> Y; {'EXIT', {_Reason, {Mod, _, _}}} when atom(Mod) -> save(X), case atom_to_list(Mod) of [$m, $n, $e|_] -> badarg; _ -> X end; _ -> X end.last_error() -> val(last_error).%% The following is a list of possible mnesia errors and what they%% actually meanerror_desc(nested_transaction) -> "Nested transactions are not allowed";error_desc(badarg) -> "Bad or invalid argument, possibly bad type";error_desc(no_transaction) -> "Operation not allowed outside transactions";error_desc(combine_error) -> "Table options were ilegally combined";error_desc(bad_index) -> "Index already exists or was out of bounds";error_desc(already_exists) -> "Some schema option we try to set is already on";error_desc(index_exists)-> "Some ops can not be performed on tabs with index";error_desc(no_exists)-> "Tried to perform op on non-existing (non alive) item";error_desc(system_limit) -> "Some system_limit was exhausted";error_desc(mnesia_down) -> "A transaction involving objects at some remote " "node which died while transaction was executing" "*and* object(s) are no longer available elsewhere" "in the network";error_desc(not_a_db_node) -> "A node which is non existant in " "the schema was mentioned";error_desc(bad_type) -> "Bad type on some provided arguments";error_desc(node_not_running) -> "Node not running";error_desc(truncated_binary_file) -> "Truncated binary in file";error_desc(active) -> "Some delete ops require that " "all active objects are removed";error_desc(illegal) -> "Operation not supported on object";error_desc({'EXIT', Reason}) -> error_desc(Reason);error_desc({error, Reason}) -> error_desc(Reason);error_desc({aborted, Reason}) -> error_desc(Reason);error_desc(Reason) when tuple(Reason), size(Reason) > 0 -> setelement(1, Reason, error_desc(element(1, Reason)));error_desc(Reason) -> Reason.dirty_rpc_error_tag(Reason) -> case Reason of {'EXIT', _} -> badarg; no_variable -> badarg; _ -> no_exists end.fatal(Format, Args) -> catch set(mnesia_status, stopping), Core = mkcore({crashinfo, {Format, Args}}), report_fatal(Format, Args, Core), timer:sleep(10000), % Enough to write the core dump to disc? mnesia:lkill(), exit(fatal).report_fatal(Format, Args) -> report_fatal(Format, Args, nocore).report_fatal(Format, Args, Core) -> report_system_event({mnesia_fatal, Format, Args, Core}), catch exit(whereis(mnesia_monitor), fatal).%% We sleep longer and longer the more we try%% Made some testing and came up with the following constantsrandom_time(Retries, _Counter0) -> % UpperLimit = 2000,% MaxIntv = trunc(UpperLimit * (1-(4/((Retries*Retries)+4)))), UpperLimit = 500, Dup = Retries * Retries, MaxIntv = trunc(UpperLimit * (1-(50/((Dup)+50)))), case get(random_seed) of undefined -> {X, Y, Z} = erlang:now(), %% time() random:seed(X, Y, Z), Time = Dup + random:uniform(MaxIntv), %% dbg_out("---random_test rs ~w max ~w val ~w---~n", [Retries, MaxIntv, Time]), Time; _ -> Time = Dup + random:uniform(MaxIntv), %% dbg_out("---random_test rs ~w max ~w val ~w---~n", [Retries, MaxIntv, Time]),
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?