rbtree和hash的全量持久化操作。rbtree的二进制安全。
粗略测试。
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,6 +1,7 @@
|
|||||||
NtyCo/
|
NtyCo/
|
||||||
.vscode/
|
.vscode/
|
||||||
*.db
|
*.db
|
||||||
|
*.copy
|
||||||
|
|
||||||
proactor copy.c
|
proactor copy.c
|
||||||
ntyco copy.c
|
ntyco copy.c
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -2,7 +2,7 @@
|
|||||||
CC = gcc
|
CC = gcc
|
||||||
FLAGS = -I ./NtyCo/core/ -L ./NtyCo/ -lntyco -lpthread -luring -ldl
|
FLAGS = -I ./NtyCo/core/ -L ./NtyCo/ -lntyco -lpthread -luring -ldl
|
||||||
# SRCS = kvstore.c ntyco.c proactor.c reactor.c kvs_array.c kvs_rbtree.c kvs_hash.c kvs_rw_tools.c
|
# SRCS = kvstore.c ntyco.c proactor.c reactor.c kvs_array.c kvs_rbtree.c kvs_hash.c kvs_rw_tools.c
|
||||||
SRCS = kvstore.c ntyco.c proactor.c reactor.c kvs_array.c kvs_rbtree.c kvs_hash_bin.c kvs_rw_tools.c
|
SRCS = kvstore.c ntyco.c proactor.c reactor.c kvs_array_bin.c kvs_rbtree_bin.c kvs_hash_bin.c kvs_rw_tools.c kvs_cmd_log.c
|
||||||
TESTCASE_SRCS = testcase.c
|
TESTCASE_SRCS = testcase.c
|
||||||
TARGET = kvstore
|
TARGET = kvstore
|
||||||
SUBDIR = ./NtyCo/
|
SUBDIR = ./NtyCo/
|
||||||
|
|||||||
220
kvs_array.c
220
kvs_array.c
@@ -38,224 +38,7 @@ void kvs_array_destroy(kvs_array_t *inst) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if BIN_SAFE
|
|
||||||
/**
|
|
||||||
* return: ==-2 not exist, == -1 error, >= 0 exist idx
|
|
||||||
*/
|
|
||||||
int kvs_array_find_index(kvs_array_t *inst, const void *key, uint32_t key_len) {
|
|
||||||
if (!inst || !inst->table || !key) return -1;
|
|
||||||
for (int i = 0; i < inst->total; i++) {
|
|
||||||
kvs_array_item_t *it = &inst->table[i];
|
|
||||||
if (!it->key) continue;
|
|
||||||
if (it->key_len == key_len && memcmp(it->key, key, key_len) == 0) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -2; // not found
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* return: <0 error; 0 success; 1 exist
|
|
||||||
*/
|
|
||||||
int kvs_array_set_bin(kvs_array_t *inst,
|
|
||||||
const void *key, uint32_t key_len,
|
|
||||||
const void *value, uint32_t value_len) {
|
|
||||||
if (!inst || !inst->table || !key || key_len == 0 || !value) return -1;
|
|
||||||
if (inst->total >= KVS_ARRAY_SIZE) return -1;
|
|
||||||
|
|
||||||
int idx = kvs_array_find_index(inst, key, key_len);
|
|
||||||
// -2 not exist
|
|
||||||
if (idx >= 0) return 1; // exist
|
|
||||||
if (idx == -1) return -1; // error
|
|
||||||
|
|
||||||
uint8_t *kcopy = (uint8_t *)kvs_malloc(key_len);
|
|
||||||
if (!kcopy) return -2;
|
|
||||||
memcpy(kcopy, key, key_len);
|
|
||||||
|
|
||||||
uint8_t *vcopy = NULL;
|
|
||||||
if (value_len > 0) {
|
|
||||||
vcopy = (uint8_t *)kvs_malloc(value_len);
|
|
||||||
if (!vcopy) {
|
|
||||||
kvs_free(kcopy);
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
memcpy(vcopy, value, value_len);
|
|
||||||
} else {
|
|
||||||
// 允许空 value(长度0),value 指针置 NULL
|
|
||||||
vcopy = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
for (i = 0;i < inst->total;i ++) {
|
|
||||||
if (inst->table[i].key == NULL) {
|
|
||||||
|
|
||||||
inst->table[i].key = kcopy;
|
|
||||||
inst->table[i].key_len = key_len;
|
|
||||||
inst->table[i].value = vcopy;
|
|
||||||
inst->table[i].value_len = value_len;
|
|
||||||
inst->total ++;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == inst->total && i < KVS_ARRAY_SIZE) {
|
|
||||||
|
|
||||||
inst->table[i].key = kcopy;
|
|
||||||
inst->table[i].key_len = key_len;
|
|
||||||
inst->table[i].value = vcopy;
|
|
||||||
inst->table[i].value_len = value_len;
|
|
||||||
inst->total ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *kvs_array_get_bin(kvs_array_t *inst, const void *key, uint32_t key_len, uint32_t *out_value_len) {
|
|
||||||
if (out_value_len) *out_value_len = 0;
|
|
||||||
if (!inst || !inst->table || !key || key_len == 0) return NULL;
|
|
||||||
|
|
||||||
int idx = kvs_array_find_index(inst, key, key_len);
|
|
||||||
if (idx < 0) return NULL;
|
|
||||||
|
|
||||||
kvs_array_item_t *it = &inst->table[idx];
|
|
||||||
if (out_value_len) *out_value_len = it->value_len;
|
|
||||||
return it->value; // 注意:由 store 持有
|
|
||||||
}
|
|
||||||
|
|
||||||
int kvs_array_del_bin(kvs_array_t *inst, const void *key, uint32_t key_len) {
|
|
||||||
if (!inst || !inst->table || !key || key_len == 0) return -1;
|
|
||||||
|
|
||||||
int idx = kvs_array_find_index(inst, key, key_len);
|
|
||||||
if (idx == -2) return 1; // not exist
|
|
||||||
if (idx < 0) return -1;
|
|
||||||
|
|
||||||
kvs_array_item_t *it = &inst->table[idx];
|
|
||||||
if (it->key) kvs_free(it->key);
|
|
||||||
if (it->value) kvs_free(it->value);
|
|
||||||
|
|
||||||
// 用末尾元素填洞,保证 total 连续,避免 “total 只增不减” 问题
|
|
||||||
int last = inst->total - 1;
|
|
||||||
if (idx != last) {
|
|
||||||
inst->table[idx] = inst->table[last];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 清理末尾(已被移动或删除)
|
|
||||||
memset(&inst->table[last], 0, sizeof(kvs_array_item_t));
|
|
||||||
inst->total--;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int kvs_array_mod_bin(kvs_array_t *inst,
|
|
||||||
const void *key, uint32_t key_len,
|
|
||||||
const void *value, uint32_t value_len) {
|
|
||||||
if (!inst || !inst->table || !key || key_len == 0 || !value) return -1;
|
|
||||||
|
|
||||||
int idx = kvs_array_find_index(inst, key, key_len);
|
|
||||||
if (idx == -2) return 1; // not exist
|
|
||||||
if (idx < 0) return -1;
|
|
||||||
|
|
||||||
kvs_array_item_t *it = &inst->table[idx];
|
|
||||||
|
|
||||||
uint8_t *vcopy = NULL;
|
|
||||||
if (value_len > 0) {
|
|
||||||
vcopy = (uint8_t *)kvs_malloc(value_len);
|
|
||||||
if (!vcopy) return -2;
|
|
||||||
memcpy(vcopy, value, value_len);
|
|
||||||
} else {
|
|
||||||
vcopy = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (it->value) kvs_free(it->value);
|
|
||||||
it->value = vcopy;
|
|
||||||
it->value_len = value_len;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int kvs_array_exist_bin(kvs_array_t *inst, const void *key, uint32_t key_len) {
|
|
||||||
if (!inst || !inst->table || !key || key_len == 0) return -1;
|
|
||||||
int idx = kvs_array_find_index(inst, key, key_len);
|
|
||||||
return (idx >= 0) ? 0 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// return: 0 success, <0 error
|
|
||||||
int kvs_array_save(kvs_array_t *inst, const char* filename){
|
|
||||||
if(!inst || !filename) return -1;
|
|
||||||
FILE *fp = fopen(filename, "wb");
|
|
||||||
if(!fp) return -2;
|
|
||||||
|
|
||||||
|
|
||||||
for(int i = 0;i < inst->total; ++ i){
|
|
||||||
kvs_array_item_t *it = &inst->table[i];
|
|
||||||
if(!it->key || it->key_len == 0) continue; // 跳过空槽
|
|
||||||
if(it->value_len > 0 && !it->value) { fclose(fp); return -3; }
|
|
||||||
|
|
||||||
uint32_t klen = htonl(it->key_len);
|
|
||||||
uint32_t vlen = htonl(it->value_len);
|
|
||||||
|
|
||||||
if (kvs_write_file(fp, &klen, 4) < 0) { fclose(fp); return -4; }
|
|
||||||
if (kvs_write_file(fp, &vlen, 4) < 0) { fclose(fp); return -4; }
|
|
||||||
|
|
||||||
if (kvs_write_file(fp, it->key, it->key_len) < 0) { fclose(fp); return -4; }
|
|
||||||
if (it->value_len > 0) {
|
|
||||||
if (kvs_write_file(fp, it->value, it->value_len) < 0) { fclose(fp); return -4; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int kvs_array_load(kvs_array_t *inst, const char* filename) {
|
|
||||||
if (!inst || !filename) return -1;
|
|
||||||
if (!inst->table) return -1;
|
|
||||||
|
|
||||||
FILE *fp = fopen(filename, "rb");
|
|
||||||
if (!fp) return -2;
|
|
||||||
|
|
||||||
int idx = 0;
|
|
||||||
while(1){
|
|
||||||
uint32_t klen = 0, vlen = 0;
|
|
||||||
|
|
||||||
if (kvs_read_file(fp, &klen, 4) < 0) { fclose(fp); return -3; }
|
|
||||||
if (kvs_read_file(fp, &vlen, 4) < 0) { fclose(fp); return -3; }
|
|
||||||
|
|
||||||
klen = ntohl(klen);
|
|
||||||
vlen = ntohl(vlen);
|
|
||||||
|
|
||||||
if (klen == 0) { fclose(fp); return -3; }
|
|
||||||
|
|
||||||
kvs_array_item_t *it = &inst->table[idx];
|
|
||||||
memset(it, 0, sizeof(*it));
|
|
||||||
|
|
||||||
it->key = (uint8_t *)kvs_malloc(klen);
|
|
||||||
if (!it->key) { fclose(fp); return -3; }
|
|
||||||
it->key_len = klen;
|
|
||||||
if (kvs_read_file(fp, it->key, klen) < 0) { fclose(fp); return -3; }
|
|
||||||
|
|
||||||
if (vlen > 0) {
|
|
||||||
it->value = (uint8_t *)kvs_malloc(vlen);
|
|
||||||
if (!it->value) { fclose(fp); return -4; }
|
|
||||||
it->value_len = vlen;
|
|
||||||
|
|
||||||
if (kvs_read_file(fp, it->value, vlen) < 0) { fclose(fp); return -3; }
|
|
||||||
} else {
|
|
||||||
it->value = NULL;
|
|
||||||
it->value_len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inst->total ++;
|
|
||||||
idx++;
|
|
||||||
if(idx >= KVS_ARRAY_SIZE){ break; }
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
/*
|
/*
|
||||||
* @return: <0, error; =0, success; >0, exist
|
* @return: <0, error; =0, success; >0, exist
|
||||||
*/
|
*/
|
||||||
@@ -406,6 +189,3 @@ int kvs_array_exist(kvs_array_t *inst, char *key) {
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
267
kvs_array_bin.c
Normal file
267
kvs_array_bin.c
Normal file
@@ -0,0 +1,267 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#include "kvstore.h"
|
||||||
|
#include "kvs_rw_tools.h"
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
|
||||||
|
// singleton
|
||||||
|
|
||||||
|
kvs_array_t global_array = {0};
|
||||||
|
|
||||||
|
int kvs_array_create(kvs_array_t *inst) {
|
||||||
|
|
||||||
|
if (!inst) return -1;
|
||||||
|
if (inst->table) {
|
||||||
|
printf("table has alloc\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
inst->table = kvs_malloc(KVS_ARRAY_SIZE * sizeof(kvs_array_item_t));
|
||||||
|
if (!inst->table) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(inst->table, 0, (size_t)KVS_ARRAY_SIZE * sizeof(kvs_array_item_t));
|
||||||
|
inst->total = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void kvs_array_destroy(kvs_array_t *inst) {
|
||||||
|
|
||||||
|
if (!inst) return ;
|
||||||
|
|
||||||
|
if (inst->table) {
|
||||||
|
kvs_free(inst->table);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return: ==-2 not exist, == -1 error, >= 0 exist idx
|
||||||
|
*/
|
||||||
|
int kvs_array_find_index(kvs_array_t *inst, const void *key, uint32_t key_len) {
|
||||||
|
if (!inst || !inst->table || !key) return -1;
|
||||||
|
for (int i = 0; i < inst->total; i++) {
|
||||||
|
kvs_array_item_t *it = &inst->table[i];
|
||||||
|
if (!it->key) continue;
|
||||||
|
if (it->key_len == key_len && memcmp(it->key, key, key_len) == 0) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -2; // not found
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return: <0 error; 0 success; 1 exist
|
||||||
|
*/
|
||||||
|
int kvs_array_set_bin(kvs_array_t *inst,
|
||||||
|
const void *key, uint32_t key_len,
|
||||||
|
const void *value, uint32_t value_len) {
|
||||||
|
if (!inst || !inst->table || !key || key_len == 0 || !value) return -1;
|
||||||
|
if (inst->total >= KVS_ARRAY_SIZE) return -1;
|
||||||
|
|
||||||
|
int idx = kvs_array_find_index(inst, key, key_len);
|
||||||
|
// -2 not exist
|
||||||
|
if (idx >= 0) return 1; // exist
|
||||||
|
if (idx == -1) return -1; // error
|
||||||
|
|
||||||
|
uint8_t *kcopy = (uint8_t *)kvs_malloc(key_len);
|
||||||
|
if (!kcopy) return -2;
|
||||||
|
memcpy(kcopy, key, key_len);
|
||||||
|
|
||||||
|
uint8_t *vcopy = NULL;
|
||||||
|
if (value_len > 0) {
|
||||||
|
vcopy = (uint8_t *)kvs_malloc(value_len);
|
||||||
|
if (!vcopy) {
|
||||||
|
kvs_free(kcopy);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
memcpy(vcopy, value, value_len);
|
||||||
|
} else {
|
||||||
|
// 允许空 value(长度0),value 指针置 NULL
|
||||||
|
vcopy = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (i = 0;i < inst->total;i ++) {
|
||||||
|
if (inst->table[i].key == NULL) {
|
||||||
|
|
||||||
|
inst->table[i].key = kcopy;
|
||||||
|
inst->table[i].key_len = key_len;
|
||||||
|
inst->table[i].value = vcopy;
|
||||||
|
inst->table[i].value_len = value_len;
|
||||||
|
inst->total ++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == inst->total && i < KVS_ARRAY_SIZE) {
|
||||||
|
|
||||||
|
inst->table[i].key = kcopy;
|
||||||
|
inst->table[i].key_len = key_len;
|
||||||
|
inst->table[i].value = vcopy;
|
||||||
|
inst->table[i].value_len = value_len;
|
||||||
|
inst->total ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @return: NULL notexist, NOTNULL exist
|
||||||
|
*/
|
||||||
|
void *kvs_array_get_bin(kvs_array_t *inst, const void *key, uint32_t key_len, uint32_t *out_value_len) {
|
||||||
|
if (out_value_len) *out_value_len = 0;
|
||||||
|
if (!inst || !inst->table || !key || key_len == 0) return NULL;
|
||||||
|
|
||||||
|
int idx = kvs_array_find_index(inst, key, key_len);
|
||||||
|
if (idx < 0) return NULL;
|
||||||
|
|
||||||
|
kvs_array_item_t *it = &inst->table[idx];
|
||||||
|
if (out_value_len) *out_value_len = it->value_len;
|
||||||
|
return it->value; // 注意:由 store 持有
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @return < 0, error; =0, success; >0, no exist
|
||||||
|
*/
|
||||||
|
int kvs_array_del_bin(kvs_array_t *inst, const void *key, uint32_t key_len) {
|
||||||
|
if (!inst || !inst->table || !key || key_len == 0) return -1;
|
||||||
|
|
||||||
|
int idx = kvs_array_find_index(inst, key, key_len);
|
||||||
|
if (idx == -2) return 1; // not exist
|
||||||
|
if (idx < 0) return -1;
|
||||||
|
|
||||||
|
kvs_array_item_t *it = &inst->table[idx];
|
||||||
|
if (it->key) kvs_free(it->key);
|
||||||
|
if (it->value) kvs_free(it->value);
|
||||||
|
|
||||||
|
// 用末尾元素填洞,保证 total 连续,避免 “total 只增不减” 问题
|
||||||
|
int last = inst->total - 1;
|
||||||
|
if (idx != last) {
|
||||||
|
inst->table[idx] = inst->table[last];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理末尾(已被移动或删除)
|
||||||
|
memset(&inst->table[last], 0, sizeof(kvs_array_item_t));
|
||||||
|
inst->total--;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @return : < 0, error; =0, success; >0, no exist
|
||||||
|
*/
|
||||||
|
|
||||||
|
int kvs_array_mod_bin(kvs_array_t *inst,
|
||||||
|
const void *key, uint32_t key_len,
|
||||||
|
const void *value, uint32_t value_len) {
|
||||||
|
if (!inst || !inst->table || !key || key_len == 0 || !value) return -1;
|
||||||
|
|
||||||
|
int idx = kvs_array_find_index(inst, key, key_len);
|
||||||
|
if (idx == -2) return 1; // not exist
|
||||||
|
if (idx < 0) return -1;
|
||||||
|
|
||||||
|
kvs_array_item_t *it = &inst->table[idx];
|
||||||
|
|
||||||
|
uint8_t *vcopy = NULL;
|
||||||
|
if (value_len > 0) {
|
||||||
|
vcopy = (uint8_t *)kvs_malloc(value_len);
|
||||||
|
if (!vcopy) return -2;
|
||||||
|
memcpy(vcopy, value, value_len);
|
||||||
|
} else {
|
||||||
|
vcopy = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it->value) kvs_free(it->value);
|
||||||
|
it->value = vcopy;
|
||||||
|
it->value_len = value_len;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @return 0: exist, 1: no exist
|
||||||
|
*/
|
||||||
|
int kvs_array_exist_bin(kvs_array_t *inst, const void *key, uint32_t key_len) {
|
||||||
|
if (!inst || !inst->table || !key || key_len == 0) return -1;
|
||||||
|
int idx = kvs_array_find_index(inst, key, key_len);
|
||||||
|
return (idx >= 0) ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return: 0 success, <0 error
|
||||||
|
int kvs_array_save(kvs_array_t *inst, const char* filename){
|
||||||
|
if(!inst || !filename) return -1;
|
||||||
|
FILE *fp = fopen(filename, "wb");
|
||||||
|
if(!fp) return -2;
|
||||||
|
|
||||||
|
|
||||||
|
for(int i = 0;i < inst->total; ++ i){
|
||||||
|
kvs_array_item_t *it = &inst->table[i];
|
||||||
|
if(!it->key || it->key_len == 0) continue; // 跳过空槽
|
||||||
|
if(it->value_len > 0 && !it->value) { fclose(fp); return -3; }
|
||||||
|
|
||||||
|
uint32_t klen = htonl(it->key_len);
|
||||||
|
uint32_t vlen = htonl(it->value_len);
|
||||||
|
|
||||||
|
if (kvs_write_file(fp, &klen, 4) < 0) { fclose(fp); return -4; }
|
||||||
|
if (kvs_write_file(fp, &vlen, 4) < 0) { fclose(fp); return -4; }
|
||||||
|
|
||||||
|
if (kvs_write_file(fp, it->key, it->key_len) < 0) { fclose(fp); return -4; }
|
||||||
|
if (it->value_len > 0) {
|
||||||
|
if (kvs_write_file(fp, it->value, it->value_len) < 0) { fclose(fp); return -4; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int kvs_array_load(kvs_array_t *inst, const char* filename) {
|
||||||
|
if (!inst || !filename) return -1;
|
||||||
|
if (!inst->table) return -1;
|
||||||
|
|
||||||
|
FILE *fp = fopen(filename, "rb");
|
||||||
|
if (!fp) return -2;
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
while(1){
|
||||||
|
uint32_t klen_n = 0, vlen_n = 0;
|
||||||
|
|
||||||
|
if (kvs_read_file(fp, &klen_n, 4) < 0) { fclose(fp); return -3; }
|
||||||
|
if (kvs_read_file(fp, &vlen_n, 4) < 0) { fclose(fp); return -3; }
|
||||||
|
|
||||||
|
uint32_t klen = ntohl(klen_n);
|
||||||
|
uint32_t vlen = ntohl(vlen_n);
|
||||||
|
|
||||||
|
if (klen == 0) { fclose(fp); return -3; }
|
||||||
|
|
||||||
|
kvs_array_item_t *it = &inst->table[idx];
|
||||||
|
memset(it, 0, sizeof(*it));
|
||||||
|
|
||||||
|
it->key = (uint8_t *)kvs_malloc(klen);
|
||||||
|
if (!it->key) { fclose(fp); return -3; }
|
||||||
|
it->key_len = klen;
|
||||||
|
if (kvs_read_file(fp, it->key, klen) < 0) { fclose(fp); return -3; }
|
||||||
|
|
||||||
|
if (vlen > 0) {
|
||||||
|
it->value = (uint8_t *)kvs_malloc(vlen);
|
||||||
|
if (!it->value) { fclose(fp); return -4; }
|
||||||
|
it->value_len = vlen;
|
||||||
|
|
||||||
|
if (kvs_read_file(fp, it->value, vlen) < 0) { fclose(fp); return -3; }
|
||||||
|
} else {
|
||||||
|
it->value = NULL;
|
||||||
|
it->value_len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inst->total ++;
|
||||||
|
idx++;
|
||||||
|
if(idx >= KVS_ARRAY_SIZE){ break; }
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
100
kvs_cmd_log.c
Normal file
100
kvs_cmd_log.c
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
#include "kvstore.h"
|
||||||
|
#include "kvs_rw_tools.h"
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int init_cmd_log(const char *file, int *logfd){
|
||||||
|
if(!file) return -1;
|
||||||
|
int fd = open(file, O_RDWR | O_CREAT | O_APPEND, 0644);
|
||||||
|
if(fd < 0) return -2;
|
||||||
|
|
||||||
|
*logfd = fd;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int destroy_cmd_log(int logfd){
|
||||||
|
close(logfd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int kvs_save_cmd_to_logfile(const uint8_t *cmd, size_t len, int logfd){
|
||||||
|
if (logfd < 0 || !cmd || len == 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (len > UINT32_MAX)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
uint32_t nlen = htonl((uint32_t)len);
|
||||||
|
|
||||||
|
if (write_full(logfd, &nlen, sizeof(nlen)) < 0)
|
||||||
|
return -3;
|
||||||
|
|
||||||
|
if (write_full(logfd, cmd, len) < 0)
|
||||||
|
return -4;
|
||||||
|
|
||||||
|
if (fsync(logfd) < 0)
|
||||||
|
return -5;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int kvs_replay_log(const char *logfile, int logfd){
|
||||||
|
if (!logfile|| logfd<0) return -1;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
uint32_t nlen = 0;
|
||||||
|
|
||||||
|
int hr = read_full(logfd, &nlen, sizeof(nlen));
|
||||||
|
if (hr == 0) break; /* EOF:正常结束 */
|
||||||
|
if (hr < 0) { return -2; } /* 半截头 */
|
||||||
|
|
||||||
|
uint32_t len = ntohl(nlen);
|
||||||
|
if (len == 0) { return -3; }
|
||||||
|
|
||||||
|
uint8_t *cmd = (uint8_t *)kvs_malloc(len);
|
||||||
|
if (!cmd) { return -5; }
|
||||||
|
|
||||||
|
int pr = read_full(logfd, cmd, len);
|
||||||
|
if (pr <= 0) { /* 半截 payload */
|
||||||
|
kvs_free(cmd);
|
||||||
|
return -6;
|
||||||
|
}
|
||||||
|
|
||||||
|
kvs_req_t req;
|
||||||
|
memset(&req, 0, sizeof(req));
|
||||||
|
|
||||||
|
int clen = kvs_parse_one_cmd(cmd, (int)len, &req);
|
||||||
|
if (clen <= 0 || clen != (int)len) {
|
||||||
|
kvs_free_request(&req);
|
||||||
|
kvs_free(cmd);
|
||||||
|
return -7;
|
||||||
|
}
|
||||||
|
|
||||||
|
kvs_rsp_t rsp;
|
||||||
|
memset(&rsp, 0, sizeof(rsp));
|
||||||
|
|
||||||
|
if (kvs_execute_one_cmd(&req, &rsp) < 0) {
|
||||||
|
kvs_free_request(&req);
|
||||||
|
kvs_free(cmd);
|
||||||
|
return -8;
|
||||||
|
}
|
||||||
|
|
||||||
|
kvs_free_request(&req);
|
||||||
|
kvs_free(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clear log file not close
|
||||||
|
*/
|
||||||
|
int ksv_clear_log(int logfd){
|
||||||
|
if(logfd < 0) return -1;
|
||||||
|
ftruncate(logfd, 0);
|
||||||
|
lseek(logfd, 0, SEEK_SET);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
108
kvs_hash_bin.c
108
kvs_hash_bin.c
@@ -8,7 +8,8 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "kvstore.h"
|
#include "kvstore.h"
|
||||||
|
#include "kvs_rw_tools.h"
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
// Key, Value -->
|
// Key, Value -->
|
||||||
// Modify
|
// Modify
|
||||||
@@ -114,7 +115,7 @@ void kvs_hash_destroy(kvs_hash_t *hash) {
|
|||||||
* @return: <0 error; =0 success; >0 exist
|
* @return: <0 error; =0 success; >0 exist
|
||||||
*/
|
*/
|
||||||
int kvs_hash_set_bin(kvs_hash_t *hash, const void *key, uint32_t key_len, const void *value, uint32_t value_len) {
|
int kvs_hash_set_bin(kvs_hash_t *hash, const void *key, uint32_t key_len, const void *value, uint32_t value_len) {
|
||||||
if (!hash || !hash->nodes || !key || key_len == 0 || !value) return -1;
|
if (!hash || !hash->nodes || !key || key_len == 0) return -1;
|
||||||
|
|
||||||
int idx = _hash(key, key_len, MAX_TABLE_SIZE);
|
int idx = _hash(key, key_len, MAX_TABLE_SIZE);
|
||||||
if (idx < 0) return -1;
|
if (idx < 0) return -1;
|
||||||
@@ -208,16 +209,16 @@ int kvs_hash_count(kvs_hash_t *hash) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @return 0 success; <0 error/noexist
|
* @return < 0, error; =0, success; >0, no exist
|
||||||
*/
|
*/
|
||||||
int kvs_hash_del_bin(kvs_hash_t *hash, const void *key, uint32_t key_len) {
|
int kvs_hash_del_bin(kvs_hash_t *hash, const void *key, uint32_t key_len) {
|
||||||
if (!hash || !key || key_len == 0) return -2;
|
if (!hash || !key || key_len == 0) return -1;
|
||||||
|
|
||||||
int idx = _hash(key, key_len, MAX_TABLE_SIZE);
|
int idx = _hash(key, key_len, MAX_TABLE_SIZE);
|
||||||
if (idx < 0) return -2;
|
if (idx < 0) return -1;
|
||||||
|
|
||||||
hashnode_t *head = hash->nodes[idx];
|
hashnode_t *head = hash->nodes[idx];
|
||||||
if (head == NULL) return -1; // noexist
|
if (head == NULL) return 1; // noexist
|
||||||
|
|
||||||
// head node
|
// head node
|
||||||
if (_key_equal(head, key, key_len)) {
|
if (_key_equal(head, key, key_len)) {
|
||||||
@@ -241,7 +242,7 @@ int kvs_hash_del_bin(kvs_hash_t *hash, const void *key, uint32_t key_len) {
|
|||||||
|
|
||||||
if (cur->next == NULL) {
|
if (cur->next == NULL) {
|
||||||
|
|
||||||
return -1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
hashnode_t *tmp = cur->next;
|
hashnode_t *tmp = cur->next;
|
||||||
@@ -264,37 +265,86 @@ int kvs_hash_exist_bin(kvs_hash_t *hash, const void *key, uint32_t key_len) {
|
|||||||
return value ? 0 : 1;
|
return value ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
// 0 suc, <0 error
|
||||||
int main() {
|
int kvs_hash_save(kvs_hash_t *inst, const char* filename){
|
||||||
|
if(!inst || !filename) return -1;
|
||||||
|
FILE *fp = fopen(filename, "wb");
|
||||||
|
if(!fp) return -2;
|
||||||
|
|
||||||
kvs_hash_create(&hash);
|
|
||||||
|
|
||||||
kvs_hash_set(&hash, "Teacher1", "King");
|
for(int i = 0;i < inst->max_slots; ++ i){
|
||||||
kvs_hash_set(&hash, "Teacher2", "Darren");
|
for (hashnode_t *n = inst->nodes[i]; n != NULL; n = n->next) {
|
||||||
kvs_hash_set(&hash, "Teacher3", "Mark");
|
if (!n->key || n->key_len == 0) continue;
|
||||||
kvs_hash_set(&hash, "Teacher4", "Vico");
|
if (n->value_len > 0 && !n->value) { fclose(fp); return -3; }
|
||||||
kvs_hash_set(&hash, "Teacher5", "Nick");
|
|
||||||
|
|
||||||
char *value1 = kvs_hash_get(&hash, "Teacher1");
|
|
||||||
printf("Teacher1 : %s\n", value1);
|
|
||||||
|
|
||||||
int ret = kvs_hash_mod(&hash, "Teacher1", "King1");
|
uint32_t klen = htonl((uint32_t)n->key_len);
|
||||||
printf("mode Teacher1 ret : %d\n", ret);
|
uint32_t vlen = htonl((uint32_t)n->value_len);
|
||||||
|
|
||||||
char *value2 = kvs_hash_get(&hash, "Teacher1");
|
if (kvs_write_file(fp, &klen, 4) < 0) { fclose(fp); return -4; }
|
||||||
printf("Teacher2 : %s\n", value1);
|
if (kvs_write_file(fp, &vlen, 4) < 0) { fclose(fp); return -4; }
|
||||||
|
|
||||||
ret = kvs_hash_del(&hash, "Teacher1");
|
if (kvs_write_file(fp, n->key, n->key_len) < 0) { fclose(fp); return -4; }
|
||||||
printf("delete Teacher1 ret : %d\n", ret);
|
if (n->value_len > 0) {
|
||||||
|
if (kvs_write_file(fp, n->value, n->value_len) < 0) { fclose(fp); return -4; }
|
||||||
ret = kvs_hash_exist(&hash, "Teacher1");
|
}
|
||||||
printf("Exist Teacher1 ret : %d\n", ret);
|
}
|
||||||
|
}
|
||||||
kvs_hash_destroy(&hash);
|
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
int kvs_hash_load(kvs_hash_t *inst, const char* filename){
|
||||||
|
if (!inst || !filename) return -1;
|
||||||
|
if (!inst->nodes || inst->max_slots <= 0) return -1;
|
||||||
|
|
||||||
|
FILE *fp = fopen(filename, "rb");
|
||||||
|
if (!fp) return -2;
|
||||||
|
|
||||||
|
while(1){
|
||||||
|
uint32_t klen_n = 0, vlen_n = 0;
|
||||||
|
|
||||||
|
if (kvs_read_file(fp, &klen_n, 4) < 0) { fclose(fp); return -3; }
|
||||||
|
if (kvs_read_file(fp, &vlen_n, 4) < 0) { fclose(fp); return -3; }
|
||||||
|
|
||||||
|
uint32_t klen = ntohl(klen_n);
|
||||||
|
uint32_t vlen = ntohl(vlen_n);
|
||||||
|
|
||||||
|
if (klen == 0) { fclose(fp); return -3; }
|
||||||
|
|
||||||
|
uint8_t *keybuf = (uint8_t*)kvs_malloc((size_t)klen);
|
||||||
|
if (!keybuf) { fclose(fp); return -4; }
|
||||||
|
if (kvs_read_file(fp, keybuf, (size_t)klen) < 0) {
|
||||||
|
kvs_free(keybuf);
|
||||||
|
fclose(fp);
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
uint8_t *valbuf = NULL;
|
||||||
|
if (vlen > 0) {
|
||||||
|
valbuf = (uint8_t*)kvs_malloc((size_t)vlen);
|
||||||
|
if (!valbuf) {
|
||||||
|
kvs_free(keybuf);
|
||||||
|
fclose(fp);
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
if (kvs_read_file(fp, valbuf, (size_t)vlen) < 0) {
|
||||||
|
kvs_free(valbuf);
|
||||||
|
kvs_free(keybuf);
|
||||||
|
fclose(fp);
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int rc = kvs_hash_set_bin(inst, keybuf, klen, valbuf, vlen);
|
||||||
|
kvs_free(keybuf);
|
||||||
|
if (vlen > 0) kvs_free(valbuf);
|
||||||
|
|
||||||
|
if (rc < 0) { // error
|
||||||
|
fclose(fp);
|
||||||
|
return -5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
934
kvs_rbtree.c
934
kvs_rbtree.c
File diff suppressed because it is too large
Load Diff
568
kvs_rbtree_bin.c
Normal file
568
kvs_rbtree_bin.c
Normal file
@@ -0,0 +1,568 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "kvstore.h"
|
||||||
|
#include "kvs_rw_tools.h"
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
int kvs_keycmp(const uint8_t *a, uint32_t alen,
|
||||||
|
const uint8_t *b, uint32_t blen) {
|
||||||
|
uint32_t min = (alen < blen) ? alen : blen;
|
||||||
|
int r = 0;
|
||||||
|
if (min > 0) {
|
||||||
|
r = memcmp(a, b, min);
|
||||||
|
if (r != 0) return r;
|
||||||
|
}
|
||||||
|
// 前缀相同,则短的更小
|
||||||
|
if (alen < blen) return -1;
|
||||||
|
if (alen > blen) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
rbtree_node *rbtree_mini(rbtree *T, rbtree_node *x) {
|
||||||
|
while (x->left != T->nil) {
|
||||||
|
x = x->left;
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
rbtree_node *rbtree_maxi(rbtree *T, rbtree_node *x) {
|
||||||
|
while (x->right != T->nil) {
|
||||||
|
x = x->right;
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
rbtree_node *rbtree_successor(rbtree *T, rbtree_node *x) {
|
||||||
|
rbtree_node *y = x->parent;
|
||||||
|
|
||||||
|
if (x->right != T->nil) {
|
||||||
|
return rbtree_mini(T, x->right);
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((y != T->nil) && (x == y->right)) {
|
||||||
|
x = y;
|
||||||
|
y = y->parent;
|
||||||
|
}
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void rbtree_left_rotate(rbtree *T, rbtree_node *x) {
|
||||||
|
|
||||||
|
rbtree_node *y = x->right; // x --> y , y --> x, right --> left, left --> right
|
||||||
|
|
||||||
|
x->right = y->left; //1 1
|
||||||
|
if (y->left != T->nil) { //1 2
|
||||||
|
y->left->parent = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
y->parent = x->parent; //1 3
|
||||||
|
if (x->parent == T->nil) { //1 4
|
||||||
|
T->root = y;
|
||||||
|
} else if (x == x->parent->left) {
|
||||||
|
x->parent->left = y;
|
||||||
|
} else {
|
||||||
|
x->parent->right = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
y->left = x; //1 5
|
||||||
|
x->parent = y; //1 6
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void rbtree_right_rotate(rbtree *T, rbtree_node *y) {
|
||||||
|
|
||||||
|
rbtree_node *x = y->left;
|
||||||
|
|
||||||
|
y->left = x->right;
|
||||||
|
if (x->right != T->nil) {
|
||||||
|
x->right->parent = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
x->parent = y->parent;
|
||||||
|
if (y->parent == T->nil) {
|
||||||
|
T->root = x;
|
||||||
|
} else if (y == y->parent->right) {
|
||||||
|
y->parent->right = x;
|
||||||
|
} else {
|
||||||
|
y->parent->left = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
x->right = y;
|
||||||
|
y->parent = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rbtree_insert_fixup(rbtree *T, rbtree_node *z) {
|
||||||
|
|
||||||
|
while (z->parent->color == RED) { //z ---> RED
|
||||||
|
if (z->parent == z->parent->parent->left) {
|
||||||
|
rbtree_node *y = z->parent->parent->right;
|
||||||
|
if (y->color == RED) {
|
||||||
|
z->parent->color = BLACK;
|
||||||
|
y->color = BLACK;
|
||||||
|
z->parent->parent->color = RED;
|
||||||
|
|
||||||
|
z = z->parent->parent; //z --> RED
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (z == z->parent->right) {
|
||||||
|
z = z->parent;
|
||||||
|
rbtree_left_rotate(T, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
z->parent->color = BLACK;
|
||||||
|
z->parent->parent->color = RED;
|
||||||
|
rbtree_right_rotate(T, z->parent->parent);
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
rbtree_node *y = z->parent->parent->left;
|
||||||
|
if (y->color == RED) {
|
||||||
|
z->parent->color = BLACK;
|
||||||
|
y->color = BLACK;
|
||||||
|
z->parent->parent->color = RED;
|
||||||
|
|
||||||
|
z = z->parent->parent; //z --> RED
|
||||||
|
} else {
|
||||||
|
if (z == z->parent->left) {
|
||||||
|
z = z->parent;
|
||||||
|
rbtree_right_rotate(T, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
z->parent->color = BLACK;
|
||||||
|
z->parent->parent->color = RED;
|
||||||
|
rbtree_left_rotate(T, z->parent->parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
T->root->color = BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int rbtree_insert(rbtree *T, rbtree_node *z) {
|
||||||
|
|
||||||
|
rbtree_node *y = T->nil;
|
||||||
|
rbtree_node *x = T->root;
|
||||||
|
|
||||||
|
while (x != T->nil) {
|
||||||
|
y = x;
|
||||||
|
|
||||||
|
int c = kvs_keycmp(z->key, z->key_len, x->key, x->key_len);
|
||||||
|
if (c < 0) {
|
||||||
|
x = x->left;
|
||||||
|
} else if (c > 0) {
|
||||||
|
x = x->right;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
z->parent = y;
|
||||||
|
if (y == T->nil) {
|
||||||
|
T->root = z;
|
||||||
|
|
||||||
|
}else{
|
||||||
|
int c = kvs_keycmp(z->key, z->key_len, y->key, y->key_len);
|
||||||
|
if (c < 0) y->left = z;
|
||||||
|
else y->right = z;
|
||||||
|
}
|
||||||
|
z->left = T->nil;
|
||||||
|
z->right = T->nil;
|
||||||
|
z->color = RED;
|
||||||
|
|
||||||
|
rbtree_insert_fixup(T, z);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rbtree_delete_fixup(rbtree *T, rbtree_node *x) {
|
||||||
|
|
||||||
|
while ((x != T->root) && (x->color == BLACK)) {
|
||||||
|
if (x == x->parent->left) {
|
||||||
|
|
||||||
|
rbtree_node *w= x->parent->right;
|
||||||
|
if (w->color == RED) {
|
||||||
|
w->color = BLACK;
|
||||||
|
x->parent->color = RED;
|
||||||
|
|
||||||
|
rbtree_left_rotate(T, x->parent);
|
||||||
|
w = x->parent->right;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((w->left->color == BLACK) && (w->right->color == BLACK)) {
|
||||||
|
w->color = RED;
|
||||||
|
x = x->parent;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (w->right->color == BLACK) {
|
||||||
|
w->left->color = BLACK;
|
||||||
|
w->color = RED;
|
||||||
|
rbtree_right_rotate(T, w);
|
||||||
|
w = x->parent->right;
|
||||||
|
}
|
||||||
|
|
||||||
|
w->color = x->parent->color;
|
||||||
|
x->parent->color = BLACK;
|
||||||
|
w->right->color = BLACK;
|
||||||
|
rbtree_left_rotate(T, x->parent);
|
||||||
|
|
||||||
|
x = T->root;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
rbtree_node *w = x->parent->left;
|
||||||
|
if (w->color == RED) {
|
||||||
|
w->color = BLACK;
|
||||||
|
x->parent->color = RED;
|
||||||
|
rbtree_right_rotate(T, x->parent);
|
||||||
|
w = x->parent->left;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((w->left->color == BLACK) && (w->right->color == BLACK)) {
|
||||||
|
w->color = RED;
|
||||||
|
x = x->parent;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (w->left->color == BLACK) {
|
||||||
|
w->right->color = BLACK;
|
||||||
|
w->color = RED;
|
||||||
|
rbtree_left_rotate(T, w);
|
||||||
|
w = x->parent->left;
|
||||||
|
}
|
||||||
|
|
||||||
|
w->color = x->parent->color;
|
||||||
|
x->parent->color = BLACK;
|
||||||
|
w->left->color = BLACK;
|
||||||
|
rbtree_right_rotate(T, x->parent);
|
||||||
|
|
||||||
|
x = T->root;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
x->color = BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
rbtree_node *rbtree_delete(rbtree *T, rbtree_node *z) {
|
||||||
|
|
||||||
|
rbtree_node *y = T->nil;
|
||||||
|
rbtree_node *x = T->nil;
|
||||||
|
|
||||||
|
if ((z->left == T->nil) || (z->right == T->nil)) {
|
||||||
|
y = z;
|
||||||
|
} else {
|
||||||
|
y = rbtree_successor(T, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y->left != T->nil) {
|
||||||
|
x = y->left;
|
||||||
|
} else if (y->right != T->nil) {
|
||||||
|
x = y->right;
|
||||||
|
}
|
||||||
|
|
||||||
|
x->parent = y->parent;
|
||||||
|
if (y->parent == T->nil) {
|
||||||
|
T->root = x;
|
||||||
|
} else if (y == y->parent->left) {
|
||||||
|
y->parent->left = x;
|
||||||
|
} else {
|
||||||
|
y->parent->right = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y != z) {
|
||||||
|
uint8_t *ktmp = z->key; z->key = y->key; y->key = ktmp;
|
||||||
|
uint32_t ltmp = z->key_len; z->key_len = y->key_len; y->key_len = ltmp;
|
||||||
|
|
||||||
|
uint8_t *vtmp = z->value; z->value = y->value; y->value = vtmp;
|
||||||
|
uint32_t tlen = z->value_len; z->value_len = y->value_len; y->value_len = tlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y->color == BLACK) {
|
||||||
|
rbtree_delete_fixup(T, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
rbtree_node *rbtree_search(rbtree *T, KEY_TYPE* key, uint32_t keylen) {
|
||||||
|
|
||||||
|
rbtree_node *node = T->root;
|
||||||
|
while (node != T->nil) {
|
||||||
|
int c = kvs_keycmp(key, keylen, node->key, node->key_len);
|
||||||
|
if (c < 0) node = node->left;
|
||||||
|
else if (c > 0) node = node->right;
|
||||||
|
else return node;
|
||||||
|
}
|
||||||
|
return T->nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void rbtree_traversal(rbtree *T, rbtree_node *node) {
|
||||||
|
if (node != T->nil) {
|
||||||
|
rbtree_traversal(T, node->left);
|
||||||
|
|
||||||
|
printf("key:%s, color:%d\n", (char*)node->key, node->color);
|
||||||
|
rbtree_traversal(T, node->right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct _rbtree kvs_rbtree_t;
|
||||||
|
|
||||||
|
kvs_rbtree_t global_rbtree;
|
||||||
|
|
||||||
|
// 5 + 2
|
||||||
|
int kvs_rbtree_create(kvs_rbtree_t *inst) {
|
||||||
|
|
||||||
|
if (inst == NULL) return 1;
|
||||||
|
|
||||||
|
inst->nil = (rbtree_node*)kvs_malloc(sizeof(rbtree_node));
|
||||||
|
if (!inst->nil) return 2;
|
||||||
|
|
||||||
|
inst->nil->color = BLACK;
|
||||||
|
inst->nil->left = inst->nil->right = inst->nil->parent = inst->nil;
|
||||||
|
inst->root = inst->nil;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void kvs_rbtree_destroy(kvs_rbtree_t *inst) {
|
||||||
|
|
||||||
|
if (inst == NULL) return ;
|
||||||
|
|
||||||
|
rbtree_node *node = NULL;
|
||||||
|
|
||||||
|
while (inst->root != inst->nil) {
|
||||||
|
|
||||||
|
rbtree_node *mini = rbtree_mini(inst, node);
|
||||||
|
|
||||||
|
rbtree_node *cur = rbtree_delete(inst, mini);
|
||||||
|
if (cur != inst->nil) {
|
||||||
|
if (cur->key) kvs_free(cur->key);
|
||||||
|
if (cur->value) kvs_free(cur->value);
|
||||||
|
kvs_free(cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
kvs_free(inst->nil);
|
||||||
|
inst->nil = NULL;
|
||||||
|
inst->root = NULL;
|
||||||
|
return ;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return: <0 error; 0 success; 1 exist
|
||||||
|
*/
|
||||||
|
int kvs_rbtree_set(kvs_rbtree_t *inst, const void *key, uint32_t key_len, const void *value, uint32_t value_len) {
|
||||||
|
|
||||||
|
if (!inst || !key || !value) return -1;
|
||||||
|
|
||||||
|
rbtree_node *node = (rbtree_node*)kvs_malloc(sizeof(rbtree_node));
|
||||||
|
if (!node) return -2;
|
||||||
|
memset(node, 0, sizeof(*node));
|
||||||
|
|
||||||
|
node->key = (uint8_t*)kvs_malloc(key_len);
|
||||||
|
if (!node->key) {
|
||||||
|
kvs_free(node);return -2;
|
||||||
|
}
|
||||||
|
memcpy(node->key, key, key_len);
|
||||||
|
node->key_len = key_len;
|
||||||
|
|
||||||
|
node->value = (uint8_t*)kvs_malloc(value_len);
|
||||||
|
if (!node->value) { kvs_free(node->key); kvs_free(node); return -2; }
|
||||||
|
if (value_len) memcpy(node->value, value, value_len);
|
||||||
|
node->value_len = value_len;
|
||||||
|
|
||||||
|
if(rbtree_insert(inst, node) < 0){
|
||||||
|
kvs_free(node->value);
|
||||||
|
kvs_free(node->key);
|
||||||
|
kvs_free(node);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @return: NULL notexist, NOTNULL exist
|
||||||
|
*/
|
||||||
|
void* kvs_rbtree_get(kvs_rbtree_t *inst, const void *key, uint32_t key_len, uint32_t *out_valuelen) {
|
||||||
|
if (!inst || !key || key_len == 0 || !out_valuelen) return NULL;
|
||||||
|
|
||||||
|
rbtree_node *node = rbtree_search(inst, (uint8_t *)key, key_len);
|
||||||
|
if (!node) return NULL; // no exist
|
||||||
|
if (node == inst->nil) return NULL;
|
||||||
|
|
||||||
|
*out_valuelen = node->value_len;
|
||||||
|
return node->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @return < 0, error; =0, success; >0, no exist
|
||||||
|
*/
|
||||||
|
int kvs_rbtree_del(rbtree *inst, const void *key, uint32_t key_len) {
|
||||||
|
|
||||||
|
if (!inst || !key || key_len == 0) return -1;
|
||||||
|
|
||||||
|
rbtree_node *node = rbtree_search(inst, (uint8_t *)key, key_len);
|
||||||
|
if (!node) return 1; // no exist
|
||||||
|
if (node == inst->nil) return 1;
|
||||||
|
|
||||||
|
rbtree_node *cur = rbtree_delete(inst, node);
|
||||||
|
if (cur != inst->nil) {
|
||||||
|
if (cur->key) kvs_free(cur->key);
|
||||||
|
if (cur->value) kvs_free(cur->value);
|
||||||
|
kvs_free(cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @return : < 0, error; =0, success; >0, no exist
|
||||||
|
*/
|
||||||
|
|
||||||
|
int kvs_rbtree_mod(kvs_rbtree_t *inst, const void *key, uint32_t key_len, const void *value, uint32_t value_len) {
|
||||||
|
|
||||||
|
if (!inst || !key || key_len==0 || !value) return -1;
|
||||||
|
|
||||||
|
rbtree_node *node = rbtree_search(inst, (uint8_t *)key, key_len);
|
||||||
|
if (!node) return 1; // no exist
|
||||||
|
if (node == inst->nil) return 1;
|
||||||
|
|
||||||
|
if (node->value) kvs_free(node->value);
|
||||||
|
|
||||||
|
node->value = (uint8_t*)kvs_malloc(value_len);
|
||||||
|
if (!node->value) { node->value_len = 0; return -2; }
|
||||||
|
|
||||||
|
if (value_len) memcpy(node->value, value, value_len);
|
||||||
|
node->value_len = value_len;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @return 0: exist, 1: no exist
|
||||||
|
*/
|
||||||
|
int kvs_rbtree_exist(kvs_rbtree_t *inst, const void *key, uint32_t key_len) {
|
||||||
|
|
||||||
|
if (!inst || !key || key_len == 0) return -1;
|
||||||
|
|
||||||
|
rbtree_node *node = rbtree_search(inst, (uint8_t*)key, key_len);
|
||||||
|
if (!node) return 1; // no exist
|
||||||
|
if (node == inst->nil) return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kvs_rbtree_save_node(FILE *fp, kvs_rbtree_t *inst, rbtree_node *node) {
|
||||||
|
if (!fp || !inst || !node) return -1;
|
||||||
|
if (node == inst->nil) return 0;
|
||||||
|
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
rc = kvs_rbtree_save_node(fp, inst, node->left);
|
||||||
|
if (rc < 0) return rc;
|
||||||
|
|
||||||
|
uint32_t klen_n = htonl(node->key_len);
|
||||||
|
uint32_t vlen_n = htonl(node->value_len);
|
||||||
|
|
||||||
|
if (kvs_write_file(fp, &klen_n, sizeof(klen_n)) < 0) return -1;
|
||||||
|
if (kvs_write_file(fp, &vlen_n, sizeof(vlen_n)) < 0) return -1;
|
||||||
|
|
||||||
|
if (node->key_len) {
|
||||||
|
if (!node->key) return -1;
|
||||||
|
if (kvs_write_file(fp, node->key, node->key_len) < 0) return -1;
|
||||||
|
}
|
||||||
|
if (node->value_len) {
|
||||||
|
if (!node->value) return -1;
|
||||||
|
if (kvs_write_file(fp, node->value, node->value_len) < 0) return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = kvs_rbtree_save_node(fp, inst, node->right);
|
||||||
|
if (rc < 0) return rc;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0 success, <0 error
|
||||||
|
int kvs_rbtree_save(kvs_rbtree_t *inst, const char* filename){
|
||||||
|
if (!inst || !filename) return -1;
|
||||||
|
|
||||||
|
FILE *fp = fopen(filename, "wb");
|
||||||
|
if (!fp) return -2;
|
||||||
|
|
||||||
|
int rc = kvs_rbtree_save_node(fp, inst, inst->root);
|
||||||
|
|
||||||
|
if (fflush(fp) != 0) rc = -3;
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int kvs_rbtree_load(kvs_rbtree_t *inst, const char* filename){
|
||||||
|
if (!inst || !filename) return -1;
|
||||||
|
|
||||||
|
FILE *fp = fopen(filename, "rb");
|
||||||
|
if (!fp) return -2;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
uint32_t klen_n = 0, vlen_n = 0;
|
||||||
|
|
||||||
|
if (kvs_read_file(fp, &klen_n, 4) < 0) { fclose(fp); return -3; }
|
||||||
|
if (kvs_read_file(fp, &vlen_n, 4) < 0) { fclose(fp); return -3; }
|
||||||
|
|
||||||
|
uint32_t klen = ntohl(klen_n);
|
||||||
|
uint32_t vlen = ntohl(vlen_n);
|
||||||
|
|
||||||
|
if (klen == 0) { fclose(fp); return -3; }
|
||||||
|
uint8_t *keybuf = (uint8_t*)kvs_malloc((size_t)klen);
|
||||||
|
if (!keybuf) { fclose(fp); return -4; }
|
||||||
|
if (kvs_read_file(fp, keybuf, (size_t)klen) < 0) {
|
||||||
|
kvs_free(keybuf);
|
||||||
|
fclose(fp);
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *valbuf = NULL;
|
||||||
|
if (vlen > 0) {
|
||||||
|
valbuf = (uint8_t*)kvs_malloc((size_t)vlen);
|
||||||
|
if (!valbuf) {
|
||||||
|
kvs_free(keybuf);
|
||||||
|
fclose(fp);
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
if (kvs_read_file(fp, valbuf, (size_t)vlen) < 0) {
|
||||||
|
kvs_free(valbuf);
|
||||||
|
kvs_free(keybuf);
|
||||||
|
fclose(fp);
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int rc = kvs_rbtree_set(inst, keybuf, klen, valbuf, vlen);
|
||||||
|
if (vlen > 0) kvs_free(valbuf);
|
||||||
|
|
||||||
|
if (rc < 0) { // error
|
||||||
|
fclose(fp);
|
||||||
|
return -5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
495
kvs_rw_tools.c
495
kvs_rw_tools.c
@@ -17,6 +17,49 @@ extern kvs_hash_t global_hash;
|
|||||||
|
|
||||||
extern int global_cmd_log_fd;
|
extern int global_cmd_log_fd;
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
int write_full(int fd, const void *buf, size_t len)
|
||||||
|
{
|
||||||
|
const uint8_t *p = buf;
|
||||||
|
|
||||||
|
while (len > 0) {
|
||||||
|
ssize_t n = write(fd, p, len);
|
||||||
|
if (n < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
p += n;
|
||||||
|
len -= n;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1 read n suc, 0 eof, -1 error
|
||||||
|
int read_full(int fd, void *buf, size_t n)
|
||||||
|
{
|
||||||
|
uint8_t *p = (uint8_t *)buf;
|
||||||
|
size_t got = 0;
|
||||||
|
|
||||||
|
while (got < n) {
|
||||||
|
ssize_t r = read(fd, p + got, n - got);
|
||||||
|
if (r > 0) {
|
||||||
|
got += (size_t)r;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (r == 0) {
|
||||||
|
return (got == 0) ? 0 : -1;
|
||||||
|
}
|
||||||
|
/* r < 0 */
|
||||||
|
if (errno == EINTR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
// 0 suc, -1 err
|
// 0 suc, -1 err
|
||||||
int kvs_need(const uint8_t *p, const uint8_t *end, size_t n) {
|
int kvs_need(const uint8_t *p, const uint8_t *end, size_t n) {
|
||||||
return (p + n <= end) ? 0 : -1;
|
return (p + n <= end) ? 0 : -1;
|
||||||
@@ -101,455 +144,3 @@ int kvs_read_file(FILE *fp, void *buf, size_t n){
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// return: -1 fail, 0 half, >0 consumed
|
|
||||||
int kvs_parse_one_cmd(const uint8_t *request, int request_length, kvs_req_t *req_out){
|
|
||||||
if (!request || request_length <= 0 || !req_out) return -1;
|
|
||||||
|
|
||||||
req_out->op = 0;
|
|
||||||
req_out->argc = 0;
|
|
||||||
req_out->args = NULL;
|
|
||||||
|
|
||||||
const uint8_t *p = request;
|
|
||||||
const uint8_t *end = request + (size_t)request_length;
|
|
||||||
|
|
||||||
// OP + ARGC
|
|
||||||
if (kvs_need(p, end, 2)) {
|
|
||||||
return 0; // NEED_MORE
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t op = 0, argc = 0;
|
|
||||||
if (kvs_read_u8(&p, end, &op) < 0) return -1;
|
|
||||||
if (kvs_read_u8(&p, end, &argc) < 0) return -1;
|
|
||||||
|
|
||||||
if (argc > KVS_MAX_ARGC) return -1;
|
|
||||||
|
|
||||||
// 先扫描一遍确认整条命令数据都在 buffer 里
|
|
||||||
const uint8_t *scan = p;
|
|
||||||
uint32_t lens[KVS_MAX_ARGC];
|
|
||||||
if (argc > 0) {
|
|
||||||
for (uint8_t i = 0; i < argc; i++) {
|
|
||||||
if (kvs_need(scan, end, 4)) {
|
|
||||||
return 0; // NEED_MORE
|
|
||||||
}
|
|
||||||
uint32_t alen = 0;
|
|
||||||
if (kvs_read_u32(&scan, end, &alen) < 0) return -1;
|
|
||||||
|
|
||||||
// 防御:单个参数长度限制
|
|
||||||
if (alen > KVS_MAX_ARGLEN) return -1;
|
|
||||||
|
|
||||||
// 防御:scan + alen 越界 / 半包
|
|
||||||
if (kvs_need(scan, end, (size_t)alen)) {
|
|
||||||
return 0; // NEED_MORE
|
|
||||||
}
|
|
||||||
lens[i] = alen;
|
|
||||||
scan += alen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t total_len = (size_t)(scan - request);
|
|
||||||
if (total_len > KVS_MAX_CMD_BYTES) return -1;
|
|
||||||
|
|
||||||
req_out->op = op;
|
|
||||||
req_out->argc = argc;
|
|
||||||
|
|
||||||
if (argc == 0) {
|
|
||||||
return (int)total_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
kvs_arg_t *args = (kvs_arg_t *)kvs_malloc((size_t)argc * sizeof(kvs_arg_t));
|
|
||||||
if (!args) {
|
|
||||||
kvs_free_request(req_out);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
memset(args, 0, (size_t)argc * sizeof(kvs_arg_t));
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < argc; i++) {
|
|
||||||
uint32_t alen = 0;
|
|
||||||
if (kvs_read_u32(&p, end, &alen) < 0) {
|
|
||||||
kvs_free(args);
|
|
||||||
kvs_free_request(req_out);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// alen 与 lens[i] 应当一致(扫描时读过),不一致说明解析器/输入异常
|
|
||||||
if (alen != lens[i]) {
|
|
||||||
kvs_free(args);
|
|
||||||
kvs_free_request(req_out);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
args[i].len = alen;
|
|
||||||
args[i].data = p; // 直接指向输入 buffer(零拷贝)
|
|
||||||
p += alen;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
req_out->args = args;
|
|
||||||
|
|
||||||
return (int)(p - request);
|
|
||||||
}
|
|
||||||
|
|
||||||
void kvs_free_request(kvs_req_t *req) {
|
|
||||||
if (!req) return;
|
|
||||||
if (req->args) {
|
|
||||||
kvs_free(req->args);
|
|
||||||
req->args = NULL;
|
|
||||||
}
|
|
||||||
req->op = 0;
|
|
||||||
req->argc = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 输入:req
|
|
||||||
* 输出:rsp
|
|
||||||
* 返回:-1 失败,参数错误,0 成功
|
|
||||||
*/
|
|
||||||
int kvs_execute_one_cmd(const kvs_req_t *req, kvs_rsp_t *rsp_out) {
|
|
||||||
if(!req || !rsp_out) return -1;
|
|
||||||
rsp_out->op = req->op;
|
|
||||||
rsp_out->status = KVS_STATUS_ERROR;
|
|
||||||
rsp_out->data = NULL;
|
|
||||||
rsp_out->dlen = 0;
|
|
||||||
|
|
||||||
int argc = req->argc;
|
|
||||||
int op = req->op;
|
|
||||||
kvs_arg_t *argv = req->args;
|
|
||||||
|
|
||||||
uint32_t key_len = 0;
|
|
||||||
const void *key = NULL;
|
|
||||||
uint32_t value_len = 0;
|
|
||||||
const void *val = NULL;
|
|
||||||
|
|
||||||
if(argc == 1){
|
|
||||||
key_len = argv[0].len;
|
|
||||||
key = argv[0].data;
|
|
||||||
}else if(argc == 2){
|
|
||||||
key_len = argv[0].len;
|
|
||||||
key = argv[0].data;
|
|
||||||
value_len = argv[1].len;
|
|
||||||
val = argv[1].data;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 基本参数校验(按你原有命令语义)
|
|
||||||
switch (op) {
|
|
||||||
case KVS_CMD_SET:
|
|
||||||
case KVS_CMD_MOD:
|
|
||||||
case KVS_CMD_RSET:
|
|
||||||
case KVS_CMD_RMOD:
|
|
||||||
case KVS_CMD_HSET:
|
|
||||||
case KVS_CMD_HMOD:
|
|
||||||
if (argc != 2 || !key || !val) { rsp_out->status = KVS_STATUS_BADREQ; return -1; }
|
|
||||||
break;
|
|
||||||
case KVS_CMD_GET:
|
|
||||||
case KVS_CMD_DEL:
|
|
||||||
case KVS_CMD_EXIST:
|
|
||||||
case KVS_CMD_RGET:
|
|
||||||
case KVS_CMD_RDEL:
|
|
||||||
case KVS_CMD_REXIST:
|
|
||||||
case KVS_CMD_HGET:
|
|
||||||
case KVS_CMD_HDEL:
|
|
||||||
case KVS_CMD_HEXIST:
|
|
||||||
if (argc != 1 || !key) { rsp_out->status = KVS_STATUS_BADREQ; return -1; }
|
|
||||||
break;
|
|
||||||
case KVS_CMD_SAVE:
|
|
||||||
if(argc != 0) { rsp_out->status = KVS_STATUS_BADREQ; return -1; }
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
rsp_out->status = KVS_STATUS_BADREQ;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ret = 0;
|
|
||||||
const char *result = NULL;
|
|
||||||
|
|
||||||
switch (op) {
|
|
||||||
#if ENABLE_ARRAY
|
|
||||||
case KVS_CMD_SET:
|
|
||||||
ret = kvs_array_set_bin(&global_array, key, key_len, val, value_len);
|
|
||||||
if (ret < 0) rsp_out->status = KVS_STATUS_ERROR;
|
|
||||||
else if (ret == 0) rsp_out->status = KVS_STATUS_OK;
|
|
||||||
else rsp_out->status = KVS_STATUS_EXIST;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case KVS_CMD_GET:
|
|
||||||
result = kvs_array_get_bin(&global_array, key, key_len, &value_len);
|
|
||||||
if (!result) { rsp_out->status = KVS_STATUS_NO_EXIST; return 0; }
|
|
||||||
rsp_out->status = KVS_STATUS_OK;
|
|
||||||
rsp_out->data = result;
|
|
||||||
rsp_out->dlen = (uint32_t)value_len;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case KVS_CMD_DEL:
|
|
||||||
ret = kvs_array_del_bin(&global_array, key, key_len);
|
|
||||||
if (ret < 0) rsp_out->status = KVS_STATUS_ERROR;
|
|
||||||
else if (ret == 0) rsp_out->status = KVS_STATUS_OK;
|
|
||||||
else rsp_out->status = KVS_STATUS_NO_EXIST;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case KVS_CMD_MOD:
|
|
||||||
ret = kvs_array_mod_bin(&global_array, key, key_len, val, value_len);
|
|
||||||
if (ret < 0) rsp_out->status = KVS_STATUS_ERROR;
|
|
||||||
else if (ret == 0) rsp_out->status = KVS_STATUS_OK;
|
|
||||||
else rsp_out->status = KVS_STATUS_NO_EXIST;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case KVS_CMD_EXIST:
|
|
||||||
ret = kvs_array_exist_bin(&global_array, key, key_len);
|
|
||||||
rsp_out->status = (ret == 0) ? KVS_STATUS_EXIST : KVS_STATUS_NO_EXIST;
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ENABLE_RBTREE
|
|
||||||
case KVS_CMD_RSET:
|
|
||||||
ret = kvs_rbtree_set(&global_rbtree, (char*)key, (char*)val);
|
|
||||||
if (ret < 0) rsp_out->status = KVS_STATUS_ERROR;
|
|
||||||
else if (ret == 0) rsp_out->status = KVS_STATUS_OK;
|
|
||||||
else rsp_out->status = KVS_STATUS_EXIST;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case KVS_CMD_RGET:
|
|
||||||
result = kvs_rbtree_get(&global_rbtree, (char*)key);
|
|
||||||
if (!result) { rsp_out->status = KVS_STATUS_NO_EXIST; return 0; }
|
|
||||||
rsp_out->status = KVS_STATUS_OK;
|
|
||||||
rsp_out->data = result;
|
|
||||||
rsp_out->dlen = (uint32_t)strlen(result);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case KVS_CMD_RDEL:
|
|
||||||
ret = kvs_rbtree_del(&global_rbtree, (char*)key);
|
|
||||||
if (ret < 0) rsp_out->status = KVS_STATUS_ERROR;
|
|
||||||
else if (ret == 0) rsp_out->status = KVS_STATUS_OK;
|
|
||||||
else rsp_out->status = KVS_STATUS_NO_EXIST;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case KVS_CMD_RMOD:
|
|
||||||
ret = kvs_rbtree_mod(&global_rbtree, (char*)key, (char*)val);
|
|
||||||
if (ret < 0) rsp_out->status = KVS_STATUS_ERROR;
|
|
||||||
else if (ret == 0) rsp_out->status = KVS_STATUS_OK;
|
|
||||||
else rsp_out->status = KVS_STATUS_NO_EXIST;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case KVS_CMD_REXIST:
|
|
||||||
ret = kvs_rbtree_exist(&global_rbtree, (char*)key);
|
|
||||||
rsp_out->status = (ret == 0) ? KVS_STATUS_EXIST : KVS_STATUS_NO_EXIST;
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ENABLE_HASH
|
|
||||||
case KVS_CMD_HSET:
|
|
||||||
ret = kvs_hash_set_bin(&global_hash, key, key_len, val, value_len);
|
|
||||||
if (ret < 0) rsp_out->status = KVS_STATUS_ERROR;
|
|
||||||
else if (ret == 0) rsp_out->status = KVS_STATUS_OK;
|
|
||||||
else rsp_out->status = KVS_STATUS_EXIST;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case KVS_CMD_HGET:
|
|
||||||
result = kvs_hash_get_bin(&global_hash, key, key_len, &value_len);
|
|
||||||
if (!result) { rsp_out->status = KVS_STATUS_NO_EXIST; return 0; }
|
|
||||||
rsp_out->status = KVS_STATUS_OK;
|
|
||||||
rsp_out->data = result;
|
|
||||||
rsp_out->dlen = (uint32_t)value_len;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case KVS_CMD_HDEL:
|
|
||||||
ret = kvs_hash_del_bin(&global_hash, key, key_len);
|
|
||||||
if (ret < 0) rsp_out->status = KVS_STATUS_ERROR;
|
|
||||||
else if (ret == 0) rsp_out->status = KVS_STATUS_OK;
|
|
||||||
else rsp_out->status = KVS_STATUS_NO_EXIST;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case KVS_CMD_HMOD:
|
|
||||||
ret = kvs_hash_mod_bin(&global_hash, key, key_len, val, value_len);
|
|
||||||
if (ret < 0) rsp_out->status = KVS_STATUS_ERROR;
|
|
||||||
else if (ret == 0) rsp_out->status = KVS_STATUS_OK;
|
|
||||||
else rsp_out->status = KVS_STATUS_NO_EXIST;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case KVS_CMD_HEXIST:
|
|
||||||
ret = kvs_hash_exist_bin(&global_hash, key, key_len);
|
|
||||||
rsp_out->status = (ret == 0) ? KVS_STATUS_EXIST : KVS_STATUS_NO_EXIST;
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
case KVS_CMD_SAVE:
|
|
||||||
ret = kvs_save_to_file();
|
|
||||||
if(ret == 0) rsp_out->status = KVS_STATUS_OK;
|
|
||||||
else rsp_out->status = KVS_STATUS_ERROR;
|
|
||||||
return 0;
|
|
||||||
default:
|
|
||||||
rsp_out->status = KVS_STATUS_BADREQ;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建单条响应
|
|
||||||
* 返回:-1 失败,>=0 响应长度
|
|
||||||
*/
|
|
||||||
int kvs_build_one_rsp(const kvs_rsp_t *results, uint8_t *response, size_t response_cap){
|
|
||||||
if (!results || !response) return -1;
|
|
||||||
|
|
||||||
const uint8_t *end = response + response_cap;
|
|
||||||
uint8_t *p = response;
|
|
||||||
|
|
||||||
// 计算所需长度:1 + 1 + 4 + dlen
|
|
||||||
// 注意防止 size_t 溢出
|
|
||||||
size_t need = 1u + 1u + 4u + (size_t)results->dlen;
|
|
||||||
if (need > response_cap) return -1;
|
|
||||||
|
|
||||||
if (kvs_write_u8(&p, end, results->op) < 0) return -1;
|
|
||||||
if (kvs_write_u8(&p, end, results->status) < 0) return -1;
|
|
||||||
if (kvs_write_u32(&p, end, results->dlen) < 0) return -1;
|
|
||||||
|
|
||||||
if (results->dlen > 0) {
|
|
||||||
if (!results->data) return -1; // 有长度却没指针,视为错误
|
|
||||||
if (kvs_need(p, end, (size_t)results->dlen) < 0) return -1;
|
|
||||||
memcpy(p, results->data, results->dlen);
|
|
||||||
p += results->dlen;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (int)(p - response);
|
|
||||||
}
|
|
||||||
|
|
||||||
int kvs_save_to_file(){
|
|
||||||
#if ENABLE_ARRAY
|
|
||||||
int ret = kvs_array_save(&global_array, KVS_ARRAY_FILE);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ENABLE_RBTREE
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ENABLE_HASH
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ksv_clear_log(global_cmd_log_fd);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
int write_full(int fd, const void *buf, size_t len)
|
|
||||||
{
|
|
||||||
const uint8_t *p = buf;
|
|
||||||
|
|
||||||
while (len > 0) {
|
|
||||||
ssize_t n = write(fd, p, len);
|
|
||||||
if (n < 0) {
|
|
||||||
if (errno == EINTR)
|
|
||||||
continue;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
p += n;
|
|
||||||
len -= n;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1 read n suc, 0 eof, -1 error
|
|
||||||
int read_full(int fd, void *buf, size_t n)
|
|
||||||
{
|
|
||||||
uint8_t *p = (uint8_t *)buf;
|
|
||||||
size_t got = 0;
|
|
||||||
|
|
||||||
while (got < n) {
|
|
||||||
ssize_t r = read(fd, p + got, n - got);
|
|
||||||
if (r > 0) {
|
|
||||||
got += (size_t)r;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (r == 0) {
|
|
||||||
return (got == 0) ? 0 : -1;
|
|
||||||
}
|
|
||||||
/* r < 0 */
|
|
||||||
if (errno == EINTR) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int kvs_save_cmd_to_logfile(const uint8_t *cmd, size_t len, int logfd){
|
|
||||||
if (logfd < 0 || !cmd || len == 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (len > UINT32_MAX)
|
|
||||||
return -2;
|
|
||||||
|
|
||||||
uint32_t nlen = htonl((uint32_t)len);
|
|
||||||
|
|
||||||
if (write_full(logfd, &nlen, sizeof(nlen)) < 0)
|
|
||||||
return -3;
|
|
||||||
|
|
||||||
if (write_full(logfd, cmd, len) < 0)
|
|
||||||
return -4;
|
|
||||||
|
|
||||||
if (fsync(logfd) < 0)
|
|
||||||
return -5;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int kvs_replay_log(const char *logfile, int logfd){
|
|
||||||
if (!logfile|| logfd<0) return -1;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
uint32_t nlen = 0;
|
|
||||||
|
|
||||||
int hr = read_full(logfd, &nlen, sizeof(nlen));
|
|
||||||
if (hr == 0) break; /* EOF:正常结束 */
|
|
||||||
if (hr < 0) { return -2; } /* 半截头 */
|
|
||||||
|
|
||||||
uint32_t len = ntohl(nlen);
|
|
||||||
if (len == 0) { return -3; }
|
|
||||||
|
|
||||||
uint8_t *cmd = (uint8_t *)kvs_malloc(len);
|
|
||||||
if (!cmd) { return -5; }
|
|
||||||
|
|
||||||
int pr = read_full(logfd, cmd, len);
|
|
||||||
if (pr <= 0) { /* 半截 payload */
|
|
||||||
kvs_free(cmd);
|
|
||||||
return -6;
|
|
||||||
}
|
|
||||||
|
|
||||||
kvs_req_t req;
|
|
||||||
memset(&req, 0, sizeof(req));
|
|
||||||
|
|
||||||
int clen = kvs_parse_one_cmd(cmd, (int)len, &req);
|
|
||||||
if (clen <= 0 || clen != (int)len) {
|
|
||||||
kvs_free_request(&req);
|
|
||||||
kvs_free(cmd);
|
|
||||||
return -7;
|
|
||||||
}
|
|
||||||
|
|
||||||
kvs_rsp_t rsp;
|
|
||||||
memset(&rsp, 0, sizeof(rsp));
|
|
||||||
|
|
||||||
if (kvs_execute_one_cmd(&req, &rsp) < 0) {
|
|
||||||
kvs_free_request(&req);
|
|
||||||
kvs_free(cmd);
|
|
||||||
return -8;
|
|
||||||
}
|
|
||||||
|
|
||||||
kvs_free_request(&req);
|
|
||||||
kvs_free(cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* clear log file not close
|
|
||||||
*/
|
|
||||||
int ksv_clear_log(int logfd){
|
|
||||||
if(logfd < 0) return -1;
|
|
||||||
ftruncate(logfd, 0);
|
|
||||||
lseek(logfd, 0, SEEK_SET);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -16,6 +16,8 @@ int kvs_write_u32(uint8_t **pp, const uint8_t *end, uint32_t v);
|
|||||||
int kvs_write_file(FILE *fp, const void *buf, size_t n);
|
int kvs_write_file(FILE *fp, const void *buf, size_t n);
|
||||||
int kvs_read_file(FILE *fp, void *buf, size_t n);
|
int kvs_read_file(FILE *fp, void *buf, size_t n);
|
||||||
|
|
||||||
|
int write_full(int fd, const void *buf, size_t len);
|
||||||
|
int read_full(int fd, void *buf, size_t n);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request
|
* Request
|
||||||
@@ -39,7 +41,7 @@ enum {
|
|||||||
KVS_STATUS_BADREQ = 4
|
KVS_STATUS_BADREQ = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
typedef enum {
|
||||||
KVS_CMD_START = 0,
|
KVS_CMD_START = 0,
|
||||||
// array
|
// array
|
||||||
KVS_CMD_SET = KVS_CMD_START,
|
KVS_CMD_SET = KVS_CMD_START,
|
||||||
@@ -62,7 +64,7 @@ enum {
|
|||||||
|
|
||||||
KVS_CMD_SAVE,
|
KVS_CMD_SAVE,
|
||||||
KVS_CMD_COUNT,
|
KVS_CMD_COUNT,
|
||||||
};
|
}kvs_cmd_t;
|
||||||
|
|
||||||
typedef struct kvs_arg_s{
|
typedef struct kvs_arg_s{
|
||||||
uint32_t len;
|
uint32_t len;
|
||||||
@@ -70,13 +72,13 @@ typedef struct kvs_arg_s{
|
|||||||
} kvs_arg_t;
|
} kvs_arg_t;
|
||||||
|
|
||||||
typedef struct kvs_req_s{
|
typedef struct kvs_req_s{
|
||||||
uint8_t op;
|
kvs_cmd_t op;
|
||||||
uint8_t argc;
|
uint8_t argc;
|
||||||
kvs_arg_t *args;
|
kvs_arg_t *args;
|
||||||
}kvs_req_t;
|
}kvs_req_t;
|
||||||
|
|
||||||
typedef struct kvs_rsp_s{
|
typedef struct kvs_rsp_s{
|
||||||
uint8_t op;
|
kvs_cmd_t op;
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
uint32_t dlen;
|
uint32_t dlen;
|
||||||
const uint8_t *data;
|
const uint8_t *data;
|
||||||
|
|||||||
511
kvstore.c
511
kvstore.c
@@ -42,211 +42,350 @@ const char *response[] = {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// return: -1 fail, 0 half, >0 consumed
|
||||||
|
int kvs_parse_one_cmd(const uint8_t *request, int request_length, kvs_req_t *req_out){
|
||||||
|
if (!request || request_length <= 0 || !req_out) return -1;
|
||||||
|
|
||||||
int kvs_split_token(char *msg, char *tokens[]) {
|
req_out->op = KVS_CMD_COUNT;
|
||||||
|
req_out->argc = 0;
|
||||||
|
req_out->args = NULL;
|
||||||
|
|
||||||
if (msg == NULL || tokens == NULL) return -1;
|
const uint8_t *p = request;
|
||||||
|
const uint8_t *end = request + (size_t)request_length;
|
||||||
|
|
||||||
int idx = 0;
|
// OP + ARGC
|
||||||
char *token = strtok(msg, " ");
|
if (kvs_need(p, end, 2)) {
|
||||||
|
return 0; // NEED_MORE
|
||||||
while (token != NULL) {
|
|
||||||
//printf("idx: %d, %s\n", idx, token);
|
|
||||||
|
|
||||||
tokens[idx ++] = token;
|
|
||||||
token = strtok(NULL, " ");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return idx;
|
uint8_t op = 0, argc = 0;
|
||||||
|
if (kvs_read_u8(&p, end, &op) < 0) return -1;
|
||||||
|
if (kvs_read_u8(&p, end, &argc) < 0) return -1;
|
||||||
|
|
||||||
|
if (argc > KVS_MAX_ARGC) return -1;
|
||||||
|
|
||||||
|
// 先扫描一遍确认整条命令数据都在 buffer 里
|
||||||
|
const uint8_t *scan = p;
|
||||||
|
uint32_t lens[KVS_MAX_ARGC];
|
||||||
|
if (argc > 0) {
|
||||||
|
for (uint8_t i = 0; i < argc; i++) {
|
||||||
|
if (kvs_need(scan, end, 4)) {
|
||||||
|
return 0; // NEED_MORE
|
||||||
|
}
|
||||||
|
uint32_t alen = 0;
|
||||||
|
if (kvs_read_u32(&scan, end, &alen) < 0) return -1;
|
||||||
|
|
||||||
|
// 防御:单个参数长度限制
|
||||||
|
if (alen > KVS_MAX_ARGLEN) return -1;
|
||||||
|
|
||||||
|
// 防御:scan + alen 越界 / 半包
|
||||||
|
if (kvs_need(scan, end, (size_t)alen)) {
|
||||||
|
return 0; // NEED_MORE
|
||||||
|
}
|
||||||
|
lens[i] = alen;
|
||||||
|
scan += alen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t total_len = (size_t)(scan - request);
|
||||||
|
if (total_len > KVS_MAX_CMD_BYTES) return -1;
|
||||||
|
|
||||||
|
req_out->op = op;
|
||||||
|
req_out->argc = argc;
|
||||||
|
|
||||||
|
if (argc == 0) {
|
||||||
|
return (int)total_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
kvs_arg_t *args = (kvs_arg_t *)kvs_malloc((size_t)argc * sizeof(kvs_arg_t));
|
||||||
|
if (!args) {
|
||||||
|
kvs_free_request(req_out);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memset(args, 0, (size_t)argc * sizeof(kvs_arg_t));
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < argc; i++) {
|
||||||
|
uint32_t alen = 0;
|
||||||
|
if (kvs_read_u32(&p, end, &alen) < 0) {
|
||||||
|
kvs_free(args);
|
||||||
|
kvs_free_request(req_out);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// alen 与 lens[i] 应当一致(扫描时读过),不一致说明解析器/输入异常
|
||||||
|
if (alen != lens[i]) {
|
||||||
|
kvs_free(args);
|
||||||
|
kvs_free_request(req_out);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
args[i].len = alen;
|
||||||
|
args[i].data = p; // 直接指向输入 buffer(零拷贝)
|
||||||
|
p += alen;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
req_out->args = args;
|
||||||
|
|
||||||
|
return (int)(p - request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void kvs_free_request(kvs_req_t *req) {
|
||||||
|
if (!req) return;
|
||||||
|
if (req->args) {
|
||||||
|
kvs_free(req->args);
|
||||||
|
req->args = NULL;
|
||||||
|
}
|
||||||
|
req->op = KVS_CMD_COUNT;
|
||||||
|
req->argc = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// SET Key Value
|
/**
|
||||||
// tokens[0] : SET
|
* 输入:req
|
||||||
// tokens[1] : Key
|
* 输出:rsp
|
||||||
// tokens[2] : Value
|
* 返回:-1 失败,参数错误,0 成功
|
||||||
|
*/
|
||||||
|
int kvs_execute_one_cmd(const kvs_req_t *req, kvs_rsp_t *rsp_out) {
|
||||||
|
if(!req || !rsp_out) return -1;
|
||||||
|
rsp_out->op = req->op;
|
||||||
|
rsp_out->status = KVS_STATUS_ERROR;
|
||||||
|
rsp_out->data = NULL;
|
||||||
|
rsp_out->dlen = 0;
|
||||||
|
|
||||||
#if !BIN_SAFE
|
int argc = req->argc;
|
||||||
int kvs_filter_protocol(char **tokens, int count, char *response) {
|
kvs_cmd_t op = req->op;
|
||||||
|
kvs_arg_t *argv = req->args;
|
||||||
|
|
||||||
if (tokens[0] == NULL || count == 0 || response == NULL) return -1;
|
uint32_t key_len = 0;
|
||||||
|
const void *key = NULL;
|
||||||
|
uint32_t value_len = 0;
|
||||||
|
const void *val = NULL;
|
||||||
|
|
||||||
int cmd = KVS_CMD_START;
|
if(argc == 1){
|
||||||
for (cmd = KVS_CMD_START;cmd < KVS_CMD_COUNT;cmd ++) {
|
key_len = argv[0].len;
|
||||||
if (strcmp(tokens[0], command[cmd]) == 0) {
|
key = argv[0].data;
|
||||||
|
}else if(argc == 2){
|
||||||
|
key_len = argv[0].len;
|
||||||
|
key = argv[0].data;
|
||||||
|
value_len = argv[1].len;
|
||||||
|
val = argv[1].data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 基本参数校验(按你原有命令语义)
|
||||||
|
switch (op) {
|
||||||
|
case KVS_CMD_SET:
|
||||||
|
case KVS_CMD_MOD:
|
||||||
|
case KVS_CMD_RSET:
|
||||||
|
case KVS_CMD_RMOD:
|
||||||
|
case KVS_CMD_HSET:
|
||||||
|
case KVS_CMD_HMOD:
|
||||||
|
if (argc != 2 || !key || !val) { rsp_out->status = KVS_STATUS_BADREQ; return -1; }
|
||||||
break;
|
break;
|
||||||
}
|
case KVS_CMD_GET:
|
||||||
|
case KVS_CMD_DEL:
|
||||||
|
case KVS_CMD_EXIST:
|
||||||
|
case KVS_CMD_RGET:
|
||||||
|
case KVS_CMD_RDEL:
|
||||||
|
case KVS_CMD_REXIST:
|
||||||
|
case KVS_CMD_HGET:
|
||||||
|
case KVS_CMD_HDEL:
|
||||||
|
case KVS_CMD_HEXIST:
|
||||||
|
if (argc != 1 || !key) { rsp_out->status = KVS_STATUS_BADREQ; return -1; }
|
||||||
|
break;
|
||||||
|
case KVS_CMD_SAVE:
|
||||||
|
if(argc != 0) { rsp_out->status = KVS_STATUS_BADREQ; return -1; }
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rsp_out->status = KVS_STATUS_BADREQ;
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int length = 0;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
char *key = tokens[1];
|
const char *result = NULL;
|
||||||
char *value = tokens[2];
|
|
||||||
|
|
||||||
switch(cmd) {
|
switch (op) {
|
||||||
#if ENABLE_ARRAY
|
#if ENABLE_ARRAY
|
||||||
case KVS_CMD_SET:
|
case KVS_CMD_SET:
|
||||||
ret = kvs_array_set(&global_array ,key, value);
|
ret = kvs_array_set_bin(&global_array, key, key_len, val, value_len);
|
||||||
if (ret < 0) {
|
if (ret < 0) rsp_out->status = KVS_STATUS_ERROR;
|
||||||
length = sprintf(response, "ERROR\r\n");
|
else if (ret == 0) rsp_out->status = KVS_STATUS_OK;
|
||||||
} else if (ret == 0) {
|
else rsp_out->status = KVS_STATUS_EXIST;
|
||||||
length = sprintf(response, "OK\r\n");
|
return 0;
|
||||||
} else {
|
|
||||||
length = sprintf(response, "EXIST\r\n");
|
case KVS_CMD_GET:
|
||||||
}
|
result = kvs_array_get_bin(&global_array, key, key_len, &value_len);
|
||||||
|
if (!result) { rsp_out->status = KVS_STATUS_NO_EXIST; return 0; }
|
||||||
|
rsp_out->status = KVS_STATUS_OK;
|
||||||
|
rsp_out->data = (uint8_t*)result;
|
||||||
|
rsp_out->dlen = (uint32_t)value_len;
|
||||||
|
return 0;
|
||||||
|
|
||||||
break;
|
|
||||||
case KVS_CMD_GET: {
|
|
||||||
char *result = kvs_array_get(&global_array, key);
|
|
||||||
if (result == NULL) {
|
|
||||||
length = sprintf(response, "NO EXIST\r\n");
|
|
||||||
} else {
|
|
||||||
length = sprintf(response, "%s\r\n", result);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case KVS_CMD_DEL:
|
case KVS_CMD_DEL:
|
||||||
ret = kvs_array_del(&global_array ,key);
|
ret = kvs_array_del_bin(&global_array, key, key_len);
|
||||||
if (ret < 0) {
|
if (ret < 0) rsp_out->status = KVS_STATUS_ERROR;
|
||||||
length = sprintf(response, "ERROR\r\n");
|
else if (ret == 0) rsp_out->status = KVS_STATUS_OK;
|
||||||
} else if (ret == 0) {
|
else rsp_out->status = KVS_STATUS_NO_EXIST;
|
||||||
length = sprintf(response, "OK\r\n");
|
return 0;
|
||||||
} else {
|
|
||||||
length = sprintf(response, "NO EXIST\r\n");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case KVS_CMD_MOD:
|
case KVS_CMD_MOD:
|
||||||
ret = kvs_array_mod(&global_array ,key, value);
|
ret = kvs_array_mod_bin(&global_array, key, key_len, val, value_len);
|
||||||
if (ret < 0) {
|
if (ret < 0) rsp_out->status = KVS_STATUS_ERROR;
|
||||||
length = sprintf(response, "ERROR\r\n");
|
else if (ret == 0) rsp_out->status = KVS_STATUS_OK;
|
||||||
} else if (ret == 0) {
|
else rsp_out->status = KVS_STATUS_NO_EXIST;
|
||||||
length = sprintf(response, "OK\r\n");
|
return 0;
|
||||||
} else {
|
|
||||||
length = sprintf(response, "NO EXIST\r\n");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case KVS_CMD_EXIST:
|
case KVS_CMD_EXIST:
|
||||||
ret = kvs_array_exist(&global_array ,key);
|
ret = kvs_array_exist_bin(&global_array, key, key_len);
|
||||||
if (ret == 0) {
|
rsp_out->status = (ret == 0) ? KVS_STATUS_EXIST : KVS_STATUS_NO_EXIST;
|
||||||
length = sprintf(response, "EXIST\r\n");
|
return 0;
|
||||||
} else {
|
|
||||||
length = sprintf(response, "NO EXIST\r\n");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
// rbtree
|
|
||||||
#if ENABLE_RBTREE
|
#if ENABLE_RBTREE
|
||||||
case KVS_CMD_RSET:
|
case KVS_CMD_RSET:
|
||||||
ret = kvs_rbtree_set(&global_rbtree ,key, value);
|
ret = kvs_rbtree_set(&global_rbtree, key, key_len, val, value_len);
|
||||||
if (ret < 0) {
|
if (ret < 0) rsp_out->status = KVS_STATUS_ERROR;
|
||||||
length = sprintf(response, "ERROR\r\n");
|
else if (ret == 0) rsp_out->status = KVS_STATUS_OK;
|
||||||
} else if (ret == 0) {
|
else rsp_out->status = KVS_STATUS_EXIST;
|
||||||
length = sprintf(response, "OK\r\n");
|
return 0;
|
||||||
} else {
|
|
||||||
length = sprintf(response, "EXIST\r\n");
|
case KVS_CMD_RGET:
|
||||||
}
|
result = kvs_rbtree_get(&global_rbtree, key, key_len, &value_len);
|
||||||
|
if (!result) { rsp_out->status = KVS_STATUS_NO_EXIST; return 0; }
|
||||||
|
rsp_out->status = KVS_STATUS_OK;
|
||||||
|
rsp_out->data = (uint8_t*)result;
|
||||||
|
rsp_out->dlen = (uint32_t)value_len;
|
||||||
|
return 0;
|
||||||
|
|
||||||
break;
|
|
||||||
case KVS_CMD_RGET: {
|
|
||||||
char *result = kvs_rbtree_get(&global_rbtree, key);
|
|
||||||
if (result == NULL) {
|
|
||||||
length = sprintf(response, "NO EXIST\r\n");
|
|
||||||
} else {
|
|
||||||
length = sprintf(response, "%s\r\n", result);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case KVS_CMD_RDEL:
|
case KVS_CMD_RDEL:
|
||||||
ret = kvs_rbtree_del(&global_rbtree ,key);
|
ret = kvs_rbtree_del(&global_rbtree, key, key_len);
|
||||||
if (ret < 0) {
|
if (ret < 0) rsp_out->status = KVS_STATUS_ERROR;
|
||||||
length = sprintf(response, "ERROR\r\n");
|
else if (ret == 0) rsp_out->status = KVS_STATUS_OK;
|
||||||
} else if (ret == 0) {
|
else rsp_out->status = KVS_STATUS_NO_EXIST;
|
||||||
length = sprintf(response, "OK\r\n");
|
return 0;
|
||||||
} else {
|
|
||||||
length = sprintf(response, "NO EXIST\r\n");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case KVS_CMD_RMOD:
|
case KVS_CMD_RMOD:
|
||||||
ret = kvs_rbtree_mod(&global_rbtree ,key, value);
|
ret = kvs_rbtree_mod(&global_rbtree, key, key_len, val, value_len);
|
||||||
if (ret < 0) {
|
if (ret < 0) rsp_out->status = KVS_STATUS_ERROR;
|
||||||
length = sprintf(response, "ERROR\r\n");
|
else if (ret == 0) rsp_out->status = KVS_STATUS_OK;
|
||||||
} else if (ret == 0) {
|
else rsp_out->status = KVS_STATUS_NO_EXIST;
|
||||||
length = sprintf(response, "OK\r\n");
|
return 0;
|
||||||
} else {
|
|
||||||
length = sprintf(response, "NO EXIST\r\n");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case KVS_CMD_REXIST:
|
case KVS_CMD_REXIST:
|
||||||
ret = kvs_rbtree_exist(&global_rbtree ,key);
|
ret = kvs_rbtree_exist(&global_rbtree, key, key_len);
|
||||||
if (ret == 0) {
|
rsp_out->status = (ret == 0) ? KVS_STATUS_EXIST : KVS_STATUS_NO_EXIST;
|
||||||
length = sprintf(response, "EXIST\r\n");
|
return 0;
|
||||||
} else {
|
|
||||||
length = sprintf(response, "NO EXIST\r\n");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ENABLE_HASH
|
#if ENABLE_HASH
|
||||||
case KVS_CMD_HSET:
|
case KVS_CMD_HSET:
|
||||||
ret = kvs_hash_set(&global_hash ,key, value);
|
ret = kvs_hash_set_bin(&global_hash, key, key_len, val, value_len);
|
||||||
if (ret < 0) {
|
if (ret < 0) rsp_out->status = KVS_STATUS_ERROR;
|
||||||
length = sprintf(response, "ERROR\r\n");
|
else if (ret == 0) rsp_out->status = KVS_STATUS_OK;
|
||||||
} else if (ret == 0) {
|
else rsp_out->status = KVS_STATUS_EXIST;
|
||||||
length = sprintf(response, "OK\r\n");
|
return 0;
|
||||||
} else {
|
|
||||||
length = sprintf(response, "EXIST\r\n");
|
case KVS_CMD_HGET:
|
||||||
}
|
result = kvs_hash_get_bin(&global_hash, key, key_len, &value_len);
|
||||||
|
if (!result) { rsp_out->status = KVS_STATUS_NO_EXIST; return 0; }
|
||||||
|
rsp_out->status = KVS_STATUS_OK;
|
||||||
|
rsp_out->data = (uint8_t*)result;
|
||||||
|
rsp_out->dlen = (uint32_t)value_len;
|
||||||
|
return 0;
|
||||||
|
|
||||||
break;
|
|
||||||
case KVS_CMD_HGET: {
|
|
||||||
char *result = kvs_hash_get(&global_hash, key);
|
|
||||||
if (result == NULL) {
|
|
||||||
length = sprintf(response, "NO EXIST\r\n");
|
|
||||||
} else {
|
|
||||||
length = sprintf(response, "%s\r\n", result);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case KVS_CMD_HDEL:
|
case KVS_CMD_HDEL:
|
||||||
ret = kvs_hash_del(&global_hash ,key);
|
ret = kvs_hash_del_bin(&global_hash, key, key_len);
|
||||||
if (ret < 0) {
|
if (ret < 0) rsp_out->status = KVS_STATUS_ERROR;
|
||||||
length = sprintf(response, "ERROR\r\n");
|
else if (ret == 0) rsp_out->status = KVS_STATUS_OK;
|
||||||
} else if (ret == 0) {
|
else rsp_out->status = KVS_STATUS_NO_EXIST;
|
||||||
length = sprintf(response, "OK\r\n");
|
return 0;
|
||||||
} else {
|
|
||||||
length = sprintf(response, "NO EXIST\r\n");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case KVS_CMD_HMOD:
|
case KVS_CMD_HMOD:
|
||||||
ret = kvs_hash_mod(&global_hash ,key, value);
|
ret = kvs_hash_mod_bin(&global_hash, key, key_len, val, value_len);
|
||||||
if (ret < 0) {
|
if (ret < 0) rsp_out->status = KVS_STATUS_ERROR;
|
||||||
length = sprintf(response, "ERROR\r\n");
|
else if (ret == 0) rsp_out->status = KVS_STATUS_OK;
|
||||||
} else if (ret == 0) {
|
else rsp_out->status = KVS_STATUS_NO_EXIST;
|
||||||
length = sprintf(response, "OK\r\n");
|
return 0;
|
||||||
} else {
|
|
||||||
length = sprintf(response, "NO EXIST\r\n");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case KVS_CMD_HEXIST:
|
case KVS_CMD_HEXIST:
|
||||||
ret = kvs_hash_exist(&global_hash ,key);
|
ret = kvs_hash_exist_bin(&global_hash, key, key_len);
|
||||||
if (ret == 0) {
|
rsp_out->status = (ret == 0) ? KVS_STATUS_EXIST : KVS_STATUS_NO_EXIST;
|
||||||
length = sprintf(response, "EXIST\r\n");
|
return 0;
|
||||||
} else {
|
|
||||||
length = sprintf(response, "NO EXIST\r\n");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
|
case KVS_CMD_SAVE:
|
||||||
|
ret = kvs_save_to_file();
|
||||||
|
if(ret == 0) rsp_out->status = KVS_STATUS_OK;
|
||||||
|
else rsp_out->status = KVS_STATUS_ERROR;
|
||||||
|
return 0;
|
||||||
default:
|
default:
|
||||||
assert(0);
|
rsp_out->status = KVS_STATUS_BADREQ;
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return length;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
/**
|
||||||
|
* 构建单条响应
|
||||||
|
* 返回:-1 失败,>=0 响应长度
|
||||||
|
*/
|
||||||
|
int kvs_build_one_rsp(const kvs_rsp_t *results, uint8_t *response, size_t response_cap){
|
||||||
|
if (!results || !response) return -1;
|
||||||
|
|
||||||
|
const uint8_t *end = response + response_cap;
|
||||||
|
uint8_t *p = response;
|
||||||
|
|
||||||
|
// 计算所需长度:1 + 1 + 4 + dlen
|
||||||
|
// 注意防止 size_t 溢出
|
||||||
|
size_t need = 1u + 1u + 4u + (size_t)results->dlen;
|
||||||
|
if (need > response_cap) return -1;
|
||||||
|
|
||||||
|
if (kvs_write_u8(&p, end, (uint8_t)results->op) < 0) return -1;
|
||||||
|
if (kvs_write_u8(&p, end, results->status) < 0) return -1;
|
||||||
|
if (kvs_write_u32(&p, end, results->dlen) < 0) return -1;
|
||||||
|
|
||||||
|
if (results->dlen > 0) {
|
||||||
|
if (!results->data) return -1; // 有长度却没指针,视为错误
|
||||||
|
if (kvs_need(p, end, (size_t)results->dlen) < 0) return -1;
|
||||||
|
memcpy(p, results->data, results->dlen);
|
||||||
|
p += results->dlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int)(p - response);
|
||||||
|
}
|
||||||
|
|
||||||
|
int kvs_save_to_file(){
|
||||||
|
int ret = 0;
|
||||||
|
int rc = 0;
|
||||||
|
#if ENABLE_ARRAY
|
||||||
|
rc = kvs_array_save(&global_array, KVS_ARRAY_FILE);
|
||||||
|
if(rc < 0){
|
||||||
|
printf("kvs_engine_array save error\n");
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ENABLE_RBTREE
|
||||||
|
rc = kvs_rbtree_save(&global_rbtree, KVS_RBTREE_FILE);
|
||||||
|
if(rc < 0){
|
||||||
|
printf("kvs_engine_rbtree save error\n");
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ENABLE_HASH
|
||||||
|
rc = kvs_hash_save(&global_hash, KVS_HASH_FILE);
|
||||||
|
if(rc < 0){
|
||||||
|
printf("kvs_engine_hash save error\n");
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ksv_clear_log(global_cmd_log_fd);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#if NEW_KVSTORE
|
|
||||||
/**
|
/**
|
||||||
* input : request request_length
|
* input : request request_length
|
||||||
* output : response response_length
|
* output : response response_length
|
||||||
@@ -296,7 +435,9 @@ int kvs_protocol(char *request, int request_length, char *response, int *respons
|
|||||||
}else{
|
}else{
|
||||||
// 执行成功,在这里保存到日志中。
|
// 执行成功,在这里保存到日志中。
|
||||||
if(rsp.status == KVS_STATUS_OK){
|
if(rsp.status == KVS_STATUS_OK){
|
||||||
if(req.op == KVS_CMD_SET || req.op == KVS_CMD_MOD || req.op == KVS_CMD_DEL){
|
if(req.op != KVS_CMD_GET && req.op != KVS_CMD_EXIST
|
||||||
|
&& req.op != KVS_CMD_RGET && req.op != KVS_CMD_REXIST
|
||||||
|
&& req.op != KVS_CMD_HGET && req.op != KVS_CMD_HEXIST ){
|
||||||
kvs_save_cmd_to_logfile(p, len, global_cmd_log_fd);
|
kvs_save_cmd_to_logfile(p, len, global_cmd_log_fd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -319,48 +460,6 @@ int kvs_protocol(char *request, int request_length, char *response, int *respons
|
|||||||
*response_length = out_len;
|
*response_length = out_len;
|
||||||
return consumed;
|
return consumed;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
/*
|
|
||||||
* msg: request message
|
|
||||||
* length: length of request message
|
|
||||||
* response: need to send
|
|
||||||
* @return : length of response
|
|
||||||
*/
|
|
||||||
|
|
||||||
int kvs_protocol(char *msg, int length, char *response) { //
|
|
||||||
|
|
||||||
// SET Key Value
|
|
||||||
// GET Key
|
|
||||||
// DEL Key
|
|
||||||
if (msg == NULL || length <= 0 || response == NULL) return -1;
|
|
||||||
|
|
||||||
//printf("recv %d : %s\n", length, msg);
|
|
||||||
|
|
||||||
char *tokens[KVS_MAX_TOKENS] = {0};
|
|
||||||
|
|
||||||
int count = kvs_split_token(msg, tokens);
|
|
||||||
if (count == -1) return -1;
|
|
||||||
|
|
||||||
//memcpy(response, msg, length);
|
|
||||||
|
|
||||||
return kvs_filter_protocol(tokens, count, response);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
int init_cmd_log(const char *file, int *logfd){
|
|
||||||
if(!file) return -1;
|
|
||||||
int fd = open(file, O_RDWR | O_CREAT | O_APPEND, 0644);
|
|
||||||
if(fd < 0) return -2;
|
|
||||||
|
|
||||||
*logfd = fd;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int destroy_cmd_log(int logfd){
|
|
||||||
close(logfd);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int init_kvengine(void) {
|
int init_kvengine(void) {
|
||||||
|
|
||||||
@@ -374,11 +473,15 @@ int init_kvengine(void) {
|
|||||||
#if ENABLE_RBTREE
|
#if ENABLE_RBTREE
|
||||||
memset(&global_rbtree, 0, sizeof(kvs_rbtree_t));
|
memset(&global_rbtree, 0, sizeof(kvs_rbtree_t));
|
||||||
kvs_rbtree_create(&global_rbtree);
|
kvs_rbtree_create(&global_rbtree);
|
||||||
|
|
||||||
|
kvs_rbtree_load(&global_rbtree, KVS_RBTREE_FILE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ENABLE_HASH
|
#if ENABLE_HASH
|
||||||
memset(&global_hash, 0, sizeof(kvs_hash_t));
|
memset(&global_hash, 0, sizeof(kvs_hash_t));
|
||||||
kvs_hash_create(&global_hash);
|
kvs_hash_create(&global_hash);
|
||||||
|
|
||||||
|
kvs_hash_load(&global_hash, KVS_HASH_FILE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
init_cmd_log(KVS_CMD_LOG_FILE, &global_cmd_log_fd);
|
init_cmd_log(KVS_CMD_LOG_FILE, &global_cmd_log_fd);
|
||||||
|
|||||||
55
kvstore.h
55
kvstore.h
@@ -31,7 +31,10 @@
|
|||||||
#define BIN_SAFE 1
|
#define BIN_SAFE 1
|
||||||
|
|
||||||
#define KVS_CMD_LOG_FILE "kvs_cmd_log.db"
|
#define KVS_CMD_LOG_FILE "kvs_cmd_log.db"
|
||||||
#define KVS_ARRAY_FILE "kvs_array.db"
|
#define KVS_ARRAY_FILE "kvs_snap_array.db"
|
||||||
|
#define KVS_RBTREE_FILE "kvs_snap_rbtree.db"
|
||||||
|
#define KVS_HASH_FILE "kvs_snap_hash.db"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// typedef int (*msg_handler)(char *msg, int length, char *response);
|
// typedef int (*msg_handler)(char *msg, int length, char *response);
|
||||||
@@ -41,7 +44,11 @@ extern int reactor_start(unsigned short port, msg_handler handler);
|
|||||||
extern int proactor_start(unsigned short port, msg_handler handler);
|
extern int proactor_start(unsigned short port, msg_handler handler);
|
||||||
extern int ntyco_start(unsigned short port, msg_handler handler);
|
extern int ntyco_start(unsigned short port, msg_handler handler);
|
||||||
|
|
||||||
|
extern int init_cmd_log(const char *file, int *logfd);
|
||||||
|
extern int destroy_cmd_log(int logfd);
|
||||||
|
extern int kvs_save_cmd_to_logfile(const uint8_t *cmd, size_t len, int logfd);
|
||||||
|
extern int kvs_replay_log(const char *logfile, int logfd);
|
||||||
|
extern int ksv_clear_log(int logfd);
|
||||||
|
|
||||||
#if ENABLE_ARRAY
|
#if ENABLE_ARRAY
|
||||||
|
|
||||||
@@ -112,6 +119,38 @@ int kvs_array_exist(kvs_array_t *inst, char *key);
|
|||||||
#define RED 1
|
#define RED 1
|
||||||
#define BLACK 2
|
#define BLACK 2
|
||||||
|
|
||||||
|
#if BIN_SAFE
|
||||||
|
typedef uint8_t KEY_TYPE; // key
|
||||||
|
|
||||||
|
typedef struct _rbtree_node {
|
||||||
|
unsigned char color;
|
||||||
|
struct _rbtree_node *right;
|
||||||
|
struct _rbtree_node *left;
|
||||||
|
struct _rbtree_node *parent;
|
||||||
|
KEY_TYPE *key;
|
||||||
|
uint32_t key_len;
|
||||||
|
KEY_TYPE *value;
|
||||||
|
uint32_t value_len;
|
||||||
|
} rbtree_node;
|
||||||
|
|
||||||
|
typedef struct _rbtree {
|
||||||
|
rbtree_node *root;
|
||||||
|
rbtree_node *nil;
|
||||||
|
} rbtree;
|
||||||
|
|
||||||
|
typedef struct _rbtree kvs_rbtree_t;
|
||||||
|
|
||||||
|
int kvs_rbtree_create(kvs_rbtree_t *inst);
|
||||||
|
void kvs_rbtree_destroy(kvs_rbtree_t *inst);
|
||||||
|
int kvs_rbtree_set(kvs_rbtree_t *inst, const void *key, uint32_t key_len, const void *value, uint32_t value_len);
|
||||||
|
void* kvs_rbtree_get(kvs_rbtree_t *inst, const void *key, uint32_t key_len, uint32_t *out_valuelen);
|
||||||
|
int kvs_rbtree_del(rbtree *inst, const void *key, uint32_t key_len);
|
||||||
|
int kvs_rbtree_mod(kvs_rbtree_t *inst, const void *key, uint32_t key_len, const void *value, uint32_t value_len);
|
||||||
|
int kvs_rbtree_exist(kvs_rbtree_t *inst, const void *key, uint32_t key_len);
|
||||||
|
|
||||||
|
int kvs_rbtree_save(kvs_rbtree_t *inst, const char* filename);
|
||||||
|
int kvs_rbtree_load(kvs_rbtree_t *inst, const char* filename);
|
||||||
|
#else
|
||||||
#define ENABLE_KEY_CHAR 1
|
#define ENABLE_KEY_CHAR 1
|
||||||
|
|
||||||
#if ENABLE_KEY_CHAR
|
#if ENABLE_KEY_CHAR
|
||||||
@@ -144,7 +183,7 @@ char* kvs_rbtree_get(kvs_rbtree_t *inst, char *key);
|
|||||||
int kvs_rbtree_del(kvs_rbtree_t *inst, char *key);
|
int kvs_rbtree_del(kvs_rbtree_t *inst, char *key);
|
||||||
int kvs_rbtree_mod(kvs_rbtree_t *inst, char *key, char *value);
|
int kvs_rbtree_mod(kvs_rbtree_t *inst, char *key, char *value);
|
||||||
int kvs_rbtree_exist(kvs_rbtree_t *inst, char *key);
|
int kvs_rbtree_exist(kvs_rbtree_t *inst, char *key);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -152,9 +191,6 @@ int kvs_rbtree_exist(kvs_rbtree_t *inst, char *key);
|
|||||||
|
|
||||||
#if ENABLE_HASH
|
#if ENABLE_HASH
|
||||||
|
|
||||||
#define MAX_KEY_LEN 128
|
|
||||||
#define MAX_VALUE_LEN 512
|
|
||||||
#define MAX_TABLE_SIZE 1024
|
|
||||||
|
|
||||||
#if BIN_SAFE
|
#if BIN_SAFE
|
||||||
#define MAX_TABLE_SIZE 1024
|
#define MAX_TABLE_SIZE 1024
|
||||||
@@ -186,9 +222,14 @@ int kvs_hash_del_bin(kvs_hash_t *h, const void *key, uint32_t key_len);
|
|||||||
int kvs_hash_exist_bin(kvs_hash_t *h, const void *key, uint32_t key_len);
|
int kvs_hash_exist_bin(kvs_hash_t *h, const void *key, uint32_t key_len);
|
||||||
int kvs_hash_count(kvs_hash_t *h);
|
int kvs_hash_count(kvs_hash_t *h);
|
||||||
|
|
||||||
int save(kvs_hash_t *h, const char* filename);
|
int kvs_hash_save(kvs_hash_t *inst, const char* filename);
|
||||||
|
int kvs_hash_load(kvs_hash_t *inst, const char* filename);
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
#define MAX_KEY_LEN 128
|
||||||
|
#define MAX_VALUE_LEN 512
|
||||||
|
#define MAX_TABLE_SIZE 1024
|
||||||
|
|
||||||
#define ENABLE_KEY_POINTER 1
|
#define ENABLE_KEY_POINTER 1
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ int accept_cb(int fd) {
|
|||||||
int recv_cb(int fd) {
|
int recv_cb(int fd) {
|
||||||
struct conn *c = &conn_list[fd];
|
struct conn *c = &conn_list[fd];
|
||||||
int avail = BUFFER_LENGTH - c->rlength;
|
int avail = BUFFER_LENGTH - c->rlength;
|
||||||
printf("avail: %d\n", avail);
|
// printf("avail: %d\n", avail);
|
||||||
if (avail <= 0) {
|
if (avail <= 0) {
|
||||||
// 缓冲满了还没解析出来:协议异常或包过大
|
// 缓冲满了还没解析出来:协议异常或包过大
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ int kvs_write_u32(uint8_t **pp, const uint8_t *end, uint32_t v) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
int getcmd(uint8_t op, const char *key, const char *value, uint8_t *buf){
|
int getcmd(uint8_t op, const char *key, uint32_t key_len, const char *value, uint32_t value_len, uint8_t *buf){
|
||||||
if(!buf) return -1;
|
if(!buf) return -1;
|
||||||
uint8_t *end = buf + CMD_SIZE;
|
uint8_t *end = buf + CMD_SIZE;
|
||||||
uint8_t *p = buf;
|
uint8_t *p = buf;
|
||||||
@@ -79,7 +79,7 @@ int getcmd(uint8_t op, const char *key, const char *value, uint8_t *buf){
|
|||||||
|
|
||||||
// 写入 key
|
// 写入 key
|
||||||
if(key){
|
if(key){
|
||||||
int keylen = strlen(key);
|
int keylen = key_len;
|
||||||
if (kvs_write_u32(&p, end, keylen) < 0) return -1;
|
if (kvs_write_u32(&p, end, keylen) < 0) return -1;
|
||||||
if (kvs_need(p, end, keylen) < 0) return -1;
|
if (kvs_need(p, end, keylen) < 0) return -1;
|
||||||
if (keylen > 0) {
|
if (keylen > 0) {
|
||||||
@@ -89,7 +89,7 @@ int getcmd(uint8_t op, const char *key, const char *value, uint8_t *buf){
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(value){
|
if(value){
|
||||||
int vallen = strlen(value);
|
int vallen = value_len;
|
||||||
if (kvs_write_u32(&p, end, vallen) < 0) return -1;
|
if (kvs_write_u32(&p, end, vallen) < 0) return -1;
|
||||||
if (kvs_need(p, end, vallen) < 0) return -1;
|
if (kvs_need(p, end, vallen) < 0) return -1;
|
||||||
if (vallen > 0) {
|
if (vallen > 0) {
|
||||||
@@ -102,6 +102,7 @@ int getcmd(uint8_t op, const char *key, const char *value, uint8_t *buf){
|
|||||||
}
|
}
|
||||||
|
|
||||||
int parse_response(const uint8_t *buf, int buflen, kvs_response_t *rsp) {
|
int parse_response(const uint8_t *buf, int buflen, kvs_response_t *rsp) {
|
||||||
|
if(buflen == 0) return 0;
|
||||||
const uint8_t *p = buf;
|
const uint8_t *p = buf;
|
||||||
const uint8_t *end = buf + buflen;
|
const uint8_t *end = buf + buflen;
|
||||||
|
|
||||||
@@ -139,7 +140,7 @@ int parse_response(const uint8_t *buf, int buflen, kvs_response_t *rsp) {
|
|||||||
|
|
||||||
void print_response(const char *cmd_name, const kvs_response_t *rsp) {
|
void print_response(const char *cmd_name, const kvs_response_t *rsp) {
|
||||||
printf("%s ", cmd_name);
|
printf("%s ", cmd_name);
|
||||||
if(rsp->op == KVS_CMD_GET){
|
if(rsp->op == KVS_CMD_GET || rsp->op == KVS_CMD_HGET || rsp->op == KVS_CMD_RGET){
|
||||||
if (rsp->datalen > 0 && rsp->data != NULL) {
|
if (rsp->datalen > 0 && rsp->data != NULL) {
|
||||||
printf("Data: ");
|
printf("Data: ");
|
||||||
// 尝试以字符串形式打印(如果是可打印字符)
|
// 尝试以字符串形式打印(如果是可打印字符)
|
||||||
@@ -190,7 +191,7 @@ void print_response(const char *cmd_name, const kvs_response_t *rsp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int verify_response(const kvs_response_t *rsp, uint8_t expected_op,
|
int verify_response(const kvs_response_t *rsp, uint8_t expected_op,
|
||||||
uint8_t expected_status, const char *expected_data) {
|
uint8_t expected_status, const char *expected_data, uint32_t expected_len) {
|
||||||
if (rsp->op != expected_op) {
|
if (rsp->op != expected_op) {
|
||||||
printf("❌ OP mismatch: expected %u, got %u\n", expected_op, rsp->op);
|
printf("❌ OP mismatch: expected %u, got %u\n", expected_op, rsp->op);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -202,7 +203,6 @@ int verify_response(const kvs_response_t *rsp, uint8_t expected_op,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (expected_data != NULL) {
|
if (expected_data != NULL) {
|
||||||
uint32_t expected_len = strlen(expected_data);
|
|
||||||
if (rsp->datalen != expected_len) {
|
if (rsp->datalen != expected_len) {
|
||||||
printf("❌ Data length mismatch: expected %u, got %u\n", expected_len, rsp->datalen);
|
printf("❌ Data length mismatch: expected %u, got %u\n", expected_len, rsp->datalen);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -72,12 +72,12 @@ int kvs_write_u8(uint8_t **pp, const uint8_t *end, uint8_t v);
|
|||||||
int kvs_write_u16(uint8_t **pp, const uint8_t *end, uint16_t v);
|
int kvs_write_u16(uint8_t **pp, const uint8_t *end, uint16_t v);
|
||||||
int kvs_write_u32(uint8_t **pp, const uint8_t *end, uint32_t v);
|
int kvs_write_u32(uint8_t **pp, const uint8_t *end, uint32_t v);
|
||||||
|
|
||||||
int getcmd(uint8_t op, const char *key, const char *value, uint8_t *buf);
|
int getcmd(uint8_t op, const char *key, uint32_t key_len, const char *value, uint32_t value_len, uint8_t *buf);
|
||||||
|
|
||||||
int parse_response(const uint8_t *buf, int buflen, kvs_response_t *rsp);
|
int parse_response(const uint8_t *buf, int buflen, kvs_response_t *rsp);
|
||||||
void print_response(const char *cmd_name, const kvs_response_t *rsp);
|
void print_response(const char *cmd_name, const kvs_response_t *rsp);
|
||||||
int verify_response(const kvs_response_t *rsp, uint8_t expected_op,
|
int verify_response(const kvs_response_t *rsp, uint8_t expected_op,
|
||||||
uint8_t expected_status, const char *expected_data);
|
uint8_t expected_status, const char *expected_data, uint32_t expected_len);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -101,10 +101,10 @@ static void kvs_batch_init(kvs_batch_t *b)
|
|||||||
* 用 getcmd() 生成单条命令,然后 append 到 batch buffer
|
* 用 getcmd() 生成单条命令,然后 append 到 batch buffer
|
||||||
* 返回:0 成功,-1 失败(太多条 or buffer 不够)
|
* 返回:0 成功,-1 失败(太多条 or buffer 不够)
|
||||||
*/
|
*/
|
||||||
static int kvs_batch_add(kvs_batch_t *b, uint8_t op, const char *key, const char *value){
|
static int kvs_batch_add(kvs_batch_t *b, uint8_t op, const char *key, uint32_t key_len, const char *value, uint32_t value_len){
|
||||||
if (b->cnt >= KVS_BATCH_MAX) return -1;
|
if (b->cnt >= KVS_BATCH_MAX) return -1;
|
||||||
uint8_t tmp[CMD_SIZE];
|
uint8_t tmp[CMD_SIZE];
|
||||||
int n = getcmd(op, key, value, tmp); // 你提供的函数
|
int n = getcmd(op, key, key_len, value, value_len, tmp); // 你提供的函数
|
||||||
if (n <= 0) return -1;
|
if (n <= 0) return -1;
|
||||||
|
|
||||||
if (b->len + n > (int)sizeof(b->buf)) return -1;
|
if (b->len + n > (int)sizeof(b->buf)) return -1;
|
||||||
@@ -122,7 +122,7 @@ static int kvs_batch_add(kvs_batch_t *b, uint8_t op, const char *key, const char
|
|||||||
*/
|
*/
|
||||||
static int kvs_batch_send(int fd, const kvs_batch_t *b)
|
static int kvs_batch_send(int fd, const kvs_batch_t *b)
|
||||||
{
|
{
|
||||||
printf("send : %d\n", b->len);
|
// printf("send : %d\n", b->len);
|
||||||
return (int)send(fd, b->buf, b->len, 0);
|
return (int)send(fd, b->buf, b->len, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,9 +141,7 @@ static int kvs_batch_recv_parse(int fd,
|
|||||||
int used = 0;
|
int used = 0;
|
||||||
|
|
||||||
while(parsed < b->cnt){
|
while(parsed < b->cnt){
|
||||||
printf("recv loop: parsed=%d\n", parsed);
|
|
||||||
int nrecv = (int)recv(fd, recvbuf+used, recvbuf_cap, 0);
|
int nrecv = (int)recv(fd, recvbuf+used, recvbuf_cap, 0);
|
||||||
printf("recv nrecv=%d\n", nrecv);
|
|
||||||
if (nrecv <= 0) return -1;
|
if (nrecv <= 0) return -1;
|
||||||
|
|
||||||
int off = 0;
|
int off = 0;
|
||||||
@@ -156,7 +154,6 @@ static int kvs_batch_recv_parse(int fd,
|
|||||||
used+= consumed;
|
used+= consumed;
|
||||||
parsed++;
|
parsed++;
|
||||||
}
|
}
|
||||||
printf("after parse: parsed=%d, used=%d\n", parsed, used);
|
|
||||||
}
|
}
|
||||||
return parsed;
|
return parsed;
|
||||||
}
|
}
|
||||||
263
test/testcase.c
263
test/testcase.c
@@ -45,18 +45,19 @@ int recv_msg(int connfd, char *msg, int length) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void testcase(int connfd, uint8_t op, const char* key, const char* value, rsp_ret_status_e st, const char* rsp_value, const char* command_name){
|
void testcase(int connfd, uint8_t op, const char* key, uint32_t key_len, const char* value,
|
||||||
|
uint32_t value_len, rsp_ret_status_e st, const char* rsp_value, uint32_t expect_len, const char* command_name){
|
||||||
uint8_t buf[CMD_SIZE];
|
uint8_t buf[CMD_SIZE];
|
||||||
uint8_t result[CMD_SIZE];
|
uint8_t result[CMD_SIZE];
|
||||||
kvs_response_t rsp;
|
kvs_response_t rsp;
|
||||||
int len, recv_len;
|
int len, recv_len;
|
||||||
|
|
||||||
len = getcmd(op, key, value, buf);
|
len = getcmd(op, key, key_len, value, value_len, buf);
|
||||||
send_msg(connfd, buf, len);
|
send_msg(connfd, buf, len);
|
||||||
recv_len = recv_msg(connfd, result, CMD_SIZE);
|
recv_len = recv_msg(connfd, result, CMD_SIZE);
|
||||||
if (parse_response(result, recv_len, &rsp) > 0) {
|
if (parse_response(result, recv_len, &rsp) > 0) {
|
||||||
PRESP(command_name, &rsp);
|
PRESP(command_name, &rsp);
|
||||||
if(!verify_response(&rsp, op, st, rsp_value)) printf("%s\n", command_name);
|
if(!verify_response(&rsp, op, st, rsp_value, expect_len)) printf("%s\n", command_name);
|
||||||
}else{
|
}else{
|
||||||
printf("parser error\n");
|
printf("parser error\n");
|
||||||
}
|
}
|
||||||
@@ -67,23 +68,23 @@ void testcase(int connfd, uint8_t op, const char* key, const char* value, rsp_re
|
|||||||
|
|
||||||
void array_testcase_1w(int connfd) {
|
void array_testcase_1w(int connfd) {
|
||||||
|
|
||||||
int count = 1000;
|
int count = 1;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
struct timeval tv_begin;
|
struct timeval tv_begin;
|
||||||
gettimeofday(&tv_begin, NULL);
|
gettimeofday(&tv_begin, NULL);
|
||||||
|
|
||||||
for (i = 0;i < count;i ++) {
|
for (i = 0;i < count;i ++) {
|
||||||
testcase(connfd, KVS_CMD_SET, "name", "lian", KVS_STATUS_OK, NULL, "SET NAME");
|
testcase(connfd, KVS_CMD_SET, "name", 4, "l\r\0n", 4, KVS_STATUS_OK, NULL, 0, "SET NAME");
|
||||||
testcase(connfd, KVS_CMD_GET, "name", NULL, KVS_STATUS_OK, "lian", "GET NAME");
|
testcase(connfd, KVS_CMD_GET, "name", 4, NULL, 0, KVS_STATUS_OK, "l\r\0n", 4, "GET NAME");
|
||||||
testcase(connfd, KVS_CMD_MOD, "name", "liu", KVS_STATUS_OK, NULL, "MOD NAME");
|
testcase(connfd, KVS_CMD_MOD, "name", 4, "liu", 3, KVS_STATUS_OK, NULL, 0, "MOD NAME");
|
||||||
testcase(connfd, KVS_CMD_GET, "name", NULL, KVS_STATUS_OK, "liu", "GET NAME");
|
testcase(connfd, KVS_CMD_GET, "name", 4, NULL, 0, KVS_STATUS_OK, "liu", 3, "GET NAME");
|
||||||
testcase(connfd, KVS_CMD_EXIST, "name", NULL, KVS_STATUS_EXIST, NULL, "EXIST NAME");
|
testcase(connfd, KVS_CMD_EXIST, "name", 4, NULL, 0, KVS_STATUS_EXIST, NULL, 0, "EXIST NAME");
|
||||||
testcase(connfd, KVS_CMD_DEL, "name", NULL, KVS_STATUS_OK, NULL, "DEL NAME");
|
testcase(connfd, KVS_CMD_DEL, "name", 4, NULL, 0, KVS_STATUS_OK, NULL, 0, "DEL NAME");
|
||||||
testcase(connfd, KVS_CMD_EXIST, "name", NULL, KVS_STATUS_NO_EXIST, NULL, "NOT EXIST NAME");
|
testcase(connfd, KVS_CMD_EXIST, "name", 4, NULL, 0, KVS_STATUS_NO_EXIST, NULL, 0, "EXIST NAME");
|
||||||
|
|
||||||
testcase(connfd, KVS_CMD_MOD, "stu", "liu", KVS_STATUS_NO_EXIST, NULL, "MOD NAME");
|
testcase(connfd, KVS_CMD_MOD, "stu", 3, "liu", 3, KVS_STATUS_NO_EXIST, NULL, 0, "MOD NAME");
|
||||||
testcase(connfd, KVS_CMD_DEL, "stu", NULL, KVS_STATUS_NO_EXIST, NULL, "DEL SUT");
|
testcase(connfd, KVS_CMD_DEL, "stu", 3, NULL, 0, KVS_STATUS_NO_EXIST, NULL, 0, "DEL SUT");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timeval tv_end;
|
struct timeval tv_end;
|
||||||
@@ -97,23 +98,23 @@ void array_testcase_1w(int connfd) {
|
|||||||
|
|
||||||
void rbtree_testcase_1w(int connfd) {
|
void rbtree_testcase_1w(int connfd) {
|
||||||
|
|
||||||
int count = 1000;
|
int count = 1;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
struct timeval tv_begin;
|
struct timeval tv_begin;
|
||||||
gettimeofday(&tv_begin, NULL);
|
gettimeofday(&tv_begin, NULL);
|
||||||
|
|
||||||
for (i = 0;i < count;i ++) {
|
for (i = 0;i < count;i ++) {
|
||||||
testcase(connfd, KVS_CMD_RSET, "name", "lian", KVS_STATUS_OK, NULL, "SET NAME");
|
testcase(connfd, KVS_CMD_RSET, "name", 4, "l\r\0n", 4, KVS_STATUS_OK, NULL, 0, "RSET NAME");
|
||||||
testcase(connfd, KVS_CMD_RGET, "name", NULL, KVS_STATUS_OK, "lian", "GET NAME");
|
testcase(connfd, KVS_CMD_RGET, "name", 4, NULL, 0, KVS_STATUS_OK, "l\r\0n", 4, "RGET NAME");
|
||||||
testcase(connfd, KVS_CMD_RMOD, "name", "liu", KVS_STATUS_OK, NULL, "MOD NAME");
|
testcase(connfd, KVS_CMD_RMOD, "name", 4, "liu", 3, KVS_STATUS_OK, NULL, 0, "RMOD NAME");
|
||||||
testcase(connfd, KVS_CMD_RGET, "name", NULL, KVS_STATUS_OK, "liu", "GET NAME");
|
testcase(connfd, KVS_CMD_RGET, "name", 4, NULL, 0, KVS_STATUS_OK, "liu", 3, "RGET NAME");
|
||||||
testcase(connfd, KVS_CMD_REXIST, "name", NULL, KVS_STATUS_EXIST, NULL, "EXIST NAME");
|
testcase(connfd, KVS_CMD_REXIST, "name", 4, NULL, 0, KVS_STATUS_EXIST, NULL, 0, "REXIST NAME");
|
||||||
testcase(connfd, KVS_CMD_RDEL, "name", NULL, KVS_STATUS_OK, NULL, "DEL NAME");
|
testcase(connfd, KVS_CMD_RDEL, "name", 4, NULL, 0, KVS_STATUS_OK, NULL, 0, "RDEL NAME");
|
||||||
testcase(connfd, KVS_CMD_REXIST, "name", NULL, KVS_STATUS_NO_EXIST, NULL, "NOT EXIST NAME");
|
testcase(connfd, KVS_CMD_REXIST, "name", 4, NULL, 0, KVS_STATUS_NO_EXIST, NULL, 0, "REXIST NAME");
|
||||||
|
|
||||||
testcase(connfd, KVS_CMD_RMOD, "stu", "liu", KVS_STATUS_NO_EXIST, NULL, "MOD NAME");
|
testcase(connfd, KVS_CMD_RMOD, "stu", 3, "liu", 3, KVS_STATUS_NO_EXIST, NULL, 0, "RMOD NAME");
|
||||||
testcase(connfd, KVS_CMD_RDEL, "stu", NULL, KVS_STATUS_NO_EXIST, NULL, "DEL SUT");
|
testcase(connfd, KVS_CMD_RDEL, "stu", 3, NULL, 0, KVS_STATUS_NO_EXIST, NULL, 0, "RDEL SUT");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timeval tv_end;
|
struct timeval tv_end;
|
||||||
@@ -127,23 +128,23 @@ void rbtree_testcase_1w(int connfd) {
|
|||||||
|
|
||||||
void hash_testcase_1w(int connfd) {
|
void hash_testcase_1w(int connfd) {
|
||||||
|
|
||||||
int count = 1000;
|
int count = 1;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
struct timeval tv_begin;
|
struct timeval tv_begin;
|
||||||
gettimeofday(&tv_begin, NULL);
|
gettimeofday(&tv_begin, NULL);
|
||||||
|
|
||||||
for (i = 0;i < count;i ++) {
|
for (i = 0;i < count;i ++) {
|
||||||
testcase(connfd, KVS_CMD_HSET, "name", "lian", KVS_STATUS_OK, NULL, "SET NAME");
|
testcase(connfd, KVS_CMD_HSET, "name", 4, "l\r\0n", 4, KVS_STATUS_OK, NULL, 0, "HSET NAME");
|
||||||
testcase(connfd, KVS_CMD_HGET, "name", NULL, KVS_STATUS_OK, "lian", "GET NAME");
|
testcase(connfd, KVS_CMD_HGET, "name", 4, NULL, 0, KVS_STATUS_OK, "l\r\0n", 4, "HGET NAME");
|
||||||
testcase(connfd, KVS_CMD_HMOD, "name", "liu", KVS_STATUS_OK, NULL, "MOD NAME");
|
testcase(connfd, KVS_CMD_HMOD, "name", 4, "liu", 3, KVS_STATUS_OK, NULL, 0, "HMOD NAME");
|
||||||
testcase(connfd, KVS_CMD_HGET, "name", NULL, KVS_STATUS_OK, "liu", "GET NAME");
|
testcase(connfd, KVS_CMD_HGET, "name", 4, NULL, 0, KVS_STATUS_OK, "liu", 3, "HGET NAME");
|
||||||
testcase(connfd, KVS_CMD_HEXIST, "name", NULL, KVS_STATUS_EXIST, NULL, "EXIST NAME");
|
testcase(connfd, KVS_CMD_HEXIST, "name", 4, NULL, 0, KVS_STATUS_EXIST, NULL, 0, "HEXIST NAME");
|
||||||
testcase(connfd, KVS_CMD_HDEL, "name", NULL, KVS_STATUS_OK, NULL, "DEL NAME");
|
testcase(connfd, KVS_CMD_HDEL, "name", 4, NULL, 0, KVS_STATUS_OK, NULL, 0, "HDEL NAME");
|
||||||
testcase(connfd, KVS_CMD_HEXIST, "name", NULL, KVS_STATUS_NO_EXIST, NULL, "NOT EXIST NAME");
|
testcase(connfd, KVS_CMD_HEXIST, "name", 4, NULL, 0, KVS_STATUS_NO_EXIST, NULL, 0, "HEXIST NAME");
|
||||||
|
|
||||||
testcase(connfd, KVS_CMD_HMOD, "stu", "liu", KVS_STATUS_NO_EXIST, NULL, "MOD NAME");
|
testcase(connfd, KVS_CMD_HMOD, "stu", 3, "liu", 3, KVS_STATUS_NO_EXIST, NULL, 0, "HMOD NAME");
|
||||||
testcase(connfd, KVS_CMD_HDEL, "stu", NULL, KVS_STATUS_NO_EXIST, NULL, "DEL SUT");
|
testcase(connfd, KVS_CMD_HDEL, "stu", 3, NULL, 0, KVS_STATUS_NO_EXIST, NULL, 0, "HDEL SUT");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timeval tv_end;
|
struct timeval tv_end;
|
||||||
@@ -155,18 +156,110 @@ void hash_testcase_1w(int connfd) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_batch_SET_example(int fd)
|
// void do_batch_SET_example(int fd)
|
||||||
{
|
// {
|
||||||
|
// kvs_batch_t batch;
|
||||||
|
// kvs_batch_init(&batch);
|
||||||
|
|
||||||
|
// char key[10]={0}, val[10]={0};
|
||||||
|
|
||||||
|
// // 组 batch(最多 64 条)
|
||||||
|
// for(int i = 0;i < 48; ++ i){
|
||||||
|
// int len = sprintf(key, "k%d", i);
|
||||||
|
// len = sprintf(val, "v%d", i);
|
||||||
|
// kvs_batch_add(&batch, KVS_CMD_SET, key, val);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 一次性发送
|
||||||
|
// kvs_batch_send(fd, &batch);
|
||||||
|
|
||||||
|
// // 一次性 recv + parse
|
||||||
|
// uint8_t recvbuf[BATCH_SIZE];
|
||||||
|
// kvs_response_t rsps[KVS_BATCH_MAX];
|
||||||
|
|
||||||
|
// int nrsp = kvs_batch_recv_parse(fd, &batch, rsps, recvbuf, sizeof(recvbuf));
|
||||||
|
|
||||||
|
// // 打印/处理
|
||||||
|
// for (int i = 0; i < nrsp; i++) {
|
||||||
|
// int len = sprintf(key, "SET%d", i);
|
||||||
|
// PRESP(key, &rsps[i]);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// void do_batch_GET_example(int fd)
|
||||||
|
// {
|
||||||
|
// kvs_batch_t batch;
|
||||||
|
// kvs_batch_init(&batch);
|
||||||
|
|
||||||
|
// char key[10]={0}, val[10]={0};
|
||||||
|
|
||||||
|
// // 组 batch(最多 64 条)
|
||||||
|
// for(int i = 0;i < 48; ++ i){
|
||||||
|
// int len = sprintf(key, "k%d", i);
|
||||||
|
// kvs_batch_add(&batch, KVS_CMD_GET, key, NULL);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 一次性发送
|
||||||
|
// kvs_batch_send(fd, &batch);
|
||||||
|
|
||||||
|
// // 一次性 recv + parse
|
||||||
|
// uint8_t recvbuf[BATCH_SIZE];
|
||||||
|
// kvs_response_t rsps[KVS_BATCH_MAX];
|
||||||
|
|
||||||
|
// int nrsp = kvs_batch_recv_parse(fd, &batch, rsps, recvbuf, sizeof(recvbuf));
|
||||||
|
|
||||||
|
// // 打印/处理
|
||||||
|
// for (int i = 0; i < nrsp; i++) {
|
||||||
|
// int len = sprintf(key, "GET%d", i);
|
||||||
|
// PRESP(key, &rsps[i]);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// void do_batch_DEL_example(int fd)
|
||||||
|
// {
|
||||||
|
// kvs_batch_t batch;
|
||||||
|
// kvs_batch_init(&batch);
|
||||||
|
|
||||||
|
// char key[10]={0}, val[10]={0};
|
||||||
|
|
||||||
|
// // 组 batch(最多 64 条)
|
||||||
|
// for(int i = 0;i < 48; ++ i){
|
||||||
|
// int len = sprintf(key, "k%d", i);
|
||||||
|
// kvs_batch_add(&batch, KVS_CMD_DEL, key, NULL);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 一次性发送
|
||||||
|
// kvs_batch_send(fd, &batch);
|
||||||
|
|
||||||
|
// // 一次性 recv + parse
|
||||||
|
// uint8_t recvbuf[BATCH_SIZE];
|
||||||
|
// kvs_response_t rsps[KVS_BATCH_MAX];
|
||||||
|
|
||||||
|
// int nrsp = kvs_batch_recv_parse(fd, &batch, rsps, recvbuf, sizeof(recvbuf));
|
||||||
|
|
||||||
|
// // 打印/处理
|
||||||
|
// for (int i = 0; i < nrsp; i++) {
|
||||||
|
// int len = sprintf(key, "DEL%d", i);
|
||||||
|
// PRESP(key, &rsps[i]);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
void do_batch_test(int fd, int op, const char *key, const char *value){
|
||||||
kvs_batch_t batch;
|
kvs_batch_t batch;
|
||||||
kvs_batch_init(&batch);
|
kvs_batch_init(&batch);
|
||||||
|
|
||||||
char key[10]={0}, val[10]={0};
|
char bkey[15]={0}, bval[15]={0};
|
||||||
|
|
||||||
// 组 batch(最多 64 条)
|
// 组 batch(最多 64 条)
|
||||||
for(int i = 0;i < 48; ++ i){
|
for(int i = 0;i < 48; ++ i){
|
||||||
int len = sprintf(key, "k%d", i);
|
if(value == NULL){
|
||||||
len = sprintf(val, "v%d", i);
|
int klen = sprintf(bkey, "%s%d", key, i);
|
||||||
kvs_batch_add(&batch, KVS_CMD_SET, key, val);
|
kvs_batch_add(&batch, op, bkey, klen, NULL, 0);
|
||||||
|
}else{
|
||||||
|
int klen = sprintf(bkey, "%s%d", key, i);
|
||||||
|
int vlen = sprintf(bval, "%s%d", value, i);
|
||||||
|
kvs_batch_add(&batch, op, bkey, klen, bval, vlen);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 一次性发送
|
// 一次性发送
|
||||||
@@ -180,71 +273,13 @@ void do_batch_SET_example(int fd)
|
|||||||
|
|
||||||
// 打印/处理
|
// 打印/处理
|
||||||
for (int i = 0; i < nrsp; i++) {
|
for (int i = 0; i < nrsp; i++) {
|
||||||
int len = sprintf(key, "SET%d", i);
|
int len = sprintf(bkey, "PRT%d", i);
|
||||||
PRESP(key, &rsps[i]);
|
PRESP(bkey, &rsps[i]);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void do_batch_GET_example(int fd)
|
|
||||||
{
|
|
||||||
kvs_batch_t batch;
|
|
||||||
kvs_batch_init(&batch);
|
|
||||||
|
|
||||||
char key[10]={0}, val[10]={0};
|
|
||||||
|
|
||||||
// 组 batch(最多 64 条)
|
|
||||||
for(int i = 0;i < 48; ++ i){
|
|
||||||
int len = sprintf(key, "k%d", i);
|
|
||||||
kvs_batch_add(&batch, KVS_CMD_GET, key, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 一次性发送
|
|
||||||
kvs_batch_send(fd, &batch);
|
|
||||||
|
|
||||||
// 一次性 recv + parse
|
|
||||||
uint8_t recvbuf[BATCH_SIZE];
|
|
||||||
kvs_response_t rsps[KVS_BATCH_MAX];
|
|
||||||
|
|
||||||
int nrsp = kvs_batch_recv_parse(fd, &batch, rsps, recvbuf, sizeof(recvbuf));
|
|
||||||
|
|
||||||
// 打印/处理
|
|
||||||
for (int i = 0; i < nrsp; i++) {
|
|
||||||
int len = sprintf(key, "GET%d", i);
|
|
||||||
PRESP(key, &rsps[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void do_batch_DEL_example(int fd)
|
|
||||||
{
|
|
||||||
kvs_batch_t batch;
|
|
||||||
kvs_batch_init(&batch);
|
|
||||||
|
|
||||||
char key[10]={0}, val[10]={0};
|
|
||||||
|
|
||||||
// 组 batch(最多 64 条)
|
|
||||||
for(int i = 0;i < 48; ++ i){
|
|
||||||
int len = sprintf(key, "k%d", i);
|
|
||||||
kvs_batch_add(&batch, KVS_CMD_DEL, key, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 一次性发送
|
|
||||||
kvs_batch_send(fd, &batch);
|
|
||||||
|
|
||||||
// 一次性 recv + parse
|
|
||||||
uint8_t recvbuf[BATCH_SIZE];
|
|
||||||
kvs_response_t rsps[KVS_BATCH_MAX];
|
|
||||||
|
|
||||||
int nrsp = kvs_batch_recv_parse(fd, &batch, rsps, recvbuf, sizeof(recvbuf));
|
|
||||||
|
|
||||||
// 打印/处理
|
|
||||||
for (int i = 0; i < nrsp; i++) {
|
|
||||||
int len = sprintf(key, "DEL%d", i);
|
|
||||||
PRESP(key, &rsps[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void save(int connfd){
|
void save(int connfd){
|
||||||
testcase(connfd, KVS_CMD_SAVE, NULL, NULL, KVS_STATUS_OK, NULL, "SAVE");
|
testcase(connfd, KVS_CMD_SAVE, NULL, 0, NULL, 0, KVS_STATUS_OK, NULL, 0, "SAVE");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -261,17 +296,29 @@ int main(int argc, char *argv[]) {
|
|||||||
int connfd = connect_tcpserver(ip, port);
|
int connfd = connect_tcpserver(ip, port);
|
||||||
|
|
||||||
if(mode == 0){
|
if(mode == 0){
|
||||||
do_batch_SET_example(connfd);
|
|
||||||
}else if(mode == 1){
|
|
||||||
do_batch_GET_example(connfd);
|
|
||||||
}else if(mode == 2){
|
|
||||||
do_batch_DEL_example(connfd);
|
|
||||||
}else if(mode == 10){
|
|
||||||
array_testcase_1w(connfd);
|
array_testcase_1w(connfd);
|
||||||
}else if(mode == 11){
|
}else if(mode == 1){
|
||||||
rbtree_testcase_1w(connfd);
|
rbtree_testcase_1w(connfd);
|
||||||
}else if(mode == 12){
|
}else if(mode == 2){
|
||||||
hash_testcase_1w(connfd);
|
hash_testcase_1w(connfd);
|
||||||
|
}else if(mode == 10){
|
||||||
|
do_batch_test(connfd, KVS_CMD_SET, "array_set", "array_val");
|
||||||
|
}else if(mode == 11){
|
||||||
|
do_batch_test(connfd, KVS_CMD_GET, "array_set", NULL);
|
||||||
|
}else if(mode == 12){
|
||||||
|
do_batch_test(connfd, KVS_CMD_EXIST, "array_set", NULL);
|
||||||
|
}else if(mode == 20){
|
||||||
|
do_batch_test(connfd, KVS_CMD_RSET, "rbtree_set", "rbtree_val");
|
||||||
|
}else if(mode == 21){
|
||||||
|
do_batch_test(connfd, KVS_CMD_RGET, "rbtree_set", NULL);
|
||||||
|
}else if(mode == 22){
|
||||||
|
do_batch_test(connfd, KVS_CMD_REXIST, "rbtree_set", NULL);
|
||||||
|
}else if(mode == 30){
|
||||||
|
do_batch_test(connfd, KVS_CMD_HSET, "hash_set", "hash_val");
|
||||||
|
}else if(mode == 31){
|
||||||
|
do_batch_test(connfd, KVS_CMD_HGET, "hash_set", NULL);
|
||||||
|
}else if(mode == 32){
|
||||||
|
do_batch_test(connfd, KVS_CMD_HEXIST, "hash_set", NULL);
|
||||||
}else if(mode == -1){
|
}else if(mode == -1){
|
||||||
save(connfd);
|
save(connfd);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user