polardbxengine/extra/IS/consensus/client/dummy_leader.cc

260 lines
6.8 KiB
C++

/************************************************************************
*
* Copyright (c) 2016 Alibaba.com, Inc. All Rights Reserved
* $Id: dummy_leader.cc,v 1.0 05/08/2017 3:47:33 PM jarry.zj(jarry.zj@alibaba-inc.com) $
*
************************************************************************/
/**
* @file dummy_leader.cc
* @author jarry.zj(jarry.zj@alibaba-inc.com)
* @date 05/08/2017 3:47:33 PM
* @version 1.0
* @brief
*
**/
#include <iostream>
#include <unistd.h>
#include <string>
#include <stddef.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <errno.h>
#include "single_leader.h"
using namespace alisql;
using namespace std;
#define PARSE_THRESHOLD (30*1024*1024) // 30M
#define BLOB_SPLIT (2*1024*1024) // 2M
/*
* For test:
* ./echo_debug 1 127.0.0.1:11001 1 127.0.0.1:11002
* ./dummy_learner 1 127.0.0.1:11002 ./dl.sock 0 0
* ./dummy_leader 1 11003 127.0.0.1:11004 ./dl.sock 0 0
* ./echo_learner_client 127.0.0.1:11004 0 1 0
*/
/*
* add a special mode: read from file
* socketFilePath ends with '.sock': read from socket
* others: read from file
*/
struct BlobEntryManager {
BlobEntryManager(): startindex(0), endindex(0) {}
void reset()
{
startindex = endindex = 0;
for (auto leptr: entryList)
delete leptr;
entryList.clear();
}
uint64_t startindex;
uint64_t endindex;
vector<LogEntry*> entryList;
};
BlobEntryManager blobMgr;
int processBlobEntry(LogEntry &le)
{
/*
* FLAG_BLOB = 1 << 5
* FLAG_BLOB_END = 1 << 6
* FLAG_BLOB_START = 1 << 7
*/
if (le.info() & (1 << 7))
{
assert(blobMgr.startindex == 0);
assert(blobMgr.endindex == 0);
blobMgr.startindex = le.index();
}
LogEntry *newle = new LogEntry();
newle->set_term(le.term());
newle->set_index(le.index());
newle->set_optype(le.optype());
newle->set_info(le.info());
newle->set_checksum(le.checksum());
blobMgr.entryList.push_back(newle);
if (le.info() & (1 << 6)) {
if (blobMgr.startindex == 0)
{
easy_error_log("blob entry parse fail, start index not found.");
return 1;
}
blobMgr.endindex = le.index();
const char *buf = le.value().c_str();
uint64_t buf_len = le.value().length();
uint64_t splitlen = buf_len / (blobMgr.endindex - blobMgr.startindex + 1);
splitlen = BLOB_SPLIT;
uint64_t spos = 0;
uint64_t epos = spos + splitlen > buf_len? buf_len: spos + splitlen;
for (int i=0; i<blobMgr.entryList.size(); ++i)
{
if (i == (blobMgr.entryList.size()-1))
epos = buf_len;
blobMgr.entryList[i]->set_value(buf + spos, epos - spos);
spos = epos;
epos = spos + splitlen > buf_len? buf_len: spos + splitlen;
}
assert(epos == buf_len);
}
return 0;
}
int main(int argc, char *argv[])
{
if (argc < 7)
{
easy_error_log("Usage: ./dummy_leader <clusterId> <leaderPort> <learnerAddr> <socketFilePath> <lastLogIndex> <lastTerm>\n");
easy_error_log("Example: ./dummy_leader 1 10001 127.0.0.1:10005 /tmp/dl.sock 0 0\n");
return 1;
}
uint64_t clusterId = strtoull(argv[1], NULL, 10);
int port = atol(argv[2]);
const char *laddr = argv[3];
const char *socketFilePath = argv[4];
uint64_t lastLogIndex = strtoull(argv[5], NULL, 10);
uint64_t lastTerm = strtoull(argv[6], NULL, 10);
int socketfd;
/* decide read from socket or file */
int slen = strlen(socketFilePath);
if (strcmp(socketFilePath+slen-5, ".sock") == 0)
{
struct sockaddr_un sa;
// connect socket
socketfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (socketfd < 0) {
easy_error_log("Fail to create socket.\n");
return 1;
}
memset(&sa, 0, sizeof(struct sockaddr_un));
sa.sun_family = AF_UNIX;
strncpy(sa.sun_path, socketFilePath, sizeof(sa.sun_path)-1);
int len = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path);
if (connect(socketfd, (struct sockaddr *) &sa, len) < 0) {
easy_error_log("Fail to connect socket.\n");
close(socketfd);
return 1;
}
}
else
{
/* read from file */
socketfd = open(socketFilePath, O_RDONLY);
if (socketfd < 0)
{
easy_error_log("Fail to read file, errno = %d.\n", errno);
return 1;
}
}
// read from socket and send log
SingleLeader *dl = new SingleLeader(clusterId);
dl->init(port, laddr, lastLogIndex, lastTerm);
uint64_t w;
uint64_t rindex, term, optype;
int ret = 0;
bool markStart= false; // make sure we send logentry: index=lastLogIndex+1
while(1) {
LogEntry le;
if (read(socketfd, (void *)&w, sizeof(uint64_t)) < (ssize_t)sizeof(uint64_t))
{
easy_error_log("Fail to read from fd or EOF. Error %s\n", strerror(errno));
ret = 1;
break;
}
term = w;
if (read(socketfd, (void *)&w, sizeof(uint64_t)) < (ssize_t)sizeof(uint64_t))
{
easy_error_log("Fail to read from fd or EOF. Error %s\n", strerror(errno));
ret = 1;
break;
}
rindex = w;
if (read(socketfd, (void *)&w, sizeof(uint64_t)) < (ssize_t)sizeof(uint64_t))
{
easy_error_log("Fail to read from fd or EOF. Error %s\n", strerror(errno));
ret = 1;
break;
}
optype = w;
if (read(socketfd, (void *)&w, sizeof(uint64_t)) < (ssize_t)sizeof(uint64_t))
{
easy_error_log("Fail to read from fd or EOF. Error %s\n", strerror(errno));
ret = 1;
break;
}
char *conbuf = new char[w+100];
if (read(socketfd, conbuf, w) < (ssize_t)w)
{
easy_error_log("Fail to read from fd or EOF. Error %s\n", strerror(errno));
ret = 1;
delete conbuf;
break;
}
if (w < PARSE_THRESHOLD)
{
le.ParseFromArray((void*)conbuf, w);
}
else
{
if (!MyParseFromArray(le, conbuf, w))
{
easy_error_log("Error parse logentry (index: %d).", rindex);
abort();
}
}
delete conbuf;
assert(le.index() == rindex);
assert(le.term() == term);
assert(le.optype() == optype);
if (rindex == (lastLogIndex+1))
markStart = true;
if (!markStart && rindex > (lastLogIndex+1))
{
easy_error_log("The current logindex is %ld, logindex %ld not found, recheck the data source.\n", rindex, (lastLogIndex+1));
abort();
}
if (le.info() & (1 << 5 | 1 << 6))
{
if (processBlobEntry(le))
abort();
if (le.info() & (1 << 6)) // blob end
{
for (auto leptr: blobMgr.entryList)
{
if (leptr->index() > lastLogIndex)
{
dl->replicateLog(*leptr);
}
}
blobMgr.reset();
}
}
else
{
if (markStart)
dl->replicateLog(le);
}
}
close(socketfd);
/* wait to send all data before stop */
while(dl->getLearnerMatchIndex() < dl->getLastLogIndex())
{
dl->appendLogToLearner(true);
sleep(1);
}
delete dl;
return ret;
}