#include "lib_acl.h" #ifndef WIN32 #include #include #endif #include "db/zdb.h" #include "zdb_test.h" #include "md5.h" #pragma pack(4) typedef struct { int n; char s[4]; } DUMMY; #pragma pack(8) #ifndef STORE_PATH #define STORE_PATH(s) ACL_FHANDLE_PATH(&(s)->fhandle) #endif struct RANGE { int from; int to; }; #ifdef WIN32 #define snprintf _snprintf #endif /****************************************************************************/ #ifdef WIN32 static const char *var_md5_key = "hello world!"; #endif static const char *var_str = "hi!"; /* 模拟取得一个随机的整形数组 */ #ifndef WIN32 static int *random_get(int max, int mod) { int *a = (int*) acl_mymalloc(sizeof(int) * max); int n = 1; if (mod > 1) { max /= mod; mod--; } else mod = 0; for (int i = 0; i < max; i++) a[i] = i + mod; printf("shuffle: %d\n", n++); std::random_shuffle(a, a + max); printf("shuffle: %d\n", n++); std::random_shuffle(a, a + max); printf("shuffle: %d\n", n++); std::random_shuffle(a, a + max); printf("shuffle: %d\n", n++); std::random_shuffle(a, a + max); return (a); } #else static int *random_get(int max, int mod) { int i, j, k, *a, key, off = 0; char buf[64], key_buf[16]; int m = 0; /* 先分配一个大数组 */ a = (int*) acl_mymalloc(sizeof(int) * max); /* 初始化该大数组 */ memset(a, -1, sizeof(int) * max); printf("begin: max: %d\n", max); for (i = 0; i < max; i++) { snprintf(buf, sizeof(buf), "key: %d", i); /* 先 mda5 */ MD5Key(buf, strlen(buf), var_md5_key, strlen(var_md5_key), key_buf, sizeof(key_buf)); /* 再取模 */ key = acl_hash_crc32(key_buf, sizeof(key_buf)) % max; if (a[key] == -1) { a[key] = i; continue; } acl_assert(a[key] != i); // printf("key: %d, %d\n", i, a[key]); m++; /* 说明该 key 的数组下标已经被占用,需要顺序找一个位置即可 */ for (j = off; j < max; j++) { if (a[j] == -1) { a[j] = i; for (k = j + 1; k < max; k++) { if (a[k] == -1) { off = k; break; } } break; } } acl_assert(j != max); } printf("end, m: %d\n", m); return (a); } #endif static void random_free(int *a) { acl_myfree(a); } /* 随机批量写 */ static int bench_random_add(ZDB *db, int max, int mod) { DUMMY dummy; int i, ret, *a; time_t begin; ACL_SAFE_STRNCPY(dummy.s, var_str, sizeof(dummy.s)); a = random_get(max, mod); if (mod > 1) max /= mod; time(&begin); printf("---range_random_add: >> max: %d, ", max); ACL_METER_TIME(" "); for (i = 0; i < max; i++) { dummy.n = i; ret = zdb_update(db, a[i], NULL, &dummy, sizeof(dummy)); if (ret < 0) { printf("zdb_udpate error, i: %d, key: %d\n", i, a[i]); random_free(a); return (-1); } if (i > 0 && i % 100000 == 0) { printf("---%s: >> current: i: %d, key: %d, ", __FUNCTION__, i, a[i]); ACL_METER_TIME(" "); } } printf("---range_add: >> end: current: %d, max: %d, ", i, max); ACL_METER_TIME(" "); printf("================= update ok, time: %ld ===============\n", (long) (time(NULL) - begin)); random_free(a); return (max); } /* 随机批量读 */ static int bench_random_get(ZDB *db, int max, int mod) { DUMMY *dummy; int i, *a; size_t size; ZDB_BLK *blk; ZDB_BLK_OFF blk_off; time_t begin; char buf[64]; a = random_get(max, mod); if (mod > 1) max /= mod; time(&begin); printf("---range_random_get: >> begin: max: %d, ", max); ACL_METER_TIME(" "); for (i = 0; i < max; i++) { snprintf(buf, sizeof(buf), "key: %d", i); blk = zdb_lookup(db, a[i], &size, &blk_off); if (blk == NULL) { printf("zdb_lookup error, i: %d\n", i); random_free(a); return (-1); } dummy = (DUMMY*) zdb_blk_data(blk); if (i > 0 && i % 100000 == 0) { printf("---%s: >> current: i: %d, n: %d," " key: %d, blk_off: %lld, ", __FUNCTION__, i, dummy->n, a[i], blk_off.offset); ACL_METER_TIME(" "); } zdb_blk_free(blk); } printf("---range_get: >> end: current: %d, max: %d, ", i, max); ACL_METER_TIME(" "); printf("================= lookup ok, time: %ld ===============\n", (long) (time(NULL) - begin)); random_free(a); return (max); } /****************************************************************************/ /* 顺序批量写 */ static int bench_add(ZDB *db, int max) { time_t begin; int i, ret, delta = 100000; DUMMY dummy; if (max <= 100) delta = 0; time(&begin); ACL_SAFE_STRNCPY(dummy.s, var_str, sizeof(dummy.s)); ACL_METER_TIME("----begin---"); for (i = 0; i < max; i++) { dummy.n = i; ret = zdb_update(db, i, NULL, &dummy, sizeof(dummy)); if (ret < 0) { printf("zdb_udpate error, i: %d\n", i); return (-1); } if (delta > 0 && i % delta == 0) { printf("---%s: i: %d, ", __FUNCTION__, i); ACL_METER_TIME("-----"); } else if (delta == 0) printf("---%s: i: %d\n", __FUNCTION__, i); } printf("---%s: max: %d, ", __FUNCTION__, max); ACL_METER_TIME("----end---"); printf("================= add ok, time: %ld ===============\n", (long) (time(NULL) - begin)); return (max); } /* 顺序批量修改 */ static int bench_update(ZDB *db, int max, int num) { time_t begin; int i, ret, j, delta = 100000; DUMMY *dummy; if (max <= 100) delta = 0; time(&begin); dummy = (DUMMY*) acl_mycalloc(num, sizeof(DUMMY)); for (i = 0; i < num; i++) { snprintf(dummy[i].s, sizeof(dummy[i].s), "%d", i); } ACL_METER_TIME("----begin---"); for (i = 0; i < max; i++) { for (j = 0; j < num; j++) dummy[j].n = 0; ret = zdb_update(db, i, NULL, dummy, num * sizeof(DUMMY)); if (ret < 0) { printf("zdb_udpate error, i: %d\n", i); return (-1); } if (delta > 0 && i % delta == 0) { printf("---%s: i: %d, ", __FUNCTION__, i); ACL_METER_TIME("-----"); } else if (delta == 0) printf("---%s: i: %d\n", __FUNCTION__, i); } printf("---%s: max: %d, ", __FUNCTION__, max); ACL_METER_TIME("----end---"); printf("================= update ok, time: %ld ===============\n", (long) (time(NULL) - begin)); acl_myfree(dummy); return (max); } /* 顺序批量读 */ static int bench_get(ZDB *db, int max) { ZDB_BLK *blk; DUMMY *dummy; time_t begin; size_t size; int i, delta = 100000; ZDB_BLK_OFF blk_off; if (max <= 100) delta = 0; printf(">> max: %d, delta: %d\n", max, delta); time(&begin); ACL_METER_TIME("----begin---"); //for (i = 0; i < max; i++) { for (i = max - 1; i >= 0; i--) { blk = zdb_lookup(db, i, &size, &blk_off); if (blk == NULL) { printf("zdb_lookup error, i: %d\n", i); return (-1); } dummy = (DUMMY*) zdb_blk_data(blk); if (delta == 0) printf("---%s: i: %d, n: %d, %s, size: %d," " blk_off: %lld, \n", __FUNCTION__, i, dummy[0].n, dummy[0].s, (int) size, blk_off.offset); else if (delta > 0 && i % delta == 0) { printf("---%s: i: %d, n: %d, %s, size: %d," " blk_off: %lld, ", __FUNCTION__, i, dummy[0].n, dummy[0].s, (int) size, blk_off.offset); ACL_METER_TIME(""); } zdb_blk_free(blk); } printf("---%s: max: %d, ", __FUNCTION__, max); ACL_METER_TIME("----end---"); printf("================= lookup ok, time: %ld ===============\n", (long) (time(NULL) - begin)); return (max); } /****************************************************************************/ static int zdb_test1(ZDB *db) { DUMMY dummy[2], *pdummy; ZDB_BLK *blk; size_t size; zdb_key_t key = 10000; int ret, i; dummy[0].n = (int) key; ACL_SAFE_STRNCPY(dummy[0].s, var_str, sizeof(dummy[0].s)); dummy[1].n = (int) key + 1; ACL_SAFE_STRNCPY(dummy[1].s, var_str, sizeof(dummy[1].s)); printf(">>> first update, key: %lld, ", key); ret = zdb_update(db, key, NULL, &dummy, sizeof(dummy) / 2); printf("zdb_update: return %d\n\n", ret); printf(">>> second update, key: %lld, ", key); ret = zdb_update(db, key, NULL, &dummy, sizeof(dummy) / 2); blk = zdb_lookup(db, key, &size, NULL); if (blk) { printf("zdb_lookup: key(%lld), size: %u\n", key, (unsigned) size); pdummy = (DUMMY*) zdb_blk_data(blk); for (i = 0; i < (int) (size / sizeof(DUMMY)); i++) { printf("zdb_lookup: n: %d, s: %s\n", pdummy->n, pdummy->s); pdummy++; } zdb_blk_free(blk); } else printf("zdb_lookup: key(%lld), return null\n", key); printf(">>> third update, key: %lld\n", key); ret = zdb_update(db, key, NULL, &dummy, sizeof(dummy) / 2); return (ret); } static int zdb_test2(ZDB *db) { DUMMY dummy1[1], dummy2[2], dummy3[3], *pdummy; ZDB_BLK *blk; int key = 100, ret; size_t size, i; dummy1[0].n = key; ACL_SAFE_STRNCPY(dummy1[0].s, "1: hello world!", sizeof(dummy1[0].s)); dummy2[0].n = key; ACL_SAFE_STRNCPY(dummy2[0].s, "2: hello world!", sizeof(dummy2[0].s)); dummy2[1].n = key; ACL_SAFE_STRNCPY(dummy2[1].s, "2: hello world!", sizeof(dummy2[1].s)); dummy3[0].n = key; ACL_SAFE_STRNCPY(dummy3[0].s, "3: hello world!", sizeof(dummy3[0].s)); dummy3[1].n = key; ACL_SAFE_STRNCPY(dummy3[1].s, "3: hello world!", sizeof(dummy3[1].s)); dummy3[2].n = key; ACL_SAFE_STRNCPY(dummy3[2].s, "3: hello world!", sizeof(dummy3[2].s)); ret = zdb_update(db, key, NULL, &dummy1, sizeof(dummy1)); if (ret < 0) { printf("zdb_update: set dummy1 error\n"); return (-1); } blk = zdb_lookup(db, key, &size, NULL); if (blk == NULL) { printf("zdb_lookup: get dummy1 error\n"); return (-1); } pdummy = (DUMMY*) zdb_blk_data(blk); for (i = 0; i < sizeof(dummy1) / sizeof(DUMMY); i++) { printf("dummy1: key: %d, n: %d, s: %s\n", key, pdummy->n, pdummy->s); pdummy++; } zdb_blk_free(blk); ret = zdb_update(db, key, NULL, &dummy2, sizeof(dummy2)); if (ret < 0) { printf("zdb_update: set dummy2 error\n"); return (-1); } blk = zdb_lookup(db, key, &size, NULL); if (blk == NULL) { printf("zdb_lookup: get dummy2 error\n"); return (-1); } pdummy = (DUMMY*) zdb_blk_data(blk); for (i = 0; i < sizeof(dummy2) / sizeof(DUMMY); i++) { printf("dummy2: key: %d, n: %d, s: %s\n", key, pdummy->n, pdummy->s); pdummy++; } zdb_blk_free(blk); ret = zdb_update(db, key, NULL, &dummy3, sizeof(dummy3)); if (ret < 0) { printf("zdb_update: set dummy3 error\n"); return (-1); } blk = zdb_lookup(db, key, &size, NULL); if (blk == NULL) { printf("zdb_lookup: get dummy3 error\n"); return (-1); } pdummy = (DUMMY*) zdb_blk_data(blk); for (i = 0; i < sizeof(dummy3) / sizeof(DUMMY); i++) { printf("dummy3: key: %d, n: %d, s: %s\n", key, pdummy->n, pdummy->s); pdummy++; } zdb_blk_free(blk); return (3); } static int key_walk_fn(ZDB_KEY_STORE *store) { const char *myname = "key_walk_fn"; ACL_ITER iter; ZDB_BLK_OFF *blk_off; int i = 0; printf(">>> acl_foreach for %s now:\n", STORE_PATH((ZDB_STORE*) store)); acl_foreach(iter, (ZDB_STORE*) store) { blk_off = (ZDB_BLK_OFF*) iter.data; if (i > 0 && (i % 100000) == 0) { printf("%s: i:%d, key: %d, blk_off: %lld, inode: %d, ", myname, i, iter.i, blk_off->offset, blk_off->inode); ACL_METER_TIME("-"); } i++; } return (i); } static int test_zdb_key_walk(ZDB *db) { const char *myname = "test_zdb_key_walk"; int ret; time_t begin; time(&begin); ret = zdb_key_walk(db, key_walk_fn); printf(">>>%s, acl_foreach for key, total: %d, time: %ld\n", myname, ret, (long) (time(NULL) - begin)); return (0); } static int dat_walk_fn(ZDB_DAT_STORE *store) { const char *myname = "dat_walk_fn"; int i = 0; ZDB_BLK *blk; DUMMY *dummy; ACL_ITER iter; printf(">>>%s, acl_foreach for %s now:\n", myname, STORE_PATH((ZDB_STORE*) store)); acl_foreach(iter, (ZDB_STORE*) store) { blk = (ZDB_BLK*) iter.data; dummy = (DUMMY*) zdb_blk_data(blk); if (i > 0 && (i % 100000) == 0) { printf("%s: i:%d,key:%lld,data:%s,inext:%d,", myname, i, blk->hdr.key, dummy->s, iter.i); ACL_METER_TIME("-"); } else if (store->hdr.count <= 100) { printf("%s: i:%d, key:%lld, data:%s, inext:%d\n", myname, i, blk->hdr.key, dummy->s, iter.i); } i++; } return (i); } static int test_zdb_dat_walk(ZDB *db) { const char *myname = "test_zdb_dat_walk"; time_t begin; int ret; time(&begin); ret = zdb_dat_walk(db, dat_walk_fn); printf(">>>%s, acl_foreach for dat, total: %d, time: %ld\n", myname, ret, (long) (time(NULL) - begin)); return (ret); } static int dat_stat_fn(ZDB_DAT_STORE *store) { const char *myname = "dat_stat_fn"; ZDB_DAT_HDR hdr; memcpy(&hdr, &store->hdr, sizeof(ZDB_DAT_HDR)); printf("%s(%d): %s's hdr status\n", myname, __LINE__, STORE_PATH((ZDB_STORE*) store)); printf("%s(%d):\tlimit: %lld, size: %lld, used count: %lld\n", myname, __LINE__, hdr.limit, hdr.size, hdr.count); printf("%s(%d):\tnstep: %d, blk_hdr_dlen: %d, blk_dlen: %d," " blk_count: %d\n", myname, __LINE__, hdr.nstep, hdr.blk_hdr_dlen, hdr.blk_dlen, hdr.blk_count); printf("%s(%d):\tihead_idle: %d, ihead_busy: %d\n", myname, __LINE__, hdr.ihead_idle, hdr.ihead_busy); return (0); } static int test_zdb_dat_stat(ZDB *db) { return (zdb_dat_walk(db, dat_stat_fn)); } static int key_stat_fn(ZDB_KEY_STORE *store) { const char *myname = "key_stat_fn"; ZDB_KEY_HDR key_hdr; memcpy(&key_hdr, &store->hdr, sizeof(ZDB_KEY_HDR)); printf(">> %s: %s's status:\n", myname, STORE_PATH((ZDB_STORE*) store)); printf(">>\tkey_limit: %lld, key_count: %lld, key_begin: %lld\n", key_hdr.key_limit, key_hdr.key_count, key_hdr.key_begin); return (0); } static int test_zdb_key_stat(ZDB *db) { return (zdb_key_walk(db, key_stat_fn)); } static int dat_check_fn(ZDB_DAT_STORE *store) { return (zdb_dat_check(store, NULL)); } static int test_zdb_dat_check(ZDB *db) { return (zdb_dat_walk(db, dat_check_fn)); } static int key_check_fn(ZDB_KEY_STORE *store) { return (zdb_key_check(store, NULL)); } static int test_zdb_key_check(ZDB *db) { return (zdb_key_walk(db, key_check_fn)); } void zdb_test_main(const char *cmd) { const char *myname = "zdb_test"; ZDB *db; const char *dbname = "test", *key_path = "./var"; /*ZDB_FLAG_CACHE_DAT | ZDB_FLAG_CACHE_KEY | ZDB_FLAG_SLICE_KEY | ZDB_FLAG_SLICE_DAT;*/ unsigned int oflags = 0; ZDB_CFG zdb_cfg; zdb_key_t key_begin = 0, key_limit = 1000000, dat_limit = 10000000, blk_dlen = sizeof(DUMMY); int ret, max = 10000000, use_random = 0, walk_all = 0, dat_nstep = 1000, mod = 1; int cache_key_limit = 0, cache_key_timeout = 0; int cmd_add = 0, cmd_get = 0, cmd_update = 0, update_num = 2; int cmd_stat = 0, cmd_check = 0; ACL_ARGV *argv = acl_argv_split(cmd, ":"); ACL_ITER iter; char *name, *value, *ptr; char usage[] = "help:stat:check:link:random:walk:add:get:update={d}" ":max={d}:key_limit={d}:dat_limit={d}:nstep={d}:mod={d}:cache_key_limit={d}" ":cache_key_timeout={d}"; acl_make_dirs(key_path, 0700); acl_foreach(iter, argv) { name = ptr = (char*) iter.data; if (strcasecmp(name, "help") == 0) { printf("usage: %s\n", usage); acl_argv_free(argv); return; } else if (strcasecmp(name, "stat") == 0) { cmd_stat = 1; continue; } else if (strcasecmp(name, "check") == 0) { cmd_check = 1; continue; } else if (strcasecmp(name, "link") == 0) { oflags |= ZDB_FLAG_LINK_BUSY; continue; } else if (strcasecmp(name, "random") == 0) { use_random = 1; continue; } else if (strcasecmp(name, "walk") == 0) { walk_all = 1; continue; } else if (strcasecmp(name, "add") == 0) { cmd_add = 1; continue; } else if (strcasecmp(name, "get") == 0) { cmd_get = 1; continue; } name = acl_mystrtok(&ptr, "="); if (name == NULL) continue; value = acl_mystrtok(&ptr, "="); if (value == NULL) continue; if (strcasecmp(name, "max") == 0) { ret = atoi(value); if (ret > 0) max = ret; } else if (strcasecmp(name, "key_limit") == 0) { ret = atoi(value); if (ret > 0) key_limit = ret; } else if (strcasecmp(name, "dat_limit") == 0) { ret = atoi(value); if (ret > 0) dat_limit = ret; } else if (strcasecmp(name, "update") == 0) { ret = atoi(value); if (ret > 0) { update_num = ret; cmd_update = 1; } } else if (strcasecmp(name, "nstep") == 0) { ret = atoi(value); if (ret > 0) dat_nstep = ret; } else if (strcasecmp(name, "mod") == 0) { ret = atoi(value); if (ret > 0) mod = ret; } else if (strcasecmp(name, "cache_key_limit") == 0) { ret = atoi(value); if (ret > 0) cache_key_limit = ret; } else if (strcasecmp(name, "cache_key_timeout") == 0) { ret = atoi(value); if (ret > 0) cache_key_timeout = ret; } } acl_argv_free(argv); memset(&zdb_cfg, 0, sizeof(zdb_cfg)); /* 初始化 ZDB 存储引擎 */ zdb_init(); /* 开始配置 ZDB 配置对象 */ zdb_cfg.key_path = key_path; zdb_cfg.key_begin = key_begin; zdb_cfg.key_limit = key_limit; zdb_cfg.dat_limit = dat_limit; zdb_cfg.blk_dlen = (int) blk_dlen; zdb_cfg.dat_nstep = dat_nstep; /* 值存储文件每次增加的数据块个数 */ if (cache_key_limit > 0 && cache_key_timeout > 0) { zdb_cfg.key_cache_max = cache_key_limit * 2; zdb_cfg.key_cache_timeout = cache_key_timeout; zdb_cfg.key_wback_max = cache_key_limit; oflags |= ZDB_FLAG_CACHE_KEY | ZDB_FLAG_SLICE_KEY; printf("===========open key\n"); } else { zdb_cfg.key_cache_max = 0; zdb_cfg.key_cache_timeout = 0; zdb_cfg.key_wback_max = 0; } zdb_cfg.dat_cache_max = 0; zdb_cfg.dat_cache_timeout = 0; zdb_cfg.dat_wback_max = 0; /* 打开一个 ZDB 数据库对象 */ db = zdb_open(dbname, oflags, &zdb_cfg); if (db == NULL) acl_msg_fatal("%s: zdb open error(%s)", myname, acl_last_serror()); printf("DUMMY.sizeof: %d\n", (int) sizeof(DUMMY)); if (0) { ret = zdb_test1(db); if (ret > 0) ret = zdb_test2(db); } else ret = 1; if (!use_random) { if (ret > 0 && cmd_add) ret = bench_add(db, max); if (ret > 0 && cmd_get) ret = bench_get(db, max); if (ret > 0 && cmd_update) ret = bench_update(db, max, update_num); } else { if (ret > 0 && cmd_add) ret = bench_random_add(db, max, mod); if (ret > 0 && cmd_get) ret = bench_random_get(db, max, mod); } if (walk_all) { if (ret > 0) ret = test_zdb_dat_walk(db); if (ret >= 0) ret = test_zdb_key_walk(db); } if (cmd_stat) { if (ret >= 0) ret = test_zdb_dat_stat(db); if (ret >= 0) ret = test_zdb_key_stat(db); } if (cmd_check) { if (ret >= 0) ret = test_zdb_dat_check(db); if (ret >= 0) ret = test_zdb_key_check(db); } zdb_close(db); zdb_end(); }