dets_utils.erl

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

ERL
1,580
字号
%% ``The contents of this file are subject to the Erlang Public License,%% Version 1.1, (the "License"); you may not use this file except in%% compliance with the License. You should have received a copy of the%% Erlang Public License along with this software. If not, it can be%% retrieved via the world wide web at http://www.erlang.org/.%% %% Software distributed under the License is distributed on an "AS IS"%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See%% the License for the specific language governing rights and limitations%% under the License.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %%     $Id $%%-module(dets_utils).%% Utility functions common to several dets file formats.%% To be used from dets, dets_v8 and dets_v9 only.-export([cmp/2, msort/1, mkeysort/2, mkeysearch/3, family/1]).-export([rename/2, pread/2, pread/4, ipread/3, pwrite/2, write/2,         truncate/2, position/2, sync/1, open/2, truncate/3, fwrite/3,         write_file/2, position/3, position_close/3, pwrite/4,         pwrite/3, pread_close/4, read_n/2, pread_n/3, read_4/2]).-export([code_to_type/1, type_to_code/1]).-export([corrupt_reason/2, corrupt/2, corrupt_file/2,          vformat/2, file_error/2]).-export([cache_lookup/4, cache_size/1, new_cache/1,	 reset_cache/1, is_empty_cache/1]).-export([empty_free_lists/0, init_alloc/1, alloc_many/4, alloc/2,         free/3, get_freelists/1, all_free/1, all_allocated/1,         all_allocated_as_list/1, find_allocated/4, find_next_allocated/3,         log2/1, make_zeros/1]).-export([init_slots_from_old_file/2]).-export([list_to_tree/1, tree_to_bin/5]).-compile({inline, [{sz2pos,1}, {adjust_addr,3}]}).-compile({inline, [{bplus_mk_leaf,1}, {bplus_get_size,1},		   {bplus_get_tree,2}, {bplus_get_lkey,2},		   {bplus_get_rkey,2}]}).-include("dets.hrl").%%% A total ordering of all Erlang terms.%% -> -1 | 0 | 1. T1 is (smaller than | equal | greater than) T2.%% If is_integer(I), is_float(F), I == F then I is deemed smaller than F.cmp(T, T) ->    0;cmp([E1 | T1], [E2 | T2]) ->    case cmp(E1, E2) of        0 -> cmp(T1, T2);        R -> R    end;cmp(T1, T2) when is_tuple(T1), is_tuple(T2), size(T1) =:= size(T2) ->    tcmp(T1, T2, 1, size(T1));cmp(I, F) when is_integer(I), is_float(F) ->    -1;cmp(F, I) when is_float(F), is_integer(I) ->    1;cmp(T1, T2) when T1 < T2 ->    -1;cmp(_T1, _T2) -> % when _T1 > _T2    1.tcmp(T1, T2, I, I) ->    cmp(element(I, T1), element(I,  T2));tcmp(T1, T2, I, N) ->    case cmp(element(I, T1), element(I, T2)) of        0 -> tcmp(T1, T2, I + 1, N);        R -> R    end.msort(L) ->    %% sort is very much faster than msort, let it do most of the work.        F = fun(X, Y) -> cmp(X, Y) =< 0 end,    lists:sort(F, lists:sort(L)).mkeysort(I, L) ->    F = fun(X, Y) -> cmp(element(I, X), element(I, Y)) =< 0 end,    %% keysort is much faster than mkeysort, let it do most of the work.    lists:sort(F, lists:keysort(I, L)).mkeysearch(Key, I, L) ->    case lists:keysearch(Key, I, L) of        {value, Value}=Reply when element(I, Value) =:= Key ->            Reply;        false ->            false;        _ ->            mkeysearch2(Key, I, L)    end.mkeysearch2(_Key, _I, []) ->    false;mkeysearch2(Key, I, [E | _L]) when element(I, E) =:= Key ->    {value, E};mkeysearch2(Key, I, [_ | L]) ->    mkeysearch(Key, I, L).%% Be careful never to compare key, but use matching instead.%% Otherwise sofs could have been used:%%    sofs:to_external(sofs:relation_to_family(sofs:relation(L, 2))).family([]) ->    [];family(L) ->    [{K,V}|KVL] = mkeysort(1, L),    per_key(KVL, K, [V], []).per_key([], K, Vs, KVs) ->    lists:reverse(KVs, [{K,msort(Vs)}]);per_key([{K,V}|L], K, Vs, KVs) -> % match    per_key(L, K, [V|Vs], KVs);per_key([{K1,V}|L], K, Vs, KVs) ->    per_key(L, K1, [V], [{K,msort(Vs)}|KVs]).rename(From, To) ->    case file:rename(From, To) of        ok ->            ok;        {error, Reason} ->            {error, {file_error, {From, To}, Reason}}    end.%% -> {ok, Bins} | throw({NewHead, Error})pread(Positions, Head) ->    R = case file:pread(Head#head.fptr, Positions) of	    {ok, Bins} ->		%% file:pread/2 can return 'eof' as "data".		case lists:member(eof, Bins) of		    true ->			{error, {premature_eof, Head#head.filename}};		    false ->			{ok, Bins}		end;	    {error, Reason} when enomem =:= Reason; einval =:= Reason ->		{error, {bad_object_header, Head#head.filename}};	    {error, Reason} ->		{file_error, Head#head.filename, Reason}	end,    case R of	{ok, _Bins} ->	    R;	Error ->	    throw(corrupt(Head, Error))    end.%% -> {ok, binary()} | throw({NewHead, Error})pread(Head, Pos, Min, Extra) ->    R = case file:pread(Head#head.fptr, Pos, Min+Extra) of	    {error, Reason} when enomem =:= Reason; einval =:= Reason ->		{error, {bad_object_header, Head#head.filename}};	    {error, Reason} ->		{file_error, Head#head.filename, Reason};	    {ok, Bin} when size(Bin) < Min ->		{error, {premature_eof, Head#head.filename}};	    OK -> OK	end,    case R of	{ok, _Bin} ->	    R;	Error ->	    throw(corrupt(Head, Error))    end.	    %% -> eof | [] | {ok, Pointer, binary()}ipread(Fd, Pos1, MaxSize) ->    case file:ipread_s32bu_p32bu(Fd, Pos1, MaxSize) of	{ok, {0, 0, eof}} ->	    [];	{ok, Reply} ->	    {ok, Reply};	_Else ->	    eof    end.%% -> {Head, ok} | throw({Head, Error})pwrite(Head, []) ->    {Head, ok};pwrite(Head, Bins) ->    case file:pwrite(Head#head.fptr, Bins) of	ok ->	    {Head, ok};	Error ->	    corrupt_file(Head, Error)    end.%% -> ok | throw({Head, Error})write(_Head, []) ->    ok;write(Head, Bins) ->    case file:write(Head#head.fptr, Bins) of	ok ->	    ok;	Error ->	    corrupt_file(Head, Error)    end.%% -> ok | throw({Head, Error})%% Same as file:write_file/2, but calls file:sync/1.write_file(Head, Bin) ->    R = case file:open(Head#head.filename, [binary, raw, write]) of	    {ok, Fd} ->		R1 = file:write(Fd, Bin),		R2 = file:sync(Fd),		file:close(Fd),		if R1 =:= ok -> R2; true -> R1 end;	    Else ->		Else	end,    case R of	ok ->	    ok;	Error ->	    corrupt_file(Head, Error)    end.%% -> ok | throw({Head, Error})truncate(Head, Pos) ->    case catch truncate(Head#head.fptr, Head#head.filename, Pos) of	ok ->	    ok;	Error ->	    throw(corrupt(Head, Error))    end.%% -> {ok, Pos} | throw({Head, Error})position(Head, Pos) ->    case file:position(Head#head.fptr, Pos) of	{error, _Reason} = Error -> 	    corrupt_file(Head, Error);	OK -> OK    end.	    %% -> ok | throw({Head, Error})sync(Head) ->    case file:sync(Head#head.fptr) of	ok ->	    ok;	Error ->	    corrupt_file(Head, Error)    end.open(FileSpec, Args) ->    case file:open(FileSpec, Args) of	{ok, Fd} ->	    {ok, Fd};	Error ->	    file_error(FileSpec, Error)    end.truncate(Fd, FileName, Pos) ->    if	Pos =:= cur ->	    ok;	true ->	    position(Fd, FileName, Pos)    end,    case file:truncate(Fd) of	ok    -> 	    ok;	Error ->	    file_error(FileName, {error, Error})    end.	    fwrite(Fd, FileName, B) ->    case file:write(Fd, B) of	ok    -> ok;	Error -> file_error_close(Fd, FileName, Error)    end.position(Fd, FileName, Pos) ->    case file:position(Fd, Pos) of	{error, Error} -> file_error(FileName, {error, Error});	OK -> OK    end.	    position_close(Fd, FileName, Pos) ->    case file:position(Fd, Pos) of	{error, Error} -> file_error_close(Fd, FileName, {error, Error});	OK -> OK    end.	    pwrite(Fd, FileName, Position, B) ->    case file:pwrite(Fd, Position, B) of	ok -> ok;	Error -> file_error(FileName, {error, Error})    end.pwrite(Fd, FileName, Bins) ->    case file:pwrite(Fd, Bins) of	ok ->	    ok;	{error, {_NoWrites, Reason}} ->	    file_error(FileName, {error, Reason})    end.pread_close(Fd, FileName, Pos, Size) ->    case file:pread(Fd, Pos, Size) of	{error, Error} ->	    file_error_close(Fd, FileName, {error, Error});	{ok, Bin} when size(Bin) < Size ->	    file:close(Fd),	    throw({error, {tooshort, FileName}});	eof ->	    file:close(Fd),	    throw({error, {tooshort, FileName}});	OK -> OK    end.	    file_error(FileName, {error, Reason}) ->    throw({error, {file_error, FileName, Reason}}).file_error_close(Fd, FileName, {error, Reason}) ->    file:close(Fd),    throw({error, {file_error, FileName, Reason}}).	    read_n(Fd, Max) ->    case file:read(Fd, Max) of	{ok, Bin} ->	    Bin;	_Else ->	    eof    end.pread_n(Fd, Position, Max) ->    case file:pread(Fd, Position, Max) of	{ok, Bin} ->	    Bin;	_ ->	    eof    end.read_4(Fd, Position) ->    {ok, _} = file:position(Fd, Position),    <<Four:32>> = dets_utils:read_n(Fd, 4),    Four.corrupt_file(Head, {error, Reason}) ->    Error = {error, {file_error, Head#head.filename, Reason}},    throw(corrupt(Head, Error)).%% -> {NewHead, Error}corrupt_reason(Head, Reason) ->    Error = {error, {Reason, Head#head.filename}},        corrupt(Head, Error).corrupt(Head, Error) ->    case get(verbose) of	yes -> 	    error_logger:format("** dets: Corrupt table ~p: ~p\n", 				[Head#head.name, Error]);	_ -> ok    end,    case Head#head.update_mode of	{error, _} ->	    {Head, Error};	_ ->	    {Head#head{update_mode = Error}, Error}    end.vformat(F, As) ->    case get(verbose) of	yes -> error_logger:format(F, As);	_ -> ok    end.code_to_type(?SET) -> set;code_to_type(?BAG) -> bag;code_to_type(?DUPLICATE_BAG) -> duplicate_bag;code_to_type(_Type) -> badtype.type_to_code(set) -> ?SET;type_to_code(bag) -> ?BAG;type_to_code(duplicate_bag) -> ?DUPLICATE_BAG.%%%%%% Write Cache%%% cache_size(C) ->    {C#cache.delay, C#cache.tsize}.%% -> [object()] | falsecache_lookup(Type, [Key | Keys], CL, LU) ->

⌨️ 快捷键说明

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