Skip to content

Commit

Permalink
add binding maker and editor for C++
Browse files Browse the repository at this point in the history
  • Loading branch information
liuyunbin committed Mar 21, 2024
1 parent c82399f commit 19c2aa8
Show file tree
Hide file tree
Showing 17 changed files with 1,566 additions and 0 deletions.
3 changes: 3 additions & 0 deletions ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ API 介绍,使用文档和测试程序请参考对应 `searcher` 查询客户
| :white_check_mark: | 已完成 | [erlang](binding/erlang) | erlang xdb 查询客户端实现 | [leihua996](https://github.com/leihua996) |
|     | 待开始 | [php_ext](binding/php7_ext) | php c 扩展 xdb 查询客户端实现 | 待确定 |
| :white_check_mark: | 已完成 | [nginx](binding/nginx) | nginx 扩展 xdb 查询客户端实现 | [Wu Jian Ping](https://github.com/wujjpp) |
| :white_check_mark: | 已完成 | [C++](binding/cpp) | C++ xdb 查询客户端实现 | [Yunbin Liu](https://github.com/liuyunbin) |


以下工具链实现由社区开发者通过第三方仓库贡献:
Expand All @@ -63,6 +64,7 @@ API 介绍,使用文档和测试程序请参考如下 `maker` 生成程序下
| :white_check_mark: | 已完成 | [python](maker/python) | python xdb 生成程序实现 | [leolin49](https://github.com/leolin49) |
| :white_check_mark: | 已完成 | [csharp](maker/csharp) | csharp xdb 生成程序实现 | [Alan Lee](https://github.com/malus2077) |
| :white_check_mark: | 已完成 | [rust](maker/rust) | rust xdb 生成程序实现 | [KevinWang](https://github.com/KevinWL) |
| :white_check_mark: | 已完成 | [C++](maker/cpp) | C++ xdb 生成程序实现 | [Yunbin Liu](https://github.com/liuyunbin) |


# `xdb` 数据更新
Expand All @@ -82,6 +84,7 @@ ip2region 旨在于 <b>研究 IP 数据的存储和快速查询的设计和实
|:-------------------|:----| :--- |:-------------------| :--- |
| :white_check_mark: | 已完成 | [golang](maker/golang#xdb-数据编辑) | golang 原始 IP 数据编辑器 | [Lion](https://github.com/lionsoul2014) |
| &nbsp;&nbsp;&nbsp; | 待开始 | [java](maker/java#xdb-数据编辑) | java 原始 IP 数据编辑器 | [Lion](https://github.com/lionsoul2014) |
| :white_check_mark: | 已完成 | [C++](maker/cpp#xdb-数据编辑) | C++ 原始 IP 数据编辑器 | [Yunbin Liu](https://github.com/liuyunbin) |


### 检测自动更新
Expand Down
11 changes: 11 additions & 0 deletions binding/cpp/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

all: xdb_search xdb_bench

xdb_search: xdb_search.cc xdb_search_test.cc
g++ -std=c++11 -O2 $^ -o $@

xdb_bench: xdb_search.cc xdb_bench.cc xdb_bench_test.cc
g++ -std=c++11 -O2 $^ -o $@

clean:
rm -f xdb_search xdb_bench
108 changes: 108 additions & 0 deletions binding/cpp/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# ip2region xdb C++ 查询客户端实现

## 使用方式
### 完全基于文件的查询
```
#include <iostream>
#include "xdb_search.h"
int main(int argc, char* argv[]) {
char file_name[] = "../../data/ip2region.xdb";
char ip[] = "1.2.3.4";
xdb_search_t xdb(file_name);
xdb.init_file();
std::cout << xdb.search(ip) << std::endl;
return 0;
}
```

### 缓存 `vector_index` 索引
```
#include <iostream>
#include "xdb_search.h"
int main(int argc, char* argv[]) {
char file_name[] = "../../data/ip2region.xdb";
char ip[] = "1.2.3.4";
xdb_search_t xdb(file_name);
xdb.init_vector_index();
std::cout << xdb.search(ip) << std::endl;
return 0;
}
```

### 缓存整个 `xdb` 数据
```
#include <iostream>
#include "xdb_search.h"
int main(int argc, char* argv[]) {
char file_name[] = "../../data/ip2region.xdb";
char ip[] = "1.2.3.4";
xdb_search_t xdb(file_name);
xdb.init_content();
std::cout << xdb.search(ip) << std::endl;
return 0;
}
```

## 测试程序编译
1. 切换到当前目录
2. 编译

```
$ make
g++ -std=c++11 -O2 xdb_search.cc xdb_search_test.cc -o xdb_search
g++ -std=c++11 -O2 xdb_search.cc xdb_bench.cc xdb_bench_test.cc -o xdb_bench
```

## 测试查询
### 说明
```
$ ./xdb_search --help
./xdb_search [command options]
options:
--db string ip2region binary xdb file path
--cache-policy string cache policy: file/vector_index/content
--help print help
```

### 测试
```
$ ./xdb_search --db ../../data/ip2region.xdb --cache-policy vector_index
cache policy : vector_index
ip2region>> 1.2.3.4
美国|0|华盛顿|0|谷歌
```

## bench 测试
### 说明
```
$ ./xdb_bench --help
./xdb_bench [command options]
options:
--db string ip2region binary xdb file path
--src string source ip text file path
--cache-policy string cache policy: file/vector_index/content
--help print help
```

### 测试
```
$ ./xdb_bench --db ../../data/ip2region.xdb --src ../../data/ip.merge.txt --cache-policy content
total: 3419220, took: 3.44 s, cost: 0.27 μs/op, io count: 0
$ ./xdb_bench --db ../../data/ip2region.xdb --src ../../data/ip.merge.txt --cache-policy vector_index
total: 3419220, took: 45.99 s, cost: 12.24 μs/op, io count: 21739300
$ ./xdb_bench --db ../../data/ip2region.xdb --src ../../data/ip.merge.txt --cache-policy file
total: 3419220, took: 60.39 s, cost: 16.32 μs/op, io count: 25158520
```

135 changes: 135 additions & 0 deletions binding/cpp/xdb_bench.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@

#include "xdb_bench.h"

#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>

#include <iostream>
#include <vector>

static void log_exit(const std::string &msg) {
std::cout << msg << std::endl;
exit(-1);
}

static unsigned long long get_time() {
struct timeval tv1;
gettimeofday(&tv1, NULL);
return (unsigned long long)tv1.tv_sec * 1000 * 1000 + tv1.tv_usec;
}

static bool ip2uint(const char *buf, unsigned int &ip) {
struct in_addr addr;
if (inet_pton(AF_INET, buf, &addr) == 0)
return false;
// 网络字节序为大端存储, 在此转换为小端存储
ip = (((addr.s_addr >> 0) & 0xFF) << 24) |
(((addr.s_addr >> 8) & 0xFF) << 16) |
(((addr.s_addr >> 16) & 0xFF) << 8) |
(((addr.s_addr >> 24) & 0xFF) << 0);
return true;
}

static std::string uint2ip(unsigned int ip) {
char buf[16];
snprintf(buf,
sizeof(buf),
"%d.%d.%d.%d",
(ip >> 24) & 0xFF,
(ip >> 16) & 0xFF,
(ip >> 8) & 0xFF,
ip & 0xFF);
return std::string(buf);
}

xdb_bench_t::xdb_bench_t(const std::string &file_name) : xdb_search(file_name) {
}

void xdb_bench_t::init_file() {
xdb_search.init_file();
}

void xdb_bench_t::init_vector_index() {
xdb_search.init_vector_index();
}

void xdb_bench_t::init_content() {
xdb_search.init_content();
}

void xdb_bench_t::bench_test_one(unsigned int ip_uint, const char *region) {
if (xdb_search.search(uint2ip(ip_uint)) != region)
log_exit("failed: " + uint2ip(ip_uint));
sum_io_count += xdb_search.get_io_count();
sum_cost_time += xdb_search.get_cost_time();
sum_count++;
}

void xdb_bench_t::bench_test_line(char *buf) {
size_t buf_len = strlen(buf);
if (buf_len == 0)
return;
buf[buf_len - 1] = '\0'; // 去掉换行符

char *pos1 = strchr(buf, '|');

if (pos1 == NULL)
log_exit("invalid data: " + std::string(buf));
char *pos2 = strchr(pos1 + 1, '|');
if (pos2 == NULL)
log_exit("invalid data: " + std::string(buf));
*pos1 = '\0';
*pos2 = '\0';

unsigned int ip1, ip2;
if (!ip2uint(buf, ip1) || !ip2uint(pos1 + 1, ip2) || ip1 > ip2) {
*pos1 = *pos2 = '|';
log_exit(std::string("invalid data: ") + buf);
}

const char *region = pos2 + 1;

unsigned int ip_mid = ip1 + (ip2 - ip1) / 2;
std::vector<unsigned int> ip_vec;
ip_vec.push_back(ip1);
ip_vec.push_back(ip1 + (ip_mid - ip1) / 2);
ip_vec.push_back(ip_mid);
ip_vec.push_back(ip_mid + (ip2 - ip_mid) / 2);
ip_vec.push_back(ip2);

for (auto &d : ip_vec)
bench_test_one(d, region);
}

void xdb_bench_t::bench_test_file(const std::string &file_name) {
FILE *f = fopen(file_name.data(), "r");
if (f == NULL)
log_exit("can't open " + file_name);
char buf[1024];
while (fgets(buf, sizeof(buf), f) != NULL)
bench_test_line(buf);
}

void xdb_bench_t::bench(const std::string &file_name) {
sum_io_count = 0;
sum_cost_time = 0;
sum_count = 0;

unsigned long long tv1 = get_time();
bench_test_file(file_name);
unsigned long long tv2 = get_time();

double took = (tv2 - tv1) * 1.0 / 1000 / 1000;
double cost = sum_cost_time * 1.0 / sum_count;

printf(
"total: %llu, took: %.2f s, cost: %.2f μs/op, io "
"count: "
"%llu\n",
sum_count,
took,
cost,
sum_io_count);
}
28 changes: 28 additions & 0 deletions binding/cpp/xdb_bench.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#ifndef XDB_BENCH_H
#define XDB_BENCH_H

#include "xdb_search.h"

class xdb_bench_t {
public:
xdb_bench_t(const std::string &file_name);

void init_file();
void init_vector_index();
void init_content();

void bench(const std::string &file_name);

private:
void bench_test_one(unsigned int ip_uint, const char *region);
void bench_test_line(char *buf);
void bench_test_file(const std::string &file_name);

xdb_search_t xdb_search;

unsigned long long sum_io_count;
unsigned long long sum_cost_time;
unsigned long long sum_count;
};

#endif
70 changes: 70 additions & 0 deletions binding/cpp/xdb_bench_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@

#include "xdb_bench.h"

#include <getopt.h>

#include <iostream>

void print_help(int argc, char* argv[]) {
printf("./xdb_bench [command options]\n");
printf("options:\n");
printf(" --db string ip2region binary xdb file path\n");
printf(" --src string source ip text file path\n");
printf(
" --cache-policy string cache policy: "
"file/vector_index/content\n");
printf(" --help print help\n");
exit(-1);
}

int main(int argc, char* argv[]) {
struct option long_options[] = {
{"db", required_argument, 0, 'd'},
{"cache-policy", required_argument, 0, 't'},
{"src", required_argument, 0, 's'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0 }
};

std::string db_file_name = "../../data/ip2region.xdb";
std::string src_file_name = "../../data/ip.merge.txt";
std::string cache_policy = "vector_index";

while (1) {
int c = getopt_long(argc, argv, "", long_options, NULL);
if (c == -1)
break;
switch (c) {
case 'd':
db_file_name = optarg;
break;
case 'h':
print_help(argc, argv);
break;
case 't':
cache_policy = optarg;
break;
case 's':
src_file_name = optarg;
break;
case '?':
exit(-1);
}
}

xdb_bench_t xdb(db_file_name);

if (cache_policy == "content")
xdb.init_content();
else if (cache_policy == "vector_index")
xdb.init_vector_index();
else if (cache_policy == "file")
xdb.init_file();
else {
std::cout << "invalid cache policy: " << cache_policy << std::endl;
exit(-1);
}

xdb.bench(src_file_name);
return 0;
}
Loading

0 comments on commit 19c2aa8

Please sign in to comment.