Files
ldb/kvstore.c
1iaan 0dc86f5aa5 协议定义与实现, 协议支持 批处理、特殊字符如\r\n\0。与单条命令测试。
/**
 * Header: 	| magic(4) | payloadLen(4) |
 *
 * Request
 * Payload: | opcount(4) | repeat Cmd |
 * Cmd: 	| OP(1) | argc(4) | repeat Arg |
 * Arg:		| arglen(4) | arg |
 *
 * Response
 * Payload: | opcount(4) | repeat Rsp |
 * Rsp:		| OP(1) | status(1) | datalen(4) | data |
 */

 kvstore层,先解析,再执行,最后构建返回体。
 一个是半包问题,没有处理。
 另一个是感觉协议结构有点麻烦,
2026-01-05 23:20:37 +08:00

539 lines
12 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;
}
/**
* 输入op argc argv
* 输出 status
*/
void kvs_exec_one_op(uint8_t op, uint32_t argc, char **argv,
uint8_t *status_out,
const char **data_out, uint32_t *dlen_out) {
*status_out = KVS_STATUS_ERROR;
*data_out = NULL;
*dlen_out = 0;
const char *key = (argc >= 1) ? argv[0] : NULL;
const char *val = (argc >= 2) ? argv[1] : 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) { *status_out = KVS_STATUS_BADREQ; return; }
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) { *status_out = KVS_STATUS_BADREQ; return; }
break;
default:
*status_out = KVS_STATUS_BADREQ;
return;
}
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) *status_out = KVS_STATUS_ERROR;
else if (ret == 0) *status_out = KVS_STATUS_OK;
else *status_out = KVS_STATUS_EXIST;
return;
case KVS_CMD_GET:
result = kvs_array_get(&global_array, (char*)key);
if (!result) { *status_out = KVS_STATUS_NO_EXIST; return; }
*status_out = KVS_STATUS_OK;
*data_out = result;
*dlen_out = (uint32_t)strlen(result);
return;
case KVS_CMD_DEL:
ret = kvs_array_del(&global_array, (char*)key);
if (ret < 0) *status_out = KVS_STATUS_ERROR;
else if (ret == 0) *status_out = KVS_STATUS_OK;
else *status_out = KVS_STATUS_NO_EXIST;
return;
case KVS_CMD_MOD:
ret = kvs_array_mod(&global_array, (char*)key, (char*)val);
if (ret < 0) *status_out = KVS_STATUS_ERROR;
else if (ret == 0) *status_out = KVS_STATUS_OK;
else *status_out = KVS_STATUS_NO_EXIST;
return;
case KVS_CMD_EXIST:
ret = kvs_array_exist(&global_array, (char*)key);
*status_out = (ret == 0) ? KVS_STATUS_EXIST : KVS_STATUS_NO_EXIST;
return;
#endif
#if ENABLE_RBTREE
case KVS_CMD_RSET:
ret = kvs_rbtree_set(&global_rbtree, (char*)key, (char*)val);
if (ret < 0) *status_out = KVS_STATUS_ERROR;
else if (ret == 0) *status_out = KVS_STATUS_OK;
else *status_out = KVS_STATUS_EXIST;
return;
case KVS_CMD_RGET:
result = kvs_rbtree_get(&global_rbtree, (char*)key);
if (!result) { *status_out = KVS_STATUS_NO_EXIST; return; }
*status_out = KVS_STATUS_OK;
*data_out = result;
*dlen_out = (uint32_t)strlen(result);
return;
case KVS_CMD_RDEL:
ret = kvs_rbtree_del(&global_rbtree, (char*)key);
if (ret < 0) *status_out = KVS_STATUS_ERROR;
else if (ret == 0) *status_out = KVS_STATUS_OK;
else *status_out = KVS_STATUS_NO_EXIST;
return;
case KVS_CMD_RMOD:
ret = kvs_rbtree_mod(&global_rbtree, (char*)key, (char*)val);
if (ret < 0) *status_out = KVS_STATUS_ERROR;
else if (ret == 0) *status_out = KVS_STATUS_OK;
else *status_out = KVS_STATUS_NO_EXIST;
return;
case KVS_CMD_REXIST:
ret = kvs_rbtree_exist(&global_rbtree, (char*)key);
*status_out = (ret == 0) ? KVS_STATUS_EXIST : KVS_STATUS_NO_EXIST;
return;
#endif
#if ENABLE_HASH
case KVS_CMD_HSET:
ret = kvs_hash_set(&global_hash, (char*)key, (char*)val);
if (ret < 0) *status_out = KVS_STATUS_ERROR;
else if (ret == 0) *status_out = KVS_STATUS_OK;
else *status_out = KVS_STATUS_EXIST;
return;
case KVS_CMD_HGET:
result = kvs_hash_get(&global_hash, (char*)key);
if (!result) { *status_out = KVS_STATUS_NO_EXIST; return; }
*status_out = KVS_STATUS_OK;
*data_out = result;
*dlen_out = (uint32_t)strlen(result);
return;
case KVS_CMD_HDEL:
ret = kvs_hash_del(&global_hash, (char*)key);
if (ret < 0) *status_out = KVS_STATUS_ERROR;
else if (ret == 0) *status_out = KVS_STATUS_OK;
else *status_out = KVS_STATUS_NO_EXIST;
return;
case KVS_CMD_HMOD:
ret = kvs_hash_mod(&global_hash, (char*)key, (char*)val);
if (ret < 0) *status_out = KVS_STATUS_ERROR;
else if (ret == 0) *status_out = KVS_STATUS_OK;
else *status_out = KVS_STATUS_NO_EXIST;
return;
case KVS_CMD_HEXIST:
ret = kvs_hash_exist(&global_hash, (char*)key);
*status_out = (ret == 0) ? KVS_STATUS_EXIST : KVS_STATUS_NO_EXIST;
return;
#endif
default:
*status_out = KVS_STATUS_BADREQ;
return;
}
}
#if NEW_KVSTORE
// int kvs_protocol(char *msg, int length, char *response, int *response_len){
int kvs_protocol(char *msg, int length, char *response){
if (!msg || length <= 0 || !response) return 0;
int response_len = 0;
kvs_request_t req;
int consumed = kvs_parse_request((const uint8_t *)msg, length, &req);
if (consumed < 0) return 0; // 解析失败
else if(consumed == 0) return 0; // 半包
kvs_response_t *results = (kvs_response_t *)kvs_malloc(sizeof(kvs_response_t) * req.opcount);
if (!results) { kvs_free_request(&req); return -1; }
memset(results, 0, sizeof(kvs_response_t) * req.opcount);
if (kvs_execute_request(&req, results) < 0) {
kvs_free(results);
kvs_free_request(&req);
return -1;
}
int resp_len = kvs_build_response(&req, results, (uint8_t *)response, KVS_MAX_RESPONSE);
kvs_free(results);
kvs_free_request(&req);
if (resp_len < 0) return 0; // error
response_len = resp_len;
return response_len;
}
#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();
}