#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(); }