查询返回对象增加took(us)和ioCount
This commit is contained in:
parent
743bbd204b
commit
4fde2363fa
|
|
@ -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 测试
|
||||
|
||||
## 单元测试结果
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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|江苏省|苏州市|电信')
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in New Issue