add xdb file verify util and call it before the search/bench test

This commit is contained in:
lion 2025-09-16 12:35:22 +08:00
parent 4c1b0362c8
commit 9a14e32736
4 changed files with 90 additions and 7 deletions

View File

@ -2,8 +2,8 @@
# 使用方式
第三方 composer 地址 (请自行确认仓库对 IPv6 的支持):
1. [https://github.com/zoujingli/ip2region](https://github.com/zoujingli/ip2region)
第三方 composer 地址
1. [https://github.com/zoujingli/ip2region](https://github.com/zoujingli/ip2region) - 已提供 IPv6 支持。
2. [https://github.com/chinayin/ip2region-core-php](https://github.com/chinayin/ip2region-core-php)
@ -24,6 +24,23 @@ $version = IPv6::default();
// 备注:以下演示直接使用 $dbFile 和 $version 变量
```
### XDB 文件验证
建议您主动去验证 xdb 文件的适用性,因为后期的一些新功能可能会导致目前的 Searcher 版本无法适用你使用的 xdb 文件,验证可以避免运行过程中的一些不可预测的错误。 你不需要每次都去验证,例如在服务启动的时候,或者手动调用命令验证确认版本匹配即可,不要在每次创建的 Searcher 的时候运行验证,这样会影响查询的响应速度,尤其是高并发的使用场景。
```php
use \ip2region\xdb\Util;
$err = Util::verify($dbFile);
if ($err != null) {
// 适用性验证失败!!!
// 当前查询客户端实现不适用于 dbPath 指定的 xdb 文件的查询.
// 应该停止启动服务,使用合适的 xdb 文件或者升级到适合 dbPath 的 Searcher 实现。
printf("failed to verify xdb file `%s`: %s\n", $dbFile, $err);
return;
}
// 验证通过,当前使用的 Searcher 可以安全的用于对 dbPath 指向的 xdb 的查询操作
```
### 完全基于文件的查询
```php
// require or autoload the xdb\Searcher

View File

@ -70,6 +70,16 @@ if ($handle === false) {
return;
}
// 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 = Util::verify($handle);
if ($err != null) {
printf("failed to verify xdb file `%s`: %s\n", $dbFile, $err);
return;
}
// load header
$header = Util::loadHeader($handle);
if ($header == null) {

View File

@ -66,6 +66,16 @@ if ($handle === false) {
return;
}
// 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 = Util::verify($handle);
if ($err != null) {
printf("failed to verify xdb file `%s`: %s\n", $dbFile, $err);
return;
}
// load header
$header = Util::loadHeader($handle);
if ($header == null) {

View File

@ -126,6 +126,57 @@ class Util {
return ((ord($b[$idx])) | (ord($b[$idx+1]) << 8));
}
// Verify if the current Searcher could be used to search the specified xdb file.
// Why do we need this check ?
// The future features of the xdb impl may cause the current searcher not able to work properly.
//
// @Note: You Just need to check this ONCE when the service starts
// Or use another process (eg, A command) to check once Just to confirm the suitability.
// returns: null for everything is ok or the error string.
public static function verify($handle) {
// load the header
$header = self::loadHeader($handle);
if ($header == null) {
return 'failed to load the header';
}
// get the runtime ptr bytes
$runtimePtrBytes = 0;
if ($header['version'] == Structure_20) {
$runtimePtrBytes = 4;
} else if ($header['version'] == Structure_30) {
$runtimePtrBytes = $header['runtimePtrBytes'];
} else {
return "invalid structure version `{$header['version']}`";
}
// 1, confirm the xdb file size
// to ensure that the maximum file pointer does not overflow
$stat = fstat($handle);
if ($stat == false) {
return 'failed to stat the xdb file';
}
$maxFilePtr = (1 << ($runtimePtrBytes * 8)) - 1;
// print_r([$stat['size'], $maxFilePtr]);
if ($stat['size'] > $maxFilePtr) {
return "xdb file exceeds the maximum supported bytes: {$maxFilePtr}";
}
return null;
}
public static function verifyFromFile($dbFile) {
$handle = fopen($dbFile, 'r');
if ($handle === false) {
return null;
}
$r = self::verify($handle);
fclose($handle);
return $r;
}
// load header info from a specified file handle
public static function loadHeader($handle) {
if (fseek($handle, 0) == -1) {
@ -473,11 +524,6 @@ class Searcher {
throw new Exception("failed to read segment index with ptr={$p}");
}
// printf("l=%d, h=%d, sip=%s, eip=%s\n",
// $l, $h,
// Util::ipToString(strrev(substr($buff, 0, 4))),
// Util::ipToString(strrev(substr($buff, 4, 4)))
// );
if ($this->version->ipSubCompare($ipBytes, $buff, 0) < 0) {
$h = $m - 1;
} else if ($this->version->ipSubCompare($ipBytes, $buff, $bytes) > 0) {