1%%% @author zhongwen <zhongwencool@gmail.com> 2-module(observer_cli_mnesia). 3 4%% API 5-export([start/1]). 6-export([clean/1]). 7 8-include("observer_cli.hrl"). 9 10-define(LAST_LINE, 11 "q(quit) s(sort by size) m(sort by memory) pd/pu(page:down/up) F/B(forward/back)" 12 " hide(swith between hide and display system table)" 13). 14 15-spec start(#view_opts{}) -> any(). 16start( 17 #view_opts{ 18 db = #db{ 19 interval = MillSecond, 20 hide_sys = HideSys, 21 cur_page = CurPage, 22 attr = Attr 23 }, 24 auto_row = AutoRow 25 } = HomeOpts 26) -> 27 Pid = spawn_link(fun() -> 28 ?output(?CLEAR), 29 render_worker(MillSecond, ?INIT_TIME_REF, HideSys, AutoRow, Attr, CurPage) 30 end), 31 manager(Pid, HomeOpts). 32 33-spec clean(list()) -> ok. 34clean(Pids) -> observer_cli_lib:exit_processes(Pids). 35 36%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 37%%% Private 38%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 39 40manager(ChildPid, #view_opts{db = DBOpts = #db{cur_page = CurPage, hide_sys = Hide}} = HomeOpts) -> 41 case observer_cli_lib:parse_cmd(HomeOpts, ?MODULE, [ChildPid]) of 42 quit -> 43 erlang:send(ChildPid, quit); 44 {new_interval, NewMs} = Msg -> 45 erlang:send(ChildPid, Msg), 46 manager(ChildPid, HomeOpts#view_opts{db = DBOpts#db{interval = NewMs}}); 47 hide -> 48 NewHide = not Hide, 49 erlang:send(ChildPid, {system_table, NewHide}), 50 manager(ChildPid, HomeOpts#view_opts{db = DBOpts#db{hide_sys = NewHide}}); 51 size -> 52 clean([ChildPid]), 53 start(HomeOpts#view_opts{db = DBOpts#db{attr = size}}); 54 %% Home 55 {func, proc_count, memory} -> 56 clean([ChildPid]), 57 start(HomeOpts#view_opts{db = DBOpts#db{attr = memory}}); 58 page_down_top_n -> 59 NewPage = max(CurPage + 1, 1), 60 clean([ChildPid]), 61 start(HomeOpts#view_opts{db = DBOpts#db{cur_page = NewPage}}); 62 page_up_top_n -> 63 NewPage = max(CurPage - 1, 1), 64 clean([ChildPid]), 65 start(HomeOpts#view_opts{db = DBOpts#db{cur_page = NewPage}}); 66 _ -> 67 manager(ChildPid, HomeOpts) 68 end. 69 70render_worker(Interval, LastTimeRef, HideSystemTable, AutoRow, Attr, CurPage) -> 71 TerminalRow = observer_cli_lib:get_terminal_rows(AutoRow), 72 Rows = erlang:max(TerminalRow - 5, 0), 73 Text = 74 "Interval: " ++ 75 integer_to_list(Interval) ++ 76 "ms" ++ 77 " HideSystemTable:" ++ atom_to_list(HideSystemTable), 78 Menu = observer_cli_lib:render_menu(mnesia, Text), 79 LastLine = observer_cli_lib:render_last_line(?LAST_LINE), 80 case get_table_list(HideSystemTable, Attr) of 81 {error, Reason} -> 82 ErrInfo = io_lib:format("Mnesia Error ~p~n", [Reason]), 83 ?output([?CURSOR_TOP, Menu, ErrInfo, LastLine]); 84 MnesiaList -> 85 Info = render_mnesia(MnesiaList, Attr, Rows, CurPage), 86 ?output([?CURSOR_TOP, Menu, Info, LastLine]) 87 end, 88 TimeRef = observer_cli_lib:next_redraw(LastTimeRef, Interval), 89 receive 90 quit -> 91 quit; 92 {new_interval, NewInterval} -> 93 render_worker(NewInterval, TimeRef, HideSystemTable, AutoRow, Attr, CurPage); 94 {system_table, NewHideSystemTable} -> 95 render_worker(Interval, TimeRef, NewHideSystemTable, AutoRow, Attr, CurPage); 96 _ -> 97 render_worker(Interval, TimeRef, HideSystemTable, AutoRow, Attr, CurPage) 98 end. 99 100render_mnesia(MnesiaList, Attr, Rows, CurPage) -> 101 {_StartPos, SortMnesia} = observer_cli_lib:sublist(MnesiaList, Rows, CurPage), 102 {MemColor, SizeColor} = 103 case Attr of 104 memory -> {?RED_BG, ?GRAY_BG}; 105 _ -> {?GRAY_BG, ?RED_BG} 106 end, 107 Title = ?render([ 108 ?UNDERLINE, 109 ?W2(?GRAY_BG, "Name", 25), 110 ?UNDERLINE, 111 ?W2(MemColor, " Memory ", 16), 112 ?UNDERLINE, 113 ?W2(SizeColor, "Size", 16), 114 ?UNDERLINE, 115 ?W2(?GRAY_BG, "Type", 12), 116 ?UNDERLINE, 117 ?W2(?GRAY_BG, "Storage", 15), 118 ?UNDERLINE, 119 ?W2(?GRAY_BG, "Owner", 14), 120 ?UNDERLINE, 121 ?W2(?GRAY_BG, "Index", 11), 122 ?UNDERLINE, 123 ?W2(?GRAY_BG, "Reg_name", 20) 124 ]), 125 View = [ 126 begin 127 Name = proplists:get_value(name, Mnesia), 128 Memory = proplists:get_value(memory, Mnesia), 129 Size = proplists:get_value(size, Mnesia), 130 Type = proplists:get_value(type, Mnesia), 131 RegName = proplists:get_value(reg_name, Mnesia), 132 Index = proplists:get_value(index, Mnesia), 133 Owner = proplists:get_value(owner, Mnesia), 134 Storage = proplists:get_value(storage, Mnesia), 135 ?render([ 136 ?W(Name, 24), 137 ?W({byte, Memory}, 14), 138 ?W(Size, 14), 139 ?W(Type, 10), 140 ?W(Storage, 13), 141 ?W(Owner, 12), 142 ?W(Index, 9), 143 ?W(RegName, 19) 144 ]) 145 end 146 || {_, _, Mnesia} <- SortMnesia 147 ], 148 [Title | View]. 149 150mnesia_tables() -> 151 [ 152 ir_AliasDef, 153 ir_ArrayDef, 154 ir_AttributeDef, 155 ir_ConstantDef, 156 ir_Contained, 157 ir_Container, 158 ir_EnumDef, 159 ir_ExceptionDef, 160 ir_IDLType, 161 ir_IRObject, 162 ir_InterfaceDef, 163 ir_ModuleDef, 164 ir_ORB, 165 ir_OperationDef, 166 ir_PrimitiveDef, 167 ir_Repository, 168 ir_SequenceDef, 169 ir_StringDef, 170 ir_StructDef, 171 ir_TypedefDef, 172 ir_UnionDef, 173 logTable, 174 logTransferTable, 175 mesh_meas, 176 mesh_type, 177 mnesia_clist, 178 orber_CosNaming, 179 orber_objkeys, 180 user 181 ]. 182 183get_table_list(HideSys, Attr) -> 184 Owner = ets:info(schema, owner), 185 case Owner of 186 undefined -> {error, "Mnesia is not running on: " ++ atom_to_list(node())}; 187 _ -> get_table_list2(Owner, HideSys, Attr) 188 end. 189 190get_table_list2(Owner, HideSys, Attr) -> 191 {registered_name, RegName} = process_info(Owner, registered_name), 192 WordSize = erlang:system_info(wordsize), 193 CollectFun = fun(Id, Acc) -> 194 case HideSys andalso ordsets:is_element(Id, mnesia_tables()) orelse Id =:= schema of 195 %% ignore system table 196 true -> 197 Acc; 198 false -> 199 Storage = mnesia:table_info(Id, storage_type), 200 Size = mnesia:table_info(Id, size), 201 Memory = mnesia:table_info(Id, memory) * WordSize, 202 Tab0 = [ 203 {name, Id}, 204 {owner, Owner}, 205 {size, Size}, 206 {reg_name, RegName}, 207 {type, mnesia:table_info(Id, type)}, 208 {memory, Memory}, 209 {storage, Storage}, 210 {index, mnesia:table_info(Id, index)} 211 ], 212 Tab = 213 case Storage of 214 _ when Storage =:= ram_copies orelse Storage =:= disc_copies -> 215 [ 216 {fixed, ets:info(Id, fixed)}, 217 {compressed, ets:info(Id, compressed)} 218 | Tab0 219 ]; 220 disc_only_copies -> 221 [{fixed, dets:info(Id, safe_fixed)} | Tab0]; 222 _ -> 223 Tab0 224 end, 225 [{0, proplists:get_value(Attr, Tab), Tab} | Acc] 226 end 227 end, 228 lists:foldl(CollectFun, [], mnesia:system_info(tables)). 229