dets.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 2,178 行 · 第 1/5 页
ERL
2,178 行
case catch write_cache(H) of {H2, []} -> {H2, catch file_size(H#head.fptr, H#head.filename)}; {H2, _} = HeadError when is_record(H2, head) -> HeadError end;finfo(H, fixed) -> %% true if fixtable/2 has been called {H, not (H#head.fixed =:= false)}; finfo(H, hash) -> {H, H#head.hash_bif};finfo(H, keypos) -> {H, H#head.keypos};finfo(H, memory) -> finfo(H, file_size);finfo(H, no_objects) -> finfo(H, size);finfo(H, no_keys) -> case catch write_cache(H) of {H2, []} -> {H2, H2#head.no_keys}; {H2, _} = HeadError when is_record(H2, head) -> HeadError end;finfo(H, no_slots) -> {H, (H#head.mod):no_slots(H)};finfo(H, pid) -> {H, self()};finfo(H, ram_file) -> {H, H#head.ram_file};finfo(H, safe_fixed) -> {H, H#head.fixed};finfo(H, size) -> case catch write_cache(H) of {H2, []} -> {H2, H2#head.no_objects}; {H2, _} = HeadError when is_record(H2, head) -> HeadError end;finfo(H, type) -> {H, H#head.type};finfo(H, version) -> {H, H#head.version};finfo(H, _) -> {H, undefined}.file_size(Fd, FileName) -> {ok, Pos} = dets_utils:position(Fd, FileName, eof), Pos.test_bchunk_format(_Head, undefined) -> false;test_bchunk_format(Head, _Term) when Head#head.version =:= 8 -> false;test_bchunk_format(Head, Term) -> dets_v9:try_bchunk_header(Term, Head) =/= not_ok.do_open_file([Fname, Verbose], Parent, Server, Ref) -> case catch fopen2(Fname, Ref) of {error, _Reason} = Error -> err(Error); {ok, Head} -> maybe_put(verbose, Verbose), {ok, Head#head{parent = Parent, server = Server}}; {'EXIT', _Reason} = Error -> Error; Bad -> error_logger:format ("** dets: Bug was found in open_file/1, reply was ~w.~n", [Bad]), {error, {dets_bug, Fname, Bad}} end;do_open_file([Tab, OpenArgs, Verb], Parent, Server, Ref) -> case catch fopen3(Tab, OpenArgs) of {error, {tooshort, _}} -> file:delete(OpenArgs#open_args.file), do_open_file([Tab, OpenArgs, Verb], Parent, Server, Ref); {error, _Reason} = Error -> err(Error); {ok, Head} -> maybe_put(verbose, Verb), {ok, Head#head{parent = Parent, server = Server}}; {'EXIT', _Reason} = Error -> Error; Bad -> error_logger:format ("** dets: Bug was found in open_file/2, arguments were~n" "** dets: ~w and reply was ~w.~n", [OpenArgs, Bad]), {error, {dets_bug, Tab, {open_file, OpenArgs}, Bad}} end.maybe_put(_, undefined) -> ignore;maybe_put(K, V) -> put(K, V).%% -> {Head, Result}, Result = ok | Error | {thrown, Error} | badargfinit(Head, InitFun, _Format, _NoSlots) when Head#head.access =:= read -> _ = (catch InitFun(close)), {Head, {error, {access_mode, Head#head.filename}}};finit(Head, InitFun, _Format, _NoSlots) when Head#head.fixed =/= false -> _ = (catch InitFun(close)), {Head, {error, {fixed_table, Head#head.name}}};finit(Head, InitFun, Format, NoSlots) -> case catch do_finit(Head, InitFun, Format, NoSlots) of {ok, NewHead} -> check_growth(NewHead), start_auto_save_timer(NewHead), {NewHead, ok}; badarg -> {Head, badarg}; Error -> dets_utils:corrupt(Head, Error) end.%% -> {ok, NewHead} | throw(badarg) | throw(Error)do_finit(Head, Init, Format, NoSlots) -> #head{fptr = Fd, type = Type, keypos = Kp, auto_save = Auto, cache = Cache, filename = Fname, ram_file = Ram, min_no_slots = MinSlots0, max_no_slots = MaxSlots, name = Tab, update_mode = UpdateMode, mod = HMod} = Head, CacheSz = dets_utils:cache_size(Cache), {How, Head1} = case Format of term when is_integer(NoSlots), NoSlots > MaxSlots -> throw(badarg); term -> MinSlots = choose_no_slots(NoSlots, MinSlots0), if UpdateMode =:= new_dirty, MinSlots =:= MinSlots0 -> {general_init, Head}; true -> ok = dets_utils:truncate(Fd, Fname, bof), {ok, H} = HMod:initiate_file(Fd, Tab, Fname, Type, Kp, MinSlots, MaxSlots, Ram, CacheSz, Auto, false), {general_init, H} end; bchunk -> ok = dets_utils:truncate(Fd, Fname, bof), {bchunk_init, Head} end, case How of bchunk_init -> case HMod:bchunk_init(Head1, Init) of {ok, NewHead} -> {ok, NewHead#head{update_mode = dirty}}; Error -> Error end; general_init -> Cntrs = ets:new(dets_init, []), Input = HMod:bulk_input(Head1, Init, Cntrs), SlotNumbers = {Head1#head.min_no_slots, bulk_init, MaxSlots}, {Reply, SizeData} = do_sort(Head1, SlotNumbers, Input, Cntrs, Fname, not_used), Bulk = true, case Reply of {ok, NoDups, H1} -> fsck_copy(SizeData, H1, Bulk, NoDups); Else -> close_files(Bulk, SizeData, Head1), Else end end.%% -> {NewHead, [LookedUpObject]} | {NewHead, Error}flookup_keys(Head, Keys) -> case catch update_cache(Head, Keys, {lookup, nopid}) of {NewHead, [{_NoPid,Objs}]} -> {NewHead, Objs}; {NewHead, L} when is_list(L) -> {NewHead, lists:flatmap(fun({_Pid,OL}) -> OL end, L)}; {NewHead, _} = HeadError when is_record(NewHead, head) -> HeadError end.%% -> {NewHead, Result}fmatch_init(Head, C) -> case scan(Head, C) of {scan_error, Reason} -> dets_utils:corrupt_reason(Head, Reason); {Ts, NC} -> {Head, {cont, {Ts, NC}}} end.%% -> {NewHead, Result}fmatch(Head, MP, Spec, N) -> KeyPos = Head#head.keypos, case find_all_keys(Spec, KeyPos, []) of [] -> %% Complete match case catch write_cache(Head) of {NewHead, []} -> C0 = init_scan(NewHead, N), {NewHead, {cont, C0#dets_cont{match_program = MP}}}; {NewHead, _} = HeadError when is_record(NewHead, head) -> HeadError end; List -> Keys = lists:usort(List), {NewHead, Reply} = flookup_keys(Head, Keys), case Reply of Objs when is_list(Objs) -> MatchingObjs = ets:match_spec_run(Objs, MP), {NewHead, {done, MatchingObjs}}; Error -> {NewHead, Error} end end.find_all_keys([], _, Ks) -> Ks;find_all_keys([{H,_,_} | T], KeyPos, Ks) when is_tuple(H) -> case size(H) of Enough when Enough >= KeyPos -> Key = element(KeyPos, H), case contains_variable(Key) of true -> []; false -> find_all_keys(T, KeyPos, [Key | Ks]) end; _ -> find_all_keys(T, KeyPos, Ks) end;find_all_keys(_, _, _) -> [].contains_variable('_') -> true;contains_variable(A) when is_atom(A) -> case atom_to_list(A) of [$$ | T] -> case (catch list_to_integer(T)) of {'EXIT', _} -> false; _ -> true end; _ -> false end;contains_variable(T) when is_tuple(T) -> contains_variable(tuple_to_list(T));contains_variable([]) -> false;contains_variable([H|T]) -> case contains_variable(H) of true -> true; false -> contains_variable(T) end;contains_variable(_) -> false.%% -> {NewHead, Res}fmatch_delete_init(Head, MP, Spec) -> KeyPos = Head#head.keypos, case catch case find_all_keys(Spec, KeyPos, []) of [] -> do_fmatch_delete_var_keys(Head, MP, Spec); List -> Keys = lists:usort(List), do_fmatch_constant_keys(Head, Keys, MP) end of {NewHead, _} = Reply when is_record(NewHead, head) -> Reply end.%% A note: If deleted objects reside in a bucket with other objects%% that are not deleted, the bucket is moved. If the address of the%% moved bucket is greater than original bucket address the kept%% objects will be read once again later on. %% -> {NewHead, Res}fmatch_delete(Head, C) -> case scan(Head, C) of {scan_error, Reason} -> dets_utils:corrupt_reason(Head, Reason); {[], _} -> {Head, {done, 0}}; {RTs, NC} -> MP = C#dets_cont.match_program, case catch filter_binary_terms(RTs, MP, []) of {'EXIT', _} -> dets_utils:corrupt_reason(Head, bad_object); Terms -> do_fmatch_delete(Head, Terms, NC) end end.do_fmatch_delete_var_keys(Head, _MP, ?PATTERN_TO_TRUE_MATCH_SPEC('_')) when Head#head.fixed =:= false -> %% Handle the case where the file is emptied efficiently. %% Empty the cache just to get the number of objects right. {Head1, []} = write_cache(Head), N = Head1#head.no_objects, case fdelete_all_objects(Head1) of {NewHead, ok} -> {NewHead, {done, N}}; Reply -> Reply end;do_fmatch_delete_var_keys(Head, MP, _Spec) -> {NewHead, []} = write_cache(Head), C0 = init_scan(NewHead, default), {NewHead, {cont, C0#dets_cont{match_program = MP}, 0}}.do_fmatch_constant_keys(Head, Keys, MP) -> case flookup_keys(Head, Keys) of {NewHead, ReadTerms} when is_list(ReadTerms) -> Terms = filter_terms(ReadTerms, MP, []), do_fmatch_delete(NewHead, Terms, fixed); Reply -> Reply end.filter_binary_terms([Bin | Bins], MP, L) -> Term = binary_to_term(Bin), case ets:match_spec_run([Term], MP) of [true] -> filter_binary_terms(Bins, MP, [Term | L]); _ -> filter_binary_terms(Bins, MP, L) end;filter_binary_terms([], _MP, L) -> L.filter_terms([Term | Terms], MP, L) -> case ets:match_spec_run([Term], MP) of [true] -> filter_terms(Terms, MP, [Term | L]); _ -> filter_terms(Terms, MP, L) end;filter_terms([], _MP, L) -> L.do_fmatch_delete(Head, Terms, What) -> N = length(Terms), case do_delete(Head, Terms, delete_object) of {NewHead, ok} when What =:= fixed -> {NewHead, {done, N}}; {NewHead, ok} -> {NewHead, {cont, What, N}}; Reply -> Reply end.do_delete(Head, Things, What) -> case catch update_cache(Head, Things, What) of {NewHead, []} -> {NewHead, ok}; {NewHead, _} = HeadError when is_record(NewHead, head) -> HeadError end.fmember(Head, Key) -> case catch begin {Head2, [{_NoPid,Objs}]} = update_cache(Head, [Key], {lookup, nopid}), {Head2, Objs =/= []} end of {NewHead, _} = Reply when is_record(NewHead, head) -> Reply end.fnext(Head, Key) -> Slot = (Head#head.mod):db_hash(Key, Head), Ref = make_ref(), case catch {Ref, fnext(Head, Key, Slot)} of {Ref, {H, R}} -> {H, {ok, R}}; {NewHead, _} = HeadError when is_record(NewHead, head) -> HeadError end.fnext(H, Key, Slot) -> {NH, []} = write_cache(H), case (H#head.mod):slot_objs(NH, Slot) of '$end_of_table' -> {NH, '$end_of_table'}; L -> fnext_search(NH, Key, Slot, L) end.fnext_search(H, K, Slot, L) -> Kp = H#head.keypos, case beyond_key(K, Kp, L) of [] -> fnext_slot(H, K, Slot+1); L2 -> {H, element(H#head.keypos, hd(L2))} end.%% We've got to continue to search for the next key in the next slotfnext_slot(H, K, Slot) -> case (H#head.mod):slot_objs(H, Slot) of '$end_of_table' -> {H, '$end_of_table'}; [] -> fnext_slot(H, K, Slot+1); L -> {H, element(H#head.keypos, hd(L))} end.beyond_key(_K, _Kp, []) -> [];beyond_key(K, Kp, [H|T]) -> case dets_utils:cmp(element(Kp, H), K) of 0 -> beyond_key2(K, Kp, T); _ -> beyond_key(K, Kp, T) end.beyond_key2(_K, _Kp, []) -> [];beyond_key2(K, Kp, [H|T]=L) -> case dets_utils:cmp(element(Kp, H), K) of 0 -> beyond_key2(K, Kp, T); _ -> L end.%% Open an already existing file, no arguments%% -> {ok, head()} | throw(Error)fopen2(Fname, Tab) -> case file:read_file_info(Fname) of {ok, _} -> Acc = read_write, Ram = false, %% Fd is not always closed upon error, but exit is soon called. {ok, Fd, FH} = read_file_header(Fname, Acc, Ram), Mod = FH#fileheader.mod, case Mod:check_file_header(FH, Fd) of {error, not_closed} -> io:format(user,"dets: file ~p not properly closed, " "repairing ...~n", [Fname]), Version = default, case fsck(Fd, Tab, Fname, FH, default, default, Version) of ok -> fopen2(Fname, Tab); Error -> throw(Error) end; {ok, Head, ExtraInfo} -> open_final(Head, Fname, Acc, Ram, ?DEFAULT_CACHE, Tab, ExtraInfo); {error, Reason} -> throw({error, {Reason, Fname}}) end; Error ->
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?