ets.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 744 行 · 第 1/2 页

ERL
744
字号
	_Other ->	    {error, badfile}    end.init_file2tab(Name) ->    case disk_log:chunk(Name, start) of	{error, Reason} ->	    file2tab_error(Name, Reason);	eof ->	    file2tab_error(Name, eof);	{Cont, [Info | Tail]} ->	    case catch mk_tab(tuple_to_list(Info)) of		{'EXIT', _} ->		    file2tab_error(Name, "Can't create table");		Tab ->		    fill_tab(Cont, Name, Tab, Tail),		    disk_log:close(Name),		    {ok, Tab}	    end    end.fill_tab(C, Name, Tab, [H|T]) ->    ets:insert(Tab, H),    fill_tab(C, Name, Tab, T);fill_tab(C, Name, Tab, []) ->    case disk_log:chunk(Name, C) of	{error, Reason} ->	    ets:db_delete(Tab),	    file2tab_error(Name, Reason);	eof ->	    ok;	{C2, Objs} ->	    fill_tab(C2, Name, Tab, Objs)    end.file2tab_error(Name, Reason) ->    disk_log:close(Name),    {error, Reason}.mk_tab(I) ->    {value, {name, Name}} = lists:keysearch(name, 1, I),    {value, {type, Type}} = lists:keysearch(type, 1, I),    {value, {protection, P}} = lists:keysearch(protection, 1, I),    {value, {named_table, Val}} = lists:keysearch(named_table, 1, I),    {value, {keypos, Kp}} = lists:keysearch(keypos, 1, I),    ets:new(Name, [Type, P, {keypos, Kp} | named_table(Val)]).named_table(true) -> [named_table];named_table(false) -> [].table(Tab) ->    table(Tab, []).table(Tab, Opts) ->    case options(Opts, [traverse, n_objects]) of        {badarg,_} ->            erlang:fault(badarg, [Tab, Opts]);        [[Traverse, NObjs], QlcOptions] ->            TF = case Traverse of                     first_next ->                          fun() -> qlc_next(Tab, ets:first(Tab)) end;                     last_prev ->                          fun() -> qlc_prev(Tab, ets:last(Tab)) end;                     select ->                          fun(MS) -> qlc_select(ets:select(Tab, MS, NObjs)) end;                     {select, MS} ->                         fun() -> qlc_select(ets:select(Tab, MS, NObjs)) end                 end,            PreFun = fun(_) -> ets:safe_fixtable(Tab, true) end,            PostFun = fun() -> ets:safe_fixtable(Tab, false) end,            InfoFun = fun(Tag) -> table_info(Tab, Tag) end,            LookupFun =                 case Traverse of                     {select, _MS} ->                        undefined;                    _ ->                         fun(_Pos, [K]) ->                                ets:lookup(Tab, K);                           (_Pos, Ks) ->                                 lists:flatmap(fun(K) -> ets:lookup(Tab, K)                                               end, Ks)                         end                end,            FormatFun =                 fun(all) ->                        As = case Opts of                                 [] -> [Tab];                                 _ -> [Tab, Opts]                             end,                        {?MODULE, table, As};                   ({match_spec, MS}) ->                        {?MODULE, table,                          [Tab, [{traverse, {select, MS}} |                                 listify(Opts)]]};                   ({lookup, _KeyPos, [Value]}) ->                        io_lib:format("~w:lookup(~w, ~w)",                                       [?MODULE, Tab, Value]);                   ({lookup, _KeyPos, Values}) ->                        io_lib:format("lists:flatmap(fun(V) -> "                                      "~w:lookup(~w, V) end, ~w)",                                       [?MODULE, Tab, Values])                end,            qlc:table(TF, [{pre_fun, PreFun}, {post_fun, PostFun},                            {info_fun, InfoFun}, {format_fun, FormatFun},                           {lookup_fun, LookupFun}] ++ QlcOptions)    end.         table_info(Tab, num_of_objects) ->    info(Tab, size);table_info(Tab, keypos) ->    info(Tab, keypos);table_info(Tab, is_unique_objects) ->    info(Tab, type) =/= duplicate_bag;table_info(Tab, is_sorted_key) ->    info(Tab, type) =:= ordered_set;table_info(_Tab, _) ->    undefined.qlc_next(_Tab, '$end_of_table') ->    [];qlc_next(Tab, Key) ->    ets:lookup(Tab, Key) ++ fun() -> qlc_next(Tab, ets:next(Tab, Key)) end.qlc_prev(_Tab, '$end_of_table') ->    [];qlc_prev(Tab, Key) ->    ets:lookup(Tab, Key) ++ fun() -> qlc_prev(Tab, ets:prev(Tab, Key)) end.qlc_select('$end_of_table') ->     [];qlc_select({Objects, Cont}) ->     Objects ++ fun() -> qlc_select(ets:select(Cont)) end.options(Options, Keys) when is_list(Options) ->    options(Options, Keys, []);options(Option, Keys) ->    options([Option], Keys, []).options(Options, [Key | Keys], L) when is_list(Options) ->    V = case lists:keysearch(Key, 1, Options) of            {value, {n_objects, default}} ->                {ok, default_option(Key)};            {value, {n_objects, NObjs}} when is_integer(NObjs),                                             NObjs >= 1 ->                {ok, NObjs};            {value, {traverse, select}} ->                {ok, select};            {value, {traverse, {select, MS}}} ->                {ok, {select, MS}};            {value, {traverse, first_next}} ->                {ok, first_next};            {value, {traverse, last_prev}} ->                {ok, last_prev};	    {value, {Key, _}} ->		badarg;	    false ->		Default = default_option(Key),		{ok, Default}	end,    case V of	badarg ->	    {badarg, Key};	{ok,Value} ->	    NewOptions = lists:keydelete(Key, 1, Options),	    options(NewOptions, Keys, [Value | L])    end;options(Options, [], L) ->    [lists:reverse(L), Options].default_option(traverse) -> select;default_option(n_objects) -> 100.listify(L) when is_list(L) ->    L;listify(T) ->    [T].%% End of table/2.%% Print info about all tabs on the ttyi() ->    hform('id', 'name', 'type', 'size', 'mem', 'owner'),    io:format(" -------------------------------------"	      "---------------------------------------\n"),    lists:foreach(fun prinfo/1, tabs()),    ok.tabs() ->    lists:sort(ets:all()).prinfo(Tab) ->    case catch prinfo2(Tab) of	{'EXIT', _} ->	    io:format("~-10s ... unreadable \n", [to_string(Tab)]);	ok -> 	    ok    end.prinfo2(Tab) ->    Name = ets:info(Tab, name),    Type = ets:info(Tab, type),    Size = ets:info(Tab, size),    Mem = ets:info(Tab, memory),    Owner = ets:info(Tab, owner),    hform(Tab, Name, Type, Size, Mem, is_reg(Owner)).is_reg(Owner) ->    case process_info(Owner, registered_name) of	{registered_name, Name} -> Name;	_ -> Owner    end.%%% Arndt: this code used to truncate over-sized fields. Now it%%% pushes the remaining entries to the right instead, rather than%%% losing information.hform(A0, B0, C0, D0, E0, F0) ->    [A,B,C,D,E,F] = [to_string(T) || T <- [A0,B0,C0,D0,E0,F0]],    A1 = pad_right(A, 15),    B1 = pad_right(B, 17),    C1 = pad_right(C, 5),    D1 = pad_right(D, 6),    E1 = pad_right(E, 8),    %% no need to pad the last entry on the line    io:format(" ~s ~s ~s ~s ~s ~s\n", [A1,B1,C1,D1,E1,F]).pad_right(String, Len) ->    if	length(String) >= Len ->	    String;	true ->	    [Space] = " ",	    String ++ lists:duplicate(Len - length(String), Space)    end.to_string(X) ->    lists:flatten(io_lib:format("~p", [X])).%% view a specific table i(Tab) ->    i(Tab, 40).i(Tab, Height) ->    i(Tab, Height, 80).i(Tab, Height, Width) ->    First = ets:first(Tab),    display_items(Height, Width, Tab, First, 1, 1).display_items(Height, Width, Tab, '$end_of_table', Turn, Opos) ->     P = 'EOT  (q)uit (p)Digits (k)ill /Regexp -->',    choice(Height, Width, P, eot, Tab, '$end_of_table', Turn, Opos);display_items(Height, Width, Tab, Key, Turn, Opos) when Turn < Height ->    do_display(Height, Width, Tab, Key, Turn, Opos);display_items(Height, Width, Tab, Key, Turn, Opos) when Turn >=  Height ->    P = '(c)ontinue (q)uit (p)Digits (k)ill /Regexp -->',    choice(Height, Width, P, normal, Tab, Key, Turn, Opos).choice(Height, Width, P, Mode, Tab, Key, Turn, Opos) ->    case get_line(P, "c\n") of	"c\n" when Mode =:= normal ->	    do_display(Height, Width, Tab, Key, 1, Opos);	"c\n" when is_tuple(Mode), element(1, Mode) =:= re ->	    {re, Re} = Mode,	    re_search(Height, Width, Tab, Key, Re, 1, Opos);	"q\n" ->	    quit;	"k\n" ->	    ets:delete(Tab);	[$p|Digs]  ->	    catch case catch list_to_integer(nonl(Digs)) of		      {'EXIT', _} ->			  io:format("Bad digits \n", []);		      Number when Mode =:= normal ->			  print_number(Tab, ets:first(Tab), Number);		      Number when Mode =:= eot ->			  print_number(Tab, ets:first(Tab), Number);		      Number -> %% regexp			  {re, Re} = Mode,			  print_re_num(Tab, ets:first(Tab), Number, Re)		  end,	    choice(Height, Width, P, Mode, Tab, Key, Turn, Opos);	[$/|Regexp]   -> %% from regexp	    re_search(Height, Width, Tab, ets:first(Tab), nonl(Regexp), 1, 1);	_  ->	    choice(Height, Width, P, Mode, Tab, Key, Turn, Opos)    end.get_line(P, Default) ->    case io:get_line(P) of	"\n" ->	    Default;	L ->	    L    end.nonl(S) -> string:strip(S, right, $\n).print_number(Tab, Key, Num) ->    Os = ets:lookup(Tab, Key),    Len = length(Os),    if 	(Num - Len) < 1 ->	    O = lists:nth(Num, Os),	    io:format("~p~n", [O]); %% use ppterm here instead	true ->	    print_number(Tab, ets:next(Tab, Key), Num - Len)    end.do_display(Height, Width, Tab, Key, Turn, Opos) ->    Objs = ets:lookup(Tab, Key),    do_display_items(Height, Width, Objs, Opos),    Len = length(Objs),    display_items(Height, Width, Tab, ets:next(Tab, Key), Turn+Len, Opos+Len).do_display_items(Height, Width, [Obj|Tail], Opos) ->    do_display_item(Height, Width, Obj, Opos),    do_display_items(Height, Width, Tail, Opos+1);do_display_items(_Height, _Width, [], Opos) ->    Opos.do_display_item(_Height, Width, I, Opos)  ->    L = to_string(I),    L2 = if	     length(L) > Width - 8 ->                 string:substr(L, 1, Width-13) ++ "  ...";	     true ->		 L	 end,    io:format("<~-4w> ~s~n", [Opos,L2]).re_search(Height, Width, Tab, '$end_of_table', Re, Turn, Opos) ->    P = 'EOT  (q)uit (p)Digits (k)ill /Regexp -->',    choice(Height, Width, P, {re, Re}, Tab, '$end_of_table', Turn, Opos);re_search(Height, Width, Tab, Key, Re, Turn, Opos) when Turn < Height ->    re_display(Height, Width, Tab, Key, ets:lookup(Tab, Key), Re, Turn, Opos);re_search(Height, Width, Tab, Key, Re, Turn, Opos)  ->    P = '(c)ontinue (q)uit (p)Digits (k)ill /Regexp -->',    choice(Height, Width, P, {re, Re}, Tab, Key, Turn, Opos).re_display(Height, Width, Tab, Key, [], Re, Turn, Opos) ->    re_search(Height, Width, Tab, ets:next(Tab, Key), Re, Turn, Opos);re_display(Height, Width, Tab, Key, [H|T], Re, Turn, Opos) ->    Str = to_string(H),    case regexp:match(Str, Re) of	{match,_,_} ->	    do_display_item(Height, Width, H, Opos),	    re_display(Height, Width, Tab, Key, T, Re, Turn+1, Opos+1);	_ ->	    re_display(Height, Width, Tab, Key, T, Re, Turn, Opos)    end.print_re_num(_,'$end_of_table',_,_) -> ok;print_re_num(Tab, Key, Num, Re) ->    Os = re_match(ets:lookup(Tab, Key), Re),    Len = length(Os),    if 	(Num - Len) < 1 ->	    O = lists:nth(Num, Os),	    io:format("~p~n", [O]); %% use ppterm here instead	true ->	    print_re_num(Tab, ets:next(Tab, Key), Num - Len, Re)    end.re_match([], _) -> [];re_match([H|T], Re) ->    case regexp:match(to_string(H), Re) of	{match,_,_} -> 	    [H|re_match(T,Re)];	_ ->	    re_match(T, Re)    end.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?