主从同步,实现新的更改应用到slave上,实现同步slave未上线时间的更改。
This commit is contained in:
203
kvstore.c
203
kvstore.c
@@ -8,6 +8,10 @@
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#if ENABLE_ARRAY
|
||||
extern kvs_array_t global_array;
|
||||
@@ -25,6 +29,11 @@ extern kvs_hash_t global_hash;
|
||||
extern mp_pool_t global_mempool;
|
||||
#endif
|
||||
|
||||
#define KVS_SERVER_NOT_INIT 0
|
||||
#define KVS_SERVER_MASETER 1
|
||||
#define KVS_SERVER_SLAVE 2
|
||||
int kvs_server_role = KVS_SERVER_NOT_INIT;
|
||||
|
||||
int global_cmd_log_fd = -1;
|
||||
|
||||
const char *command[] = {
|
||||
@@ -185,6 +194,7 @@ void kvs_free_request(kvs_req_t *req) {
|
||||
case KVS_CMD_HGET:
|
||||
case KVS_CMD_HDEL:
|
||||
case KVS_CMD_HEXIST:
|
||||
case KVS_CMD_PSYNC:
|
||||
if (argc != 1 || !key) { rsp_out->status = KVS_STATUS_BADREQ; return -1; }
|
||||
break;
|
||||
case KVS_CMD_SAVE:
|
||||
@@ -311,6 +321,10 @@ void kvs_free_request(kvs_req_t *req) {
|
||||
if(ret == 0) rsp_out->status = KVS_STATUS_OK;
|
||||
else rsp_out->status = KVS_STATUS_ERROR;
|
||||
return 0;
|
||||
case KVS_CMD_PSYNC:
|
||||
rsp_out->op = req->op;
|
||||
rsp_out->status = KVS_STATUS_OK;
|
||||
return 0;
|
||||
default:
|
||||
rsp_out->status = KVS_STATUS_BADREQ;
|
||||
return -1;
|
||||
@@ -380,13 +394,30 @@ int kvs_save_to_file(){
|
||||
return ret;
|
||||
}
|
||||
|
||||
int is_update_cmd(kvs_cmd_t op){
|
||||
if(op == KVS_CMD_SET || op == KVS_CMD_RSET || op == KVS_CMD_HSET
|
||||
|| op == KVS_CMD_MOD || op == KVS_CMD_RMOD || op == KVS_CMD_HMOD
|
||||
|| op == KVS_CMD_DEL || op == KVS_CMD_RDEL || op == KVS_CMD_HDEL){
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* input : request request_length
|
||||
* output : response response_length
|
||||
* return : -1 error, =0 半包, 1 成功
|
||||
*/
|
||||
int kvs_protocol(char *request, int request_length, char *response, int *response_length){
|
||||
|
||||
|
||||
// int kvs_protocol(char *request, int request_length, char *response, int *response_length){
|
||||
int kvs_protocol(struct conn* conn){
|
||||
if (!conn) return -1;
|
||||
char *request = conn->rbuffer;
|
||||
int request_length = conn->rlength;
|
||||
char *response = conn->wbuffer;
|
||||
int *response_length = &conn->wlength;
|
||||
|
||||
if (!request || request_length <= 0 || !response || !response_length) return -1;
|
||||
int consumed = 0;
|
||||
int out_len = 0;
|
||||
@@ -430,14 +461,16 @@ int kvs_protocol(char *request, int request_length, char *response, int *respons
|
||||
}else{
|
||||
// 执行成功,在这里保存到日志中。
|
||||
if(rsp.status == KVS_STATUS_OK){
|
||||
if(req.op != KVS_CMD_GET && req.op != KVS_CMD_EXIST
|
||||
&& req.op != KVS_CMD_RGET && req.op != KVS_CMD_REXIST
|
||||
&& req.op != KVS_CMD_HGET && req.op != KVS_CMD_HEXIST ){
|
||||
if(is_update_cmd(req.op)){
|
||||
kvs_save_cmd_to_logfile(p, len, global_cmd_log_fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(req.op == KVS_CMD_PSYNC){
|
||||
build_thread_to_sync(req.args->data, conn);
|
||||
}
|
||||
|
||||
int resp_len = kvs_build_one_rsp(&rsp, (uint8_t *)response+out_len, KVS_MAX_RESPONSE-out_len);
|
||||
// 构建响应 <0 构建失败
|
||||
kvs_free_request(&req);
|
||||
@@ -446,16 +479,147 @@ int kvs_protocol(char *request, int request_length, char *response, int *respons
|
||||
return -1;
|
||||
}
|
||||
|
||||
// printf("resp_len:%d\n", resp_len);
|
||||
// printf("consumed:%d\n", len);
|
||||
out_len += resp_len;
|
||||
consumed += len;
|
||||
}
|
||||
|
||||
// slave 暂时不需要回报,或者回一个new_offset
|
||||
if(conn->is_from_master){
|
||||
conn->wlength = 0;
|
||||
return consumed;
|
||||
}
|
||||
*response_length = out_len;
|
||||
return consumed;
|
||||
}
|
||||
|
||||
extern void sync_wakeup(int fd);
|
||||
static int g_slavefd = -1;
|
||||
static uint64_t g_offset = 0;
|
||||
|
||||
static void *sync_thread_main(void *arg) {
|
||||
struct conn *conn = (struct conn*) arg;
|
||||
|
||||
int logfd = open(KVS_CMD_LOG_FILE, O_RDONLY);
|
||||
if (logfd < 0) {
|
||||
printf("open replaylog failed: %s\n", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&conn->g_sync_lock);
|
||||
uint64_t off = g_offset;
|
||||
pthread_mutex_unlock(&conn->g_sync_lock);
|
||||
|
||||
while (1) {
|
||||
|
||||
// 单槽位:等 reactor 发完再填
|
||||
pthread_mutex_lock(&conn->g_sync_lock);
|
||||
int busy = (conn->wlength > 0);
|
||||
pthread_mutex_unlock(&conn->g_sync_lock);
|
||||
if (busy) { usleep(10 * 1000); continue; }
|
||||
|
||||
size_t filled = 0;
|
||||
int records = 0;
|
||||
|
||||
// 试图攒一批
|
||||
while (filled < (size_t)KVS_MAX_RESPONSE && records < 128) {
|
||||
|
||||
// 读 len 头
|
||||
uint32_t nlen = 0;
|
||||
ssize_t r = pread(logfd, &nlen, sizeof(nlen), (off_t)off);
|
||||
|
||||
if (r == 0) {
|
||||
// EOF:文件当前没更多数据
|
||||
break;
|
||||
}
|
||||
if (r < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
printf("pread len error: %s\n", strerror(errno));
|
||||
close(logfd);
|
||||
return NULL;
|
||||
}
|
||||
if (r < (ssize_t)sizeof(nlen)) {
|
||||
// 半截 len:writer 还没写完头
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t len = ntohl(nlen);
|
||||
if(len <= 0) {
|
||||
printf("sync error\n");
|
||||
}
|
||||
|
||||
// 这一条放不进本批次,就先发已有的
|
||||
if (filled + len > (size_t)KVS_MAX_RESPONSE) {
|
||||
break;
|
||||
}
|
||||
|
||||
// 读 payload(cmd)
|
||||
ssize_t pr = pread(logfd, conn->wbuffer + filled, len,
|
||||
(off_t)(off + sizeof(nlen)));
|
||||
|
||||
if (pr == 0) {
|
||||
// payload 还没写到
|
||||
break;
|
||||
}
|
||||
if (pr < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
printf("pread payload error: %s\n", strerror(errno));
|
||||
close(logfd);
|
||||
return NULL;
|
||||
}
|
||||
if (pr < (ssize_t)len) {
|
||||
// 半截 payload:writer 还没写完这一条
|
||||
break;
|
||||
}
|
||||
|
||||
// 成功拿到一条完整记录:推进
|
||||
off += sizeof(nlen) + (uint64_t)len;
|
||||
filled += (size_t)len;
|
||||
records++;
|
||||
|
||||
}
|
||||
|
||||
if (filled > 0) {
|
||||
// 提交给 reactor 发送
|
||||
pthread_mutex_lock(&conn->g_sync_lock);
|
||||
conn->wlength = (int)filled;
|
||||
g_offset = off;
|
||||
pthread_mutex_unlock(&conn->g_sync_lock);
|
||||
|
||||
// 唤醒 reactor 发
|
||||
sync_wakeup(conn->fd); // 或 g_slavefd
|
||||
continue;
|
||||
}
|
||||
|
||||
// 没攒到任何完整记录:说明真到末尾/半条记录,等一会儿
|
||||
usleep(10*1000);
|
||||
}
|
||||
|
||||
close(logfd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void build_thread_to_sync(const uint8_t *offset, struct conn* conn){
|
||||
uint64_t off64 = 0;
|
||||
memcpy(&off64, offset, 8);
|
||||
|
||||
pthread_mutex_lock(&conn->g_sync_lock);
|
||||
g_slavefd = conn->fd;
|
||||
g_offset = (uint64_t)off64;
|
||||
|
||||
conn->wlength = 0;
|
||||
pthread_mutex_unlock(&conn->g_sync_lock);
|
||||
|
||||
pthread_t tid;
|
||||
|
||||
int rc = pthread_create(&tid, NULL, sync_thread_main, conn);
|
||||
if (rc != 0) {
|
||||
printf("pthread_create failed: %s\n", strerror(rc));
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_detach(tid);
|
||||
}
|
||||
|
||||
int init_kvengine(void) {
|
||||
|
||||
#if ENABLE_ARRAY
|
||||
@@ -511,18 +675,39 @@ void dest_memory_pool(void){
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* ./ksvtore [role] [port]
|
||||
* ./kvstore master 8888
|
||||
*
|
||||
* ./ksvtore [role] [port] [masterip] [masterport]
|
||||
* ./kvstore slave 7000 192.168.10.129 8888
|
||||
*/
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
if (argc != 2) return -1;
|
||||
if (argc < 3) return -1;
|
||||
|
||||
char *role = argv[1];
|
||||
int port = atoi(argv[2]);
|
||||
|
||||
char *master_ip = NULL;
|
||||
int master_port = -1;
|
||||
|
||||
int port = atoi(argv[1]);
|
||||
if(strcmp(role, "master") == 0){
|
||||
kvs_server_role = KVS_SERVER_SLAVE;
|
||||
}else if(strcmp(role, "slave") == 0){
|
||||
kvs_server_role = KVS_SERVER_MASETER;
|
||||
if(argc < 5) return -1;
|
||||
master_ip = argv[3];
|
||||
master_port = atoi(argv[4]);
|
||||
|
||||
}
|
||||
|
||||
init_memory_pool();
|
||||
init_kvengine();
|
||||
|
||||
|
||||
#if (NETWORK_SELECT == NETWORK_REACTOR)
|
||||
reactor_start(port, kvs_protocol); //
|
||||
reactor_start(port, kvs_protocol, master_ip, master_port); //
|
||||
#elif (NETWORK_SELECT == NETWORK_PROACTOR)
|
||||
proactor_start(port, kvs_protocol);
|
||||
#elif (NETWORK_SELECT == NETWORK_NTYCO)
|
||||
|
||||
Reference in New Issue
Block a user