Files
ldb/kvstore.c
1iaan 144b374aa2 简化协议,
/**
 * Request
 * Cmd: 	| OP(1) | argc(1) | repeat { arglen(4) | arg } |
 *
 * Response
 * Rsp:		| OP(1) | status(1) | datalen(4) | data |
 */

封装客户端进行批处理和单条命令测试。
2026-01-06 19:16:12 +08:00

580 lines
14 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "kvstore.h"
#include "kvs_rw_tools.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
void *kvs_malloc(size_t size) {
return malloc(size);
}
void kvs_free(void *ptr) {
return free(ptr);
}
const char *command[] = {
"SET", "GET", "DEL", "MOD", "EXIST",
"RSET", "RGET", "RDEL", "RMOD", "REXIST",
"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[] = {
};
int kvs_split_token(char *msg, char *tokens[]) {
if (msg == NULL || tokens == NULL) return -1;
int idx = 0;
char *token = strtok(msg, " ");
while (token != NULL) {
//printf("idx: %d, %s\n", idx, token);
tokens[idx ++] = token;
token = strtok(NULL, " ");
}
return idx;
}
// SET Key Value
// tokens[0] : SET
// tokens[1] : Key
// tokens[2] : Value
int kvs_filter_protocol(char **tokens, int count, char *response) {
if (tokens[0] == NULL || count == 0 || response == NULL) return -1;
int cmd = KVS_CMD_START;
for (cmd = KVS_CMD_START;cmd < KVS_CMD_COUNT;cmd ++) {
if (strcmp(tokens[0], command[cmd]) == 0) {
break;
}
}
int length = 0;
int ret = 0;
char *key = tokens[1];
char *value = tokens[2];
switch(cmd) {
#if ENABLE_ARRAY
case KVS_CMD_SET:
ret = kvs_array_set(&global_array ,key, value);
if (ret < 0) {
length = sprintf(response, "ERROR\r\n");
} else if (ret == 0) {
length = sprintf(response, "OK\r\n");
} else {
length = sprintf(response, "EXIST\r\n");
}
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:
ret = kvs_array_del(&global_array ,key);
if (ret < 0) {
length = sprintf(response, "ERROR\r\n");
} else if (ret == 0) {
length = sprintf(response, "OK\r\n");
} else {
length = sprintf(response, "NO EXIST\r\n");
}
break;
case KVS_CMD_MOD:
ret = kvs_array_mod(&global_array ,key, value);
if (ret < 0) {
length = sprintf(response, "ERROR\r\n");
} else if (ret == 0) {
length = sprintf(response, "OK\r\n");
} else {
length = sprintf(response, "NO EXIST\r\n");
}
break;
case KVS_CMD_EXIST:
ret = kvs_array_exist(&global_array ,key);
if (ret == 0) {
length = sprintf(response, "EXIST\r\n");
} else {
length = sprintf(response, "NO EXIST\r\n");
}
break;
#endif
// rbtree
#if ENABLE_RBTREE
case KVS_CMD_RSET:
ret = kvs_rbtree_set(&global_rbtree ,key, value);
if (ret < 0) {
length = sprintf(response, "ERROR\r\n");
} else if (ret == 0) {
length = sprintf(response, "OK\r\n");
} else {
length = sprintf(response, "EXIST\r\n");
}
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:
ret = kvs_rbtree_del(&global_rbtree ,key);
if (ret < 0) {
length = sprintf(response, "ERROR\r\n");
} else if (ret == 0) {
length = sprintf(response, "OK\r\n");
} else {
length = sprintf(response, "NO EXIST\r\n");
}
break;
case KVS_CMD_RMOD:
ret = kvs_rbtree_mod(&global_rbtree ,key, value);
if (ret < 0) {
length = sprintf(response, "ERROR\r\n");
} else if (ret == 0) {
length = sprintf(response, "OK\r\n");
} else {
length = sprintf(response, "NO EXIST\r\n");
}
break;
case KVS_CMD_REXIST:
ret = kvs_rbtree_exist(&global_rbtree ,key);
if (ret == 0) {
length = sprintf(response, "EXIST\r\n");
} else {
length = sprintf(response, "NO EXIST\r\n");
}
break;
#endif
#if ENABLE_HASH
case KVS_CMD_HSET:
ret = kvs_hash_set(&global_hash ,key, value);
if (ret < 0) {
length = sprintf(response, "ERROR\r\n");
} else if (ret == 0) {
length = sprintf(response, "OK\r\n");
} else {
length = sprintf(response, "EXIST\r\n");
}
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:
ret = kvs_hash_del(&global_hash ,key);
if (ret < 0) {
length = sprintf(response, "ERROR\r\n");
} else if (ret == 0) {
length = sprintf(response, "OK\r\n");
} else {
length = sprintf(response, "NO EXIST\r\n");
}
break;
case KVS_CMD_HMOD:
ret = kvs_hash_mod(&global_hash ,key, value);
if (ret < 0) {
length = sprintf(response, "ERROR\r\n");
} else if (ret == 0) {
length = sprintf(response, "OK\r\n");
} else {
length = sprintf(response, "NO EXIST\r\n");
}
break;
case KVS_CMD_HEXIST:
ret = kvs_hash_exist(&global_hash ,key);
if (ret == 0) {
length = sprintf(response, "EXIST\r\n");
} else {
length = sprintf(response, "NO EXIST\r\n");
}
break;
#endif
default:
assert(0);
}
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
/**
* input : request request_length
* output : response response_length consumed_out
* return : -1 error, =0 半包, 1 成功
*/
int kvs_protocol(char *request, int request_length, int *consumed_out, char *response, int *response_length){
if (!request || request_length <= 0 || !consumed_out || !response || !response_length) return KVS_NEED_MORE;
int consumed = 0;
int out_len = 0;
int budget = KVS_MAX_CMDS_PER_CALL;
while(consumed < request_length && (budget-- > 0)){
kvs_req_t req;
memset(&req, 0, sizeof(kvs_req_t));
const uint8_t *p = request+consumed;
int remain = request_length - consumed;
int len = kvs_parse_one_cmd(p, remain, &req);
if(len < 0){
kvs_free_request(&req);
*consumed_out = consumed;
*response_length = out_len;
return KVS_ERROR;
}
else if(len == 0){
kvs_free_request(&req);
break;
}
kvs_rsp_t rsp;
memset(&rsp, 0, sizeof(kvs_rsp_t));
if (kvs_execute_one_cmd(&req, &rsp) < 0){
kvs_free_request(&req);
*consumed_out = consumed;
*response_length = out_len;
return KVS_ERROR;
}
if (out_len >= KVS_MAX_RESPONSE) {
kvs_free_request(&req);
*consumed_out = consumed;
*response_length = out_len;
return KVS_ERROR;
}
int resp_len = kvs_build_one_rsp(&rsp, (uint8_t *)response+out_len, KVS_MAX_RESPONSE-out_len);
kvs_free_request(&req);
if (resp_len < 0) {
*consumed_out = consumed;
*response_length = out_len;
return KVS_ERROR;
}
// printf("resp_len:%d\n", resp_len);
// printf("consumed:%d\n", len);
out_len += resp_len;
consumed += len;
}
*consumed_out = consumed;
*response_length = out_len;
if (consumed == 0 && out_len == 0) return KVS_NEED_MORE;
return KVS_OK;
}
#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_kvengine(void) {
#if ENABLE_ARRAY
memset(&global_array, 0, sizeof(kvs_array_t));
kvs_array_create(&global_array);
#endif
#if ENABLE_RBTREE
memset(&global_rbtree, 0, sizeof(kvs_rbtree_t));
kvs_rbtree_create(&global_rbtree);
#endif
#if ENABLE_HASH
memset(&global_hash, 0, sizeof(kvs_hash_t));
kvs_hash_create(&global_hash);
#endif
return 0;
}
void dest_kvengine(void) {
#if ENABLE_ARRAY
kvs_array_destory(&global_array);
#endif
#if ENABLE_RBTREE
kvs_rbtree_destory(&global_rbtree);
#endif
#if ENABLE_HASH
kvs_hash_destory(&global_hash);
#endif
}
int main(int argc, char *argv[]) {
if (argc != 2) return -1;
int port = atoi(argv[1]);
init_kvengine();
#if (NETWORK_SELECT == NETWORK_REACTOR)
reactor_start(port, kvs_protocol); //
#elif (NETWORK_SELECT == NETWORK_PROACTOR)
proactor_start(port, kvs_protocol);
#elif (NETWORK_SELECT == NETWORK_NTYCO)
ntyco_start(port, kvs_protocol);
#endif
dest_kvengine();
}