132 lines
3.0 KiB
C
132 lines
3.0 KiB
C
#include "kvstore.h"
|
||
#include "kvs_rw_tools.h"
|
||
#include "mem_pool/mem_pool.h"
|
||
#include "kvs_protocol_resp.h"
|
||
#include "diskuring/diskuring.h"
|
||
#include <arpa/inet.h>
|
||
#include <fcntl.h>
|
||
#include <unistd.h>
|
||
|
||
int global_cmd_log_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_cmd_log_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;
|
||
} |