dets_v8.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,591 行 · 第 1/4 页
ERL
1,591 行
ObjsToRead, ToRead, Ls, LU) -> E = {P1,P2,WorkLists}, first_object(SPs, Ss, Bs, Head, [E | ObjsToRead], [{P2, ?ReadAhead} | ToRead], Ls, LU);first_object([], [], [], Head, ObjsToRead, ToRead, Ls, LU) -> {ok, Bins} = dets_utils:pread(ToRead, Head), case catch eval_first(Bins, ObjsToRead, Head, Ls, LU) of {ok, NLs, NLU} -> case create_writes(NLs, Head, [], 0) of {Head1, [], 0} -> {Head1, NLU, []}; {Head1, Ws, No} -> {NewHead, Ws2} = update_no_objects(Head1, Ws, No), {NewHead, NLU, Ws2} end; _Error -> throw(dets_utils:corrupt_reason(Head, bad_object)) end.%% Update no_objects on the file too, if the number of segments that%% dets:fsck/6 use for estimate has changed.update_no_objects(Head, Ws, 0) -> {Head, Ws};update_no_objects(Head, Ws, Delta) -> No = Head#head.no_objects, NewNo = No + Delta, NWs = if NewNo > ?MAXOBJS -> Ws; ?SLOT2SEG(No) =:= ?SLOT2SEG(NewNo) -> Ws; true -> [{?NO_OBJECTS_POS, <<NewNo:32>>} | Ws] end, {Head#head{no_objects = NewNo}, NWs}.eval_first([<<Next:32, Sz:32, _Status:32, Bin/binary>> | Bins], [SP | SPs], Head, Ls, LU) -> {P1, P2, WLs} = SP, L0 = [{old,P1}], case size(Bin) of BinSz when BinSz >= Sz -> Term = binary_to_term(Bin), Key = element(Head#head.keypos, Term), {L, NLU} = find_key(Head, P2, Next, Sz, Term, Key, WLs, L0, LU), eval_first(Bins, SPs, Head, [L | Ls], NLU); _BinSz -> {L, NLU} = eval_slot(Head, Sz+?OHDSZ, P2, WLs, L0, LU), eval_first(Bins, SPs, Head, [L | Ls], NLU) end;eval_first([], [], _Head, Ls, LU) -> {ok, Ls, LU}.eval_slot(_Head, _TrySize, _Pos=0, [], L, LU) -> {L, LU};eval_slot(Head, _TrySize, Pos=0, [WL | WLs], L, LU) -> {_Key, {_Delete, LookUp, Objects}} = WL, {NL, NLU} = end_of_key(Objects, LookUp, L, []), eval_slot(Head, ?ReadAhead, Pos, WLs, NL, NLU++LU);eval_slot(Head, TrySize, Pos, WLs, L, LU) -> {NextPos, Size, Term} = prterm(Head, Pos, TrySize), Key = element(Head#head.keypos, Term), find_key(Head, Pos, NextPos, Size, Term, Key, WLs, L, LU).find_key(Head, Pos, NextPos, Size, Term, Key, WLs, L, LU) -> case lists:keysearch(Key, 1, WLs) of {value, {_, {Delete, LookUp, Objects}} = WL} -> NWLs = lists:delete(WL, WLs), {NewObjects, NL, LUK} = eval_object(Size, Term, Delete, LookUp, Objects, Head, Pos, L, []), eval_key(Key, Delete, LookUp, NewObjects, Head, NextPos, NWLs, NL, LU, LUK); false -> L0 = [{old,Pos} | L], eval_slot(Head, ?ReadAhead, NextPos, WLs, L0, LU) end.eval_key(_Key, _Delete, Lookup, _Objects, Head, Pos, WLs, L, LU, LUK) when Head#head.type =:= set -> NLU = case Lookup of {lookup, Pid} -> [{Pid,LUK} | LU]; skip -> LU end, eval_slot(Head, ?ReadAhead, Pos, WLs, L, NLU);eval_key(_Key, _Delete, LookUp, Objects, Head, Pos, WLs, L, LU, LUK) when Pos =:= 0 -> {NL, NLU} = end_of_key(Objects, LookUp, L, LUK), eval_slot(Head, ?ReadAhead, Pos, WLs, NL, NLU++LU);eval_key(Key, Delete, LookUp, Objects, Head, Pos, WLs, L, LU, LUK) -> {NextPos, Size, Term} = prterm(Head, Pos, ?ReadAhead), case element(Head#head.keypos, Term) of Key -> {NewObjects, NL, LUK1} = eval_object(Size, Term, Delete, LookUp,Objects,Head,Pos,L,LUK), eval_key(Key, Delete, LookUp, NewObjects, Head, NextPos, WLs, NL, LU, LUK1); Key2 -> {L1, NLU} = end_of_key(Objects, LookUp, L, LUK), find_key(Head, Pos, NextPos, Size, Term, Key2, WLs, L1, NLU++LU) end.%% All objects in Objects have the key Key.eval_object(Size, Term, Delete, LookUp, Objects, Head, Pos, L, LU) -> Type = Head#head.type, case lists:keysearch(Term, 1, Objects) of {value, {_Object, N}} when N =:= 0 -> L1 = [{delete,Pos,Size} | L], {Objects, L1, LU}; {value, {_Object, N}} when N < 0, Type =:= set -> L1 = [{old,Pos} | L], wl_lookup(LookUp, Objects, Term, L1, LU); {value, {Object, _N}} when Type =:= bag -> % when N =:= 1; N =:= -1 L1 = [{old,Pos} | L], Objects1 = lists:keydelete(Object, 1, Objects), wl_lookup(LookUp, Objects1, Term, L1, LU); {value, {Object, N}} when N < 0, Type =:= duplicate_bag -> L1 = [{old,Pos} | L], Objects1 = lists:keyreplace(Object, 1, Objects, {Object,N+1}), wl_lookup(LookUp, Objects1, Term, L1, LU); {value, {_Object, N}} when N > 0, Type =:= duplicate_bag -> L1 = [{old,Pos} | L], wl_lookup(LookUp, Objects, Term, L1, LU); false when Type =:= set, Delete =:= delete -> case lists:keysearch(-1, 2, Objects) of false -> % no inserted object, perhaps deleted objects L1 = [{delete,Pos,Size} | L], {[], L1, LU}; {value, {Term2,-1}} -> Bin2 = term_to_binary(Term2), NSize = size(Bin2), Overwrite = if NSize =:= Size -> true; true -> SizePos = sz2pos(Size+?OHDSZ), NSizePos = sz2pos(NSize+?OHDSZ), SizePos =:= NSizePos end, E = if Overwrite -> {overwrite,Bin2,Pos}; true -> {replace,Bin2,Pos,Size} end, wl_lookup(LookUp, [], Term2, [E | L], LU) end; false when Delete =:= delete -> L1 = [{delete,Pos,Size} | L], {Objects, L1, LU}; false -> L1 = [{old,Pos} | L], wl_lookup(LookUp, Objects, Term, L1, LU) end.%% Inlined.wl_lookup({lookup,_}, Objects, Term, L, LU) -> {Objects, L, [Term | LU]};wl_lookup(skip, Objects, _Term, L, LU) -> {Objects, L, LU}.end_of_key([{Object,N0} | Objs], LookUp, L, LU) when N0 =/= 0 -> N = abs(N0), NL = [{insert,N,term_to_binary(Object)} | L], NLU = case LookUp of {lookup, _} -> lists:duplicate(N, Object) ++ LU; skip -> LU end, end_of_key(Objs, LookUp, NL, NLU);end_of_key([_ | Objects], LookUp, L, LU) -> end_of_key(Objects, LookUp, L, LU);end_of_key([], {lookup,Pid}, L, LU) -> {L, [{Pid,LU}]};end_of_key([], skip, L, LU) -> {L, LU}.create_writes([L | Ls], H, Ws, No) -> {NH, NWs, NNo} = create_writes(L, H, Ws, No, 0, true), create_writes(Ls, NH, NWs, NNo);create_writes([], H, Ws, No) -> {H, lists:reverse(Ws), No}.create_writes([{old,Pos} | L], H, Ws, No, _Next, true) -> create_writes(L, H, Ws, No, Pos, true);create_writes([{old,Pos} | L], H, Ws, No, Next, false) -> W = {Pos, <<Next:32>>}, create_writes(L, H, [W | Ws], No, Pos, true);create_writes([{insert,N,Bin} | L], H, Ws, No, Next, _NextIsOld) -> {NH, NWs, Pos} = create_inserts(N, H, Ws, Next, size(Bin), Bin), create_writes(L, NH, NWs, No+N, Pos, false);create_writes([{overwrite,Bin,Pos} | L], H, Ws, No, Next, _) -> Size = size(Bin), W = {Pos, [<<Next:32, Size:32, ?ACTIVE:32>>, Bin]}, create_writes(L, H, [W | Ws], No, Pos, true);create_writes([{replace,Bin,Pos,OSize} | L], H, Ws, No, Next, _) -> Size = size(Bin), {H1, _} = dets_utils:free(H, Pos, OSize+?OHDSZ), {NH, NewPos, _} = dets_utils:alloc(H1, ?OHDSZ + Size), W1 = {NewPos, [<<Next:32, Size:32, ?ACTIVE:32>>, Bin]}, NWs = if Pos =:= NewPos -> [W1 | Ws]; true -> W2 = {Pos+?STATUS_POS, <<?FREE:32>>}, [W1,W2 | Ws] end, create_writes(L, NH, NWs, No, NewPos, false);create_writes([{delete,Pos,Size} | L], H, Ws, No, Next, _) -> {NH, _} = dets_utils:free(H, Pos, Size+?OHDSZ), NWs = [{Pos+?STATUS_POS,<<?FREE:32>>} | Ws], create_writes(L, NH, NWs, No-1, Next, false);create_writes([], H, Ws, No, _Next, _NextIsOld) -> {H, Ws, No}.create_inserts(0, H, Ws, Next, _Size, _Bin) -> {H, Ws, Next};create_inserts(N, H, Ws, Next, Size, Bin) -> {NH, Pos, _} = dets_utils:alloc(H, ?OHDSZ + Size), W = {Pos, [<<Next:32, Size:32, ?ACTIVE:32>>, Bin]}, create_inserts(N-1, NH, [W | Ws], Pos, Size, Bin).slot_position(S) -> Pos = ?SEGADDR(?SLOT2SEG(S)), Segment = get_segp(Pos), FinalPos = Segment + (4 * ?REM2(S, ?SEGSZ)), {FinalPos, 4}.%% Twice the size of a segment due to the bug in sz2pos/1. Inlined.actual_seg_size() -> ?POW(sz2pos(?SEGSZ*4)-1).segp_cache(Pos, Segment) -> put(Pos, Segment).%% Inlined.get_segp(Pos) -> get(Pos).%% Bug: If Sz0 is equal to 2**k for some k, then 2**(k+1) bytes are%% allocated (wasting 2**k bytes).sz2pos(N) -> 1 + dets_utils:log2(N+1).scan_objs(_Head, Bin, From, To, L, Ts, R, _Type) -> scan_objs(Bin, From, To, L, Ts, R).scan_objs(Bin, From, To, L, Ts, -1) -> {stop, Bin, From, To, L, Ts};scan_objs(B = <<_N:32, Sz:32, St:32, T/binary>>, From, To, L, Ts, R) -> if St =:= ?ACTIVE; St =:= ?FREE -> % deleted after scanning started case T of <<BinTerm:Sz/binary, T2/binary>> -> NTs = [BinTerm | Ts], OSz = Sz + ?OHDSZ, Skip = ?POW(sz2pos(OSz)-1) - OSz, F2 = From + OSz, NR = if R < 0 -> R + 1; true -> R + OSz + Skip end, scan_skip(T2, F2, To, Skip, L, NTs, NR); _ -> {more, From, To, L, Ts, R, Sz+?OHDSZ} end; true -> % a segment scan_skip(B, From, To, actual_seg_size(), L, Ts, R) end;scan_objs(_B, From, To, L, Ts, R) -> {more, From, To, L, Ts, R, 0}.scan_skip(Bin, From, To, Skip, L, Ts, R) when From + Skip < To -> SkipPos = From + Skip, case Bin of <<_:Skip/binary, Tail/binary>> -> scan_objs(Tail, SkipPos, To, L, Ts, R); _ -> {more, SkipPos, To, L, Ts, R, 0} end;scan_skip(Bin, From, To, Skip, L, Ts, R) when From + Skip =:= To -> scan_next_allocated(Bin, From, To, L, Ts, R);scan_skip(_Bin, From, _To, Skip, L, Ts, R) -> % when From + Skip > _To From1 = From + Skip, {more, From1, From1, L, Ts, R, 0}.scan_next_allocated(_Bin, _From, To, <<>>=L, Ts, R) -> {more, To, To, L, Ts, R, 0};scan_next_allocated(Bin, From0, _To, <<From:32, To:32, L/binary>>, Ts, R) -> Skip = From - From0, scan_skip(Bin, From0, To, Skip, L, Ts, R).%% Read term from file at position Posprterm(Head, Pos, ReadAhead) -> Res = dets_utils:pread(Head, Pos, ?OHDSZ, ReadAhead), ?DEBUGF("file:pread(~p, ~p, ?) -> ~p~n", [Head#head.filename, Pos, Res]), {ok, <<Next:32, Sz:32, _Status:32, Bin0/binary>>} = Res, ?DEBUGF("{Next, Sz} = ~p~n", [{Next, Sz}]), Bin = case size(Bin0) of Actual when Actual >= Sz -> Bin0; _ -> {ok, Bin1} = dets_utils:pread(Head, Pos + ?OHDSZ, Sz, 0), Bin1 end, Term = binary_to_term(Bin), {Next, Sz, Term}.%%%%%%%%%%%%%%%%% DEBUG functions %%%%%%%%%%%%%%%%file_info(FH) -> #fileheader{closed_properly = CP, keypos = Kp, m = M, next = Next, n = N, version = Version, type = Type, no_objects = NoObjects} = FH, if CP =:= 0 -> {error, not_closed}; FH#fileheader.cookie =/= ?MAGIC -> {error, not_a_dets_file}; FH#fileheader.version =/= ?FILE_FORMAT_VERSION -> {error, bad_version}; true -> {ok, [{closed_properly,CP},{keypos,Kp},{m, M}, {n,N},{next,Next},{no_objects,NoObjects}, {type,Type},{version,Version}]} end.v_segments(H) -> v_segments(H, 0).v_segments(_H, ?SEGARRSZ) -> done;v_segments(H, SegNo) -> Seg = dets_utils:read_4(H#head.fptr, ?SEGADDR(SegNo)), if Seg =:= 0 -> done; true -> io:format("SEGMENT ~w ", [SegNo]), io:format("At position ~w~n", [Seg]), v_segment(H, SegNo, Seg, 0), v_segments(H, SegNo+1) end.v_segment(_H, _, _SegPos, ?SEGSZ) -> done;v_segment(H, SegNo, SegPos, SegSlot) -> Slot = SegSlot + (SegNo * ?SEGSZ), Chain = dets_utils:read_4(H#head.fptr, SegPos + (4 * SegSlot)), if Chain =:= 0 -> %% don't print empty chains true; true -> io:format(" <~p>~p: [",[SegPos + (4 * SegSlot), Slot]), print_chain(H, Chain) end, v_segment(H, SegNo, SegPos, SegSlot+1).print_chain(_H, 0) -> io:format("] \n", []);print_chain(H, Pos) -> {ok, _} = file:position(H#head.fptr, Pos), case rterm(H#head.fptr) of {ok, 0, _Sz, Term} -> io:format("<~p>~p] \n",[Pos, Term]); {ok, Next, _Sz, Term} -> io:format("<~p>~p, ", [Pos, Term]), print_chain(H, Next); Other -> io:format("~nERROR ~p~n", [Other]) end.%% Can't be used at the bucket level!!!!%% Only when we go down a chainrterm(F) -> case catch rterm2(F) of {'EXIT', Reason} -> %% truncated DAT file dets_utils:vformat("** dets: Corrupt or truncated dets file~n", []), {error, Reason}; Other -> Other end.rterm2(F) -> {ok, <<Next:32, Sz:32, _:32>>} = file:read(F, ?OHDSZ), {ok, Bin} = file:read(F, Sz), Term = binary_to_term(Bin), {ok, Next, Sz, Term}.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?