feat(erlang): auto-route search by IPv4/IPv6 to correct worker pool

This commit is contained in:
Alice39s 2026-06-28 00:07:22 +09:00
parent c911ca1290
commit 8849cc9130
No known key found for this signature in database
GPG Key ID: 0E0AA11C3939DDDD
2 changed files with 51 additions and 21 deletions

View File

@ -1,11 +1,10 @@
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
%% Copyright 2022 The Ip2Region Authors. All rights reserved. %% Copyright 2022 The Ip2Region Authors. All rights reserved.
%% Use of this source code is governed by a Apache2.0-style %% Use of this source code is governed by a Apache2.0-style
%% license that can be found in the LICENSE file. %% license that can be found in the LICENSE file.
%% %%
%% @doc %% @doc
%% ip2region xdb client search api %% ip2region xdb client search api with IPv4/IPv6 auto-routing.
%% @end %% @end
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(xdb). -module(xdb).
@ -13,20 +12,36 @@
-export([search/1]). -export([search/1]).
-spec search(Ip :: tuple() | list() | binary()) -> Result :: binary | {error, Reason::atom()}. -spec search(Ip :: tuple() | list() | binary() | integer()) ->
search(Ip) when is_integer(Ip); is_list(Ip); is_tuple(Ip); is_binary(Ip) -> Result :: list() | {error, Reason::atom()}.
case ip2region_util:ipv4_to_n(Ip) of search(Ip) ->
IntIp when is_integer(IntIp) -> case ip2region_util:ip_to_bytes(Ip) of
case ets:lookup(?IP2REGION_CACHE, IntIp) of {ok, ipv4, IpBin} ->
[{_IntIp, Region}] -> Region; do_search(v4_pool(), ipv4, IpBin);
_ -> {ok, ipv6, IpBin} ->
Worker = poolboy:checkout(?IP2REGION_POOL, true, infinity), do_search(?IP2REGION_POOL_V6, ipv6, IpBin);
try Ret ->
ip2region_worker:search(Worker, IntIp) Ret
after
poolboy:checkin(?IP2REGION_POOL, Worker)
end
end;
Ret ->
Ret
end. end.
do_search(PoolName, Version, IpBin) ->
CacheTable = cache_table(Version),
case ets:lookup(CacheTable, IpBin) of
[{_, Region}] -> Region;
_ ->
Worker = poolboy:checkout(PoolName, true, infinity),
try
ip2region_worker:search(Worker, IpBin)
after
poolboy:checkin(PoolName, Worker)
end
end.
v4_pool() ->
case whereis(?IP2REGION_POOL) of
Pid when is_pid(Pid) -> ?IP2REGION_POOL;
undefined -> ?IP2REGION_POOL_V4
end.
cache_table(ipv4) -> ?IP2REGION_CACHE_V4;
cache_table(ipv6) -> ?IP2REGION_CACHE_V6.

View File

@ -4,7 +4,7 @@
search_test_() -> search_test_() ->
application:ensure_started(ip2region), application:ensure_started(ip2region),
A = "中国|0|广东省|广州市|电信", A = "中国|广东省|广州市|中国电信|CN",
Region0 = xdb:search("1.0.8.0"), Region0 = xdb:search("1.0.8.0"),
Region1 = xdb:search(<<"1.0.8.0">>), Region1 = xdb:search(<<"1.0.8.0">>),
Region2 = xdb:search({1,0,8,0}), Region2 = xdb:search({1,0,8,0}),
@ -14,5 +14,20 @@ search_test_() ->
?_assert(A =:= Region1), ?_assert(A =:= Region1),
?_assert(A =:= Region2), ?_assert(A =:= Region2),
?_assert({error, bad_ip_format} =:= Region3) ?_assert({error, bad_ip_format} =:= Region3)
].
ipv6_search_test_() ->
application:ensure_started(ip2region),
[
?_assert(is_list(xdb:search("2001:4860:4860::8888"))),
?_assert(is_list(xdb:search(<<"2001:4860:4860::8888">>))),
?_assert(is_list(xdb:search({8193, 10304, 10304, 0, 0, 0, 0, 34952})))
].
invalid_search_test_() ->
application:ensure_started(ip2region),
[
?_assertEqual({error, bad_ip_format}, xdb:search("xxx.0.8.0")),
?_assertEqual({error, bad_ip_format}, xdb:search("::ggg")),
?_assertEqual({error, bad_ip_format}, xdb:search({1,2,3}))
]. ].