Current section

Files

Jump to
observer_cli src observer_cli_mnesia.erl
Raw

src/observer_cli_mnesia.erl

%%% @author zhongwen <zhongwencool@gmail.com>
-module(observer_cli_mnesia).
%% API
-export([start/1]).
-export([clean/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(switch 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).
-spec clean(list()) -> ok.
clean(Pids) -> observer_cli_lib:exit_processes(Pids).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Private
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
manager(ChildPid, #view_opts{db = DBOpts = #db{cur_page = CurPage, hide_sys = Hide}} = HomeOpts) ->
case observer_cli_lib:parse_cmd(HomeOpts, ?MODULE, [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 ->
clean([ChildPid]),
start(HomeOpts#view_opts{db = DBOpts#db{attr = size}});
%% Home
{func, proc_count, memory} ->
clean([ChildPid]),
start(HomeOpts#view_opts{db = DBOpts#db{attr = memory}});
page_down_top_n ->
NewPage = max(CurPage + 1, 1),
clean([ChildPid]),
start(HomeOpts#view_opts{db = DBOpts#db{cur_page = NewPage}});
page_up_top_n ->
NewPage = max(CurPage - 1, 1),
clean([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) ->
{_StartPos, 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.
-dialyzer([{nowarn_function, [get_table_list2/3]}]).
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
%% ignore system table
true ->
Acc;
false ->
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},
{index, mnesia:table_info(Id, index)}
],
Tab = with_storage_type(Id, Tab0),
[{0, proplists:get_value(Attr, Tab), Tab} | Acc]
end
end,
lists:foldl(CollectFun, [], mnesia:system_info(tables)).
-dialyzer([{nowarn_function, [with_storage_type/2]}]).
with_storage_type(Id, Tab0) ->
Storage = mnesia:table_info(Id, storage_type),
with_storage_type(Id, Storage, Tab0).
with_storage_type(Id, Storage, Tab0) when Storage =:= ram_copies orelse Storage =:= disc_copies ->
[
{fixed, ets:info(Id, fixed)},
{compressed, ets:info(Id, compressed)},
{storage, Storage}
| Tab0
];
with_storage_type(Id, disc_only_copies = Storage, Tab0) ->
[
{fixed, dets:info(Id, safe_fixed)},
{storage, Storage}
| Tab0
];
with_storage_type(_Id, {ext, _, _} = Storage, Tab0) ->
[
{storage, io_lib:format("~tp", [Storage])}
| Tab0
].