📄 mnemosyne_catalog.erl
字号:
?insert(exec_stat, Table, S).read_stat(Table, Name) -> ?read(Name, Table, #stat{}).insert_stat(Table, Name, Value) -> S = upd_stat(read_stat(Table,Name), Value), ?insert(Name, Table, S).%%%----parameter_default_value(Name) -> case lists:keysearch(Name,1,?default_values) of {value, {Name,Value,Unit}} -> Value; false -> undefined end.%%%----upd_stat(S, V) when is_record(S,stat) -> S#stat{latest = V, sum = S#stat.sum+V, n = S#stat.n+1};upd_stat(undefined, V) -> #stat{latest = V, sum = V, n = 1}.now_in_secs() -> {MS,S,_} = now(), MS*1000000 + S.%%%----------------------------------------------------------------select_remote_node(Table, LastResort) -> select_remote_node1([], [disc_copies,ram_copies], Table, LastResort).select_remote_node1([N|Ns], Types, Table, LastResort) -> case lists:member(N, mnesia:system_info(running_db_nodes)) of true -> N; false -> select_remote_node1(Ns, Types, Table, LastResort) end;select_remote_node1([], [Type|Types], Table, LastResort) -> select_remote_node1(mnesia:table_info(Table,Type), Types, Table, LastResort);select_remote_node1([], [], Table, []) -> none; select_remote_node1([], [], Table, LastResort) -> select_remote_node1(LastResort, [], Table, []). %%%----------------------------------------------------------------tell_friends(What) -> tell_friends(What, mnesia:system_info(running_db_nodes)).tell_friends(What, Nodes) -> gen_server:abcast(lists:delete(node(),Nodes), ?SERVER_NAME, What).%%%----------------------------------------------------------------null_image(Table) -> {0,0,0}.%%%----------------------------------------------------------------mk_insert_time_stamp(Table) -> insert_time_stamp(Table, {date(),time(),node(),now_in_secs()}).mk_insert_image(Table) -> NewImage = mk_image_stat(Table), insert_image(Table, NewImage), mk_insert_time_stamp(Table), insert_counter(Table, limit, update_limit(Table,NewImage)), update_counter(Table, n_upd_local, 1, 1), tell_friends({remote_data,Table,NewImage,read_time_stamp(Table)}), NewImage.impatient_mk_insert_image(Table, MaxWait_ms) -> Pid = spawn(?MODULE,mk_insert_image_send,[Table,self()]), receive {image,Image,Pid} -> Image after MaxWait_ms -> Pid ! no_msg, % Skip result, but keep calculating an image null_image(Table) end.mk_insert_image_send(Table, Pid) -> CatalogPid = whereis(?SERVER_NAME), link(CatalogPid), Image = mk_insert_image(Table), receive no_msg -> ok after 0 -> Pid ! {image,Image,self()} end, subscribe(Table), unlink(CatalogPid).update_limit(Table) -> update_limit(Table,read_image(Table)).update_limit(Table,{Nobjs,Sizes,_}) -> (Nobjs * read_parameter(Table,upd_limit)) div 100;update_limit(Table, none) -> 0. mk_image_stat(Table) -> {Ngc0,Recl0,_} = erlang:statistics(garbage_collection), {Time,NewImage} = timer:tc(?MODULE,mk_image,[Table]), {Ngc1,Recl1,_} = erlang:statistics(garbage_collection), insert_exec_stat(Table, Time, Ngc1-Ngc0, Recl1-Recl0), NewImage. mk_image(Table) -> case mnesia:table_info(Table, storage_type) of disc_only_copies -> mk_image_dets(Table); unknown -> null_image(Table); _ -> mk_image_ets(Table) end.%%%---- etsmk_image_ets(Tab) -> SizesList = lists:map( fun(Pos) -> one_col(Tab, Pos, ets:info(Tab,type)) end, lists:seq(2,mnesia:table_info(Tab,arity))), {ets:info(Tab,size), list_to_tuple(SizesList), product(SizesList)}. %% TODO: catch exceptions (for example when Key is deleted meanwhile)%% Until we can use fix_table,%% we use match %one_col(Tab, Pos, Type) ->% TmpTab = ets:new(mnemosyne_tmp,[set,public]),% fix_table(Tab, true),% one_col_ets(Type, Tab, ets:first(Tab), Pos, TmpTab),% fix_table(Tab, false),% N_objs = ets:info(TmpTab, size),% ets:delete(TmpTab),% N_objs.%one_col_ets(_, Table, '$end_of_table', Pos, TmpTab) -> ready;%one_col_ets(Type, Table, Key, Pos, TmpTab) ->% one_col_ets_elms(Type, ets:lookup_element(Table,Key,Pos), TmpTab),% one_col_ets(Type, Table, ets:next(Table,Key), Pos, TmpTab).%one_col_ets_elms(set, E, TmpTab) -> ets:insert(TmpTab, {E});%one_col_ets_elms(bag, Es, TmpTab) -> ins_elems(Es, TmpTab).%ins_elems([E|Es], TmpTab) -> ets:insert(TmpTab, {E}), ins_elems(Es,TmpTab);%ins_elems(_, _) -> ready.one_col(Tab, Pos, Type) -> TmpTab = ets:new(mnemosyne_tmp,[set,public]), Blank = mnesia:table_info(Tab, wild_pattern), Patt = setelement(Pos, Blank, '$1'), ResList = ets:match(Tab, Patt), insert_ets(ResList, TmpTab), N_objs = ets:info(TmpTab, size), ets:delete(TmpTab), N_objs.insert_ets([H|R], Tab) -> ets:insert(Tab, {H}), insert_ets(R, Tab);insert_ets([], _) -> ok.%%%---- detsmk_image_dets(Table) -> TmpTabs = lists:map(fun(N) -> ets:new(tmp,[set,public]) end, lists:seq(2,mnesia:table_info(Table,arity))), traverse_dets(Table, 0, TmpTabs), SizesList = lists:map(fun(TmpTab) -> S = ets:info(TmpTab,size), ets:delete(TmpTab), S end, TmpTabs), {dets:info(Table,size), list_to_tuple(SizesList), product(SizesList)}. traverse_dets(Table, Islot, TmpTabs) -> case dets:slot(Table,Islot) of '$end_of_table' -> ready; Objs -> traverse_dets_objs(Objs, TmpTabs), traverse_dets(Table, Islot+1, TmpTabs) end. traverse_dets_objs([Obj|Objs], TmpTabs) -> traverse_dets_obj(tl(tuple_to_list(Obj)), TmpTabs), traverse_dets_objs(Objs, TmpTabs);traverse_dets_objs(_, _) -> ready.traverse_dets_obj([Val|Vals], [TmpTab|TmpTabs]) -> ets:insert(TmpTab, {Val}), traverse_dets_obj(Vals, TmpTabs);traverse_dets_obj(_,_) -> ready.%%%---- commonproduct(L) when is_list(L) -> lists:foldl(fun(E,Acc) -> E*Acc end, 1, L).%%%================================================================-record(inf, {name = "", image = "", limit = "", n_upd_local = "", n_upd_remote = "", subscr = "", origin = "", latest_upd_sec = "", latest_upd_sec_mean = "", stat_time_latest = "", stat_time_mean = "", stat_time_N = ""%%% stat_gc_latest = "",%%% stat_gc_mean = "",%%% stat_gc_N = "",%%% stat_recl_latest = "",%%% stat_recl_mean = "",%%% stat_recl_N = "" }). -define(str(F,A), lists:flatten(io_lib:format(F,A))).tbl_info() -> Tables = checked_tables(), Info = collect_info(Tables), {Hdr1,Hdr2,Fmt,Line,Note} = mk_hdr(Info, [{1,"Table"}, {3,"Updates"}, {7,"Update History"}, {10,"Calc. Cost"}, %%% {10,"Number of GCs"},{13,"GC:Reclaimed"}, {13,"Parameters"}], #inf{name=" name", image="image", limit="limit", subscr="subscr", n_upd_local="Nloc", n_upd_remote="Nrem", origin="origin", latest_upd_sec = "age", latest_upd_sec_mean = "mean", stat_time_latest="latest", stat_time_mean="mean", stat_time_N="N"%%% stat_gc_latest="latest",%%% stat_gc_mean="mean",%%% stat_gc_N="N",%%% stat_recl_latest="latest",%%% stat_recl_mean="mean",%%% stat_recl_N="N" }), [io_lib:format("~s~s~s~s", [Line,Hdr1,Hdr2,Line]), write_info(Info, Fmt), io_lib:format("~s~s\n", [Line,Note]) ].mk_hdr(Data, Hdr1L, Hdr2Rec) -> Hdr2L = tl(tuple_to_list(Hdr2Rec)) ++ element(1, lists:mapfoldl( fun(_,N) -> {?str("~w)",[N]),N+1} end, 1, lists:seq(1,length(?default_values)))), List_of_lengths = lists:map(fun(D) -> lists:map(fun(E) -> length(E) end, D) end, [Hdr2L|Data]), MaxL = max_l(tl(List_of_lengths), hd(List_of_lengths)), Fmt = mk_format(MaxL, Hdr1L), Hdr1 = mk_hdr1(MaxL,Hdr1L), TblWidth = length(Hdr1), Line = lists:map(fun($|) -> $+; ($\n) -> $\n; (_) -> $- end, Hdr1), MaxNoteWidth = TblWidth - 20, Note = lists:flatten( element(1, lists:mapfoldl( fun({Name,Default,Unit},{N,W}) -> Str = ?str("~w) ~w[~w ~s] ", [N,Name,Default,Unit]), Wnew = W+length(Str), {if Wnew>MaxNoteWidth -> Str++["\n"]; true -> Str end, {N+1,Wnew}} end, {1,0}, ?default_values))), {Hdr1, ?str(Fmt,Hdr2L), Fmt, Line, Note}.mk_format(MaxL, Hdr1Def) -> case Hdr1Def of [{N,_}|_] when N>1 -> "| "; _ -> "" end ++ lists:concat(mk_format(MaxL,Hdr1Def,1))++"\n".mk_format([W|Ws], [{N1,S}|Ds], N) when N==N1 -> ["| ~",W,"s "] ++ mk_format(Ws, Ds, N+1);mk_format([W|Ws], [{N1,S}|Ds], N) when N<N1 -> ["~",W,"s "] ++ mk_format(Ws, [{N1,S}|Ds], N+1);mk_format([W|Ws], [], N) -> ["~",W,"s "] ++ mk_format(Ws, [], N+1);mk_format([], _, _) -> ["|"].%% mk_hdr1(Maxs, []) -> %% "| " ++ lists:duplicate(lists:sum(Maxs)+length(Maxs),$ ) ++ "|\n";mk_hdr1(Maxs, Def) -> mk_hdr1(Maxs, Def, 1) ++ "\n".mk_hdr1([W|Ws], [{N1,S1},{N2,S2}|Ds], N) when N==N1 -> {W1,WsT} = mk_hdr1_split([W|Ws],N2-N,0), "| " ++ mk_hdr1_s(W1,S1) ++ mk_hdr1(WsT, [{N2,S2}|Ds], N2);mk_hdr1([W|Ws], [{N1,S}], N) when N==N1 -> {W1,WsT} = mk_hdr1_split([W|Ws],100,0), "| " ++ mk_hdr1_s(W1,S) ++ "|";mk_hdr1([W|Ws], [{N1,S}|Ds], N) when N<N1 -> "| " ++ lists:duplicate(W,$ ) ++ mk_hdr1(Ws, [{N1,S}|Ds], N+1).%% mk_hdr1(_, [], _) ->%% "|".mk_hdr1_split([W|Ws], I, Acc) when I>0 -> mk_hdr1_split(Ws,I-1,Acc+W+1);mk_hdr1_split(Ws, _, Acc) -> {Acc,Ws}.mk_hdr1_s(W,S) when length(S)>W -> lists:duplicate(W, $*);mk_hdr1_s(W,S) -> Nspaces = W - length(S), Npfx = Nspaces div 2, lists:duplicate(Npfx, $ ) ++ S ++ lists:duplicate(Nspaces-Npfx,$ ). max_l([L|Ls], MaxL) -> max_l(Ls, lists:map(fun(N) -> lists:max([lists:nth(N,L), lists:nth(N,MaxL)]) end, lists:seq(1,length(MaxL))));max_l([], MaxL) -> MaxL.write_info(Info, Fmt) -> lists:map( fun(L) when is_list(L) -> io_lib:format(Fmt, L); (X) -> io_lib:format(" ???: ~w\n", [X]) end, Info). cntr_info(Tab, Name) -> case read_counter(Tab,Name) of undefined -> ""; Cnt -> string(int,Cnt) end.collect_info(Tables) -> NowSecs = now_in_secs(), lists:map( fun(Tab) -> S = read_exec_stat(Tab), R = #inf{name = atom_to_list(Tab), image = case read_image(Tab) of none -> ""; {Ar,F1,Prod} -> ?str('~W', [{Ar,F1,'_'},8]) end, limit = cntr_info(Tab,limit), n_upd_local = cntr_info(Tab,n_upd_local), n_upd_remote = cntr_info(Tab,n_upd_remote), subscr = case lists:member(whereis(?SERVER_NAME), mnesia:table_info(Tab, subscribers)) of true -> "Yes"; false -> "No" end, origin = case read_time_stamp(Tab) of {_,_,Node,_} -> atom_to_list(Node); _ -> "" end, latest_upd_sec = begin MinInterv=read_parameter(Tab,min_upd_interval), case read_time_stamp(Tab) of {_,_,_,Sec} when Sec+MinInterv>NowSecs -> "("++string(time_s,(NowSecs-Sec))++")"; {_,_,_,Sec} -> string(time_s,(NowSecs-Sec))++" "; _ -> "" end end, latest_upd_sec_mean =string(time_s, stat(mean, read_stat(Tab, upd_stat))), stat_time_latest=string(time_us, stat(latest,S#stats.time)), stat_time_mean = string(time_us, stat(mean,S#stats.time)), stat_time_N = string(int, stat(n,S#stats.time))%%% stat_gc_latest = string(int, stat(latest,S#stats.gc)),%%% stat_gc_mean = string(int, stat(mean,S#stats.gc)),%%% stat_gc_N = string(int, stat(n,S#stats.gc)), %%% stat_recl_latest = string(int,%%% stat(latest,S#stats.recl)),%%% stat_recl_mean = string(int, stat(mean,S#stats.recl)),%%% stat_recl_N = string(int, stat(n,S#stats.recl)) }, tl(tuple_to_list(R)) ++ lists:map( fun({Name,_,_}) -> io_lib:write(read_parameter(Tab,Name)) end, ?default_values) end, Tables).stat(latest, S) when is_record(S,stat), is_integer(S#stat.latest) -> S#stat.latest;stat(mean, S) when is_record(S,stat), is_integer(S#stat.sum), S#stat.n=/=0 -> S#stat.sum div S#stat.n;stat(n, S) when is_record(S,stat), is_integer(S#stat.n) -> S#stat.n;stat(_, _) -> undefined.%% string(clock, {H,M,S}) -> ?str("~2..0w:~2..0w:~2..0w", [H,M,S]);%% string(date, {Y,M,D}) -> ?str("~w-~2..0w-~2..0w", [Y,M,D]);string(time_us, MicroSecs) when is_integer(MicroSecs) -> if MicroSecs < 1000 -> ?str("~wus",[MicroSecs]); MicroSecs < 3000 -> ?str("~4.2fms",[MicroSecs/1000]); true -> string(time_ms, MicroSecs div 1000) end;string(time_ms, MilliSecs) when is_integer(MilliSecs) -> if MilliSecs < 1000 -> ?str("~wms",[MilliSecs]); MilliSecs < 9000 -> ?str("~4.2fs",[MilliSecs/1000]); true -> string(time_s, MilliSecs div 1000) end;string(time_s, TotSecs) when is_integer(TotSecs) -> Hrs = TotSecs div 3600, Mins= (TotSecs div 60) rem 60, Secs= TotSecs rem 60, if Hrs>24 -> ?str("~wd~2..0wh~2..0wm~2..0ws", [Hrs div 24,Hrs rem 24,Mins,Secs]); Hrs >0 -> ?str("~wh~2..0wm~2..0ws",[Hrs,Mins,Secs]); Mins>0 -> ?str("~wm~2..0ws",[Mins,Secs]); true -> ?str("~ws",[Secs]) end;string(int, I) when is_integer(I) -> integer_to_list(I);string(_,_) -> "".
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -