Current section
Files
Jump to
Current section
Files
src/observer_cli_mnesia.erl
%%% @author zhongwen <zhongwencool@gmail.com>
-module(observer_cli_mnesia).
%% API
-export([start/1]).
-include("observer_cli.hrl").
-define(LAST_LINE, "q(quit) s(sort by size) m(sort by memory) pd/pu(page:down/up) F/B(forward/back)" ++
" hide(swith between hide and display system table)").
-spec start(#view_opts{}) -> any().
start(#view_opts{db = #db{interval = MillSecond,
hide_sys = HideSys, cur_page = CurPage, attr = Attr},
auto_row = AutoRow} = HomeOpts) ->
Pid = spawn_link(fun() ->
?output(?CLEAR),
render_worker(MillSecond, ?INIT_TIME_REF, HideSys, AutoRow, Attr, CurPage)
end),
manager(Pid, HomeOpts).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Private
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
manager(ChildPid, #view_opts{db = DBOpts
= #db{cur_page = CurPage, hide_sys = Hide}} = HomeOpts) ->
case observer_cli_lib:parse_cmd(HomeOpts, [ChildPid]) of
quit -> erlang:send(ChildPid, quit);
{new_interval, NewMs} = Msg ->
erlang:send(ChildPid, Msg),
manager(ChildPid, HomeOpts#view_opts{db = DBOpts#db{interval = NewMs}});
hide ->
NewHide = not Hide,
erlang:send(ChildPid, {system_table, NewHide}),
manager(ChildPid, HomeOpts#view_opts{db = DBOpts#db{hide_sys = NewHide}});
size ->
observer_cli_lib:exit_processes([ChildPid]),
start(HomeOpts#view_opts{db = DBOpts#db{attr = size}});
{func, proc_count, memory} -> %% Home
observer_cli_lib:exit_processes([ChildPid]),
start(HomeOpts#view_opts{db = DBOpts#db{attr = memory}});
page_down_top_n ->
NewPage = max(CurPage + 1, 1),
observer_cli_lib:exit_processes([ChildPid]),
start(HomeOpts#view_opts{db = DBOpts#db{cur_page = NewPage}});
page_up_top_n ->
NewPage = max(CurPage - 1, 1),
observer_cli_lib:exit_processes([ChildPid]),
start(HomeOpts#view_opts{db = DBOpts#db{cur_page = NewPage}});
_ -> manager(ChildPid, HomeOpts)
end.
render_worker(Interval, LastTimeRef, HideSystemTable, AutoRow, Attr, CurPage) ->
TerminalRow = observer_cli_lib:get_terminal_rows(AutoRow),
Rows = erlang:max(TerminalRow - 5, 0),
Text = "Interval: " ++ integer_to_list(Interval) ++ "ms"
++ " HideSystemTable:" ++ atom_to_list(HideSystemTable),
Menu = observer_cli_lib:render_menu(mnesia, Text),
LastLine = observer_cli_lib:render_last_line(?LAST_LINE),
case get_table_list(HideSystemTable, Attr) of
{error, Reason} ->
ErrInfo = io_lib:format("Mnesia Error ~p~n", [Reason]),
?output([?CURSOR_TOP, Menu, ErrInfo, LastLine]);
MnesiaList ->
Info = render_mnesia(MnesiaList, Attr, Rows, CurPage),
?output([?CURSOR_TOP, Menu, Info, LastLine])
end,
TimeRef = observer_cli_lib:next_redraw(LastTimeRef, Interval),
receive
quit -> quit;
{new_interval, NewInterval} ->
render_worker(NewInterval, TimeRef, HideSystemTable, AutoRow, Attr, CurPage);
{system_table, NewHideSystemTable} ->
render_worker(Interval, TimeRef, NewHideSystemTable, AutoRow, Attr, CurPage);
_ ->
render_worker(Interval, TimeRef, HideSystemTable, AutoRow, Attr, CurPage)
end.
render_mnesia(MnesiaList, Attr, Rows, CurPage) ->
SortMnesia = observer_cli_lib:sublist(MnesiaList, Rows, CurPage),
{MemColor, SizeColor} =
case Attr of
memory -> {?RED_BG, ?GRAY_BG};
_ -> {?GRAY_BG, ?RED_BG}
end,
Title = ?render([
?UNDERLINE, ?W2(?GRAY_BG, "Name", 25),
?UNDERLINE, ?W2(MemColor, " Memory ", 16),
?UNDERLINE, ?W2(SizeColor, "Size", 16),
?UNDERLINE, ?W2(?GRAY_BG, "Type", 12),
?UNDERLINE, ?W2(?GRAY_BG, "Storage", 15),
?UNDERLINE, ?W2(?GRAY_BG, "Owner", 14),
?UNDERLINE, ?W2(?GRAY_BG, "Index", 11),
?UNDERLINE, ?W2(?GRAY_BG, "Reg_name", 20)
]),
View =
[begin
Name = proplists:get_value(name, Mnesia), Memory = proplists:get_value(memory, Mnesia),
Size = proplists:get_value(size, Mnesia), Type = proplists:get_value(type, Mnesia),
RegName = proplists:get_value(reg_name, Mnesia), Index = proplists:get_value(index, Mnesia),
Owner = proplists:get_value(owner, Mnesia), Storage = proplists:get_value(storage, Mnesia),
?render([
?W(Name, 24), ?W({byte, Memory}, 14), ?W(Size, 14),
?W(Type, 10), ?W(Storage, 13), ?W(Owner, 12),
?W(Index, 9), ?W(RegName, 19)
])
end || {_, _, Mnesia} <- SortMnesia],
[Title | View].
mnesia_tables() ->
[ir_AliasDef, ir_ArrayDef, ir_AttributeDef, ir_ConstantDef,
ir_Contained, ir_Container, ir_EnumDef, ir_ExceptionDef,
ir_IDLType, ir_IRObject, ir_InterfaceDef, ir_ModuleDef,
ir_ORB, ir_OperationDef, ir_PrimitiveDef, ir_Repository,
ir_SequenceDef, ir_StringDef, ir_StructDef, ir_TypedefDef,
ir_UnionDef, logTable, logTransferTable, mesh_meas,
mesh_type, mnesia_clist, orber_CosNaming,
orber_objkeys, user
].
get_table_list(HideSys, Attr) ->
Owner = ets:info(schema, owner),
case Owner of
undefined -> {error, "Mnesia is not running on: " ++ atom_to_list(node())};
_ -> get_table_list2(Owner, HideSys, Attr)
end.
get_table_list2(Owner, HideSys, Attr) ->
{registered_name, RegName} = process_info(Owner, registered_name),
WordSize = erlang:system_info(wordsize),
CollectFun = fun(Id, Acc) ->
case HideSys andalso ordsets:is_element(Id, mnesia_tables()) orelse Id =:= schema of
true -> Acc; %% ignore system table
false ->
Storage = mnesia:table_info(Id, storage_type),
Size = mnesia:table_info(Id, size),
Memory = mnesia:table_info(Id, memory) * WordSize,
Tab0 = [{name, Id},
{owner, Owner},
{size, Size},
{reg_name, RegName},
{type, mnesia:table_info(Id, type)},
{memory, Memory},
{storage, Storage},
{index, mnesia:table_info(Id, index)}
],
Tab =
case Storage of
_ when Storage =:= ram_copies orelse Storage =:= disc_copies ->
[{fixed, ets:info(Id, fixed)}, {compressed, ets:info(Id, compressed)} | Tab0];
disc_only_copies ->
[{fixed, dets:info(Id, safe_fixed)} | Tab0];
_ -> Tab0
end,
[{0, proplists:get_value(Attr, Tab), Tab} | Acc]
end
end,
lists:foldl(CollectFun, [], mnesia:system_info(tables)).