2025-10-23 14:02:51 +08:00

126 lines
3.4 KiB
Go

package cmd
import (
"fmt"
"log/slog"
"os"
"time"
"github.com/lionsoul2014/ip2region/maker/golang/xdb"
)
func Bench() {
var err error
var dbFile, srcFile, ipVersion, logLevel = "", "", "", ""
var ignoreError = false
var fErr = iterateFlags(func(key string, val string) error {
switch key {
case "db":
dbFile = val
case "src":
srcFile = val
case "version":
ipVersion = val
case "log-level":
logLevel = val
case "ignore-error":
if val == "true" || val == "1" {
ignoreError = true
} else if val == "false" || val == "0" {
ignoreError = false
} else {
return fmt.Errorf("invalid value for ignore-error option, could be false/0 or true/1")
}
default:
return fmt.Errorf("undefined option '%s=%s'", key, val)
}
return nil
})
if fErr != nil {
fmt.Printf("failed to parse flags: %s", fErr)
return
}
if dbFile == "" || srcFile == "" {
fmt.Printf("%s bench [command options]\n", os.Args[0])
fmt.Printf("options:\n")
fmt.Printf(" --db string ip2region binary xdb file path\n")
fmt.Printf(" --src string source ip text file path\n")
fmt.Printf(" --version string IP version, options: ipv4/ipv6, specify this flag so you don't get confused \n")
fmt.Printf(" --log-level string set the log level, options: debug/info/warn/error\n")
fmt.Printf(" --ignore-error bool keep going if bench failed\n")
return
}
// check and define the IP version
var version *xdb.Version = nil
if len(ipVersion) < 2 {
slog.Error("please specify the ip version with flag --version, ipv4 or ipv6 ?")
return
} else if v, err := xdb.VersionFromName(ipVersion); err != nil {
slog.Error("failed to parse version name", "error", err)
return
} else {
version = v
}
// check and apply the log level
err = applyLogLevel(logLevel)
if err != nil {
slog.Error("failed to apply log level", "error", err)
return
}
searcher, err := xdb.NewSearcher(version, dbFile)
if err != nil {
fmt.Printf("failed to create searcher with `%s`: %s\n", dbFile, err)
return
}
defer func() {
searcher.Close()
}()
handle, err := os.OpenFile(srcFile, os.O_RDONLY, 0600)
if err != nil {
fmt.Printf("failed to open source text file: %s\n", err)
return
}
defer handle.Close()
var count, errCount, tStart = 0, 0, time.Now()
slog.Info("Bench start", "xdbPath", dbFile, "srcPath", srcFile)
var iErr = xdb.IterateSegments(handle, nil, nil, func(seg *xdb.Segment) error {
var l = fmt.Sprintf("%d|%d|%s", seg.StartIP, seg.EndIP, seg.Region)
slog.Debug("try to bench", "segment", l)
// mip := xdb.IPMiddle(seg.StartIP, seg.EndIP)
// for _, ip := range [][]byte{seg.StartIP, xdb.IPMiddle(seg.EndIP, mip), mip, xdb.IPMiddle(mip, seg.EndIP), seg.EndIP} {
for _, ip := range [][]byte{seg.StartIP, seg.EndIP} {
slog.Debug("|-try to bench", "ip", xdb.IP2String(ip))
r, _, err := searcher.Search(ip)
if err != nil {
return fmt.Errorf("failed to search ip '%s': %s", xdb.IP2Long(ip), err)
}
// check the region info
count++
if r != seg.Region {
errCount++
slog.Error(" --[Failed] region not match", "src", r, "dst", seg.Region)
if !ignoreError {
return fmt.Errorf("")
}
} else {
slog.Debug(" --[Ok]")
}
}
return nil
})
if iErr != nil {
fmt.Printf("%s", err)
return
}
slog.Info("Bench finished", "count", count, "failed", errCount, "elapsed", time.Since(tStart))
}