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