提供array和hashtable的存储引擎层的二进制安全支持,把入口函数修改为接收参数长度,将strlen、strcmp、strcpy替换。

This commit is contained in:
2026-01-06 21:05:48 +08:00
parent 144b374aa2
commit cb0134a852
12 changed files with 767 additions and 223 deletions

View File

@@ -1,7 +1,8 @@
CC = gcc
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
TESTCASE_SRCS = testcase.c
TARGET = kvstore
SUBDIR = ./NtyCo/

View File

@@ -19,12 +19,13 @@ int kvs_array_create(kvs_array_t *inst) {
return -1;
}
memset(inst->table, 0, (size_t)KVS_ARRAY_SIZE * sizeof(kvs_array_item_t));
inst->total = 0;
return 0;
}
void kvs_array_destory(kvs_array_t *inst) {
void kvs_array_destroy(kvs_array_t *inst) {
if (!inst) return ;
@@ -35,6 +36,151 @@ void kvs_array_destory(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, size_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, size_t key_len,
const void *value, size_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长度0value 指针置 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, size_t key_len,
size_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, size_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, size_t key_len,
const void *value, size_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, size_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;
}
#else
/*
* @return: <0, error; =0, success; >0, exist
*/
@@ -187,3 +333,4 @@ int kvs_array_exist(kvs_array_t *inst, char *key) {
}
#endif

View File

@@ -84,7 +84,7 @@ int kvs_hash_create(kvs_hash_t *hash) {
}
//
void kvs_hash_destory(kvs_hash_t *hash) {
void kvs_hash_destroy(kvs_hash_t *hash) {
if (!hash) return;
@@ -275,7 +275,7 @@ int main() {
ret = kvs_hash_exist(&hash, "Teacher1");
printf("Exist Teacher1 ret : %d\n", ret);
kvs_hash_destory(&hash);
kvs_hash_destroy(&hash);
return 0;
}

BIN
kvs_hash.o Normal file

Binary file not shown.

300
kvs_hash_bin.c Executable file
View File

@@ -0,0 +1,300 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include "kvstore.h"
// Key, Value -->
// Modify
kvs_hash_t global_hash;
//Connection
// 'C' + 'o' + 'n'
static int _hash(const void *key, size_t key_len, int size) {
if (!key || size <= 0) return -1;
const uint8_t *p = (const uint8_t *)key;
uint32_t sum = 0;
for (size_t i = 0; i < key_len; i++) {
sum += p[i];
}
return sum % size;
}
static int _key_equal(const hashnode_t *node, const void *key, size_t key_len) {
if (!node || !key) return 0;
if (!node->key) return 0;
if (node->key_len != key_len) return 0;
return memcmp(node->key, key, key_len) == 0;
}
static hashnode_t *_create_node(const void *key, size_t key_len,
const void *value, size_t value_len) {
hashnode_t *node = (hashnode_t*)kvs_malloc(sizeof(hashnode_t));
if (!node) return NULL;
memset(node, 0, sizeof(*node));
if (key_len > 0) {
node->key = (uint8_t*)kvs_malloc(key_len);
if (!node->key) { kvs_free(node); return NULL; }
memcpy(node->key, key, key_len);
node->key_len = key_len;
}
if (value_len > 0) {
node->value = (uint8_t*)kvs_malloc(value_len);
if (!node->value) {
kvs_free(node->key);
kvs_free(node);
return NULL;
}
memcpy(node->value, value, value_len);
node->value_len = value_len;
} else {
node->value = NULL;
node->value_len = 0;
}
node->next = NULL;
return node;
}
//
int kvs_hash_create(kvs_hash_t *hash) {
if (!hash) return -1;
hash->nodes = (hashnode_t**)kvs_malloc(sizeof(hashnode_t*) * MAX_TABLE_SIZE);
if (!hash->nodes) return -1;
memset(hash->nodes, 0, sizeof(hashnode_t*) * MAX_TABLE_SIZE);
hash->max_slots = MAX_TABLE_SIZE;
hash->count = 0;
return 0;
}
//
void kvs_hash_destroy(kvs_hash_t *hash) {
if (!hash || !hash->nodes) return;
for (int i = 0; i < hash->max_slots; i++) {
hashnode_t *node = hash->nodes[i];
while (node != NULL) {
hashnode_t *tmp = node;
node = node->next;
if (tmp->key) kvs_free(tmp->key);
if (tmp->value) kvs_free(tmp->value);
kvs_free(tmp);
}
hash->nodes[i] = NULL;
}
kvs_free(hash->nodes);
hash->nodes = NULL;
hash->max_slots = 0;
hash->count = 0;
}
// 5 + 2
// mp
/*
* @return: <0 error; =0 success; >0 exist
*/
int kvs_hash_set_bin(kvs_hash_t *hash, const void *key, size_t key_len, const void *value, size_t value_len) {
if (!hash || !hash->nodes || !key || key_len == 0 || !value) return -1;
int idx = _hash(key, key_len, MAX_TABLE_SIZE);
if (idx < 0) return -1;
hashnode_t *node = hash->nodes[idx];
while (node != NULL) {
if (_key_equal(node, key, key_len)) { // exist
return 1;
}
node = node->next;
}
hashnode_t *new_node = _create_node(key, key_len, value, value_len);
if (!new_node) return -2;
new_node->next = hash->nodes[idx];
hash->nodes[idx] = new_node;
hash->count ++;
return 0;
}
/*
* get 返回value 指针(由 hash 持有),并通过 out_value_len 返回长度
*/
void *kvs_hash_get_bin(kvs_hash_t *hash, const void *key, size_t key_len, size_t *out_value_len) {
if (!hash || !hash->nodes || !key || key_len == 0 || !out_value_len) return NULL;
*out_value_len = 0;
int idx = _hash(key, key_len, MAX_TABLE_SIZE);
if (idx < 0) return NULL;
hashnode_t *node = hash->nodes[idx];
while (node != NULL) {
if (_key_equal(node, key, key_len)) {
*out_value_len = node->value_len;
return node->value;
}
node = node->next;
}
return NULL;
}
/*
* @return <0 error; =0 success; >0 no exist
*/
int kvs_hash_mod_bin(kvs_hash_t *hash, const void *key, size_t key_len, const void *value, size_t value_len) {
if (!hash || !hash->nodes || !key || key_len == 0 || !value) return -1;
int idx = _hash(key, key_len, MAX_TABLE_SIZE);
if (idx < 0) return -1;
hashnode_t *node = hash->nodes[idx];
while (node != NULL) {
if (_key_equal(node, key, key_len)) {
break;
}
node = node->next;
}
if (node == NULL) {
return 1;
}
// node -->
if (node->value) kvs_free(node->value);
node->value = NULL;
node->value_len = 0;
if (value_len > 0) {
uint8_t *vcopy = (uint8_t*)kvs_malloc(value_len);
if (!vcopy) return -2;
memcpy(vcopy, value, value_len);
node->value = vcopy;
node->value_len = value_len;
}
return 0;
}
int kvs_hash_count(kvs_hash_t *hash) {
return hash->count;
}
/*
* @return 0 success; <0 error/noexist
*/
int kvs_hash_del_bin(kvs_hash_t *hash, const void *key, size_t key_len) {
if (!hash || !key || key_len == 0) return -2;
int idx = _hash(key, key_len, MAX_TABLE_SIZE);
if (idx < 0) return -2;
hashnode_t *head = hash->nodes[idx];
if (head == NULL) return -1; // noexist
// head node
if (_key_equal(head, key, key_len)) {
hashnode_t *tmp = head->next;
hash->nodes[idx] = tmp;
if (head->key) kvs_free(head->key);
if (head->value) kvs_free(head->value);
kvs_free(head);
hash->count --;
return 0;
}
hashnode_t *cur = head;
while (cur->next != NULL) {
if (_key_equal(cur->next, key, key_len)) break; // search node
cur = cur->next;
}
if (cur->next == NULL) {
return -1;
}
hashnode_t *tmp = cur->next;
cur->next = tmp->next;
if (tmp->key) kvs_free(tmp->key);
if (tmp->value) kvs_free(tmp->value);
kvs_free(tmp);
hash->count --;
return 0;
}
/*
* @return 0 exist, 1 no exist
*/
int kvs_hash_exist_bin(kvs_hash_t *hash, const void *key, size_t key_len) {
size_t vlen = 0;
void *value = kvs_hash_get_bin(hash, key, key_len, &vlen);
return value ? 0 : 1;
}
#if 0
int main() {
kvs_hash_create(&hash);
kvs_hash_set(&hash, "Teacher1", "King");
kvs_hash_set(&hash, "Teacher2", "Darren");
kvs_hash_set(&hash, "Teacher3", "Mark");
kvs_hash_set(&hash, "Teacher4", "Vico");
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");
printf("mode Teacher1 ret : %d\n", ret);
char *value2 = kvs_hash_get(&hash, "Teacher1");
printf("Teacher2 : %s\n", value1);
ret = kvs_hash_del(&hash, "Teacher1");
printf("delete Teacher1 ret : %d\n", ret);
ret = kvs_hash_exist(&hash, "Teacher1");
printf("Exist Teacher1 ret : %d\n", ret);
kvs_hash_destroy(&hash);
return 0;
}
#endif

View File

@@ -451,7 +451,7 @@ int kvs_rbtree_create(kvs_rbtree_t *inst) {
}
void kvs_rbtree_destory(kvs_rbtree_t *inst) {
void kvs_rbtree_destroy(kvs_rbtree_t *inst) {
if (inst == NULL) return ;

View File

@@ -2,6 +2,18 @@
#include "kvs_rw_tools.h"
#include <arpa/inet.h>
#if ENABLE_ARRAY
extern kvs_array_t global_array;
#endif
#if ENABLE_RBTREE
extern kvs_rbtree_t global_rbtree;
#endif
#if ENABLE_HASH
extern kvs_hash_t global_hash;
#endif
int kvs_need(const uint8_t *p, const uint8_t *end, size_t n) {
return (p + n <= end) ? 0 : -1;
}
@@ -159,6 +171,181 @@ void kvs_free_request(kvs_req_t *req) {
req->argc = 0;
}
/**
* 输入req
* 输出rsp
*/
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;
size_t key_len = 0;
const void *key = NULL;
size_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;
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
default:
rsp_out->status = KVS_STATUS_BADREQ;
return -1;
}
return -1;
}
int kvs_build_one_rsp(const kvs_rsp_t *results, uint8_t *response, size_t response_cap){
if (!results || !response) return -1;

View File

@@ -25,7 +25,7 @@ int kvs_write_u32(uint8_t **pp, const uint8_t *end, uint32_t v);
#define KVS_MAX_CMDS_PER_CALL 64
// 1MB
#define KVS_MAX_RESPONSE (1024u * 1024u)
#define KVS_MAX_ARGC 64
#define KVS_MAX_ARGC 4
#define KVS_MAX_ARGLEN (1024u * 1024u)
#define KVS_MAX_CMD_BYTES (4u * 1024u * 1024u)
@@ -37,6 +37,30 @@ enum {
KVS_STATUS_BADREQ = 4
};
enum {
KVS_CMD_START = 0,
// array
KVS_CMD_SET = KVS_CMD_START,
KVS_CMD_GET,
KVS_CMD_DEL,
KVS_CMD_MOD,
KVS_CMD_EXIST,
// rbtree
KVS_CMD_RSET,
KVS_CMD_RGET,
KVS_CMD_RDEL,
KVS_CMD_RMOD,
KVS_CMD_REXIST,
// hash
KVS_CMD_HSET,
KVS_CMD_HGET,
KVS_CMD_HDEL,
KVS_CMD_HMOD,
KVS_CMD_HEXIST,
KVS_CMD_COUNT,
};
typedef enum {
KVS_OK = 1,
KVS_NEED_MORE = 0,

196
kvstore.c
View File

@@ -32,32 +32,6 @@ const char *command[] = {
"HSET", "HGET", "HDEL", "HMOD", "HEXIST"
};
enum {
KVS_CMD_START = 0,
// array
KVS_CMD_SET = KVS_CMD_START,
KVS_CMD_GET,
KVS_CMD_DEL,
KVS_CMD_MOD,
KVS_CMD_EXIST,
// rbtree
KVS_CMD_RSET,
KVS_CMD_RGET,
KVS_CMD_RDEL,
KVS_CMD_RMOD,
KVS_CMD_REXIST,
// hash
KVS_CMD_HSET,
KVS_CMD_HGET,
KVS_CMD_HDEL,
KVS_CMD_HMOD,
KVS_CMD_HEXIST,
KVS_CMD_COUNT,
};
const char *response[] = {
};
@@ -86,6 +60,10 @@ int kvs_split_token(char *msg, char *tokens[]) {
// tokens[1] : Key
// tokens[2] : Value
#if BIN_SAFE
#else
int kvs_filter_protocol(char **tokens, int count, char *response) {
if (tokens[0] == NULL || count == 0 || response == NULL) return -1;
@@ -262,168 +240,8 @@ int kvs_filter_protocol(char **tokens, int count, char *response) {
return length;
}
/**
* 输入req
* 输出rsp
*/
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;
const char *key = (argc >= 1) ? argv[0].data : NULL;
const char *val = (argc >= 2) ? argv[1].data : NULL;
// 基本参数校验(按你原有命令语义)
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;
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(&global_array, (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_GET:
result = kvs_array_get(&global_array, (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_DEL:
ret = kvs_array_del(&global_array, (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_MOD:
ret = kvs_array_mod(&global_array, (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_EXIST:
ret = kvs_array_exist(&global_array, (char*)key);
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(&global_hash, (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_HGET:
result = kvs_hash_get(&global_hash, (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_HDEL:
ret = kvs_hash_del(&global_hash, (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_HMOD:
ret = kvs_hash_mod(&global_hash, (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_HEXIST:
ret = kvs_hash_exist(&global_hash, (char*)key);
rsp_out->status = (ret == 0) ? KVS_STATUS_EXIST : KVS_STATUS_NO_EXIST;
return 0;
#endif
default:
rsp_out->status = KVS_STATUS_BADREQ;
return -1;
}
return -1;
}
#if NEW_KVSTORE
/**
@@ -542,13 +360,13 @@ int init_kvengine(void) {
void dest_kvengine(void) {
#if ENABLE_ARRAY
kvs_array_destory(&global_array);
kvs_array_destroy(&global_array);
#endif
#if ENABLE_RBTREE
kvs_rbtree_destory(&global_rbtree);
kvs_rbtree_destroy(&global_rbtree);
#endif
#if ENABLE_HASH
kvs_hash_destory(&global_hash);
kvs_hash_destroy(&global_hash);
#endif
}

View File

@@ -19,11 +19,6 @@
#define NETWORK_SELECT NETWORK_REACTOR
// 8MB
#define MAX_PAYLOAD_LEN 8388608
#define MAX_OPCOUNT 1024
// 4MB
#define MAX_ARG_LEN 4194304
#define KVS_MAX_TOKENS 128
@@ -33,6 +28,8 @@
#define NEW_KVSTORE 1
#define BIN_SAFE 1
// typedef int (*msg_handler)(char *msg, int length, char *response);
typedef int (*msg_handler)(char *request, int request_length, int *consumed_out, char *response, int *response_length);
@@ -45,6 +42,37 @@ extern int ntyco_start(unsigned short port, msg_handler handler);
#if ENABLE_ARRAY
#if BIN_SAFE
#define KVS_ARRAY_SIZE 1024
typedef struct kvs_array_item_s {
uint8_t *key;
size_t key_len;
uint8_t *value;
size_t value_len;
} kvs_array_item_t;
typedef struct kvs_array_s {
kvs_array_item_t *table;
int total; // 元素上界
} kvs_array_t;
int kvs_array_create(kvs_array_t *inst);
void kvs_array_destroy(kvs_array_t *inst);
int kvs_array_set_bin(kvs_array_t *inst,
const void *key, size_t key_len,
const void *value, size_t value_len);
void *kvs_array_get_bin(kvs_array_t *inst,
const void *key, size_t key_len,
size_t *out_value_len);
int kvs_array_del_bin(kvs_array_t *inst, const void *key, size_t key_len);
int kvs_array_mod_bin(kvs_array_t *inst,
const void *key, size_t key_len,
const void *value, size_t value_len);
int kvs_array_exist_bin(kvs_array_t *inst, const void *key, size_t key_len);
#else
typedef struct kvs_array_item_s {
char *key;
char *value;
@@ -59,14 +87,14 @@ typedef struct kvs_array_s {
} kvs_array_t;
int kvs_array_create(kvs_array_t *inst);
void kvs_array_destory(kvs_array_t *inst);
void kvs_array_destroy(kvs_array_t *inst);
int kvs_array_set(kvs_array_t *inst, char *key, char *value);
char* kvs_array_get(kvs_array_t *inst, char *key);
int kvs_array_del(kvs_array_t *inst, char *key);
int kvs_array_mod(kvs_array_t *inst, char *key, char *value);
int kvs_array_exist(kvs_array_t *inst, char *key);
#endif
#endif
@@ -102,7 +130,7 @@ typedef struct _rbtree {
typedef struct _rbtree kvs_rbtree_t;
int kvs_rbtree_create(kvs_rbtree_t *inst);
void kvs_rbtree_destory(kvs_rbtree_t *inst);
void kvs_rbtree_destroy(kvs_rbtree_t *inst);
int kvs_rbtree_set(kvs_rbtree_t *inst, char *key, char *value);
char* kvs_rbtree_get(kvs_rbtree_t *inst, char *key);
int kvs_rbtree_del(kvs_rbtree_t *inst, char *key);
@@ -120,6 +148,38 @@ int kvs_rbtree_exist(kvs_rbtree_t *inst, char *key);
#define MAX_VALUE_LEN 512
#define MAX_TABLE_SIZE 1024
#if BIN_SAFE
#define MAX_TABLE_SIZE 1024
typedef struct hashnode_s {
uint8_t *key;
size_t key_len;
uint8_t *value;
size_t value_len;
struct hashnode_s *next;
} hashnode_t;
typedef struct hashtable_s {
hashnode_t **nodes;
int max_slots;
int count;
} hashtable_t;
typedef struct hashtable_s kvs_hash_t;
int kvs_hash_create(kvs_hash_t *hash);
void kvs_hash_destroy(kvs_hash_t *hash);
int kvs_hash_set_bin(kvs_hash_t *h, const void *key, size_t key_len, const void *value, size_t value_len);
void *kvs_hash_get_bin(kvs_hash_t *h, const void *key, size_t key_len, size_t *out_value_len);
int kvs_hash_get_copy_bin(kvs_hash_t *h, const void *key, size_t key_len, void **out_buf, size_t *out_len);
int kvs_hash_mod_bin(kvs_hash_t *h, const void *key, size_t key_len, const void *value, size_t value_len);
int kvs_hash_del_bin(kvs_hash_t *h, const void *key, size_t key_len);
int kvs_hash_exist_bin(kvs_hash_t *h, const void *key, size_t key_len);
int kvs_hash_count(kvs_hash_t *h);
#else
#define ENABLE_KEY_POINTER 1
@@ -149,14 +209,14 @@ typedef struct hashtable_s kvs_hash_t;
int kvs_hash_create(kvs_hash_t *hash);
void kvs_hash_destory(kvs_hash_t *hash);
void kvs_hash_destroy(kvs_hash_t *hash);
int kvs_hash_set(hashtable_t *hash, char *key, char *value);
char * kvs_hash_get(kvs_hash_t *hash, char *key);
int kvs_hash_mod(kvs_hash_t *hash, char *key, char *value);
int kvs_hash_del(kvs_hash_t *hash, char *key);
int kvs_hash_exist(kvs_hash_t *hash, char *key);
#endif
#endif

View File

@@ -18,7 +18,8 @@
#define BATCH_SIZE (65536)
#define TIME_SUB_MS(tv1, tv2) ((tv1.tv_sec - tv2.tv_sec) * 1000 + (tv1.tv_usec - tv2.tv_usec) / 1000)
#define PRESP print_response
// #define PRESP print_response
#define PRESP
typedef enum {

View File

@@ -67,21 +67,21 @@ void testcase(int connfd, uint8_t op, const char* key, const char* value, rsp_re
void array_testcase_1w(int connfd) {
int count = 1;
int count = 10000;
int i = 0;
struct timeval tv_begin;
gettimeofday(&tv_begin, NULL);
for (i = 0;i < count;i ++) {
testcase(connfd, KVS_CMD_SET, "nage", "lian", KVS_STATUS_OK, NULL, "SET NAME");
testcase(connfd, KVS_CMD_GET, "nage", NULL, KVS_STATUS_OK, "lian", "GET NAME");
testcase(connfd, KVS_CMD_MOD, "nage", "liu", KVS_STATUS_OK, NULL, "MOD NAME");
testcase(connfd, KVS_CMD_GET, "nage", NULL, KVS_STATUS_OK, "liu", "GET NAME");
testcase(connfd, KVS_CMD_HSET, "nage", "lian", KVS_STATUS_OK, NULL, "SET NAME");
testcase(connfd, KVS_CMD_HGET, "nage", NULL, KVS_STATUS_OK, "lian", "GET NAME");
testcase(connfd, KVS_CMD_HMOD, "nage", "liu", KVS_STATUS_OK, NULL, "MOD NAME");
testcase(connfd, KVS_CMD_HGET, "nage", NULL, KVS_STATUS_OK, "liu", "GET NAME");
testcase(connfd, KVS_CMD_EXIST, "nage", NULL, KVS_STATUS_EXIST, NULL, "EXIST NAME");
testcase(connfd, KVS_CMD_DEL, "nage", NULL, KVS_STATUS_OK, NULL, "DEL NAME");
testcase(connfd, KVS_CMD_EXIST, "nage", NULL, KVS_STATUS_NO_EXIST, NULL, "NOT EXIST NAME");
testcase(connfd, KVS_CMD_HEXIST, "nage", NULL, KVS_STATUS_EXIST, NULL, "EXIST NAME");
testcase(connfd, KVS_CMD_HDEL, "nage", NULL, KVS_STATUS_OK, NULL, "DEL NAME");
testcase(connfd, KVS_CMD_HEXIST, "nage", NULL, KVS_STATUS_NO_EXIST, NULL, "NOT EXIST NAME");
}
struct timeval tv_end;
@@ -98,11 +98,14 @@ void do_batch_example(int fd)
kvs_batch_t batch;
kvs_batch_init(&batch);
char key[10]={0}, val[10]={0};
// 组 batch最多 64 条)
kvs_batch_add(&batch, KVS_CMD_SET, "k1", "v1");
kvs_batch_add(&batch, KVS_CMD_SET, "k2", "v2");
kvs_batch_add(&batch, KVS_CMD_GET, "k1", NULL);
kvs_batch_add(&batch, KVS_CMD_GET, "k2", NULL);
for(int i = 0;i < 24; ++ i){
int len = sprintf(key, "k%d", i);
len = sprintf(val, "v%d", i);
kvs_batch_add(&batch, KVS_CMD_HSET, key, val);
}
// 一次性发送
kvs_batch_send(fd, &batch);
@@ -118,10 +121,13 @@ void do_batch_example(int fd)
PRESP("BATCH", &rsps[i]);
}
printf("%d\n", nrsp);
testcase(fd, KVS_CMD_GET, "k1", NULL, KVS_STATUS_OK, "v1", "GET k1");
testcase(fd, KVS_CMD_GET, "k2", NULL, KVS_STATUS_OK, "v2", "GET k2");
for(int i = 0;i < 24; ++ i){
int len = sprintf(key, "k%d", i);
len = sprintf(val, "v%d", i);
testcase(fd, KVS_CMD_HGET, key, NULL, KVS_STATUS_OK, val, "GET K");
}
}
@@ -136,8 +142,8 @@ int main(int argc, char *argv[]) {
int connfd = connect_tcpserver(ip, port);
// array_testcase_1w(connfd);
do_batch_example(connfd);
array_testcase_1w(connfd);
// do_batch_example(connfd);
return 0;
}