dets.erl

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

ERL
2,178
字号
                    einval(Reply, [Tab, Args])            end;	_ ->	    erlang:error(badarg, [Tab, Args])    end;open_file(Tab, Arg) ->    open_file(Tab, [Arg]).pid2name(Pid) ->    dets_server:pid2name(Pid).remove_user(Pid, From) ->    req(Pid, {close, From}).repair_continuation(#dets_cont{match_program = B}=Cont, MS)     when is_binary(B) ->    case ets:is_compiled_ms(B) of	true ->	    Cont;	false ->            Cont#dets_cont{match_program = ets:match_spec_compile(MS)}    end;repair_continuation(#dets_cont{}=Cont, _MS) ->    Cont;repair_continuation(T, MS) ->    erlang:error(badarg, [T, MS]).safe_fixtable(Tab, Bool) when Bool; not Bool ->    badarg(treq(Tab, {safe_fixtable, Bool}), [Tab, Bool]);safe_fixtable(Tab, Term) ->    erlang:error(badarg, [Tab, Term]).select(Tab, Pat) ->    badarg(safe_match(Tab, Pat, select), [Tab, Pat]).select(Tab, Pat, N) ->    badarg(init_chunk_match(Tab, Pat, select, N), [Tab, Pat, N]).    select(State) when State#dets_cont.what =:= select ->    badarg(chunk_match(State), [State]);select(Term) ->    erlang:error(badarg, [Term]).select_delete(Tab, Pat) ->    badarg(match_delete(Tab, Pat, select), [Tab, Pat]).slot(Tab, Slot) when is_integer(Slot), Slot >= 0 ->    badarg(treq(Tab, {slot, Slot}), [Tab, Slot]);slot(Tab, Term) ->    erlang:error(badarg, [Tab, Term]).start() ->    dets_server:start().stop() ->    dets_server:stop().istart_link(Server) ->    {ok, proc_lib:spawn_link(dets, init, [self(), Server])}.sync(Tab) ->    badarg(treq(Tab, sync), [Tab]).table(Tab) ->    table(Tab, []).table(Tab, Opts) ->    case options(Opts, [traverse, n_objects]) of        {badarg,_} ->            erlang:error(badarg, [Tab, Opts]);        [Traverse, NObjs] ->            TF = case Traverse of                     first_next ->                          fun() -> qlc_next(Tab, first(Tab)) end;                     select ->                          fun(MS) -> qlc_select(select(Tab, MS, NObjs)) end;                     {select, MS} ->                         fun() -> qlc_select(select(Tab, MS, NObjs)) end                 end,            PreFun = fun(_) -> safe_fixtable(Tab, true) end,            PostFun = fun() -> safe_fixtable(Tab, false) end,            InfoFun = fun(Tag) -> table_info(Tab, Tag) end,            %% lookup_keys is not public, but convenient            LookupFun =                 case Traverse of                    {select, _MS} ->                         undefined;                    _ ->                         fun(_KeyPos, [K]) -> lookup(Tab, K);                           (_KeyPos, Ks) -> lookup_keys(Tab, 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}])    end.         qlc_next(_Tab, '$end_of_table') ->    [];qlc_next(Tab, Key) ->    case lookup(Tab, Key) of        Objects when is_list(Objects) ->            Objects ++ fun() -> qlc_next(Tab, next(Tab, Key)) end;        Error ->            %% Do what first and next do.            exit(Error)    end.qlc_select('$end_of_table') ->     [];qlc_select({Objects, Cont}) when is_list(Objects) ->     Objects ++ fun() -> qlc_select(select(Cont)) end;qlc_select(Error) ->    Error.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, _) ->    undefined.%% End of table/2.to_ets(DTab, ETab) ->    case ets:info(ETab, protection) of	undefined ->	    erlang:error(badarg, [DTab, ETab]);        _ ->	    Fun = fun(X, T) -> true = ets:insert(T, X), T end,	    foldl(Fun, ETab, DTab)    end.traverse(Tab, Fun) ->    Ref = make_ref(),    TFun = 	fun(O, Acc) ->		case Fun(O) of		    continue  ->			Acc;		    {continue, Val} ->			[Val | Acc];		    {done, Value} ->			throw({Ref, [Value | Acc]});		    Other ->			throw({Ref, Other})		end	end,    do_traverse(TFun, [], Tab, Ref).update_counter(Tab, Key, C) ->    badarg(treq(Tab, {update_counter, Key, C}), [Tab, Key, C]).verbose() ->               verbose(true).verbose(What) ->    ok = dets_server:verbose(What),    All = dets_server:all(),    Fun = fun(Tab) -> treq(Tab, {set_verbose, What}) end,    lists:foreach(Fun, All),    All.%% Where in the (open) table is Object located? %% The address of the first matching object is returned.%% Format 9 returns the address of the object collection.%% -> {ok, Address} | falsewhere(Tab, Object) ->    badarg(treq(Tab, {where, Object}), [Tab, Object]).do_traverse(Fun, Acc, Tab, Ref) ->    safe_fixtable(Tab, true),        Proc = dets_server:get_pid(Tab),    try        do_trav(Proc, Acc, Fun)    catch {Ref, Result} ->        Result    after         safe_fixtable(Tab, false)    end.do_trav(Proc, Acc, Fun) ->    {Spec, MP} = compile_match_spec(object, '_'),    %% MP not used    case req(Proc, {match, MP, Spec, default}) of	{cont, State} ->	    do_trav(State, Proc, Acc, Fun);	Error ->	    Error    end.    do_trav(#dets_cont{bin = eof}, _Proc, Acc, _Fun) ->    Acc;do_trav(State, Proc, Acc, Fun) ->    case req(Proc, {match_init, State}) of	{cont, {Bins, NewState}} ->	    do_trav_bins(NewState, Proc, Acc, Fun, lists:reverse(Bins));	Error ->	    Error    end.do_trav_bins(State, Proc, Acc, Fun, []) ->    do_trav(State, Proc, Acc, Fun);do_trav_bins(State, Proc, Acc, Fun, [Bin | Bins]) ->    %% Unpack one binary at a time, using the client's heap.    case catch binary_to_term(Bin) of 	{'EXIT', _} ->	    req(Proc, {corrupt, bad_object});	Term ->	    NewAcc = Fun(Term, Acc),	    do_trav_bins(State, Proc, NewAcc, Fun, Bins)    end.safe_match(Tab, Pat, What) ->    safe_fixtable(Tab, true),    R = do_safe_match(init_chunk_match(Tab, Pat, What, default), []),    safe_fixtable(Tab, false),    R.    do_safe_match({error, Error}, _L) ->    {error, Error};do_safe_match({L, C}, LL) ->    do_safe_match(chunk_match(C), L++LL);do_safe_match('$end_of_table', L) ->    L;do_safe_match(badarg, _L) ->    badarg.%% What = object | bindings | selectinit_chunk_match(Tab, Pat, What, N) when is_integer(N), N >= 0;                                          N =:= default ->    case compile_match_spec(What, Pat) of	{Spec, MP} ->	    case req(dets_server:get_pid(Tab), {match, MP, Spec, N}) of		{done, L} ->		    {L, #dets_cont{tab = Tab, what = What, bin = eof}};		{cont, State} ->		    chunk_match(State#dets_cont{what = What, tab = Tab});		Error ->		    Error	    end;	badarg ->	    badarg    end;init_chunk_match(_Tab, _Pat, _What, _) ->    badarg.chunk_match(State) ->    case catch dets_server:get_pid(State#dets_cont.tab) of	{'EXIT', _Reason} ->	    badarg;	_Proc when State#dets_cont.bin =:= eof ->	    '$end_of_table';	Proc ->	    case req(Proc, {match_init, State}) of		{cont, {Bins, NewState}} ->		    MP = NewState#dets_cont.match_program,		    case catch do_foldl_bins(Bins, MP) of			{'EXIT', _} ->                            case ets:is_compiled_ms(MP) of                                true ->                                    req(Proc, {corrupt, bad_object});                                false ->                                    badarg                            end;                        [] ->                            chunk_match(NewState);			Terms ->			    {Terms, NewState}		    end;		Error ->		    Error	    end    end.do_foldl_bins(Bins, true) ->    foldl_bins(Bins, []);do_foldl_bins(Bins, MP) ->    foldl_bins(Bins, MP, []).foldl_bins([], Terms) ->    %% Preserve time order (version 9).     Terms;foldl_bins([Bin | Bins], Terms) ->        foldl_bins(Bins, [binary_to_term(Bin) | Terms]).foldl_bins([], _MP, Terms) ->    %% Preserve time order (version 9).    Terms;foldl_bins([Bin | Bins], MP, Terms) ->    Term = binary_to_term(Bin),    case ets:match_spec_run([Term], MP) of	[] ->	    foldl_bins(Bins, MP, Terms);	[Result] ->	    foldl_bins(Bins, MP, [Result | Terms])    end.%% -> {Spec, binary()} | badargcompile_match_spec(select, ?PATTERN_TO_OBJECT_MATCH_SPEC('_') = Spec) ->    {Spec, true};compile_match_spec(select, Spec) ->    case catch ets:match_spec_compile(Spec) of	X when is_binary(X) ->	    {Spec, X};	_ ->	    badarg    end;compile_match_spec(object, Pat) ->    compile_match_spec(select, ?PATTERN_TO_OBJECT_MATCH_SPEC(Pat));compile_match_spec(bindings, Pat) ->    compile_match_spec(select, ?PATTERN_TO_BINDINGS_MATCH_SPEC(Pat));compile_match_spec(delete, Pat) ->    compile_match_spec(select, ?PATTERN_TO_TRUE_MATCH_SPEC(Pat)).%% Process the args list as provided to open_file/2.defaults(Tab, Args) ->    Defaults = #open_args{file = to_list(Tab),                          type = set,                          keypos = 1,                          repair = true,                           min_no_slots = default,			  max_no_slots = default,                          ram_file = false,                          delayed_write = ?DEFAULT_CACHE,                          auto_save = timer:minutes(?DEFAULT_AUTOSAVE),                          access = read_write,                          version = default},    Fun = fun repl/2,    lists:foldl(Fun, Defaults, Args).to_list(T) when is_atom(T) -> atom_to_list(T);to_list(T) -> T.repl({access, A}, Defs) ->    mem(A, [read, read_write]),    Defs#open_args{access = A};repl({auto_save, Int}, Defs) when is_integer(Int), Int >= 0 ->    Defs#open_args{auto_save = Int};repl({auto_save, infinity}, Defs) ->    Defs#open_args{auto_save =infinity};repl({cache_size, Int}, Defs) when is_integer(Int), Int >= 0 ->    %% Recognized, but ignored.    Defs;repl({cache_size, infinity}, Defs) ->    Defs;repl({delayed_write, default}, Defs) ->    Defs#open_args{delayed_write = ?DEFAULT_CACHE};repl({delayed_write, {Delay,Size} = C}, Defs)           when is_integer(Delay), Delay >= 0, is_integer(Size), Size >= 0 ->    Defs#open_args{delayed_write = C};repl({estimated_no_objects, I}, Defs)  ->    repl({min_no_slots, I}, Defs);repl({file, File}, Defs) ->    Defs#open_args{file = to_list(File)};repl({keypos, P}, Defs) when is_integer(P), P > 0 ->    Defs#open_args{keypos =P};repl({max_no_slots, I}, Defs)  ->    %% Version 9 only.    MaxSlots = is_max_no_slots(I),    is_comp_min_max(Defs#open_args{max_no_slots = MaxSlots});repl({min_no_slots, I}, Defs)  ->    MinSlots = is_min_no_slots(I),    is_comp_min_max(Defs#open_args{min_no_slots = MinSlots});repl({ram_file, Bool}, Defs) ->    mem(Bool, [true, false]),    Defs#open_args{ram_file = Bool};repl({repair, T}, Defs) ->    mem(T, [true, false, force]),    Defs#open_args{repair = T};repl({type, T}, Defs) ->    mem(T, [set, bag, duplicate_bag]),    Defs#open_args{type =T};repl({version, Version}, Defs) ->    V = is_version(Version),    is_comp_min_max(Defs#open_args{version = V});repl({_, _}, _) ->    exit(badarg).is_min_no_slots(default) -> default;is_min_no_slots(I) when is_integer(I), I >= ?DEFAULT_MIN_NO_SLOTS -> I;is_min_no_slots(I) when is_integer(I), I >= 0 -> ?DEFAULT_MIN_NO_SLOTS.is_max_no_slots(default) -> default;is_max_no_slots(I) when is_integer(I), I > 0, I < 1 bsl 31 -> I.is_comp_min_max(Defs) ->    %% Bug: accepts version = default, when default means version 8.    #open_args{max_no_slots = Max, min_no_slots = Min, version = V} = Defs,    case V of	8 when Max =:= default, Min =:= default -> Defs;	_ when V =/= 8, Min =:= default -> Defs;	_ when V =/= 8, Max =:= default -> Defs;	_ -> V =/= 8, true = Min =< Max, Defs    end.is_version(default) -> default;is_version(8) -> 8;is_version(9) -> 9.mem(X, L) ->    case lists:member(X, L) of	true -> true;	false -> exit(badarg)    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, {format, Format}} when Format =:= term;                                            Format =:= bchunk ->		{ok, Format};

⌨️ 快捷键说明

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