#include "kvs_dump.h" #include "kvs_rw_tools.h" #include "memory/alloc_dispatch.h" #include "kvs_protocol_resp.h" #include "diskuring/diskuring.h" #include #include #include int global_oplog_fd = -1; static off_t g_log_off = -1; int init_cmd_log(const char *file, int *logfd){ if(!file) return -1; int fd = open(file, O_RDWR | O_CREAT , 0644); if(fd < 0) return -2; g_log_off = lseek(fd, 0, SEEK_END); *logfd = fd; return 0; } int destroy_cmd_log(int logfd){ fsync(logfd); close(logfd); global_oplog_fd = -1; return 0; } int kvs_oplog_append(const uint8_t *cmd, size_t len, int logfd){ if (logfd < 0 || !cmd || len == 0) return -1; if (len > UINT32_MAX) return -2; uint32_t nlen = htonl((uint32_t)len); void *bufs[2]; size_t lens[2]; bufs[0] = (void *)&nlen; lens[0] = sizeof(nlen); bufs[1] = (void *)cmd; lens[1] = len; size_t total = sizeof(nlen) + len; off_t myoff = g_log_off; g_log_off += (off_t)total; task_t *t = submit_write(&global_uring_ctx, logfd, bufs, lens, 2, myoff); if (!t) { return -4; } // task_wait(t); // task_destroy(t); return 0; } int kvs_replay_log(int logfd){ if (logfd < 0) return -1; if (lseek(logfd, 0, SEEK_SET) < 0) { return -1; } for (;;) { uint32_t nlen = 0; int hr = read_full(logfd, &nlen, sizeof(nlen)); if (hr == 0) break; /* EOF:正常结束 */ if (hr < 0) { return -2; } /* 半截头 */ uint32_t len = ntohl(nlen); if (len == 0) { return -3; } uint8_t *cmd_bytes = (uint8_t *)kvs_malloc(len); if (!cmd_bytes ) { return -5; } int pr = read_full(logfd, cmd_bytes, len); if (pr <= 0) { /* 半截 payload */ kvs_free(cmd_bytes ); return -6; } /* -------- RESP parse -------- */ resp_cmd_t cmd; memset(&cmd, 0, sizeof(cmd)); int clen = resp_parse_one_cmd(cmd_bytes, (int)len, &cmd); if (clen <= 0 || clen != (int)len) { /* clen==0: need more data,但日志记录必须是一条完整命令,所以视为坏日志 */ kvs_free(cmd_bytes); return -7; } /* -------- execute -------- */ resp_value_t outvalue; memset(&outvalue, 0, sizeof(outvalue)); int dr = resp_dispatch(&cmd, &outvalue); if (dr < 0) { kvs_free(cmd_bytes); return -8; } /* 注意: * outv 可能引用存储内存,但我们不 build response,因此无需处理。 * cmd_bytes 可以释放,因为 cmd slice 指向 cmd_bytes,仅在 dispatch 期间使用。 * */ kvs_free(cmd_bytes); } g_log_off = lseek(logfd, 0, SEEK_CUR); return 0; } /** * clear log file not close */ int ksv_clear_log(int logfd){ if(logfd < 0) return -1; ftruncate(logfd, 0); lseek(logfd, 0, SEEK_SET); g_log_off = 0; return 0; }