bugfix: reactor网络模型的的半包解析错误问题。

全量持久化时清除增量持久化的记录。
This commit is contained in:
2026-01-08 16:20:00 +08:00
parent 3cc97b9454
commit de21fe94ec
10 changed files with 282 additions and 121 deletions

View File

@@ -138,59 +138,55 @@ int parse_response(const uint8_t *buf, int buflen, kvs_response_t *rsp) {
void print_response(const char *cmd_name, const kvs_response_t *rsp) {
printf("\n=== %s Response ===\n", cmd_name);
printf("OP: %u\n", rsp->op);
printf("Status: %u ", rsp->status);
switch (rsp->status) {
case KVS_STATUS_OK:
printf("(OK)\n");
break;
case KVS_STATUS_ERROR:
printf("(ERROR)\n");
break;
case KVS_STATUS_NO_EXIST:
printf("(NO_EXIST)\n");
break;
case KVS_STATUS_EXIST:
printf("(EXISTS)\n");
break;
default:
printf("(UNKNOWN)\n");
break;
}
printf("Data Length: %u\n", rsp->datalen);
if (rsp->datalen > 0 && rsp->data != NULL) {
printf("Data: ");
// 尝试以字符串形式打印(如果是可打印字符)
int is_printable = 1;
for (uint32_t i = 0; i < rsp->datalen; i++) {
if (rsp->data[i] < 32 || rsp->data[i] > 126) {
is_printable = 0;
break;
}
}
if (is_printable) {
printf("\"");
printf("%s ", cmd_name);
if(rsp->op == KVS_CMD_GET){
if (rsp->datalen > 0 && rsp->data != NULL) {
printf("Data: ");
// 尝试以字符串形式打印(如果是可打印字符)
int is_printable = 1;
for (uint32_t i = 0; i < rsp->datalen; i++) {
printf("%c", rsp->data[i]);
if (rsp->data[i] < 32 || rsp->data[i] > 126) {
is_printable = 0;
break;
}
}
if (is_printable) {
printf("\"");
for (uint32_t i = 0; i < rsp->datalen; i++) {
printf("%c", rsp->data[i]);
}
printf("\"\n");
} else {
// 以十六进制打印
printf("0x");
for (uint32_t i = 0; i < rsp->datalen; i++) {
printf("%02x", rsp->data[i]);
}
printf("\n");
}
printf("\"\n");
} else {
// 以十六进制打印
printf("0x");
for (uint32_t i = 0; i < rsp->datalen; i++) {
printf("%02x", rsp->data[i]);
}
printf("\n");
printf("Data: (empty)\n");
}
}else {
switch (rsp->status) {
case KVS_STATUS_OK:
printf("(OK)\n");
break;
case KVS_STATUS_ERROR:
printf("(ERROR)\n");
break;
case KVS_STATUS_NO_EXIST:
printf("(NO_EXIST)\n");
break;
case KVS_STATUS_EXIST:
printf("(EXISTS)\n");
break;
default:
printf("(UNKNOWN)\n");
break;
}
} else {
printf("Data: (empty)\n");
}
printf("==================\n");
}
int verify_response(const kvs_response_t *rsp, uint8_t expected_op,

View File

@@ -14,8 +14,9 @@
#include <sys/socket.h>
#include <arpa/inet.h>
#define CMD_SIZE (4096)
#define CMD_SIZE (1024)
#define BATCH_SIZE (65536)
#define KVS_BATCH_MAX 64
#define TIME_SUB_MS(tv1, tv2) ((tv1.tv_sec - tv2.tv_sec) * 1000 + (tv1.tv_usec - tv2.tv_usec) / 1000)
#define PRESP print_response
@@ -81,7 +82,6 @@ int verify_response(const kvs_response_t *rsp, uint8_t expected_op,
#define KVS_BATCH_MAX 64
typedef struct {
uint8_t buf[BATCH_SIZE];
@@ -101,10 +101,8 @@ static void kvs_batch_init(kvs_batch_t *b)
* 用 getcmd() 生成单条命令,然后 append 到 batch buffer
* 返回0 成功,-1 失败(太多条 or buffer 不够)
*/
static int kvs_batch_add(kvs_batch_t *b, uint8_t op, const char *key, const char *value)
{
static int kvs_batch_add(kvs_batch_t *b, uint8_t op, const char *key, const char *value){
if (b->cnt >= KVS_BATCH_MAX) return -1;
uint8_t tmp[CMD_SIZE];
int n = getcmd(op, key, value, tmp); // 你提供的函数
if (n <= 0) return -1;
@@ -124,6 +122,7 @@ static int kvs_batch_add(kvs_batch_t *b, uint8_t op, const char *key, const char
*/
static int kvs_batch_send(int fd, const kvs_batch_t *b)
{
printf("send : %d\n", b->len);
return (int)send(fd, b->buf, b->len, 0);
}
@@ -138,19 +137,26 @@ static int kvs_batch_recv_parse(int fd,
uint8_t *recvbuf,
int recvbuf_cap)
{
int nrecv = (int)recv(fd, recvbuf, recvbuf_cap, 0);
if (nrecv <= 0) return -1;
int off = 0;
int parsed = 0;
int used = 0;
while (parsed < b->cnt && off < nrecv) {
int consumed = parse_response(recvbuf + off, nrecv - off, &rsps[parsed]);
if (consumed <= 0) break; // 不够解析/失败,简单处理:直接退出
while(parsed < b->cnt){
printf("recv loop: parsed=%d\n", parsed);
int nrecv = (int)recv(fd, recvbuf+used, recvbuf_cap, 0);
printf("recv nrecv=%d\n", nrecv);
if (nrecv <= 0) return -1;
off += consumed;
parsed++;
int off = 0;
while (parsed < b->cnt) {
int consumed = parse_response(recvbuf + used, nrecv - off, &rsps[parsed]);
if (consumed <= 0) break; // 不够解析/失败,简单处理:直接退出
off += consumed;
used+= consumed;
parsed++;
}
printf("after parse: parsed=%d, used=%d\n", parsed, used);
}
return parsed;
}

View File

@@ -95,7 +95,67 @@ void array_testcase_1w(int connfd) {
}
void do_batch_example(int fd)
void rbtree_testcase_1w(int connfd) {
int count = 1000;
int i = 0;
struct timeval tv_begin;
gettimeofday(&tv_begin, NULL);
for (i = 0;i < count;i ++) {
testcase(connfd, KVS_CMD_RSET, "name", "lian", KVS_STATUS_OK, NULL, "SET NAME");
testcase(connfd, KVS_CMD_RGET, "name", NULL, KVS_STATUS_OK, "lian", "GET NAME");
testcase(connfd, KVS_CMD_RMOD, "name", "liu", KVS_STATUS_OK, NULL, "MOD NAME");
testcase(connfd, KVS_CMD_RGET, "name", NULL, KVS_STATUS_OK, "liu", "GET NAME");
testcase(connfd, KVS_CMD_REXIST, "name", NULL, KVS_STATUS_EXIST, NULL, "EXIST NAME");
testcase(connfd, KVS_CMD_RDEL, "name", NULL, KVS_STATUS_OK, NULL, "DEL NAME");
testcase(connfd, KVS_CMD_REXIST, "name", NULL, KVS_STATUS_NO_EXIST, NULL, "NOT EXIST NAME");
testcase(connfd, KVS_CMD_RMOD, "stu", "liu", KVS_STATUS_NO_EXIST, NULL, "MOD NAME");
testcase(connfd, KVS_CMD_RDEL, "stu", NULL, KVS_STATUS_NO_EXIST, NULL, "DEL SUT");
}
struct timeval tv_end;
gettimeofday(&tv_end, NULL);
int time_used = TIME_SUB_MS(tv_end, tv_begin); // ms
printf("array testcase --> time_used: %d, qps: %d\n", time_used, 9000 * 1000 / time_used);
}
void hash_testcase_1w(int connfd) {
int count = 1000;
int i = 0;
struct timeval tv_begin;
gettimeofday(&tv_begin, NULL);
for (i = 0;i < count;i ++) {
testcase(connfd, KVS_CMD_HSET, "name", "lian", KVS_STATUS_OK, NULL, "SET NAME");
testcase(connfd, KVS_CMD_HGET, "name", NULL, KVS_STATUS_OK, "lian", "GET NAME");
testcase(connfd, KVS_CMD_HMOD, "name", "liu", KVS_STATUS_OK, NULL, "MOD NAME");
testcase(connfd, KVS_CMD_HGET, "name", NULL, KVS_STATUS_OK, "liu", "GET NAME");
testcase(connfd, KVS_CMD_HEXIST, "name", NULL, KVS_STATUS_EXIST, NULL, "EXIST NAME");
testcase(connfd, KVS_CMD_HDEL, "name", NULL, KVS_STATUS_OK, NULL, "DEL NAME");
testcase(connfd, KVS_CMD_HEXIST, "name", NULL, KVS_STATUS_NO_EXIST, NULL, "NOT EXIST NAME");
testcase(connfd, KVS_CMD_HMOD, "stu", "liu", KVS_STATUS_NO_EXIST, NULL, "MOD NAME");
testcase(connfd, KVS_CMD_HDEL, "stu", NULL, KVS_STATUS_NO_EXIST, NULL, "DEL SUT");
}
struct timeval tv_end;
gettimeofday(&tv_end, NULL);
int time_used = TIME_SUB_MS(tv_end, tv_begin); // ms
printf("array testcase --> time_used: %d, qps: %d\n", time_used, 9000 * 1000 / time_used);
}
void do_batch_SET_example(int fd)
{
kvs_batch_t batch;
kvs_batch_init(&batch);
@@ -103,7 +163,7 @@ void do_batch_example(int fd)
char key[10]={0}, val[10]={0};
// 组 batch最多 64 条)
for(int i = 0;i < 24; ++ i){
for(int i = 0;i < 48; ++ i){
int len = sprintf(key, "k%d", i);
len = sprintf(val, "v%d", i);
kvs_batch_add(&batch, KVS_CMD_SET, key, val);
@@ -120,16 +180,67 @@ void do_batch_example(int fd)
// 打印/处理
for (int i = 0; i < nrsp; i++) {
PRESP("BATCH", &rsps[i]);
}
int len = sprintf(key, "SET%d", i);
PRESP(key, &rsps[i]);
}
}
void do_batch_GET_example(int fd)
{
kvs_batch_t batch;
kvs_batch_init(&batch);
// for(int i = 0;i < 24; ++ i){
// int len = sprintf(key, "k%d", i);
// len = sprintf(val, "v%d", i);
// testcase(fd, KVS_CMD_GET, key, NULL, KVS_STATUS_OK, val, "GET K");
// }
char key[10]={0}, val[10]={0};
// 组 batch最多 64 条)
for(int i = 0;i < 48; ++ i){
int len = sprintf(key, "k%d", i);
kvs_batch_add(&batch, KVS_CMD_GET, key, NULL);
}
// 一次性发送
kvs_batch_send(fd, &batch);
// 一次性 recv + parse
uint8_t recvbuf[BATCH_SIZE];
kvs_response_t rsps[KVS_BATCH_MAX];
int nrsp = kvs_batch_recv_parse(fd, &batch, rsps, recvbuf, sizeof(recvbuf));
// 打印/处理
for (int i = 0; i < nrsp; i++) {
int len = sprintf(key, "GET%d", i);
PRESP(key, &rsps[i]);
}
}
void do_batch_DEL_example(int fd)
{
kvs_batch_t batch;
kvs_batch_init(&batch);
char key[10]={0}, val[10]={0};
// 组 batch最多 64 条)
for(int i = 0;i < 48; ++ i){
int len = sprintf(key, "k%d", i);
kvs_batch_add(&batch, KVS_CMD_DEL, key, NULL);
}
// 一次性发送
kvs_batch_send(fd, &batch);
// 一次性 recv + parse
uint8_t recvbuf[BATCH_SIZE];
kvs_response_t rsps[KVS_BATCH_MAX];
int nrsp = kvs_batch_recv_parse(fd, &batch, rsps, recvbuf, sizeof(recvbuf));
// 打印/处理
for (int i = 0; i < nrsp; i++) {
int len = sprintf(key, "DEL%d", i);
PRESP(key, &rsps[i]);
}
}
void save(int connfd){
@@ -150,10 +261,18 @@ int main(int argc, char *argv[]) {
int connfd = connect_tcpserver(ip, port);
if(mode == 0){
do_batch_example(connfd);
do_batch_SET_example(connfd);
}else if(mode == 1){
array_testcase_1w(connfd);
do_batch_GET_example(connfd);
}else if(mode == 2){
do_batch_DEL_example(connfd);
}else if(mode == 10){
array_testcase_1w(connfd);
}else if(mode == 11){
rbtree_testcase_1w(connfd);
}else if(mode == 12){
hash_testcase_1w(connfd);
}else if(mode == -1){
save(connfd);
}
return 0;