# xdb-parse
高性能、零拷贝的 xdb IP 地理位置数据库查询库(兼容 ip2region 格式)。基于优化的两级二分查找算法,同时支持 IPv4 和 IPv6。
[English](README.md)
## 特性
- **双协议支持**:完整的 IPv4 和 IPv6 查询
- **极速查询**:IPv4 `search_ip(u32)` 约 258ns,`search_ip(&str)` 约 527ns(全量 segment IP 池)
- **零拷贝**:返回 `&str` 直接从已加载数据借用,每次查询无堆分配
- **原始整数 API**:`search_by_uint` / `search_by_u128` 完全跳过字符串解析
- **线程安全**:`Send + Sync`,加载一次即可通过 `Arc` 在多线程中共享
## 安装
```toml
[dependencies]
xdb-parse = "0.2.0"
```
## 快速上手
```rust
use xdb_parse::{load_file, search_ip};
fn main() -> anyhow::Result<()> {
let data = load_file("./assets/ip2region_v4.xdb".into())?;
let location = search_ip("73.24.63.66", &data)?;
println!("{}", location);
Ok(())
}
```
## API 参考
### 加载
```rust
pub fn load_file(path: PathBuf) -> Result<Vec<u8>, XdbError>
```
预分配精确文件大小的缓冲区,避免读取时多次重分配。
### 查询
```rust
// 通过 IP 字符串查询(支持点分十进制、冒号十六进制、数字字符串)
pub fn search_ip(ip: &str, data: &[u8]) -> Result<&str, XdbError>
// 通过原始 u32 查询(IPv4)— 最快路径
pub fn search_by_uint(ip: u32, data: &[u8]) -> Result<&str, XdbError>
// 通过原始 u128 查询(IPv6)— 最快路径
pub fn search_by_u128(ip: u128, data: &[u8]) -> Result<&str, XdbError>
// 通过 std::net::IpAddr 查询
pub fn search_by_ipaddr(ip: IpAddr, data: &[u8]) -> Result<&str, XdbError>
```
所有查询函数返回 `&str` 借用已加载数据 — 每次查询零堆分配。
### 支持的 IP 格式
```rust
search_ip("192.168.1.1", &data)?; // 标准 IPv4
search_ip("2001:0db8:85a3::0370:7334", &data)?; // 标准 IPv6
search_ip("3232235777", &data)?; // 数字格式 IPv4
search_ip("42540766411282592856903984951653826560", &data)?; // 数字格式 IPv6
```
### Header 与版本检测
```rust
use xdb_parse::{Header, IpVersion, detect_version};
let data = load_file("./assets/ip2region_v4.xdb".into())?;
let version = detect_version(&data)?;
assert_eq!(version, IpVersion::V4);
let header = Header::parse(&data)?;
println!("xdb 版本: {}, 生成时间戳: {}", header.version, header.generation_time);
```
## 多线程使用
```rust
use std::sync::Arc;
use xdb_parse::{load_file, search_ip};
let data = Arc::new(load_file("./assets/ip2region_v6.xdb".into())?);
let data_clone = Arc::clone(&data);
println!("{}", result);
}).join().unwrap();
```
## 性能
使用全量 segment IP 池测量(52 万 IPv4 / 70 万 IPv6),criterion release 模式:
| IPv4 `search_by_uint` | ~272 ns |
| IPv4 `search_ip(u32)` | ~258 ns |
| IPv4 `search_ip(&str)` | ~527 ns |
| IPv6 `search_ip(&str)` | ~476 ns |
运行基准测试:
```bash
cargo bench
```
## 数据库文件格式
```
┌─────────────────┐
│ Header │ 256 字节
├─────────────────┤
│ Vector Index │ 256×256×8 字节
├─────────────────┤
│ Segment Data │ 可变长度
└─────────────────┘
```
IPv4 segment:14 字节(`u32` 起始, `u32` 结束, `u16` 数据长度, `u32` 数据指针)。
IPv6 segment:38 字节(`u128` 起始, `u128` 结束, `u16` 数据长度, `u32` 数据指针)。
## 算法
1. 解析 IP 字符串为 `IpAddr`(支持 `"192.168.1.1"`、`"::1"`、数字 `"3232235777"` 等格式)
2. 取 IP 的前两个字节作为 row(`il0`)和 col(`il1`),在 256×256 向量索引中查找
3. 向量索引条目给出 segment 数据中的 `[start_ptr, end_ptr)` 范围
4. 在该范围内对 segment 进行二分查找(segment 按 IP 起始地址排序)
5. 返回匹配 segment 对应的地理位置字符串
## License
MIT OR Apache-2.0