add NtyCo as submodule & 搭建设计ebpf主从同步代码框架
This commit is contained in:
26
dump/kvs_dump.h
Normal file
26
dump/kvs_dump.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef __KVS_DUMP_H__
|
||||
#define __KVS_DUMP_H__
|
||||
|
||||
#include "kvstore.h"
|
||||
|
||||
extern char global_oplog_file[256];
|
||||
extern char global_array_file[256];
|
||||
extern char global_rbtree_file[256];
|
||||
extern char global_hash_file[256];
|
||||
|
||||
int kvs_create_snapshot(const char* array_file, const char* rbtree_file, const char* hash_file);
|
||||
int kvs_create_snapshot_async(const char *ip, int port);
|
||||
void __create_snapshot_ok(const char* array_file, const char* rbtree_file, const char* hash_file);
|
||||
|
||||
extern int global_oplog_fd;
|
||||
|
||||
|
||||
int init_cmd_log(const char *file, int *logfd);
|
||||
int destroy_cmd_log(int logfd);
|
||||
|
||||
int kvs_oplog_append(const uint8_t *cmd, size_t len, int logfd);
|
||||
int kvs_replay_log(int logfd);
|
||||
int ksv_clear_log(int logfd);
|
||||
|
||||
|
||||
#endif
|
||||
132
dump/kvs_oplog.c
Normal file
132
dump/kvs_oplog.c
Normal file
@@ -0,0 +1,132 @@
|
||||
#include "kvs_dump.h"
|
||||
#include "kvs_rw_tools.h"
|
||||
#include "memory/alloc_dispatch.h"
|
||||
#include "kvs_protocol_resp.h"
|
||||
#include "diskuring/diskuring.h"
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
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;
|
||||
}
|
||||
78
dump/kvs_snapshot.c
Normal file
78
dump/kvs_snapshot.c
Normal file
@@ -0,0 +1,78 @@
|
||||
#include "kvstore.h"
|
||||
#include <unistd.h>
|
||||
|
||||
char global_oplog_file[256] = "kvs_oplog.default.db";
|
||||
char global_array_file[256] = "kvs_array.default.db";
|
||||
char global_rbtree_file[256] = "kvs_rbtree.default.db";
|
||||
char global_hash_file[256] = "kvs_hash.default.db";
|
||||
|
||||
int kvs_create_snapshot(const char* array_file, const char* rbtree_file, const char* hash_file){
|
||||
int ret = 0;
|
||||
int rc = 0;
|
||||
#if ENABLE_ARRAY
|
||||
rc = kvs_array_save(&global_array, array_file);
|
||||
if(rc < 0){
|
||||
printf("kvs_engine_array save error\n");
|
||||
ret = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ENABLE_RBTREE
|
||||
rc = kvs_rbtree_save(&global_rbtree, rbtree_file);
|
||||
if(rc < 0){
|
||||
printf("kvs_engine_rbtree save error\n");
|
||||
ret = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ENABLE_HASH
|
||||
rc = kvs_hash_save(&global_hash, hash_file);
|
||||
if(rc < 0){
|
||||
printf("kvs_engine_hash save error\n");
|
||||
ret = -1;
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __create_snapshot_ok(const char* array_file, const char* rbtree_file, const char* hash_file){
|
||||
|
||||
}
|
||||
|
||||
int kvs_create_snapshot_async(const char *ip, int port){
|
||||
int pipefd[2]; // 用于子进程通知主进程
|
||||
if (pipe(pipefd) == -1) { perror("pipe"); return -1; }
|
||||
pid_t pid = fork();
|
||||
if (pid == -1) { perror("fork"); return -1; }
|
||||
|
||||
if (pid == 0) { // 子进程
|
||||
close(pipefd[0]); // 关闭读端
|
||||
// 指定临时文件路径,避免覆盖 global_xxx_file
|
||||
char tmp_array[128]; // 可写缓冲区
|
||||
char tmp_rbtree[128];
|
||||
char tmp_hash[128];
|
||||
|
||||
snprintf(tmp_array, sizeof(tmp_array), "snapshot_array_%s.tmp", ip);
|
||||
snprintf(tmp_rbtree, sizeof(tmp_rbtree), "snapshot_rbtree_%s.tmp", ip);
|
||||
snprintf(tmp_hash, sizeof(tmp_hash), "snapshot_hash_%s.tmp", ip);
|
||||
|
||||
int ret = kvs_create_snapshot(tmp_array, tmp_rbtree, tmp_hash);
|
||||
if (ret == 0) {
|
||||
// 成功:rename 到最终路径,或直接通知
|
||||
write(pipefd[1], "OK", 2); // 通知主进程
|
||||
} else {
|
||||
write(pipefd[1], "ERR", 3);
|
||||
}
|
||||
close(pipefd[1]);
|
||||
_exit(0); // 子进程退出
|
||||
|
||||
// hook point
|
||||
__create_snapshot_ok(tmp_array, tmp_rbtree, tmp_hash);
|
||||
} else { // 主进程
|
||||
close(pipefd[1]); // 关闭写端
|
||||
// 立即返回,继续处理其他请求(不阻塞)
|
||||
// 可以记录 pid,在别处 waitpid(pid, NULL, WNOHANG) 检查完成
|
||||
// 或用信号:signal(SIGCHLD, handler); 在 handler 中 read(pipefd[0]) 检查 "OK"
|
||||
return 0; // SYNC 响应成功,主进程继续
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user