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 + -
显示快捷键?