fix(erlang): integer guard, cache dedup, dead macro cleanup
This commit is contained in:
parent
a1667d1182
commit
445eb4cb8e
|
|
@ -158,11 +158,11 @@ System:
|
||||||
CPU : Apple M4
|
CPU : Apple M4
|
||||||
Cores : 10 cores / 10 threads
|
Cores : 10 cores / 10 threads
|
||||||
Erlang : Erlang/OTP 29 [erts-17.0.2] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1] [jit] [dtrace]
|
Erlang : Erlang/OTP 29 [erts-17.0.2] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1] [jit] [dtrace]
|
||||||
Loaded : 487169 IPs in 1.574 s
|
Loaded : 487169 IPs in 1.335 s
|
||||||
|
|
||||||
Benchmarks:
|
Benchmarks:
|
||||||
file total= 9.460s count= 487169 qps= 51500.40 avg= 0.019417 ms/op (19.417 us/op)
|
cold total= 9.601s count= 487169 qps= 50740.66 avg= 0.019708 ms/op (19.708 us/op)
|
||||||
cache total= 0.150s count= 487169 qps= 3245240.41 avg= 0.000308 ms/op ( 0.308 us/op)
|
warm total= 0.160s count= 487169 qps= 3053164.29 avg= 0.000328 ms/op ( 0.328 us/op)
|
||||||
|
|
||||||
Done.
|
Done.
|
||||||
```
|
```
|
||||||
|
|
@ -174,11 +174,11 @@ System:
|
||||||
CPU : Apple M4
|
CPU : Apple M4
|
||||||
Cores : 10 cores / 10 threads
|
Cores : 10 cores / 10 threads
|
||||||
Erlang : Erlang/OTP 29 [erts-17.0.2] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1] [jit] [dtrace]
|
Erlang : Erlang/OTP 29 [erts-17.0.2] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1] [jit] [dtrace]
|
||||||
Loaded : 638953 IPs in 2.724 s
|
Loaded : 638953 IPs in 2.949 s
|
||||||
|
|
||||||
Benchmarks:
|
Benchmarks:
|
||||||
file total= 16.326s count= 638953 qps= 39137.65 avg= 0.025551 ms/op (25.551 us/op)
|
cold total= 20.504s count= 638953 qps= 31162.52 avg= 0.032090 ms/op (32.090 us/op)
|
||||||
cache total= 0.469s count= 638953 qps= 1361972.38 avg= 0.000734 ms/op ( 0.734 us/op)
|
warm total= 0.444s count= 638953 qps= 1437781.56 avg= 0.000696 ms/op ( 0.696 us/op)
|
||||||
|
|
||||||
Done.
|
Done.
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -135,11 +135,11 @@ System:
|
||||||
CPU : Apple M4
|
CPU : Apple M4
|
||||||
Cores : 10 cores / 10 threads
|
Cores : 10 cores / 10 threads
|
||||||
Erlang : Erlang/OTP 29 [erts-17.0.2] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1] [jit] [dtrace]
|
Erlang : Erlang/OTP 29 [erts-17.0.2] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1] [jit] [dtrace]
|
||||||
Loaded : 487169 IPs in 1.574 s
|
Loaded : 487169 IPs in 1.335 s
|
||||||
|
|
||||||
Benchmarks:
|
Benchmarks:
|
||||||
file total= 9.460s count= 487169 qps= 51500.40 avg= 0.019417 ms/op (19.417 us/op)
|
cold total= 9.601s count= 487169 qps= 50740.66 avg= 0.019708 ms/op (19.708 us/op)
|
||||||
cache total= 0.150s count= 487169 qps= 3245240.41 avg= 0.000308 ms/op ( 0.308 us/op)
|
warm total= 0.160s count= 487169 qps= 3053164.29 avg= 0.000328 ms/op ( 0.328 us/op)
|
||||||
|
|
||||||
Done.
|
Done.
|
||||||
```
|
```
|
||||||
|
|
@ -151,11 +151,11 @@ System:
|
||||||
CPU : Apple M4
|
CPU : Apple M4
|
||||||
Cores : 10 cores / 10 threads
|
Cores : 10 cores / 10 threads
|
||||||
Erlang : Erlang/OTP 29 [erts-17.0.2] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1] [jit] [dtrace]
|
Erlang : Erlang/OTP 29 [erts-17.0.2] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1] [jit] [dtrace]
|
||||||
Loaded : 638953 IPs in 2.724 s
|
Loaded : 638953 IPs in 2.949 s
|
||||||
|
|
||||||
Benchmarks:
|
Benchmarks:
|
||||||
file total= 16.326s count= 638953 qps= 39137.65 avg= 0.025551 ms/op (25.551 us/op)
|
cold total= 20.504s count= 638953 qps= 31162.52 avg= 0.032090 ms/op (32.090 us/op)
|
||||||
cache total= 0.469s count= 638953 qps= 1361972.38 avg= 0.000734 ms/op ( 0.734 us/op)
|
warm total= 0.444s count= 638953 qps= 1437781.56 avg= 0.000696 ms/op ( 0.696 us/op)
|
||||||
|
|
||||||
Done.
|
Done.
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ PROJECT_ROOT="$(cd ../.. && pwd)"
|
||||||
if [ "$VERSION" = "ipv6" ]; then
|
if [ "$VERSION" = "ipv6" ]; then
|
||||||
DB_FILE="${PROJECT_ROOT}/data/ip2region_v6.xdb"
|
DB_FILE="${PROJECT_ROOT}/data/ip2region_v6.xdb"
|
||||||
DATA_FILE="${PROJECT_ROOT}/data/ipv6_source.txt"
|
DATA_FILE="${PROJECT_ROOT}/data/ipv6_source.txt"
|
||||||
DB_CONFIG="[{ipv4, \"ip2region.xdb\"}, {ipv6, \"${DB_FILE}\"}]"
|
DB_CONFIG="[{ipv6, \"${DB_FILE}\"}]"
|
||||||
elif [ "$VERSION" = "ipv4" ]; then
|
elif [ "$VERSION" = "ipv4" ]; then
|
||||||
DATA_FILE="${PROJECT_ROOT}/data/ipv4_source.txt"
|
DATA_FILE="${PROJECT_ROOT}/data/ipv4_source.txt"
|
||||||
DB_CONFIG="[{ipv4, \"ip2region.xdb\"}]"
|
DB_CONFIG="[{ipv4, \"ip2region.xdb\"}]"
|
||||||
|
|
|
||||||
|
|
@ -4,20 +4,11 @@
|
||||||
-define(NONE, none).
|
-define(NONE, none).
|
||||||
-define(APP_NAME, ip2region).
|
-define(APP_NAME, ip2region).
|
||||||
|
|
||||||
-define(XDB_VECTOR_INDEX, ets_xdb_vector_index).
|
|
||||||
-define(XDB_SEGMENT_INDEX, ets_xdb_segement_index).
|
|
||||||
-define(IP2REGION_CACHE, ets_ip2region_cache).
|
|
||||||
|
|
||||||
|
|
||||||
-define(XDB_HEADER_SIZE, 256).
|
-define(XDB_HEADER_SIZE, 256).
|
||||||
-define(XDB_VECTOR_COLS, 256).
|
-define(XDB_VECTOR_COLS, 256).
|
||||||
-define(XDB_VECTOR_INDEX_SIZE, 8).
|
-define(XDB_VECTOR_INDEX_SIZE, 8).
|
||||||
-define(XDB_VECTOR_INDEX_COUNT, (16#10000)). %% 256*256
|
-define(XDB_VECTOR_INDEX_COUNT, (16#10000)). %% 256*256
|
||||||
|
|
||||||
-define(XDB_SEGMENT_INDEX_SIZE, 14).
|
|
||||||
|
|
||||||
-define(IP2REGION_POOL, ip2region_pool).
|
|
||||||
|
|
||||||
%% xdb header field offsets (bytes)
|
%% xdb header field offsets (bytes)
|
||||||
-define(XDB_HEADER_VERSION_OFFSET, 0).
|
-define(XDB_HEADER_VERSION_OFFSET, 0).
|
||||||
-define(XDB_HEADER_INDEX_POLICY_OFFSET, 2).
|
-define(XDB_HEADER_INDEX_POLICY_OFFSET, 2).
|
||||||
|
|
@ -26,7 +17,6 @@
|
||||||
-define(XDB_HEADER_END_INDEX_PTR_OFFSET, 12).
|
-define(XDB_HEADER_END_INDEX_PTR_OFFSET, 12).
|
||||||
-define(XDB_HEADER_IP_VERSION_OFFSET, 16).
|
-define(XDB_HEADER_IP_VERSION_OFFSET, 16).
|
||||||
-define(XDB_HEADER_RUNTIME_PTR_BYTES_OFFSET, 18).
|
-define(XDB_HEADER_RUNTIME_PTR_BYTES_OFFSET, 18).
|
||||||
-define(XDB_HEADER_INFO_LENGTH, 256).
|
|
||||||
|
|
||||||
%% IP versions as stored in xdb header
|
%% IP versions as stored in xdb header
|
||||||
-define(IP_VERSION_4, 4).
|
-define(IP_VERSION_4, 4).
|
||||||
|
|
@ -45,12 +35,8 @@
|
||||||
-define(IP2REGION_CACHE_V6, ets_ip2region_cache_v6).
|
-define(IP2REGION_CACHE_V6, ets_ip2region_cache_v6).
|
||||||
|
|
||||||
%% Per-version pool names. ?IP2REGION_POOL is kept as the legacy v4 pool name.
|
%% Per-version pool names. ?IP2REGION_POOL is kept as the legacy v4 pool name.
|
||||||
|
-define(IP2REGION_POOL, ip2region_pool).
|
||||||
-define(IP2REGION_POOL_V4, ip2region_pool_v4).
|
-define(IP2REGION_POOL_V4, ip2region_pool_v4).
|
||||||
-define(IP2REGION_POOL_V6, ip2region_pool_v6).
|
-define(IP2REGION_POOL_V6, ip2region_pool_v6).
|
||||||
|
|
||||||
-ifndef(IF).
|
|
||||||
-define(IF(C, T, F), case (C) of true -> (T); false -> (F) end).
|
|
||||||
-define(IF(C, T), ?IF(C, T, skip)).
|
|
||||||
-endif.
|
|
||||||
|
|
||||||
-endif.
|
-endif.
|
||||||
|
|
@ -41,10 +41,6 @@ init([]) ->
|
||||||
%%
|
%%
|
||||||
create_table() ->
|
create_table() ->
|
||||||
Opts = [named_table, set, public, {read_concurrency, true}, {keypos, 1}],
|
Opts = [named_table, set, public, {read_concurrency, true}, {keypos, 1}],
|
||||||
%% Legacy tables (kept for backward compatibility)
|
|
||||||
ensure_table(?XDB_VECTOR_INDEX, Opts),
|
|
||||||
ensure_table(?XDB_SEGMENT_INDEX, Opts),
|
|
||||||
ensure_table(?IP2REGION_CACHE, Opts),
|
|
||||||
%% Version-specific tables for dual-stack support
|
%% Version-specific tables for dual-stack support
|
||||||
ensure_table(?XDB_VECTOR_INDEX_V4, Opts),
|
ensure_table(?XDB_VECTOR_INDEX_V4, Opts),
|
||||||
ensure_table(?XDB_VECTOR_INDEX_V6, Opts),
|
ensure_table(?XDB_VECTOR_INDEX_V6, Opts),
|
||||||
|
|
@ -64,11 +60,14 @@ pool_child_specs() ->
|
||||||
{ok, PoolArgsCfg} = application:get_env(poolargs),
|
{ok, PoolArgsCfg} = application:get_env(poolargs),
|
||||||
Versions = [Version || {Version, _File} <- DbConfig],
|
Versions = [Version || {Version, _File} <- DbConfig],
|
||||||
UseLegacyName = (Versions == [ipv4]),
|
UseLegacyName = (Versions == [ipv4]),
|
||||||
|
V4PoolName = case UseLegacyName of
|
||||||
|
true -> ?IP2REGION_POOL;
|
||||||
|
false -> ?IP2REGION_POOL_V4
|
||||||
|
end,
|
||||||
|
ok = application:set_env(?APP_NAME, v4_pool_name, V4PoolName),
|
||||||
lists:foldl(
|
lists:foldl(
|
||||||
fun({ipv4, File}, Acc) when UseLegacyName ->
|
fun({ipv4, File}, Acc) ->
|
||||||
[make_pool_spec(?IP2REGION_POOL, ipv4, File, PoolArgsCfg) | Acc];
|
[make_pool_spec(V4PoolName, ipv4, File, PoolArgsCfg) | Acc];
|
||||||
({ipv4, File}, Acc) ->
|
|
||||||
[make_pool_spec(?IP2REGION_POOL_V4, ipv4, File, PoolArgsCfg) | Acc];
|
|
||||||
({ipv6, File}, Acc) ->
|
({ipv6, File}, Acc) ->
|
||||||
[make_pool_spec(?IP2REGION_POOL_V6, ipv6, File, PoolArgsCfg) | Acc];
|
[make_pool_spec(?IP2REGION_POOL_V6, ipv6, File, PoolArgsCfg) | Acc];
|
||||||
(_, Acc) ->
|
(_, Acc) ->
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
-spec ip_version(Ip :: tuple() | list() | binary() | integer()) ->
|
-spec ip_version(Ip :: tuple() | list() | binary() | integer()) ->
|
||||||
ipv4 | ipv6 | {error, atom()}.
|
ipv4 | ipv6 | {error, atom()}.
|
||||||
ip_version(Ip) when is_integer(Ip) -> ipv4;
|
ip_version(Ip) when is_integer(Ip), Ip >= 0, Ip =< 16#FFFFFFFF -> ipv4;
|
||||||
ip_version({_, _, _, _}) -> ipv4;
|
ip_version({_, _, _, _}) -> ipv4;
|
||||||
ip_version({_, _, _, _, _, _, _, _}) -> ipv6;
|
ip_version({_, _, _, _, _, _, _, _}) -> ipv6;
|
||||||
ip_version(Ip) when is_binary(Ip) ->
|
ip_version(Ip) when is_binary(Ip) ->
|
||||||
|
|
@ -29,7 +29,7 @@ ip_version(_) ->
|
||||||
|
|
||||||
-spec ip_to_bytes(Ip :: tuple() | list() | binary() | integer()) ->
|
-spec ip_to_bytes(Ip :: tuple() | list() | binary() | integer()) ->
|
||||||
{ok, ipv4 | ipv6, binary()} | {error, atom()}.
|
{ok, ipv4 | ipv6, binary()} | {error, atom()}.
|
||||||
ip_to_bytes(Ip) when is_integer(Ip) ->
|
ip_to_bytes(Ip) when is_integer(Ip), Ip >= 0, Ip =< 16#FFFFFFFF ->
|
||||||
{ok, ipv4, <<Ip:32>>};
|
{ok, ipv4, <<Ip:32>>};
|
||||||
ip_to_bytes({A, B, C, D}) ->
|
ip_to_bytes({A, B, C, D}) ->
|
||||||
{ok, ipv4, <<A, B, C, D>>};
|
{ok, ipv4, <<A, B, C, D>>};
|
||||||
|
|
@ -51,7 +51,7 @@ ip_to_bytes(_) ->
|
||||||
|
|
||||||
-spec ipv4_to_n(Ip :: tuple() | list() | binary() | integer()) ->
|
-spec ipv4_to_n(Ip :: tuple() | list() | binary() | integer()) ->
|
||||||
non_neg_integer() | {error, atom()}.
|
non_neg_integer() | {error, atom()}.
|
||||||
ipv4_to_n(IntIp) when is_integer(IntIp) -> IntIp;
|
ipv4_to_n(IntIp) when is_integer(IntIp), IntIp >= 0, IntIp =< 16#FFFFFFFF -> IntIp;
|
||||||
ipv4_to_n({A, B, C, D}) ->
|
ipv4_to_n({A, B, C, D}) ->
|
||||||
<<N:32>> = <<A, B, C, D>>,
|
<<N:32>> = <<A, B, C, D>>,
|
||||||
N;
|
N;
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,7 @@
|
||||||
|
|
||||||
-record(state, {
|
-record(state, {
|
||||||
xdb_fd,
|
xdb_fd,
|
||||||
version :: ipv4 | ipv6,
|
version :: ipv4 | ipv6
|
||||||
segment_index_size :: pos_integer()
|
|
||||||
}).
|
}).
|
||||||
|
|
||||||
%%==========================================
|
%%==========================================
|
||||||
|
|
@ -63,14 +62,14 @@ init(Args) ->
|
||||||
{ok, IoDevice} = file:open(XdbFileName, [read, binary]),
|
{ok, IoDevice} = file:open(XdbFileName, [read, binary]),
|
||||||
{ok, HeaderBin} = file:read(IoDevice, ?XDB_HEADER_SIZE),
|
{ok, HeaderBin} = file:read(IoDevice, ?XDB_HEADER_SIZE),
|
||||||
{ok, Header} = ip2region_xdb:parse_header(HeaderBin),
|
{ok, Header} = ip2region_xdb:parse_header(HeaderBin),
|
||||||
Version = resolve_version(Header),
|
case resolve_version(Header) of
|
||||||
SegmentIndexSize = ip2region_xdb:segment_index_size(Version),
|
{ok, Version} ->
|
||||||
load_vector_index(IoDevice, Version),
|
load_vector_index(IoDevice, Version),
|
||||||
{ok, #state{
|
{ok, #state{xdb_fd = IoDevice, version = Version}};
|
||||||
xdb_fd = IoDevice,
|
{error, Reason} ->
|
||||||
version = Version,
|
file:close(IoDevice),
|
||||||
segment_index_size = SegmentIndexSize
|
{stop, Reason}
|
||||||
}}.
|
end.
|
||||||
|
|
||||||
handle_call(Request, From, State) ->
|
handle_call(Request, From, State) ->
|
||||||
try
|
try
|
||||||
|
|
@ -137,18 +136,18 @@ do_info(Info, State) ->
|
||||||
|
|
||||||
resolve_version(Header) ->
|
resolve_version(Header) ->
|
||||||
case ip2region_xdb:header_version(Header) of
|
case ip2region_xdb:header_version(Header) of
|
||||||
2 -> ipv4;
|
2 -> {ok, ipv4};
|
||||||
3 ->
|
3 ->
|
||||||
case ip2region_xdb:header_ip_version(Header) of
|
case ip2region_xdb:header_ip_version(Header) of
|
||||||
?IP_VERSION_4 -> ipv4;
|
?IP_VERSION_4 -> {ok, ipv4};
|
||||||
?IP_VERSION_6 -> ipv6;
|
?IP_VERSION_6 -> {ok, ipv6};
|
||||||
_ -> ipv4
|
V -> {error, {invalid_xdb_ip_version, V}}
|
||||||
end;
|
end;
|
||||||
_ -> ipv4
|
V -> {error, {invalid_xdb_version, V}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
load_vector_index(IoDevice, Version) ->
|
load_vector_index(IoDevice, Version) ->
|
||||||
Table = vector_index_table(Version),
|
Table = ip2region_xdb:vector_index_table(Version),
|
||||||
case ets:info(Table, size) of
|
case ets:info(Table, size) of
|
||||||
undefined ->
|
undefined ->
|
||||||
Opts = [named_table, set, public, {read_concurrency, true}, {keypos, 1}],
|
Opts = [named_table, set, public, {read_concurrency, true}, {keypos, 1}],
|
||||||
|
|
@ -162,7 +161,7 @@ load_vector_index(IoDevice, Version) ->
|
||||||
|
|
||||||
load_vector_index_data(IoDevice, Table) ->
|
load_vector_index_data(IoDevice, Table) ->
|
||||||
{ok, VectorIndexBin} =
|
{ok, VectorIndexBin} =
|
||||||
file:read(IoDevice, ?XDB_VECTOR_INDEX_COUNT * 8),
|
file:read(IoDevice, ?XDB_VECTOR_INDEX_COUNT * ?XDB_VECTOR_INDEX_SIZE),
|
||||||
load_vector_index_aux(VectorIndexBin, 0, Table).
|
load_vector_index_aux(VectorIndexBin, 0, Table).
|
||||||
|
|
||||||
load_vector_index_aux(<<>>, _Index, _Table) -> ok;
|
load_vector_index_aux(<<>>, _Index, _Table) -> ok;
|
||||||
|
|
@ -170,24 +169,15 @@ load_vector_index_aux(<<SPtr:32/little, EPtr:32/little, VectorIndexBin/binary>>,
|
||||||
ets:insert(Table, {Index, SPtr, EPtr}),
|
ets:insert(Table, {Index, SPtr, EPtr}),
|
||||||
load_vector_index_aux(VectorIndexBin, Index + 1, Table).
|
load_vector_index_aux(VectorIndexBin, Index + 1, Table).
|
||||||
|
|
||||||
search_ip(IoDevice, IpInt, State) when is_integer(IpInt) ->
|
search_ip(IoDevice, Ip, #state{version = Version}) ->
|
||||||
search_ip(IoDevice, <<IpInt:32>>, State);
|
SegSize = ip2region_xdb:segment_index_size(Version),
|
||||||
search_ip(IoDevice, Ip, #state{version = Version, segment_index_size = SegSize}) ->
|
VectorTable = ip2region_xdb:vector_index_table(Version),
|
||||||
CacheTable = cache_table(Version),
|
SegmentTable = ip2region_xdb:segment_index_table(Version),
|
||||||
VectorTable = vector_index_table(Version),
|
<<A:8, B:8, _/binary>> = Ip,
|
||||||
SegmentTable = segment_index_table(Version),
|
VectorIdx = A * ?XDB_VECTOR_COLS + B,
|
||||||
case ets:lookup(CacheTable, Ip) of
|
[{_, SPtr, EPtr}] = ets:lookup(VectorTable, VectorIdx),
|
||||||
[{_, RegionInfo}] ->
|
search_ip(IoDevice, Ip, SPtr, EPtr, 0,
|
||||||
RegionInfo;
|
(EPtr - SPtr) div SegSize, SegSize, Version, SegmentTable).
|
||||||
_ ->
|
|
||||||
<<A:8, B:8, _/binary>> = Ip,
|
|
||||||
VectorIdx = A * ?XDB_VECTOR_COLS + B,
|
|
||||||
[{_, SPtr, EPtr}] = ets:lookup(VectorTable, VectorIdx),
|
|
||||||
RegionInfo = search_ip(IoDevice, Ip, SPtr, EPtr, 0,
|
|
||||||
(EPtr - SPtr) div SegSize, SegSize, Version, SegmentTable),
|
|
||||||
ets:insert_new(CacheTable, {Ip, RegionInfo}),
|
|
||||||
RegionInfo
|
|
||||||
end.
|
|
||||||
|
|
||||||
search_ip(IoDevice, Ip, SPtr, EPtr, Low, High, SegSize, Version, SegmentTable) when Low =< High ->
|
search_ip(IoDevice, Ip, SPtr, EPtr, Low, High, SegSize, Version, SegmentTable) when Low =< High ->
|
||||||
Middle = (Low + High) bsr 1,
|
Middle = (Low + High) bsr 1,
|
||||||
|
|
@ -240,12 +230,3 @@ decode_segment_index(Bin, ?XDB_SEGMENT_INDEX_SIZE_V4) ->
|
||||||
decode_segment_index(Bin, ?XDB_SEGMENT_INDEX_SIZE_V6) ->
|
decode_segment_index(Bin, ?XDB_SEGMENT_INDEX_SIZE_V6) ->
|
||||||
<<SIp:16/binary, EIp:16/binary, DataLen:16/little, DataPtr:32/little>> = Bin,
|
<<SIp:16/binary, EIp:16/binary, DataLen:16/little, DataPtr:32/little>> = Bin,
|
||||||
{SIp, EIp, DataLen, DataPtr}.
|
{SIp, EIp, DataLen, DataPtr}.
|
||||||
|
|
||||||
vector_index_table(ipv4) -> ?XDB_VECTOR_INDEX_V4;
|
|
||||||
vector_index_table(ipv6) -> ?XDB_VECTOR_INDEX_V6.
|
|
||||||
|
|
||||||
segment_index_table(ipv4) -> ?XDB_SEGMENT_INDEX_V4;
|
|
||||||
segment_index_table(ipv6) -> ?XDB_SEGMENT_INDEX_V6.
|
|
||||||
|
|
||||||
cache_table(ipv4) -> ?IP2REGION_CACHE_V4;
|
|
||||||
cache_table(ipv6) -> ?IP2REGION_CACHE_V6.
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
header_start_index_ptr/1, header_end_index_ptr/1,
|
header_start_index_ptr/1, header_end_index_ptr/1,
|
||||||
header_ip_version/1, header_runtime_ptr_bytes/1]).
|
header_ip_version/1, header_runtime_ptr_bytes/1]).
|
||||||
-export([segment_index_size/1]).
|
-export([segment_index_size/1]).
|
||||||
|
-export([vector_index_table/1, segment_index_table/1, cache_table/1]).
|
||||||
|
|
||||||
-include("ip2region.hrl").
|
-include("ip2region.hrl").
|
||||||
|
|
||||||
|
|
@ -55,3 +56,12 @@ header_runtime_ptr_bytes(#xdb_header{runtime_ptr_bytes = B}) -> B.
|
||||||
-spec segment_index_size(ipv4 | ipv6) -> pos_integer().
|
-spec segment_index_size(ipv4 | ipv6) -> pos_integer().
|
||||||
segment_index_size(ipv4) -> ?XDB_SEGMENT_INDEX_SIZE_V4;
|
segment_index_size(ipv4) -> ?XDB_SEGMENT_INDEX_SIZE_V4;
|
||||||
segment_index_size(ipv6) -> ?XDB_SEGMENT_INDEX_SIZE_V6.
|
segment_index_size(ipv6) -> ?XDB_SEGMENT_INDEX_SIZE_V6.
|
||||||
|
|
||||||
|
vector_index_table(ipv4) -> ?XDB_VECTOR_INDEX_V4;
|
||||||
|
vector_index_table(ipv6) -> ?XDB_VECTOR_INDEX_V6.
|
||||||
|
|
||||||
|
segment_index_table(ipv4) -> ?XDB_SEGMENT_INDEX_V4;
|
||||||
|
segment_index_table(ipv6) -> ?XDB_SEGMENT_INDEX_V6.
|
||||||
|
|
||||||
|
cache_table(ipv4) -> ?IP2REGION_CACHE_V4;
|
||||||
|
cache_table(ipv6) -> ?IP2REGION_CACHE_V6.
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
-export([search/1]).
|
-export([search/1]).
|
||||||
|
|
||||||
-spec search(Ip :: tuple() | list() | binary() | integer()) ->
|
-spec search(Ip :: tuple() | list() | binary() | integer()) ->
|
||||||
Result :: list() | {error, Reason::atom()}.
|
Result :: list() | {error, term()}.
|
||||||
search(Ip) ->
|
search(Ip) ->
|
||||||
case ip2region_util:ip_to_bytes(Ip) of
|
case ip2region_util:ip_to_bytes(Ip) of
|
||||||
{ok, ipv4, IpBin} ->
|
{ok, ipv4, IpBin} ->
|
||||||
|
|
@ -25,23 +25,22 @@ search(Ip) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
do_search(PoolName, Version, IpBin) ->
|
do_search(PoolName, Version, IpBin) ->
|
||||||
CacheTable = cache_table(Version),
|
CacheTable = ip2region_xdb:cache_table(Version),
|
||||||
case ets:lookup(CacheTable, IpBin) of
|
case ets:lookup(CacheTable, IpBin) of
|
||||||
[{_, Region}] -> Region;
|
[{_, Region}] -> Region;
|
||||||
_ ->
|
_ ->
|
||||||
Worker = poolboy:checkout(PoolName, true, infinity),
|
Worker = poolboy:checkout(PoolName, true, infinity),
|
||||||
try
|
try
|
||||||
ip2region_worker:search(Worker, IpBin)
|
Region = ip2region_worker:search(Worker, IpBin),
|
||||||
|
ets:insert(CacheTable, {IpBin, Region}),
|
||||||
|
Region
|
||||||
after
|
after
|
||||||
poolboy:checkin(PoolName, Worker)
|
poolboy:checkin(PoolName, Worker)
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
v4_pool() ->
|
v4_pool() ->
|
||||||
case whereis(?IP2REGION_POOL) of
|
case application:get_env(?APP_NAME, v4_pool_name) of
|
||||||
Pid when is_pid(Pid) -> ?IP2REGION_POOL;
|
{ok, PoolName} -> PoolName;
|
||||||
undefined -> ?IP2REGION_POOL_V4
|
undefined -> ?IP2REGION_POOL
|
||||||
end.
|
end.
|
||||||
|
|
||||||
cache_table(ipv4) -> ?IP2REGION_CACHE_V4;
|
|
||||||
cache_table(ipv6) -> ?IP2REGION_CACHE_V6.
|
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ cpu_info() ->
|
||||||
{unix, linux} ->
|
{unix, linux} ->
|
||||||
Model = linux_cpu_field("model name"),
|
Model = linux_cpu_field("model name"),
|
||||||
Clock = format_clock_mhz(linux_cpu_field("cpu MHz")),
|
Clock = format_clock_mhz(linux_cpu_field("cpu MHz")),
|
||||||
Cores = trim(os:cmd("grep -c '^processor' /proc/cpuinfo 2>/dev/null")),
|
Cores = string:trim(os:cmd("grep -c '^processor' /proc/cpuinfo 2>/dev/null")),
|
||||||
Threads = Cores,
|
Threads = Cores,
|
||||||
{Model, Clock, Cores, Threads};
|
{Model, Clock, Cores, Threads};
|
||||||
_ ->
|
_ ->
|
||||||
|
|
@ -54,28 +54,28 @@ cpu_info() ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
sysctl(Key) ->
|
sysctl(Key) ->
|
||||||
trim(os:cmd("sysctl -n " ++ Key ++ " 2>/dev/null")).
|
string:trim(os:cmd("sysctl -n " ++ Key ++ " 2>/dev/null")).
|
||||||
|
|
||||||
linux_cpu_field(Key) ->
|
linux_cpu_field(Key) ->
|
||||||
Cmd = "grep -m1 '^" ++ Key ++ "' /proc/cpuinfo 2>/dev/null | cut -d: -f2- | sed 's/^ *//'",
|
Cmd = "grep -m1 '^" ++ Key ++ "' /proc/cpuinfo 2>/dev/null | cut -d: -f2- | sed 's/^ *//'",
|
||||||
trim(os:cmd(Cmd)).
|
string:trim(os:cmd(Cmd)).
|
||||||
|
|
||||||
first_non_empty(["" | Rest]) -> first_non_empty(Rest);
|
first_non_empty(["" | Rest]) -> first_non_empty(Rest);
|
||||||
first_non_empty([Val | _]) -> Val;
|
first_non_empty([Val | _]) -> Val;
|
||||||
first_non_empty([]) -> "".
|
first_non_empty([]) -> "".
|
||||||
|
|
||||||
format_clock(HzStr) ->
|
format_clock(HzStr) ->
|
||||||
case string:to_integer(trim(HzStr)) of
|
case string:to_integer(string:trim(HzStr)) of
|
||||||
{ok, Hz, _} when Hz > 1000000000 ->
|
{ok, Hz, _} when Hz > 1000000000 ->
|
||||||
lists:flatten(io_lib:format("~.2f GHz", [Hz / 1000000000]));
|
lists:flatten(io_lib:format("~.2f GHz", [Hz / 1000000000]));
|
||||||
{ok, Hz, _} when Hz > 1000000 ->
|
{ok, Hz, _} when Hz > 1000000 ->
|
||||||
lists:flatten(io_lib:format("~.2f GHz", [Hz / 1000000000]));
|
lists:flatten(io_lib:format("~.2f MHz", [Hz / 1000000]));
|
||||||
_ ->
|
_ ->
|
||||||
""
|
""
|
||||||
end.
|
end.
|
||||||
|
|
||||||
format_clock_mhz(MhzStr) ->
|
format_clock_mhz(MhzStr) ->
|
||||||
case string:to_float(trim(MhzStr)) of
|
case string:to_float(string:trim(MhzStr)) of
|
||||||
{ok, Mhz, _} ->
|
{ok, Mhz, _} ->
|
||||||
lists:flatten(io_lib:format("~.3f GHz", [Mhz / 1000]));
|
lists:flatten(io_lib:format("~.3f GHz", [Mhz / 1000]));
|
||||||
_ ->
|
_ ->
|
||||||
|
|
@ -108,8 +108,8 @@ load_test_data(Fd, IpList) ->
|
||||||
run(IpList) ->
|
run(IpList) ->
|
||||||
garbage_collect(),
|
garbage_collect(),
|
||||||
io:format("~nBenchmarks:~n", []),
|
io:format("~nBenchmarks:~n", []),
|
||||||
run_test("file", IpList),
|
run_test("cold", IpList),
|
||||||
run_test("cache", IpList),
|
run_test("warm", IpList),
|
||||||
io:format("~nDone.~n", []).
|
io:format("~nDone.~n", []).
|
||||||
|
|
||||||
run_test(Label, IpList) ->
|
run_test(Label, IpList) ->
|
||||||
|
|
@ -128,5 +128,3 @@ run_test_aux([]) -> ok;
|
||||||
run_test_aux([Ip | Tail]) ->
|
run_test_aux([Ip | Tail]) ->
|
||||||
xdb:search(Ip),
|
xdb:search(Ip),
|
||||||
run_test_aux(Tail).
|
run_test_aux(Tail).
|
||||||
|
|
||||||
trim(Str) -> string:trim(Str).
|
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,11 @@ pools_started_test() ->
|
||||||
application:stop(ip2region),
|
application:stop(ip2region),
|
||||||
application:unload(ip2region),
|
application:unload(ip2region),
|
||||||
ok = application:load(ip2region),
|
ok = application:load(ip2region),
|
||||||
{ok, Cwd} = file:get_cwd(),
|
TestDir = filename:dirname(?FILE),
|
||||||
V6File = filename:join([Cwd, "..", "..", "data", "ip2region_v6.xdb"]),
|
ErlangDir = filename:dirname(TestDir),
|
||||||
|
BindingDir = filename:dirname(ErlangDir),
|
||||||
|
RepoRoot = filename:dirname(BindingDir),
|
||||||
|
V6File = filename:join([RepoRoot, "data", "ip2region_v6.xdb"]),
|
||||||
ok = application:set_env(ip2region, db, [
|
ok = application:set_env(ip2region, db, [
|
||||||
{ipv4, "ip2region.xdb"},
|
{ipv4, "ip2region.xdb"},
|
||||||
{ipv6, V6File}
|
{ipv6, V6File}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,11 @@ invalid_inputs_test_() ->
|
||||||
?_assertEqual({error, bad_ip_format}, ip2region_util:ip_to_bytes("xxx.0.8.0")),
|
?_assertEqual({error, bad_ip_format}, ip2region_util:ip_to_bytes("xxx.0.8.0")),
|
||||||
?_assertEqual({error, bad_ip_format}, ip2region_util:ip_to_bytes("::ggg")),
|
?_assertEqual({error, bad_ip_format}, ip2region_util:ip_to_bytes("::ggg")),
|
||||||
?_assertEqual({error, bad_ip_format}, ip2region_util:ip_to_bytes({1,2,3})),
|
?_assertEqual({error, bad_ip_format}, ip2region_util:ip_to_bytes({1,2,3})),
|
||||||
?_assertEqual({error, bad_ip_format}, ip2region_util:ip_to_bytes(atom))
|
?_assertEqual({error, bad_ip_format}, ip2region_util:ip_to_bytes(atom)),
|
||||||
|
?_assertEqual({error, bad_ip_format}, ip2region_util:ip_to_bytes(-1)),
|
||||||
|
?_assertEqual({error, bad_ip_format}, ip2region_util:ip_to_bytes(16#100000000)),
|
||||||
|
?_assertEqual({error, bad_ip_format}, ip2region_util:ipv4_to_n(-1)),
|
||||||
|
?_assertEqual({error, bad_ip_format}, ip2region_util:ipv4_to_n(16#100000000))
|
||||||
].
|
].
|
||||||
|
|
||||||
legacy_ipv4_to_n_test_() ->
|
legacy_ipv4_to_n_test_() ->
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue