/**
* Request
* Cmd: | OP(1) | argc(1) | repeat { arglen(4) | arg } |
*
* Response
* Rsp: | OP(1) | status(1) | datalen(4) | data |
*/
封装客户端进行批处理和单条命令测试。
580 lines
14 KiB
C
580 lines
14 KiB
C
|
||
|
||
|
||
|
||
#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();
|
||
|
||
}
|
||
|
||
|