ip 地址库, 现在手机/web/app 的基础部件.
LBS 应用的基础.
在网络上找到了一个简单的私有协议的ip地址库部件.
对ip地址的定位, 基本在 0.0x 毫秒 的效率.
根据 项目介绍以及对应的代码 做了一个分析.
项目地址:
里面有提到对应的文件协议的定义.
然后就根据这个协议直接读取了这个文件的二进制文件. 然后绕过了. 软件支持, 直接把数据读出来了.
* db struct:
* 1. header part
* 1): super part:
* +------------+-----------+
* | 4 bytes
| 4 bytes |
* +------------+-----------+
* start index ptr, end index ptr
*
* 2): b-tree index part
* +------------+-----------+-----------+-----------+
* | 4bytes | 4bytes
| 4bytes
| 4bytes
| ...
* +------------+-----------+-----------+-----------+
* start ip ptr index ptr
*
* 2. data part:
* +------------+-----------------------+
* | 2bytes
| dynamic length
|
* +------------+-----------------------+
* data length city_id|Country|Province|Area|City|ISP
*
* 3. index part: (ip range)
* +------------+-----------+---------------+
* | 4bytes
| 4bytes
| 4bytes
|
* +------------+-----------+---------------+
* start ip
end ip
3 byte data ptr & 1 byte data length
结构就比较简单.
跟pg / oracle 的数据块协议有相似之处.
文件开头, 定义了一个了一个超级块 ( supper block ) 两个 4 字节的 字段.
8个字节, 存储了 索引快 ( index block) 开始地址, 跟结束地址.
为了支持btree 索引, 对index block 又构建另一个二级索引. head -- index- block.
对 索引块,(index block) 按照 4K 分区, 抽取了ip地址的最小值 ,以及对应的 位置指针.
具体的ip地址索引, 索引块 ( index block) 12字节
start ip : 4 bytes ;
end ip : 4 bytes ;
dataptr : 4 bytes : {
datalenth 1 byte ,
dataptr : 3 bytes
}
dataptr 存储了对应IP地址段 的地区名称, 以及 对应的 文本的存储长度.
对二进制文件的直接读取, 到这里, 就基本可以开工了.
根据 supper block 的 定位到 start- index- block 以及last-index-block
然后构建一个循环.
然后直接按照格式读出来, 生成文本数据就可以了.
i ( , (blkcnt) + ) :
file.seek(sidx + i * idxblklen )
row = file.read(idxblklen )
sip,eip,ptr,datlen = getrow(row)
fip, lip,cityid,city = getdata(file,sip,eip,ptr,datlen )
(%(L2ip(sip),L2ip(lip),city))
经过抽取, 发现 实际文件存储, 与java 版本的maker 的对吧.
文件里多了2笔记录. 即 超级块的位置定义上应该还是有一个bug.
实际上最后多出来的两个 index-block 的内容是错误的. 是不能合在一个ip段里面的.
代码部分提供的3种 搜索方法.
memory search / binary search /btree - search 基本还是基于二分法的查找.
还有一个问题. 这个maker 代码目前没有实现 merge 功能, 每次都是只能重建db 文件.
如果要实现merge 功能, 即 增量数据的入库.
需要考虑 . 索引分裂, 以及 head-index block 的重写. 以及位置移动.
由此引发的一点小思考.