查询返回对象增加took(us)和ioCount

This commit is contained in:
Wu Jian Ping 2022-07-21 22:31:44 +08:00
parent f890285bb6
commit 056fac27c1
4 changed files with 46 additions and 10 deletions

View File

@ -66,6 +66,29 @@ try {
## 查询测试
可以通过 `java -jar ip2region-{version}.jar search` 命令来测试查询:
```shell
➜ java git:(v2.0_xdb) ✗ java -jar target/ip2region-2.6.0.jar search
java -jar ip2region-{version}.jar search [command options]
options:
--db string ip2region binary xdb file path
--cache-policy string cache policy: file/vectorIndex/content
```
例如:使用默认的 data/ip2region.xdb 文件进行查询测试:
```shell
➜ java git:(v2.0_xdb) ✗ java -jar target/ip2region-2.6.0.jar search --db=../../data/ip2region.xdb
ip2region xdb searcher test program, cachePolicy: vectorIndex
type 'quit' to exit
ip2region>> 1.2.3.4
{region: 美国|0|华盛顿|0|谷歌, ioCount: 7, took: 82 μs}
ip2region>>
```
输入 ip 即可进行查询测试,也可以分别设置 `cache-policy` 为 file/vectorIndex/content 来测试三种不同缓存实现的查询效果。
## bench 测试
## 单元测试结果

View File

@ -15,6 +15,7 @@ const IP_REGEX = /((25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))\.){3}(25[0-5]|2[0-4]
const getStartEndPtr = Symbol('#getStartEndPtr')
const getBuffer = Symbol('#getBuffer')
const openFilePromise = Symbol('#openFilePromise')
const NS_PER_SEC = 1e9
class Searcher {
constructor (dbFile, vectorIndex, buffer) {
@ -27,7 +28,7 @@ class Searcher {
}
}
async [getStartEndPtr] (idx, fd) {
async [getStartEndPtr] (idx, fd, ioStatus) {
if (this._vectorIndex) {
// 区域二分索引的开始地址
// idx 开始读取 4 个字节,用小端字节序解码得到一个整数
@ -37,20 +38,21 @@ class Searcher {
const ePtr = this._vectorIndex.readUInt32LE(idx + 4)
return { sPtr, ePtr }
} else {
const buf = await this[getBuffer](256 + idx, 8, fd)
const buf = await this[getBuffer](256 + idx, 8, fd, ioStatus)
const sPtr = buf.readUInt32LE()
const ePtr = buf.readUInt32LE(4)
return { sPtr, ePtr }
}
}
async [getBuffer] (offset, length, fd) {
async [getBuffer] (offset, length, fd, ioStatus) {
if (this._buffer) {
return this._buffer.subarray(offset, offset + length)
} else {
// 从文件中读取
const buf = Buffer.alloc(length)
return new Promise((resolve, reject) => {
ioStatus.ioCount += 1
fs.read(fd, buf, 0, length, offset, (err) => {
if (err) {
reject(err)
@ -76,6 +78,11 @@ class Searcher {
}
async search (ip) {
const startTime = process.hrtime()
const ioStatus = {
ioCount: 0
}
if (!IP_REGEX.test(ip)) {
throw new Error(`IP: ${ip} is invalid`)
}
@ -104,7 +111,7 @@ class Searcher {
const idx = i0 * VectorIndexCols * VectorIndexSize + i1 * VectorIndexSize
// 区域二分索引的开始地址和结束地址
const { sPtr, ePtr } = await this[getStartEndPtr](idx, fd)
const { sPtr, ePtr } = await this[getStartEndPtr](idx, fd, ioStatus)
// 二分搜索低位
let l = 0
@ -126,7 +133,7 @@ class Searcher {
// 从 p 位置开始读取 SegmentIndexSize = 14 个字节到 buff
// 得到一个完整的上述描述的二分索引项,不过为了减少不必要的操作
// 我们是按需要解码,此处 buff 为 p 开始的 14 个 byte 的数据
const buff = await this[getBuffer](p, SegmentIndexSize, fd)
const buff = await this[getBuffer](p, SegmentIndexSize, fd, ioStatus)
// 前面 4 个字节是起始 IP
const sip = buff.readUInt32LE(0)
@ -149,7 +156,7 @@ class Searcher {
const dataLen = buff.readUInt16LE(8)
// 10 ~ 13 的 4 个字节是地域数据的地址
const dataPtr = buff.readUInt32LE(10)
const data = await this[getBuffer](dataPtr, dataLen, fd)
const data = await this[getBuffer](dataPtr, dataLen, fd, ioStatus)
result = data.toString('utf-8')
break
}
@ -163,7 +170,10 @@ class Searcher {
fs.close(fd)
}
return result
const diff = process.hrtime(startTime)
const took = (diff[0] * NS_PER_SEC + diff[1]) / 1e6
return { region: result, ioCount: ioStatus.ioCount, took }
}
}

View File

@ -14,16 +14,19 @@ const searcher3 = Searcher.newWithFileOnly(dbPath)
describe('ip2region', () => {
it('#newWithFileOnly and search', async () => {
const d = await searcher3.search('218.4.167.70')
expect(d).equal('中国|0|江苏省|苏州市|电信')
console.log(d)
expect(d.region).equal('中国|0|江苏省|苏州市|电信')
})
it('#newWithVectorIndex and search', async () => {
const d = await searcher2.search('218.4.167.70')
expect(d).equal('中国|0|江苏省|苏州市|电信')
console.log(d)
expect(d.region).equal('中国|0|江苏省|苏州市|电信')
})
it('#newWithBuffer and search', async () => {
const d = await searcher1.search('218.4.167.70')
expect(d).equal('中国|0|江苏省|苏州市|电信')
expect(d.region).equal('中国|0|江苏省|苏州市|电信')
})
})

View File