From 6531f3970f415ee84728fed72157c3df9a87dbe3 Mon Sep 17 00:00:00 2001 From: lionsoul2014 Date: Sun, 7 Dec 2025 00:38:14 +0800 Subject: [PATCH] search test driven by ip2region service --- binding/golang/ReadMe.md | 51 ++++----- binding/golang/main.go | 237 ++++++++++++++++++++++++++------------- 2 files changed, 187 insertions(+), 101 deletions(-) diff --git a/binding/golang/ReadMe.md b/binding/golang/ReadMe.md index 4222cf6..412bcb0 100644 --- a/binding/golang/ReadMe.md +++ b/binding/golang/ReadMe.md @@ -178,39 +178,40 @@ make # 查询测试 -通过 `xdb_searcher search` 命令来测试 xdb 的查询: +### 查询命令 +通过 `./xdb_searcher search` 命令来测试 xdb 的查询: ```bash -➜ golang git:(fr_xdb_ipv6) ✗ ./xdb_searcher search +➜ golang git:(master) ✗ ./xdb_searcher search --help ./xdb_searcher search [command options] options: - --db string ip2region binary xdb file path - --cache-policy string cache policy: file/vectorIndex/content + --v4-db string ip2region v4 binary xdb file path + --v4-cache-policy string v4 cache policy, default vectorIndex, options: file/vectorIndex/content + --v6-db string ip2region v6 binary xdb file path + --v6-cache-policy string v6 cache policy, default vectorIndex, options: file/vectorIndex/content + --help print this help menu ``` -例如:使用默认的 data/ip2region_v4.xdb 进行 IPv4 的查询测试 +### 参数解析 +1. `v4-xdb`: IPv4 的 xdb 文件路径,默认为仓库中的 data/ip2region_v4.xdb +2. `v6-xdb`: IPv6 的 xdb 文件路径,默认为仓库中的 data/ip2region_v6.xdb +3. `v4-cache-policy`: v4 查询使用的缓存策略,默认为 `vectorIndex`,可选:file/vectorIndex/content +4. `v6-cache-policy`: v6 查询使用的缓存策略,默认为 `vectorIndex`,可选:file/vectorIndex/content + +### 测试 Demo +例如:使用默认的 data/ip2region_v4.xdb 和 data/ip2region_v6.xdb 进行查询测试: ```bash -➜ golang git:(master) ./xdb_searcher search --db=../../data/ip2region_v4.xdb -ip2region xdb searcher test program -source xdb: ../../data/ip2region_v4.xdb (IPv4, vectorIndex) +➜ golang git:(master) ✗ ./xdb_searcher search +ip2region search service test program ++-v4 db: /data01/code/c/ip2region/data/ip2region_v4.xdb (vectorIndex) ++-v6 db: /data01/code/c/ip2region/data/ip2region_v6.xdb (vectorIndex) type 'quit' to exit -ip2region>> 219.133.111.87 -{region: 中国|广东省|深圳市|电信, ioCount: 2, took: 19.005µs} -ip2region>> +ip2region>> 1.2.3.4 +{region: 美国|华盛顿|0|谷歌, took: 69.088µs} +ip2region>> 240e:3b7:3272:d8d0:db09:c067:8d59:539e +{region: 中国|广东省|深圳市|家庭宽带, took: 67.756µs} +ip2region>> ``` - -例如:使用默认的 data/ip2region_v6.xdb 进行 IPv6 的查询: -```bash -➜ golang git:(master) ✗ ./xdb_searcher search --db=../../data/ip2region_v6.xdb -ip2region xdb searcher test program -source xdb: ../../data/ip2region_v6.xdb (IPv6, vectorIndex) -type 'quit' to exit -ip2region>> :: -{region: , ioCount: 1, took: 42.157µs} -ip2region>> 240e:87c:892:ffff:ffff:ffff:ffff:ffff -{region: 中国|北京市|北京市|专线用户, ioCount: 10, took: 88.769µs} -``` - -输入对应版本的 ip 地址进行查询即可,输入 quit 退出测试程序。可以设置 `cache-policy` 为 file/vectorIndex/content 来测试不同的查询缓存机制。 +输入 v4 或者 v6 的 IP 地址即可进行查询测试,也可以分别设置 `cache-policy` 为 file/vectorIndex/content 来测试三种不同缓存实现的查询效果。 # bench 测试 diff --git a/binding/golang/main.go b/binding/golang/main.go index 2bb0288..8d1d200 100644 --- a/binding/golang/main.go +++ b/binding/golang/main.go @@ -13,13 +13,114 @@ import ( "fmt" "log" "os" + "path/filepath" "strings" "time" + "github.com/lionsoul2014/ip2region/binding/golang/service" "github.com/lionsoul2014/ip2region/binding/golang/xdb" "github.com/mitchellh/go-homedir" ) +func getXdbPath(fileName string) (string, error) { + binPath, err := os.Executable() + if err != nil { + return "", fmt.Errorf("failed to get executale: %w", err) + } + + xdbPath := filepath.Join(filepath.Dir(filepath.Dir(filepath.Dir(binPath))), "/data/", fileName) + _, err = os.Stat(xdbPath) + if err != nil { + return "", nil + } + + // fmt.Printf("xdbPath=%s\n", xdbPath) + return xdbPath, nil +} + +func createService(v4XdbPath string, v4CachePolicy string, v6XdbPath string, v6CachePolicy string) (*service.Ip2Region, error) { + // try to create v4 config + v4CPolicy, err := service.CachePolicyFromName(v4CachePolicy) + if err != nil { + return nil, fmt.Errorf("parse v4 cache policy: %w", err) + } + + v4DbPath, err := homedir.Expand(v4XdbPath) + if err != nil { + return nil, fmt.Errorf("Expand(`%s`): %s", v4XdbPath, err) + } + v4Config, err := service.NewV4Config(v4CPolicy, v4DbPath, 1) + if err != nil { + return nil, fmt.Errorf("NewV4Config: %w", err) + } + + // try to create v6 config + v6Policy, err := service.CachePolicyFromName(v6CachePolicy) + if err != nil { + return nil, fmt.Errorf("parse v6 cache policy: %w", err) + } + + v6DbPath, err := homedir.Expand(v6XdbPath) + if err != nil { + return nil, fmt.Errorf("Expand(`%s`): %s", v6XdbPath, err) + } + v6Config, err := service.NewV6Config(v6Policy, v6DbPath, 1) + if err != nil { + return nil, fmt.Errorf("NewV6Config: %w", err) + } + + return service.NewIp2Region(v4Config, v6Config) +} + +func createSearcher(dbPath string, cachePolicy string) (*xdb.Searcher, error) { + handle, err := os.OpenFile(dbPath, os.O_RDONLY, 0600) + if err != nil { + return nil, fmt.Errorf("open xdb file `%s`: %w", dbPath, err) + } + + defer handle.Close() + + // verify the xdb file + // @Note: do NOT call it every time you create a searcher since this will slow down the search response. + // @see the util.Verify function for details. + err = xdb.Verify(handle) + if err != nil { + return nil, fmt.Errorf("xdb verify: %w", err) + } + + // auto-detect the ip version from the xdb header + header, err := xdb.LoadHeader(handle) + if err != nil { + return nil, fmt.Errorf("failed to load header from `%s`: %s", dbPath, err) + } + + version, err := xdb.VersionFromHeader(header) + if err != nil { + return nil, fmt.Errorf("failed to detect IP version from `%s`: %s", dbPath, err) + } + + switch cachePolicy { + case "nil", "file": + return xdb.NewWithFileOnly(version, dbPath) + case "vectorIndex": + vIndex, err := xdb.LoadVectorIndexFromFile(dbPath) + if err != nil { + return nil, fmt.Errorf("failed to load vector index from `%s`: %w", dbPath, err) + } + + return xdb.NewWithVectorIndex(version, dbPath, vIndex) + case "content": + cBuff, err := xdb.LoadContentFromFile(dbPath) + if err != nil { + return nil, fmt.Errorf("failed to load content from '%s': %w", dbPath, err) + } + + return xdb.NewWithBuffer(version, cBuff) + default: + return nil, fmt.Errorf("invalid cache policy `%s`, options: file/vectorIndex/content", cachePolicy) + } +} + func printHelp() { fmt.Printf("ip2region xdb searcher\n") fmt.Printf("%s [command] [command options]\n", os.Args[0]) @@ -30,7 +131,9 @@ func printHelp() { func testSearch() { var err error - var dbFile, cachePolicy = "", "vectorIndex" + var help = "" + var v4DbPath, v4CachePolicy = "", "vectorIndex" + var v6DbPath, v6CachePolicy = "", "vectorIndex" for i := 2; i < len(os.Args); i++ { r := os.Args[i] if len(r) < 5 { @@ -41,52 +144,83 @@ func testSearch() { continue } + var key, val = "", "" var sIdx = strings.Index(r, "=") if sIdx < 0 { - fmt.Printf("missing = for args pair '%s'\n", r) - return + // fmt.Printf("missing = for args pair '%s'\n", r) + // return + key = r[2:] + } else { + key = r[2:sIdx] + val = r[sIdx+1:] } - switch r[2:sIdx] { - case "db": - dbFile = r[sIdx+1:] - case "cache-policy": - cachePolicy = r[sIdx+1:] + switch key { + case "help": + if val == "" { + help = "true" + } else { + help = val + } + case "v4-db": + v4DbPath = val + case "v4-cache-policy": + v4CachePolicy = val + case "v6-db": + v6DbPath = val + case "v6-cache-policy": + v6CachePolicy = val default: fmt.Printf("undefined option `%s`\n", r) return } } - if dbFile == "" { + // check and get the get the default v4 xdb path + if v4DbPath == "" { + v4DbPath, err = getXdbPath("ip2region_v4.xdb") + if err != nil { + fmt.Printf("failed to get v4 xdb path: %s", err) + return + } + } + + // check and get the get the default v6 xdb path + if v6DbPath == "" { + v6DbPath, err = getXdbPath("ip2region_v6.xdb") + if err != nil { + fmt.Printf("failed to get v6 xdb path: %s", err) + return + } + } + + if v4DbPath == "" || v6DbPath == "" || help == "true" { fmt.Printf("%s search [command options]\n", os.Args[0]) fmt.Printf("options:\n") - fmt.Printf(" --db string ip2region binary xdb file path\n") - fmt.Printf(" --cache-policy string cache policy: file/vectorIndex/content\n") + fmt.Printf(" --v4-db string ip2region v4 binary xdb file path\n") + fmt.Printf(" --v4-cache-policy string v4 cache policy, default vectorIndex, options: file/vectorIndex/content\n") + fmt.Printf(" --v6-db string ip2region v6 binary xdb file path\n") + fmt.Printf(" --v6-cache-policy string v6 cache policy, default vectorIndex, options: file/vectorIndex/content\n") + fmt.Printf(" --help print this help menu\n") return } - dbPath, err := homedir.Expand(dbFile) + // create the search service with the xdb paths and cache policies + ip2region, err := createService(v4DbPath, v4CachePolicy, v6DbPath, v6CachePolicy) if err != nil { - fmt.Printf("invalid xdb file path `%s`: %s", dbFile, err) - return - } - - // create the searcher with the cache policy setting - searcher, err := createSearcher(dbPath, cachePolicy) - if err != nil { - fmt.Printf("failed to create searcher: %s\n", err.Error()) + fmt.Printf("failed to create ip2region service: %s\n", err.Error()) return } defer func() { - searcher.Close() + ip2region.Close() fmt.Printf("searcher test program exited, thanks for trying\n") }() - fmt.Printf(`ip2region xdb searcher test program -source xdb: %s (%s, %s) + fmt.Printf(`ip2region search service test program ++-v4 db: %s (%s) ++-v6 db: %s (%s) type 'quit' to exit -`, dbPath, searcher.IPVersion().Name, cachePolicy) +`, v4DbPath, v4CachePolicy, v6DbPath, v6CachePolicy) reader := bufio.NewReader(os.Stdin) for { fmt.Print("ip2region>> ") @@ -105,11 +239,11 @@ type 'quit' to exit } tStart := time.Now() - region, err := searcher.SearchByStr(line) + region, err := ip2region.SearchByStr(line) if err != nil { - fmt.Printf("\x1b[0;31m{err: %s, ioCount: %d}\x1b[0m\n", err.Error(), searcher.GetIOCount()) + fmt.Printf("\x1b[0;31m{err: %s}\x1b[0m\n", err.Error()) } else { - fmt.Printf("\x1b[0;32m{region: %s, ioCount: %d, took: %s}\x1b[0m\n", region, searcher.GetIOCount(), time.Since(tStart)) + fmt.Printf("\x1b[0;32m{region: %s, took: %s}\x1b[0m\n", region, time.Since(tStart)) } } } @@ -230,55 +364,6 @@ func testBench() { cachePolicy, count, cost, costs/count/1000) } -func createSearcher(dbPath string, cachePolicy string) (*xdb.Searcher, error) { - handle, err := os.OpenFile(dbPath, os.O_RDONLY, 0600) - if err != nil { - return nil, fmt.Errorf("open xdb file `%s`: %w", dbPath, err) - } - - defer handle.Close() - - // verify the xdb file - // @Note: do NOT call it every time you create a searcher since this will slow down the search response. - // @see the util.Verify function for details. - err = xdb.Verify(handle) - if err != nil { - return nil, fmt.Errorf("xdb verify: %w", err) - } - - // auto-detect the ip version from the xdb header - header, err := xdb.LoadHeader(handle) - if err != nil { - return nil, fmt.Errorf("failed to load header from `%s`: %s", dbPath, err) - } - - version, err := xdb.VersionFromHeader(header) - if err != nil { - return nil, fmt.Errorf("failed to detect IP version from `%s`: %s", dbPath, err) - } - - switch cachePolicy { - case "nil", "file": - return xdb.NewWithFileOnly(version, dbPath) - case "vectorIndex": - vIndex, err := xdb.LoadVectorIndexFromFile(dbPath) - if err != nil { - return nil, fmt.Errorf("failed to load vector index from `%s`: %w", dbPath, err) - } - - return xdb.NewWithVectorIndex(version, dbPath, vIndex) - case "content": - cBuff, err := xdb.LoadContentFromFile(dbPath) - if err != nil { - return nil, fmt.Errorf("failed to load content from '%s': %w", dbPath, err) - } - - return xdb.NewWithBuffer(version, cBuff) - default: - return nil, fmt.Errorf("invalid cache policy `%s`, options: file/vectorIndex/content", cachePolicy) - } -} - func main() { if len(os.Args) < 2 { printHelp()