diff --git a/Makefile b/Makefile index a9fe9fb..789e60b 100644 --- a/Makefile +++ b/Makefile @@ -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/ diff --git a/kvs_array.c b/kvs_array.c index f8f9664..0c483ee 100644 --- a/kvs_array.c +++ b/kvs_array.c @@ -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(长度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, 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 \ No newline at end of file diff --git a/kvs_hash.c b/kvs_hash.c index ea31eba..2dc83cb 100755 --- a/kvs_hash.c +++ b/kvs_hash.c @@ -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; } diff --git a/kvs_hash.o b/kvs_hash.o new file mode 100644 index 0000000..1c85d5c Binary files /dev/null and b/kvs_hash.o differ diff --git a/kvs_hash_bin.c b/kvs_hash_bin.c new file mode 100755 index 0000000..979ad03 --- /dev/null +++ b/kvs_hash_bin.c @@ -0,0 +1,300 @@ + + + +#include +#include +#include +#include + + +#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 + + diff --git a/kvs_rbtree.c b/kvs_rbtree.c index 4746b70..ac47a7c 100755 --- a/kvs_rbtree.c +++ b/kvs_rbtree.c @@ -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 ; diff --git a/kvs_rw_tools.c b/kvs_rw_tools.c index a324b0d..21f7a11 100644 --- a/kvs_rw_tools.c +++ b/kvs_rw_tools.c @@ -2,6 +2,18 @@ #include "kvs_rw_tools.h" #include +#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; diff --git a/kvs_rw_tools.h b/kvs_rw_tools.h index ef895cd..81cd003 100644 --- a/kvs_rw_tools.h +++ b/kvs_rw_tools.h @@ -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, diff --git a/kvstore.c b/kvstore.c index a887e42..8ecd5c1 100644 --- a/kvstore.c +++ b/kvstore.c @@ -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 } diff --git a/kvstore.h b/kvstore.h index c894e64..eef0110 100644 --- a/kvstore.h +++ b/kvstore.h @@ -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 diff --git a/test/test_client.h b/test/test_client.h index 6541dcc..74e9ca5 100644 --- a/test/test_client.h +++ b/test/test_client.h @@ -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 { diff --git a/test/testcase.c b/test/testcase.c index 836514b..bf341a2 100644 --- a/test/testcase.c +++ b/test/testcase.c @@ -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; } \ No newline at end of file