polardbxengine/extra/IS/consensus/unittest/consensus-t.cc

1654 lines
53 KiB
C++

/************************************************************************
*
* Copyright (c) 2016 Alibaba.com, Inc. All Rights Reserved
* $Id: consensus-t.cc,v 1.0 07/30/2016 02:41:21 PM yingqiang.zyq(yingqiang.zyq@alibaba-inc.com) $
*
************************************************************************/
/**
* @file consensus-t.cc
* @author yingqiang.zyq(yingqiang.zyq@alibaba-inc.com)
* @date 07/30/2016 02:41:21 PM
* @version 1.0
* @brief unit test for alisql::Consensus
*
**/
#include <atomic>
#include <thread>
#include <gtest/gtest.h>
#include "easyNet.h"
#include "service.h"
#include "paxos.h"
#include "paxos_log.h"
#include "paxos_server.h"
#include "paxos_configuration.h"
#include "paxos.pb.h"
#include "files.h"
#include "rd_paxos_log.h"
#include "file_paxos_log.h"
using namespace alisql;
TEST(consensus, helloworld)
{
EXPECT_TRUE(1);
}
TEST(consensus, StableConfiguration)
{
std::shared_ptr<StableConfiguration> config= std::shared_ptr<StableConfiguration>(new StableConfiguration());
EXPECT_TRUE(static_cast<bool>(config));
std::shared_ptr<RemoteServer> ptr;
std::shared_ptr<LocalServer> lptr;
config->servers.push_back(lptr= std::make_shared<LocalServer>(1));
lptr->strAddr= std::string("127.0.0.1:10001");
config->servers.push_back(ptr= std::make_shared<RemoteServer>(2));
ptr->matchIndex= 5;
ptr->strAddr= std::string("127.0.0.1:10002");
config->servers.push_back(ptr= std::make_shared<RemoteServer>(3));
ptr->strAddr= std::string("127.0.0.1:10003");
ptr->matchIndex= 6;
uint64_t qmin= config->quorumMin(&Server::getMatchIndex);
EXPECT_EQ(qmin, 5);
config->delMember(std::string("127.0.0.1:10002"), NULL);
EXPECT_EQ(config->getServerNum(), 2);
EXPECT_EQ(config->servers[0]->serverId, 1);
EXPECT_EQ(config->servers[0]->strAddr, std::string("127.0.0.1:10001"));
EXPECT_EQ(config->servers[2]->serverId, 3);
EXPECT_EQ(config->servers[2]->strAddr, std::string("127.0.0.1:10003"));
//EXPECT_EQ(config->membersToString(lptr->strAddr), std::string("127.0.0.1:10001#5N;127.0.0.1:10003#5N@1"));
EXPECT_EQ(config->membersToString(lptr->strAddr), std::string("127.0.0.1:10001#5N;0;127.0.0.1:10003#5N@1"));
config->configureMember(1, true, 9, NULL);
//EXPECT_EQ(config->membersToString(lptr->strAddr), std::string("127.0.0.1:10001#9F;127.0.0.1:10003#5N@1"));
EXPECT_EQ(config->membersToString(lptr->strAddr), std::string("127.0.0.1:10001#9F;0;127.0.0.1:10003#5N@1"));
std::string strConfig= "127.0.0.1:10001;127.0.0.1:10002;127.0.0.1:10003@1";
uint64_t index= 0;
std::vector<std::string> v= StableConfiguration::stringToVector(strConfig, index);
EXPECT_EQ(v[0], "127.0.0.1:10001");
EXPECT_EQ(v[1], "127.0.0.1:10002");
EXPECT_EQ(v[2], "127.0.0.1:10003");
EXPECT_EQ(index, 1);
//for Learner string
strConfig= "127.0.0.1:10001;127.0.0.1:10002";
v= StableConfiguration::stringToVector(strConfig, index);
EXPECT_EQ(v[0], "127.0.0.1:10001");
EXPECT_EQ(v[1], "127.0.0.1:10002");
EXPECT_EQ(std::string("127.0.0.1:10001"), StableConfiguration::getAddr(std::string("127.0.0.1:10001#5N")));
EXPECT_EQ(std::string("127.0.0.1:10001"), StableConfiguration::getAddr(std::string("127.0.0.1:10001$:2")));
strConfig= "127.0.0.1:11004$00;127.0.0.1:11005$00;0;127.0.0.1:11006$00";
v= StableConfiguration::stringToVector(strConfig, index);
EXPECT_TRUE(StableConfiguration::isServerInVector(std::string("127.0.0.1:11005"), v));
EXPECT_TRUE(StableConfiguration::isServerInVector(std::string("127.0.0.1:11005$02"), v));
EXPECT_TRUE(StableConfiguration::isServerInVector(std::string("127.0.0.1:11005#5N"), v));
EXPECT_FALSE(StableConfiguration::isServerInVector(std::string("127.0.0.1:11001"), v));
EXPECT_FALSE(StableConfiguration::isServerInVector(std::string("127.0.0.1:11001#5N"), v));
// test learnerSource larger than 99 and 109 and 159
strConfig= "127.0.0.1:11004$:1;127.0.0.1:11005$;2;0;127.0.0.1:11006$00;127.0.0.1:11007$@3";
index = 0;
v= StableConfiguration::stringToVector(strConfig, index);
EXPECT_TRUE(index == 0);
EXPECT_TRUE(v.size() == 5);
EXPECT_TRUE(StableConfiguration::isServerInVector(std::string("127.0.0.1:11005"), v));
EXPECT_TRUE(StableConfiguration::isServerInVector(std::string("127.0.0.1:11005$;2"), v));
EXPECT_TRUE(StableConfiguration::isServerInVector(std::string("127.0.0.1:11007$@3"), v));
strConfig= "127.0.0.1:11004$00;127.0.0.1:11005$00;0;127.0.0.1:11006$00;127.0.0.1:11007$;0";
index = 0;
v= StableConfiguration::stringToVector(strConfig, index);
EXPECT_TRUE(index == 0);
EXPECT_EQ(v.size(), 5);
EXPECT_TRUE(StableConfiguration::isServerInVector(std::string("127.0.0.1:11007"), v));
EXPECT_TRUE(StableConfiguration::isServerInVector(std::string("127.0.0.1:11007$;0"), v));
EXPECT_TRUE(StableConfiguration::isServerInVector(std::string("127.0.0.1:11004"), v));
EXPECT_TRUE(StableConfiguration::isServerInVector(std::string("127.0.0.1:11004$00"), v));
EXPECT_EQ(v[0], "127.0.0.1:11004$00");
EXPECT_EQ(v[4], "127.0.0.1:11007$;0");
strConfig= "0;127.0.0.1:11004$00;127.0.0.1:11005$00;0;127.0.0.1:11006$00;127.0.0.1:11007$;0";
index = 0;
v= StableConfiguration::stringToVector(strConfig, index);
EXPECT_TRUE(index == 0);
EXPECT_EQ(v.size(), 6);
EXPECT_TRUE(StableConfiguration::isServerInVector(std::string("127.0.0.1:11007"), v));
EXPECT_TRUE(StableConfiguration::isServerInVector(std::string("127.0.0.1:11007$;0"), v));
EXPECT_TRUE(StableConfiguration::isServerInVector(std::string("127.0.0.1:11004"), v));
EXPECT_TRUE(StableConfiguration::isServerInVector(std::string("127.0.0.1:11004$00"), v));
EXPECT_EQ(v[0], "0");
EXPECT_EQ(v[5], "127.0.0.1:11007$;0");
}
TEST(consensus, StableConfiguration_uncontinue_serverid)
{
std::string strConfig;
uint64_t index= 0;
std::shared_ptr<StableConfiguration> config= std::shared_ptr<StableConfiguration>(new StableConfiguration());
EXPECT_TRUE(static_cast<bool>(config));
std::shared_ptr<RemoteServer> ptr;
std::shared_ptr<LocalServer> lptr;
config->servers.push_back(lptr= std::make_shared<LocalServer>(1));
lptr->strAddr= std::string("127.0.0.1:10001");
config->servers.push_back(nullptr);
config->servers.push_back(ptr= std::make_shared<RemoteServer>(3));
ptr->matchIndex= 5;
ptr->strAddr= std::string("127.0.0.1:10002");
config->servers.push_back(ptr= std::make_shared<RemoteServer>(4));
ptr->strAddr= std::string("127.0.0.1:10003");
ptr->matchIndex= 6;
uint64_t qmin= config->quorumMin(&Server::getMatchIndex);
EXPECT_EQ(qmin, 5);
config->delMember(std::string("127.0.0.1:10002"), NULL);
EXPECT_EQ(config->getServerNum(), 2);
EXPECT_EQ(config->servers[0]->serverId, 1);
EXPECT_EQ(config->servers[0]->strAddr, std::string("127.0.0.1:10001"));
EXPECT_EQ(config->servers[3]->serverId, 4);
EXPECT_EQ(config->servers[3]->strAddr, std::string("127.0.0.1:10003"));
//EXPECT_EQ(config->membersToString(lptr->strAddr), std::string("127.0.0.1:10001#5N;127.0.0.1:10003#5N@1"));
EXPECT_EQ(config->membersToString(lptr->strAddr), std::string("127.0.0.1:10001#5N;0;0;127.0.0.1:10003#5N@1"));
/*
config->configureMember(1, true, 9, NULL);
EXPECT_EQ(config->membersToString(lptr->strAddr), std::string("127.0.0.1:10001#9F;127.0.0.1:10003#5N@1"));
strConfig= "127.0.0.1:10001;127.0.0.1:10002;127.0.0.1:10003@1";
std::vector<std::string> v= StableConfiguration::stringToVector(strConfig, index);
EXPECT_EQ(v[0], "127.0.0.1:10001");
EXPECT_EQ(v[1], "127.0.0.1:10002");
EXPECT_EQ(v[2], "127.0.0.1:10003");
EXPECT_EQ(index, 1);
*/
//for Learner string
strConfig= "127.0.0.1:10001;0;127.0.0.1:10002";
auto v1= StableConfiguration::stringToVector(strConfig, index);
EXPECT_EQ(v1[0], "127.0.0.1:10001");
EXPECT_EQ(v1[1], "0");
EXPECT_EQ(v1[2], "127.0.0.1:10002");
}
TEST(consensus, PaxosLog)
{
// TODO need a factory.
//PaxosLog *rlog= new PaxosLog();
PaxosLog *rlog= (PaxosLog *) new RDPaxosLog("paxosLogTestDir", true, 4 * 1024 * 1024);
LogEntry entry;
EXPECT_EQ(rlog->getLastLogIndex(), 0);
rlog->getEntry(0, entry);
EXPECT_EQ(entry.term(), 0);
EXPECT_EQ(entry.index(), 0);
entry.set_term(1);
entry.set_index(1);
entry.set_optype(1);
entry.set_ikey("aa");
entry.set_value("bb");
rlog->append(entry);
entry.Clear();
rlog->getEntry(1, entry);
EXPECT_EQ(rlog->getLastLogIndex(), 1);
EXPECT_EQ(entry.term(), 1);
EXPECT_EQ(entry.index(), 1);
EXPECT_EQ(entry.optype(), 1);
EXPECT_EQ(entry.ikey(), "aa");
EXPECT_EQ(entry.value(), "bb");
entry.set_term(1);
entry.set_index(2);
entry.set_optype(1);
entry.set_ikey("aa1");
entry.set_value("bb1");
rlog->append(entry);
entry.set_term(1);
entry.set_index(3);
entry.set_optype(1);
entry.set_ikey("aa2");
entry.set_value("bb2");
rlog->append(entry);
entry.Clear();
rlog->getEntry(3, entry);
EXPECT_EQ(entry.term(), 1);
EXPECT_EQ(entry.index(), 3);
EXPECT_EQ(entry.optype(), 1);
EXPECT_EQ(entry.ikey(), "aa2");
EXPECT_EQ(entry.value(), "bb2");
rlog->truncateBackward(2);
EXPECT_EQ(rlog->getLastLogIndex(), 1);
entry.Clear();
rlog->getEntry(1, entry);
EXPECT_EQ(rlog->getLastLogIndex(), 1);
EXPECT_EQ(entry.term(), 1);
EXPECT_EQ(entry.index(), 1);
EXPECT_EQ(entry.optype(), 1);
EXPECT_EQ(entry.ikey(), "aa");
EXPECT_EQ(entry.value(), "bb");
rlog->truncateBackward(1);
EXPECT_EQ(rlog->getLastLogIndex(), 0);
// Patch entries append API
::google::protobuf::RepeatedPtrField<LogEntry> entries;
entry.set_term(1);
entry.set_index(1);
entry.set_optype(1);
entry.set_ikey("aa");
entry.set_value("bb");
*(entries.Add())= entry;
entry.set_term(2);
entry.set_index(2);
entry.set_optype(1);
entry.set_ikey("bb");
entry.set_value("cc");
*(entries.Add())= entry;
EXPECT_EQ(2, rlog->append(entries));
rlog->getEntry(1, entry);
EXPECT_EQ(rlog->getLastLogIndex(), 2);
EXPECT_EQ(entry.term(), 1);
EXPECT_EQ(entry.index(), 1);
EXPECT_EQ(entry.optype(), 1);
EXPECT_EQ(entry.ikey(), "aa");
EXPECT_EQ(entry.value(), "bb");
rlog->getEntry(2, entry);
EXPECT_EQ(rlog->getLastLogIndex(), 2);
EXPECT_EQ(entry.term(), 2);
EXPECT_EQ(entry.index(), 2);
EXPECT_EQ(entry.optype(), 1);
EXPECT_EQ(entry.ikey(), "bb");
EXPECT_EQ(entry.value(), "cc");
delete rlog;
deleteDir("paxosLogTestDir");
}
TEST(consensus, FilePaxosLog)
{
//PaxosLog *rlog= new PaxosLog();
PaxosLog *rlog= (PaxosLog *) new FilePaxosLog("filelog", FilePaxosLog::LTSync);
LogEntry entry;
EXPECT_EQ(rlog->getLastLogIndex(), 0);
rlog->getEntry(0, entry);
EXPECT_EQ(entry.term(), 0);
EXPECT_EQ(entry.index(), 0);
entry.set_term(1);
entry.set_index(1);
entry.set_optype(1);
entry.set_ikey("aa");
entry.set_value("bb");
rlog->append(entry);
entry.Clear();
rlog->getEntry(1, entry);
EXPECT_EQ(rlog->getLastLogIndex(), 1);
EXPECT_EQ(entry.term(), 1);
EXPECT_EQ(entry.index(), 1);
EXPECT_EQ(entry.optype(), 1);
EXPECT_EQ(entry.ikey(), "aa");
EXPECT_EQ(entry.value(), "bb");
entry.set_term(1);
entry.set_index(2);
entry.set_optype(1);
entry.set_ikey("aa1");
entry.set_value("bb1");
rlog->append(entry);
entry.set_term(1);
entry.set_index(3);
entry.set_optype(1);
entry.set_ikey("aa2");
entry.set_value("bb2");
rlog->append(entry);
entry.Clear();
rlog->getEntry(3, entry);
EXPECT_EQ(entry.term(), 1);
EXPECT_EQ(entry.index(), 3);
EXPECT_EQ(entry.optype(), 1);
EXPECT_EQ(entry.ikey(), "aa2");
EXPECT_EQ(entry.value(), "bb2");
rlog->truncateBackward(2);
EXPECT_EQ(rlog->getLastLogIndex(), 1);
entry.Clear();
rlog->getEntry(1, entry);
EXPECT_EQ(rlog->getLastLogIndex(), 1);
EXPECT_EQ(entry.term(), 1);
EXPECT_EQ(entry.index(), 1);
EXPECT_EQ(entry.optype(), 1);
EXPECT_EQ(entry.ikey(), "aa");
EXPECT_EQ(entry.value(), "bb");
rlog->truncateBackward(1);
EXPECT_EQ(rlog->getLastLogIndex(), 0);
// Patch entries append API
::google::protobuf::RepeatedPtrField<LogEntry> entries;
entry.set_term(1);
entry.set_index(1);
entry.set_optype(1);
entry.set_ikey("aa");
entry.set_value("bb");
*(entries.Add())= entry;
entry.set_term(2);
entry.set_index(2);
entry.set_optype(1);
entry.set_ikey("bb");
entry.set_value("cc");
*(entries.Add())= entry;
EXPECT_EQ(2, rlog->append(entries));
rlog->getEntry(1, entry);
EXPECT_EQ(rlog->getLastLogIndex(), 2);
EXPECT_EQ(entry.term(), 1);
EXPECT_EQ(entry.index(), 1);
EXPECT_EQ(entry.optype(), 1);
EXPECT_EQ(entry.ikey(), "aa");
EXPECT_EQ(entry.value(), "bb");
rlog->getEntry(2, entry);
EXPECT_EQ(rlog->getLastLogIndex(), 2);
EXPECT_EQ(entry.term(), 2);
EXPECT_EQ(entry.index(), 2);
EXPECT_EQ(entry.optype(), 1);
EXPECT_EQ(entry.ikey(), "bb");
EXPECT_EQ(entry.value(), "cc");
delete rlog;
deleteDir("filelog");
}
TEST(consensus, pbTest)
{
PaxosMsg msg;
msg.set_clusterid(0);
msg.set_msgid(0);
msg.set_serverid(0);
msg.set_msgtype(1);
msg.set_term(2);
msg.set_leaderid(3);
EXPECT_TRUE(msg.IsInitialized());
uint32_t length = uint32_t(msg.ByteSize());
length= length;
std::string buf;
msg.SerializeToString(&buf);
EXPECT_GT(buf.length(), 1);
PaxosMsg rcv;
rcv.ParseFromString(buf);
EXPECT_EQ(rcv.msgtype(), 1);
EXPECT_EQ(rcv.term(), 2);
EXPECT_TRUE(rcv.has_leaderid());
EXPECT_EQ(rcv.leaderid(), 3);
EXPECT_FALSE(rcv.has_prevlogindex());
}
TEST(consensus, RemoteServerSendMsg)
{
auto srv= std::shared_ptr<Service>(new Service(NULL));
EXPECT_TRUE(static_cast<bool>(srv));
srv->init();
srv->start(11001);
auto ptr= std::make_shared<RemoteServer>(1);
ptr->matchIndex= 5;
ptr->strAddr= std::string("127.0.0.1:11001");
ptr->srv= srv;
PaxosMsg msg;
msg.set_clusterid(0);
msg.set_msgid(0);
msg.set_serverid(0);
msg.set_msgtype(1);
msg.set_term(2);
msg.set_leaderid(3);
EXPECT_TRUE(msg.IsInitialized());
msg.clear_msgid();
ptr->connect(NULL);
sleep(0.5);
ptr->sendMsg(&msg);
sleep(0.5);
ptr.reset();
srv->shutdown();
}
TEST(consensus, Paxos_requestVote3)
{
std::vector<std::string> strConfig;
strConfig.emplace_back("127.0.0.1:11001");
strConfig.emplace_back("127.0.0.1:11002");
strConfig.emplace_back("127.0.0.1:11003");
const uint64_t timeout= 2000;
std::shared_ptr<PaxosLog> rlog;
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir1", true, 4 * 1024 * 1024);
Paxos *paxos1= new Paxos(timeout, rlog);
paxos1->init(strConfig, 1);
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir2", true, 4 * 1024 * 1024);
Paxos *paxos2= new Paxos(timeout, rlog);
paxos2->init(strConfig, 2);
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir3", true, 4 * 1024 * 1024);
Paxos *paxos3= new Paxos(timeout, rlog);
paxos3->init(strConfig, 3);
sleep(3);
paxos1->requestVote();
sleep(1);
EXPECT_EQ(paxos1->getState(), Paxos::LEADER);
LogEntry le;
le.set_index(0);
le.set_optype(0);
le.set_ikey("bbb");
le.set_value("ccc");
paxos1->replicateLog(le);
// Test Learner
std::string strTmp("127.0.0.1:11004");
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir4", true, 4 * 1024 * 1024);
Paxos *learner1= new Paxos(timeout, rlog);
learner1->initAsLearner(strTmp);
sleep(1);
strConfig.clear();
strConfig.push_back(strTmp);
paxos1->changeLearners(Paxos::CCAddNode, strConfig);
sleep(2);
EXPECT_EQ(learner1->getLastLogIndex(), paxos1->getLastLogIndex());
le.clear_term();
paxos1->replicateLog(le);
sleep(2);
EXPECT_EQ(learner1->getLastLogIndex(), paxos1->getLastLogIndex());
//Transfer Leader to Server 2 success case
sleep(1);
paxos1->leaderTransfer(2);
sleep(1);
EXPECT_EQ(paxos2->getState(), Paxos::LEADER);
//Test if the learners can still recieve msgs from new leader.
le.clear_term();
paxos2->replicateLog(le);
sleep(1);
EXPECT_EQ(learner1->getLastLogIndex(), paxos2->getLastLogIndex());
le.clear_term();
paxos2->replicateLog(le);
sleep(1);
EXPECT_EQ(learner1->getLastLogIndex(), paxos2->getLastLogIndex());
// Remove unexist Learner and add already exist.
strConfig.clear();
strConfig.emplace_back("127.0.0.1:11010");
EXPECT_EQ(paxos2->changeLearners(Paxos::CCDelNode, strConfig), PaxosErrorCode::PE_NOTFOUND);
strConfig.clear();
strConfig.push_back(strTmp);;
EXPECT_EQ(paxos2->changeLearners(Paxos::CCAddNode, strConfig), PaxosErrorCode::PE_EXISTS);
// Remove Learner
strConfig.clear();
strConfig.push_back(strTmp);
paxos2->changeLearners(Paxos::CCDelNode, strConfig);
sleep(2);
le.clear_term();
paxos2->replicateLog(le);
sleep(1);
EXPECT_LT(learner1->getLastLogIndex(), paxos2->getLastLogIndex());
// add member
// // create 2 learners
std::string strTmp2("127.0.0.1:11005");
std::string strTmp3("127.0.0.1:11006");
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir5", true, 4 * 1024 * 1024);
Paxos *learner2= new Paxos(timeout, rlog);
learner2->initAsLearner(strTmp2);
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir6", true, 4 * 1024 * 1024);
Paxos *learner3= new Paxos(timeout, rlog);
learner3->initAsLearner(strTmp3);
sleep(1);
// // add 2 learners
strConfig.clear();
strConfig.push_back(strTmp2);
strConfig.push_back(strTmp3);
paxos2->changeLearners(Paxos::CCAddNode, strConfig);
sleep(1);
auto config= std::dynamic_pointer_cast<StableConfiguration>(paxos2->getConfig());
//auto& servers= config->getServers();
auto& learners= config->getLearners();
EXPECT_EQ(config->getServerNum(), 3);
EXPECT_EQ(learners.size(), 2);
EXPECT_EQ(learner2->getLastLogIndex(), paxos2->getLastLogIndex());
EXPECT_EQ(learner3->getLastLogIndex(), paxos2->getLastLogIndex());
EXPECT_EQ(config->membersToString(("127.0.0.1:11002")), std::string("127.0.0.1:11001#5N;127.0.0.1:11002#5N;127.0.0.1:11003#5N@2"));
EXPECT_EQ(config->learnersToString(), std::string("127.0.0.1:11005$00;127.0.0.1:11006$00"));
// // change learners to followers one by one
paxos2->changeMember(Paxos::CCAddNode, strTmp2);
sleep(1);
le.clear_term();
paxos2->replicateLog(le);
sleep(1);
EXPECT_EQ(learner2->getState(), Paxos::FOLLOWER);
EXPECT_EQ(config->getServerNum(), 4);
EXPECT_EQ(learners.size(), 2);
EXPECT_EQ(config->getLearnerNum(), 1);
paxos2->changeMember(Paxos::CCAddNode, strTmp3);
sleep(1);
paxos2->configureMember(5, true, 9);
le.clear_term();
paxos2->replicateLog(le);
sleep(1);
EXPECT_EQ(learner3->getState(), Paxos::FOLLOWER);
EXPECT_EQ(config->getServerNum(), 5);
EXPECT_EQ(learners.size(), 0);
EXPECT_EQ(config->membersToString(("127.0.0.1:11002")), std::string("127.0.0.1:11001#5N;127.0.0.1:11002#5N;127.0.0.1:11003#5N;127.0.0.1:11005#5N;127.0.0.1:11006#9F@2"));
EXPECT_EQ(config->learnersToString(), std::string(""));
EXPECT_EQ(learner3->getConfig()->membersToString(learner3->getLocalServer()->strAddr), std::string("127.0.0.1:11001#5N;127.0.0.1:11002#5N;127.0.0.1:11003#5N;127.0.0.1:11005#5N;127.0.0.1:11006#9F@5"));
// // check 2 new followers
EXPECT_EQ(learner2->getLastLogIndex(), paxos2->getLastLogIndex());
EXPECT_EQ(learner3->getLastLogIndex(), paxos2->getLastLogIndex());
std::vector<Paxos::ClusterInfoType> cis;
paxos2->getClusterInfo(cis);
for (auto& ci : cis)
{
std::cout<< "serverId:"<< ci.serverId<< " ipPort:"<< ci.ipPort<< " matchIndex:"<< ci.matchIndex<< " nextIndex:"<< ci.nextIndex<< " role:"<< ci.role<< " hasVoted:"<< ci.hasVoted << " forceSync:" << ci.forceSync << " electionWeight: " << ci.electionWeight << std::endl<< std::flush;
}
EXPECT_EQ(cis[3].ipPort, strTmp2);
EXPECT_EQ(cis[3].forceSync, false);
EXPECT_EQ(cis[3].electionWeight, 5);
EXPECT_EQ(cis[4].ipPort, strTmp3);
EXPECT_EQ(cis[4].forceSync, true);
EXPECT_EQ(cis[4].electionWeight, 9);
// // delete one follower
paxos2->changeMember(Paxos::CCDelNode, strTmp2);
sleep(1);
le.clear_term();
paxos2->replicateLog(le);
sleep(1);
EXPECT_EQ(config->getServerNum(), 4);
EXPECT_EQ(learners.size(), 0);
EXPECT_EQ(config->learnersToString(), std::string(""));
EXPECT_LT(learner2->getLastLogIndex(), paxos2->getLastLogIndex());
EXPECT_EQ(learner3->getLastLogIndex(), paxos2->getLastLogIndex());
paxos2->getClusterInfo(cis);
for (auto& ci : cis)
{
std::cout<< "serverId:"<< ci.serverId<< " ipPort:"<< ci.ipPort<< " matchIndex:"<< ci.matchIndex<< " nextIndex:"<< ci.nextIndex<< " role:"<< ci.role<< " hasVoted:"<< ci.hasVoted << " forceSync:" << ci.forceSync << " electionWeight: " << ci.electionWeight << std::endl<< std::flush;
}
EXPECT_EQ(cis[3].ipPort, strTmp3);
//Transfer Leader to Server 3 fail case
delete paxos3;
sleep(1);
paxos2->leaderTransfer(3);
sleep(1);
EXPECT_EQ(paxos2->getState(), Paxos::LEADER);
EXPECT_EQ(paxos2->getSubState(), Paxos::SubLeaderTransfer);
sleep(2);
EXPECT_EQ(paxos2->getState(), Paxos::LEADER);
EXPECT_EQ(paxos2->getSubState(), Paxos::SubNone);
delete paxos1;
delete learner2;
delete learner3;
// Leader stepdown.
sleep(3);
if (paxos2->getState() != Paxos::FOLLOWER)
sleep(1);
EXPECT_EQ(paxos2->getState(), Paxos::FOLLOWER);
config.reset();
delete paxos2;
delete learner1;
deleteDir("paxosLogTestDir1");
deleteDir("paxosLogTestDir2");
deleteDir("paxosLogTestDir3");
deleteDir("paxosLogTestDir4");
deleteDir("paxosLogTestDir5");
deleteDir("paxosLogTestDir6");
}
TEST(consensus, Paxos_requestVoteAuto)
{
std::vector<std::string> strConfig;
strConfig.emplace_back("127.0.0.1:11011");
strConfig.emplace_back("127.0.0.1:11012");
strConfig.emplace_back("127.0.0.1:11013");
std::shared_ptr<PaxosLog> rlog1= std::make_shared<RDPaxosLog>("paxosLogTestDir11", true, 4 * 1024 * 1024);
std::shared_ptr<PaxosLog> rlog2= std::make_shared<RDPaxosLog>("paxosLogTestDir12", true, 4 * 1024 * 1024);
std::shared_ptr<PaxosLog> rlog3= std::make_shared<RDPaxosLog>("paxosLogTestDir13", true, 4 * 1024 * 1024);
Paxos *paxos1= new Paxos(500, rlog1);
paxos1->init(strConfig, 1);
Paxos *paxos2= new Paxos(500, rlog2);
paxos2->init(strConfig, 2);
Paxos *paxos3= new Paxos(500, rlog3);
paxos3->init(strConfig, 3);
sleep(2.2);
EXPECT_TRUE(paxos1->getState() == Paxos::LEADER || paxos2->getState() == Paxos::LEADER || paxos3->getState() == Paxos::LEADER);
delete paxos1;
delete paxos2;
delete paxos3;
deleteDir("paxosLogTestDir11");
deleteDir("paxosLogTestDir12");
deleteDir("paxosLogTestDir13");
}
void applyThread(Paxos *paxos)
{
paxos->waitCommitIndexUpdate(0);
EXPECT_GE(paxos->getCommitIndex(), 1);
uint64_t i= 0;
std::shared_ptr<PaxosLog> log= paxos->getLog();
for (i= 1; i <= paxos->getCommitIndex(); ++i)
{
LogEntry entry;
log->getEntry(i, entry);
std::cout<< "LogIndex "<<i <<": key:"<< entry.ikey()<<", value:"<< entry.value() << std::endl;
}
std::cout<< "ApplyThread: commitIndex has been updated to "<< paxos->getCommitIndex()<< " ."<<std::endl<< std::flush;
paxos->waitCommitIndexUpdate(10, 3);
EXPECT_LE(paxos->getCommitIndex(), 10);
EXPECT_NE(paxos->getTerm(), 3);
std::cout<< "ApplyThread: return because state changed."<<std::endl<< std::flush;
}
void stateChangeCb(Paxos::StateType state, uint64_t term, uint64_t commitIndex)
{
static uint64_t cnt= 0;
std::cout<< "State change to "<< state<< " in stateChangeCb term:"<< term<< " commitIndex:"<< commitIndex<< std::endl;
if (cnt == 0)
{
EXPECT_EQ(state, Paxos::CANDIDATE);
EXPECT_EQ(term, 2);
EXPECT_EQ(commitIndex, 0);
}
else if(cnt == 1)
{
EXPECT_EQ(state, Paxos::LEADER);
EXPECT_EQ(term, 2);
EXPECT_EQ(commitIndex, 0);
}
else if(cnt == 2)
{
EXPECT_EQ(state, Paxos::FOLLOWER);
EXPECT_EQ(term, 3);
EXPECT_EQ(commitIndex, 4);
}
else if(cnt == 3)
{
EXPECT_EQ(state, Paxos::FOLLOWER);
EXPECT_EQ(term, 4);
EXPECT_EQ(commitIndex, 4);
}
++ cnt;
}
void printPaxosStats(Paxos *paxos)
{
const Paxos::StatsType &stats= paxos->getStats();
std::cout<< "countMsgAppendLog:"<<stats.countMsgAppendLog<< " countMsgRequestVote:"<<stats.countMsgRequestVote<< " countOnMsgAppendLog:"<< stats.countOnMsgAppendLog<< " countHeartbeat:"<< stats.countHeartbeat << " countOnMsgRequestVote:"<<stats.countOnMsgRequestVote<< " countOnHeartbeat:"<<stats.countOnHeartbeat<< " countReplicateLog:"<<stats.countReplicateLog<< std::endl<< std::flush;
}
TEST(consensus, Paxos_replicateLog)
{
std::vector<std::string> strConfig;
strConfig.emplace_back("127.0.0.1:11001");
strConfig.emplace_back("127.0.0.1:11002");
strConfig.emplace_back("127.0.0.1:11003");
uint64_t timeout= 12500;
std::shared_ptr<PaxosLog> rlog;
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir21", true, 4 * 1024 * 1024);
ClientService *cs1= new ClientService();
Paxos *paxos1= new Paxos(timeout, rlog);
paxos1->init(strConfig, 1, cs1);
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir22", true, 4 * 1024 * 1024);
ClientService *cs2= new ClientService();
Paxos *paxos2= new Paxos(timeout, rlog);
paxos2->init(strConfig, 2, cs2);
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir23", true, 4 * 1024 * 1024);
ClientService *cs3= new ClientService();
Paxos *paxos3= new Paxos(timeout, rlog);
paxos3->init(strConfig, 3, cs3);
// Need one reconnect, because the other Paxos is not inited.
sleep(5);
paxos1->setStateChangeCb(stateChangeCb);
paxos1->requestVote();
sleep(1);
EXPECT_EQ(paxos1->getState(), Paxos::LEADER);
LogEntry le;
le.set_index(0);
le.set_optype(1);
le.set_ikey("bbb");
//le.set_value("ccc");
const Paxos::StatsType &stats= paxos1->getStats();
//std::cout<< "countMsgAppendLog:"<<stats.countMsgAppendLog << " countHeartbeat:"<< stats.countHeartbeat<< std::endl<< std::flush;
printPaxosStats(paxos1);
std::thread th1(applyThread, paxos1);
paxos1->replicateLog(le);
//std::cout<< "countMsgAppendLog:"<<stats.countMsgAppendLog <<" countHeartbeat:"<< stats.countHeartbeat<< std::endl<< std::flush;
printPaxosStats(paxos1);
sleep(1);
paxos1->replicateLog(le);
//std::cout<< "countMsgAppendLog:"<<stats.countMsgAppendLog <<" countHeartbeat:"<< stats.countHeartbeat<< std::endl<< std::flush;
printPaxosStats(paxos1);
sleep(1);
paxos1->replicateLog(le);
//std::cout<< "countMsgAppendLog:"<<stats.countMsgAppendLog <<" countHeartbeat:"<< stats.countHeartbeat<< std::endl<< std::flush;
printPaxosStats(paxos1);
EXPECT_EQ(stats.countHeartbeat, 0);
sleep(3);
//std::cout<< "countMsgAppendLog:"<<stats.countMsgAppendLog << " countHeartbeat:"<< stats.countHeartbeat<< std::endl<< std::flush;
printPaxosStats(paxos1);
EXPECT_EQ(stats.countHeartbeat, 2);
printPaxosStats(paxos2);
paxos2->requestVote();
sleep(1);
paxos3->requestVote();
sleep(1);
th1.join();
delete paxos1;
delete paxos2;
delete paxos3;
delete cs1;
delete cs2;
delete cs3;
deleteDir("paxosLogTestDir21");
deleteDir("paxosLogTestDir22");
deleteDir("paxosLogTestDir23");
}
std::atomic<uint64_t> failCnt(0);
class FailRDPaxosLog : public RDPaxosLog {
public:
FailRDPaxosLog(const std::string &dataDir, bool compress, size_t writeBufferSize, bool sync=true)
:RDPaxosLog(dataDir, compress, writeBufferSize, sync)
{};
virtual int getEntry(uint64_t logIndex, LogEntry &entry, bool fastfail= false) {
if (failCnt > 0) {
--failCnt;
std::cout<< "getEntry will return fail."<< std::endl<< std::flush;
return 1;
}
else {
return RDPaxosLog::getEntry(logIndex, entry);
}
}
};
TEST(consensus, Paxos_AliSQLServer)
{
std::vector<std::string> strConfig;
strConfig.emplace_back("127.0.0.1:11001");
strConfig.emplace_back("127.0.0.1:11002");
std::string strTmp3("127.0.0.1:11003");
uint64_t timeout= 12500;
std::shared_ptr<AliSQLServer> aserver;
std::shared_ptr<AliSQLServer> aserver1= std::make_shared<AliSQLServer>(1);
std::shared_ptr<PaxosLog> rlog, rlog1;
std::shared_ptr<FailRDPaxosLog> rdlog;
rlog1= rlog= rdlog= std::make_shared<FailRDPaxosLog>("paxosLogTestDir1", true, 4 * 1024 * 1024);
rdlog->set_debug_async();
ClientService *cs1= new ClientService();
Paxos *paxos1= new Paxos(timeout, rlog);
paxos1->init(strConfig, 1, cs1, 2, 2, aserver= std::make_shared<AliSQLServer>(1));
rlog= rdlog= std::make_shared<FailRDPaxosLog>("paxosLogTestDir2", true, 4 * 1024 * 1024);
ClientService *cs2= new ClientService();
Paxos *paxos2= new Paxos(timeout, rlog);
paxos2->init(strConfig, 2, cs2);
rlog= rdlog= std::make_shared<FailRDPaxosLog>("paxosLogTestDir3", true, 4 * 1024 * 1024);
rdlog->set_debug_async();
Paxos *paxos3= new Paxos(timeout, rlog);
paxos3->initAsLearner(strTmp3, nullptr, 2, 2, aserver1);
sleep(5);
paxos1->requestVote();
sleep(2);
EXPECT_EQ(paxos1->getState(), Paxos::LEADER);
LogEntry le;
le.set_index(0);
le.set_optype(1);
le.set_ikey("bbb");
le.set_value("ccc");
const Paxos::StatsType &stats= paxos1->getStats();
std::cout<< "countMsgAppendLog:"<<stats.countMsgAppendLog << " countHeartbeat:"<< stats.countHeartbeat<< std::endl<< std::flush;
paxos1->replicateLog(le);
// reject the old term replicateLog call.
le.set_term(1);
EXPECT_EQ(0, paxos1->replicateLog(le));
le.set_term(0);
std::cout<< "countMsgAppendLog:"<<stats.countMsgAppendLog <<" countHeartbeat:"<< stats.countHeartbeat<< std::endl<< std::flush;
sleep(1);
std::cout<< "commitIndex: "<< paxos1->getCommitIndex()<< std::endl<< std::flush;
EXPECT_EQ(paxos1->getCommitIndex(), 1);
std::cout<< "lastLogIndex: "<< rlog1->getLastLogIndex()<< std::endl<< std::flush;
EXPECT_GE(rlog1->getLastLogIndex(), 1);
aserver->writeLogDone(rlog1->getLastLogIndex());
sleep(1);
EXPECT_EQ(paxos1->getCommitIndex(), rlog1->getLastLogIndex());
std::cout<< "commitIndex: "<< paxos1->getCommitIndex()<< std::endl<< std::flush;
std::vector<Paxos::ClusterInfoType> cis;
paxos1->getClusterInfo(cis);
for (auto& ci : cis)
{
std::cout<< "serverId:"<< ci.serverId<< " ipPort:"<< ci.ipPort<< " matchIndex:"<< ci.matchIndex<< " nextIndex:"<< ci.nextIndex<< " role:"<< ci.role<< " hasVoted:"<< ci.hasVoted << " forceSync:" << ci.forceSync << " electionWeight: " << ci.electionWeight << std::endl<< std::flush;
}
Paxos::MemberInfoType mi;
paxos1->getMemberInfo(&mi);
std::cout
<< "serverId:"<< mi.serverId
<< " currentTerm:"<< mi.currentTerm
<< " currentLeader:"<< mi.currentLeader
<< " commitIndex:"<< mi.commitIndex
<< " lastLogTerm:"<< mi.lastLogTerm
<< " lastLogIndex:"<< mi.lastLogIndex
<< " role:"<< mi.role
<< " votedFor:"<< mi.votedFor
<< " lastAppliedIndex:"<< mi.lastAppliedIndex
<< " currentLeaderAddr:"<< mi.currentLeaderAddr
<< std::endl<< std::flush;
paxos2->getMemberInfo(&mi);
std::cout
<< "serverId:"<< mi.serverId
<< " currentTerm:"<< mi.currentTerm
<< " currentLeader:"<< mi.currentLeader
<< " commitIndex:"<< mi.commitIndex
<< " lastLogTerm:"<< mi.lastLogTerm
<< " lastLogIndex:"<< mi.lastLogIndex
<< " role:"<< mi.role
<< " votedFor:"<< mi.votedFor
<< " lastAppliedIndex:"<< mi.lastAppliedIndex
<< " currentLeaderAddr:"<< mi.currentLeaderAddr
<< std::endl<< std::flush;
strConfig.clear();
strConfig.push_back(strTmp3);
paxos1->changeLearners(Paxos::CCAddNode, strConfig);
sleep(1);
EXPECT_EQ(0, paxos1->changeMember(Paxos::CCAddNode, strTmp3));
sleep(1);
cis.clear();
paxos1->getClusterInfo(cis);
Paxos::printClusterInfo(cis);
EXPECT_EQ(0, paxos1->downgradeMember(3));
sleep(1);
cis.clear();
paxos1->getClusterInfo(cis);
Paxos::printClusterInfo(cis);
paxos3->forceSingleLeader();
sleep(1);
le.clear_term();
paxos3->replicateLog(le);
aserver1->writeLogDone(paxos3->getLastLogIndex());
sleep(1);
EXPECT_EQ(paxos3->getCommitIndex(), paxos3->getLastLogIndex());
sleep(1);
failCnt.store(1, std::memory_order_relaxed);
paxos1->replicateLog(le);
sleep(1);
/*
sleep(1);
paxos1->replicateLog(le);
std::cout<< "countMsgAppendLog:"<<stats.countMsgAppendLog <<" countHeartbeat:"<< stats.countHeartbeat<< std::endl<< std::flush;
sleep(1);
paxos1->replicateLog(le);
std::cout<< "countMsgAppendLog:"<<stats.countMsgAppendLog <<" countHeartbeat:"<< stats.countHeartbeat<< std::endl<< std::flush;
EXPECT_EQ(stats.countHeartbeat, 0);
sleep(3);
std::cout<< "countMsgAppendLog:"<<stats.countMsgAppendLog << " countHeartbeat:"<< stats.countHeartbeat<< std::endl<< std::flush;
EXPECT_EQ(stats.countHeartbeat, 2);
*/
delete paxos1;
delete paxos2;
delete paxos3;
delete cs1;
delete cs2;
deleteDir("paxosLogTestDir1");
deleteDir("paxosLogTestDir2");
deleteDir("paxosLogTestDir3");
}
void stateChangeCb2_1(Paxos *p, Paxos::StateType state, uint64_t term, uint64_t commitIndex)
{
static uint64_t cnt= 0;
std::cout<< "Server(" << p->getLocalServer()->strAddr << ") state change to "<< state<< " in stateChangeCb term:"<< term<< " commitIndex:"<< commitIndex<< std::endl;
if (cnt == 0)
{
EXPECT_EQ(state, Paxos::CANDIDATE);
EXPECT_EQ(term, 2);
EXPECT_EQ(commitIndex, 0);
EXPECT_EQ(p->getLocalServer()->strAddr, "127.0.0.1:11001");
}
else if(cnt == 1)
{
EXPECT_EQ(state, Paxos::LEADER);
EXPECT_EQ(term, 2);
EXPECT_EQ(commitIndex, 0);
EXPECT_EQ(p->getLocalServer()->strAddr, "127.0.0.1:11001");
}
else if(cnt == 2)
{
EXPECT_EQ(state, Paxos::FOLLOWER);
EXPECT_EQ(term, 3);
EXPECT_EQ(commitIndex, 4);
EXPECT_EQ(p->getLocalServer()->strAddr, "127.0.0.1:11001");
}
else if(cnt == 3)
{
EXPECT_EQ(state, Paxos::FOLLOWER);
EXPECT_EQ(term, 4);
EXPECT_EQ(commitIndex, 4);
EXPECT_EQ(p->getLocalServer()->strAddr, "127.0.0.1:11001");
}
++ cnt;
}
void stateChangeCb2_2(Paxos *p, Paxos::StateType state, uint64_t term, uint64_t commitIndex)
{
std::cout << "Callback with 4 arguments" << std::endl;
EXPECT_EQ(p->getLocalServer()->strAddr, "127.0.0.1:11002");
}
void stateChangeCb2_3_lessarg(Paxos::StateType state, uint64_t term, uint64_t commitIndex)
{
std::cout << "Callback with 3 arguments" << std::endl;
}
// callback1: Paxos_replicateLog
TEST(consensus, callback2)
{
std::vector<std::string> strConfig;
strConfig.emplace_back("127.0.0.1:11001");
strConfig.emplace_back("127.0.0.1:11002");
strConfig.emplace_back("127.0.0.1:11003");
uint64_t timeout= 12500;
std::shared_ptr<PaxosLog> rlog;
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir21", true, 4 * 1024 * 1024);
Paxos *paxos1= new Paxos(timeout, rlog);
paxos1->init(strConfig, 1);
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir22", true, 4 * 1024 * 1024);
Paxos *paxos2= new Paxos(timeout, rlog);
paxos2->init(strConfig, 2);
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir23", true, 4 * 1024 * 1024);
Paxos *paxos3= new Paxos(timeout, rlog);
paxos3->init(strConfig, 3);
// Need one reconnect, because the other Paxos is not inited.
sleep(5);
paxos1->setStateChangeCb(stateChangeCb2_1);
paxos2->setStateChangeCb(stateChangeCb2_2);
paxos3->setStateChangeCb(stateChangeCb2_3_lessarg);
paxos1->requestVote();
sleep(1);
EXPECT_EQ(paxos1->getState(), Paxos::LEADER);
LogEntry le;
le.set_index(0);
le.set_optype(1);
le.set_ikey("bbb");
//le.set_value("ccc");
le.set_value("0123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 12345");
const Paxos::StatsType &stats= paxos1->getStats();
std::thread th1(applyThread, paxos1);
paxos1->replicateLog(le);
sleep(1);
paxos1->replicateLog(le);
sleep(1);
paxos1->replicateLog(le);
EXPECT_EQ(stats.countHeartbeat, 0);
sleep(3);
EXPECT_EQ(stats.countHeartbeat, 2);
printPaxosStats(paxos2);
paxos2->requestVote();
sleep(1);
paxos3->requestVote();
sleep(1);
th1.join();
delete paxos1;
delete paxos2;
delete paxos3;
deleteDir("paxosLogTestDir21");
deleteDir("paxosLogTestDir22");
deleteDir("paxosLogTestDir23");
}
TEST(consensus, timeout_set)
{
std::vector<std::string> strConfig;
strConfig.emplace_back("127.0.0.1:11001");
strConfig.emplace_back("127.0.0.1:11002");
strConfig.emplace_back("127.0.0.1:11003");
const uint64_t timeout= 2000;
std::shared_ptr<PaxosLog> rlog, rlog1;
rlog1= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir1", true, 4 * 1024 * 1024);
Paxos *paxos1= new Paxos(timeout, rlog);
paxos1->init(strConfig, 1);
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir2", true, 4 * 1024 * 1024);
Paxos *paxos2= new Paxos(timeout, rlog);
paxos2->init(strConfig, 2);
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir3", true, 4 * 1024 * 1024);
Paxos *paxos3= new Paxos(timeout, rlog);
paxos3->init(strConfig, 3);
sleep(3);
paxos1->requestVote();
sleep(1);
EXPECT_EQ(paxos1->getState(), Paxos::LEADER);
std::string strTmp("127.0.0.1:11004");
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir4", true, 4 * 1024 * 1024);
Paxos *learner1= new Paxos(timeout, rlog);
learner1->initAsLearner(strTmp);
sleep(1);
strConfig.clear();
strConfig.push_back(strTmp);
paxos1->changeLearners(Paxos::CCAddNode, strConfig);
sleep(2);
LogEntry le;
for (int i=0; i<10; ++i)
{
le.Clear();
le.set_optype(1);
paxos1->replicateLog(le);
}
paxos1->setSendPacketTimeout(10000);
for (int i=0; i<10; ++i)
{
le.Clear();
le.set_optype(1);
paxos1->replicateLog(le);
}
paxos1->setLearnerConnTimeout(1000);
for (int i=0; i<10; ++i)
{
le.Clear();
le.set_optype(1);
paxos1->replicateLog(le);
}
sleep(2);
EXPECT_EQ(learner1->getLastLogIndex(), paxos1->getLastLogIndex());
EXPECT_EQ(paxos2->getLastLogIndex(), paxos1->getLastLogIndex());
delete learner1;
delete paxos1;
delete paxos2;
delete paxos3;
deleteDir("paxosLogTestDir1");
deleteDir("paxosLogTestDir2");
deleteDir("paxosLogTestDir3");
deleteDir("paxosLogTestDir4");
}
TEST(consensus, fix_match_index)
{
std::vector<std::string> strConfig = { "127.0.0.1:11001", "127.0.0.1:11002",
"127.0.0.1:11003" };
uint64_t timeout = 10000;
std::shared_ptr<PaxosLog> rlog;
rlog = std::make_shared<RDPaxosLog>("paxosLogTestDir1", true, 4 * 1024 * 1024);
Paxos *paxos1 = new Paxos(timeout, rlog);
paxos1->init(strConfig, 1, NULL);
rlog = std::make_shared<RDPaxosLog>("paxosLogTestDir2", true, 4 * 1024 * 1024);
Paxos *paxos2 = new Paxos(timeout, rlog);
paxos2->init(strConfig, 2, NULL);
rlog = std::make_shared<RDPaxosLog>("paxosLogTestDir3", true, 4 * 1024 * 1024);
Paxos *paxos3 = new Paxos(timeout, rlog);
paxos3->init(strConfig, 3, NULL);
sleep(1);
paxos1->requestVote();
sleep(2);
EXPECT_EQ(paxos1->getState(), Paxos::LEADER);
/* replicate a log */
LogEntry le;
le.set_index(0);
le.set_optype(1);
le.set_value("12345");
paxos1->replicateLog(le);
std::atomic<bool> shutdown(false);
auto worker_main = [&shutdown](Paxos* p, uint64_t time) {
while(shutdown.load() == false)
{
LogEntry le;
le.set_index(0);
le.set_optype(1);
le.set_value("12345");
if (p->getState() == Paxos::LEADER)
p->replicateLog(le);
usleep(time * 1000);
}
};
std::thread writer1(worker_main, paxos1, 100);
std::thread writer2(worker_main, paxos2, 100);
std::thread writer3(worker_main, paxos3, 100);
paxos2->forceFixMatchIndex(2, paxos3->getLastLogIndex() - 2);
std::thread op1([paxos1, paxos2, paxos3, &shutdown](){
sleep(1);
while(shutdown.load() == false)
{
paxos1->forceFixMatchIndex(2, paxos2->getLastLogIndex() - 2);
sleep(2);
paxos1->forceFixMatchIndex(3, paxos3->getLastLogIndex() - 2);
sleep(2);
}
});
/* how long to test */
sleep(10);
shutdown.store(true);
writer1.join();
writer2.join();
writer3.join();
op1.join();
paxos1->replicateLog(le);
paxos2->replicateLog(le);
paxos3->replicateLog(le);
sleep(2);
EXPECT_EQ(paxos1->getLastLogIndex(), paxos2->getLastLogIndex());
EXPECT_EQ(paxos2->getLastLogIndex(), paxos3->getLastLogIndex());
delete paxos1;
delete paxos2;
delete paxos3;
deleteDir("paxosLogTestDir1");
deleteDir("paxosLogTestDir2");
deleteDir("paxosLogTestDir3");
}
TEST(consensus, checksum)
{
std::vector<std::string> strConfig = { "127.0.0.1:11001", "127.0.0.1:11002",
"127.0.0.1:11003" };
uint64_t timeout = 10000;
std::shared_ptr<PaxosLog> rlog;
rlog = std::make_shared<RDPaxosLog>("paxosLogTestDir1", true, 4 * 1024 * 1024);
Paxos *paxos1 = new Paxos(timeout, rlog);
paxos1->init(strConfig, 1, NULL);
rlog = std::make_shared<RDPaxosLog>("paxosLogTestDir2", true, 4 * 1024 * 1024);
Paxos *paxos2 = new Paxos(timeout, rlog);
paxos2->init(strConfig, 2, NULL);
rlog = std::make_shared<RDPaxosLog>("paxosLogTestDir3", true, 4 * 1024 * 1024);
Paxos *paxos3 = new Paxos(timeout, rlog);
paxos3->init(strConfig, 3, NULL);
sleep(1);
paxos1->requestVote();
sleep(2);
EXPECT_EQ(paxos1->getState(), Paxos::LEADER);
/* replicate a log */
LogEntry le;
le.set_index(0);
le.set_optype(1);
le.set_value("12345");
paxos1->replicateLog(le);
sleep(1);
std::function<uint32_t(uint32_t, const unsigned char*, size_t)> checksumFunc =
[](uint32_t base, const unsigned char* buf, size_t len) -> uint32_t
{
return base + len;
};
paxos1->setChecksumCb(checksumFunc);
paxos2->setChecksumCb(checksumFunc);
paxos3->setChecksumCb(checksumFunc);
paxos1->setChecksumMode(true);
paxos2->setChecksumMode(true);
paxos3->setChecksumMode(true);
std::cout << "enable checksum..." << std::endl;
EXPECT_EQ(paxos1->getLastLogIndex(), paxos2->getLastLogIndex());
EXPECT_EQ(paxos2->getLastLogIndex(), paxos3->getLastLogIndex());
le.set_index(0);
le.set_value("12345");
le.set_checksum(0);
paxos1->replicateLog(le);
sleep(1);
EXPECT_EQ(paxos1->getLastLogIndex(), paxos2->getLastLogIndex());
EXPECT_EQ(paxos2->getLastLogIndex(), paxos3->getLastLogIndex());
le.set_index(0);
le.set_value("12345");
le.set_checksum(6); // 5 is correct
paxos1->replicateLog(le);
for (int i=0; i<10; ++i)
{
le.set_index(0);
le.set_value("12345");
le.set_checksum(0);
paxos1->replicateLog(le);
}
sleep(1);
EXPECT_EQ(paxos1->getLastLogIndex(), paxos2->getLastLogIndex() + 11);
EXPECT_EQ(paxos2->getLastLogIndex(), paxos3->getLastLogIndex());
std::cout << "disable checksum..." << std::endl;
paxos1->setChecksumMode(false);
paxos2->setChecksumMode(false);
paxos3->setChecksumMode(false);
sleep(5);
EXPECT_EQ(paxos1->getLastLogIndex(), paxos2->getLastLogIndex());
EXPECT_EQ(paxos2->getLastLogIndex(), paxos3->getLastLogIndex());
delete paxos1;
delete paxos2;
delete paxos3;
deleteDir("paxosLogTestDir1");
deleteDir("paxosLogTestDir2");
deleteDir("paxosLogTestDir3");
}
TEST(consensus, update_commitindex_in_leader_transfer)
{
std::vector<std::string> strConfig = { "127.0.0.1:11001", "127.0.0.1:11002",
"127.0.0.1:11003" };
uint64_t timeout = 10000;
std::shared_ptr<PaxosLog> rlog;
rlog = std::make_shared<RDPaxosLog>("paxosLogTestDir1", true, 4 * 1024 * 1024);
Paxos *paxos1 = new Paxos(timeout, rlog);
paxos1->init(strConfig, 1, NULL);
rlog = std::make_shared<RDPaxosLog>("paxosLogTestDir2", true, 4 * 1024 * 1024);
Paxos *paxos2 = new Paxos(timeout, rlog);
paxos2->init(strConfig, 2, NULL);
rlog = std::make_shared<RDPaxosLog>("paxosLogTestDir3", true, 4 * 1024 * 1024);
Paxos *paxos3 = new Paxos(timeout, rlog);
paxos3->init(strConfig, 3, NULL);
sleep(1);
paxos1->requestVote();
sleep(2);
EXPECT_EQ(paxos1->getState(), Paxos::LEADER);
/* replicate a log */
LogEntry le;
le.set_index(0);
le.set_optype(1);
le.set_value("12345");
paxos1->replicateLog(le);
for (int i=0; i<10; ++i)
paxos1->replicateLog(le);
while (paxos1->getLastLogIndex() != paxos2->getLastLogIndex())
sleep(1);
paxos2->debugSkipUpdateCommitIndex = true;
strConfig.clear();
strConfig.push_back("127.0.0.1:11004");
paxos1->changeLearners(Paxos::CCAddNode, strConfig);
for (int i=0; i<10; ++i)
paxos1->replicateLog(le);
while (paxos1->getLastLogIndex() != paxos2->getLastLogIndex())
sleep(1);
EXPECT_EQ(paxos1->getCommitIndex(), paxos2->getLastLogIndex());
EXPECT_NE(paxos1->getCommitIndex(), paxos2->getCommitIndex());
paxos1->leaderTransfer(2);
sleep(2);
EXPECT_EQ(paxos2->getState(), Paxos::LEADER);
paxos2->debugSkipUpdateCommitIndex = false;
while (paxos1->getLastLogIndex() != paxos2->getLastLogIndex())
sleep(1);
sleep(5);
EXPECT_EQ(paxos1->getCommitIndex(), paxos2->getLastLogIndex());
EXPECT_EQ(paxos1->getCommitIndex(), paxos2->getCommitIndex());
delete paxos1;
delete paxos2;
delete paxos3;
deleteDir("paxosLogTestDir1");
deleteDir("paxosLogTestDir2");
deleteDir("paxosLogTestDir3");
}
TEST(consensus, flow_control)
{
std::vector<std::string> strConfig = { "127.0.0.1:11001", "127.0.0.1:11002",
"127.0.0.1:11003" };
uint64_t timeout = 5000; // 1s heartbeat
std::shared_ptr<PaxosLog> rlog;
rlog = std::make_shared<RDPaxosLog>("paxosLogTestDir1", true, 4 * 1024 * 1024);
Paxos *paxos1 = new Paxos(timeout, rlog);
paxos1->init(strConfig, 1, NULL);
rlog = std::make_shared<RDPaxosLog>("paxosLogTestDir2", true, 4 * 1024 * 1024);
Paxos *paxos2 = new Paxos(timeout, rlog);
paxos2->init(strConfig, 2, NULL);
rlog = std::make_shared<RDPaxosLog>("paxosLogTestDir3", true, 4 * 1024 * 1024);
Paxos *paxos3 = new Paxos(timeout, rlog);
paxos3->init(strConfig, 3, NULL);
sleep(1);
paxos1->requestVote();
sleep(2);
EXPECT_EQ(paxos1->getState(), Paxos::LEADER);
/* replicate a log */
LogEntry le;
le.set_index(0);
le.set_optype(1);
le.set_value("12345");
paxos1->replicateLog(le);
for (int i=0; i<4; ++i)
paxos1->replicateLog(le);
sleep(2);
EXPECT_EQ(paxos1->getLastLogIndex(), paxos2->getLastLogIndex());
EXPECT_EQ(paxos1->getLastLogIndex(), paxos2->getLastLogIndex());
uint64_t mps = paxos1->getMaxPacketSize();
paxos1->setMaxPacketSize(1);
paxos1->set_flow_control(2, -1);
paxos1->set_flow_control(3, -2);
for (int i=0; i<4; ++i)
paxos1->replicateLog(le);
sleep(2);
EXPECT_NE(paxos1->getLastLogIndex(), paxos2->getLastLogIndex());
EXPECT_NE(paxos1->getLastLogIndex(), paxos3->getLastLogIndex());
sleep(6);
EXPECT_EQ(paxos1->getLastLogIndex(), paxos2->getLastLogIndex());
EXPECT_NE(paxos1->getLastLogIndex(), paxos3->getLastLogIndex());
paxos1->setMaxPacketSize(mps);
paxos1->set_flow_control(3, 0);
for (int i=0; i<4; ++i)
paxos1->replicateLog(le);
sleep(2);
EXPECT_EQ(paxos1->getLastLogIndex(), paxos2->getLastLogIndex());
EXPECT_EQ(paxos1->getLastLogIndex(), paxos3->getLastLogIndex());
delete paxos1;
delete paxos2;
delete paxos3;
deleteDir("paxosLogTestDir1");
deleteDir("paxosLogTestDir2");
deleteDir("paxosLogTestDir3");
}
TEST(consensus, memory_usage_count)
{
std::vector<std::string> strConfig = { "127.0.0.1:11001", "127.0.0.1:11002",
"127.0.0.1:11003" };
uint64_t timeout = 5000; // 1s heartbeat
std::shared_ptr<PaxosLog> rlog, rlog1;
rlog1 = rlog = std::make_shared<RDPaxosLog>("paxosLogTestDir1", true, 4 * 1024 * 1024);
Paxos *paxos1 = new Paxos(timeout, rlog1);
paxos1->init(strConfig, 1, NULL, 4, 4, NULL, true);
rlog = std::make_shared<RDPaxosLog>("paxosLogTestDir2", true, 4 * 1024 * 1024);
Paxos *paxos2 = new Paxos(timeout, rlog);
paxos2->init(strConfig, 2, NULL, 4, 4, NULL, true);
rlog = std::make_shared<RDPaxosLog>("paxosLogTestDir3", true, 4 * 1024 * 1024);
Paxos *paxos3 = new Paxos(timeout, rlog);
paxos3->init(strConfig, 3, NULL, 4, 4, NULL, true);
sleep(1);
paxos1->requestVote();
sleep(2);
EXPECT_EQ(paxos1->getState(), Paxos::LEADER);
/* replicate a log */
LogEntry le;
le.set_index(0);
le.set_optype(1);
le.set_value("12345");
paxos1->replicateLog(le);
for (int i=0; i<4; ++i)
paxos1->replicateLog(le);
sleep(2);
EXPECT_EQ(paxos1->getLastLogIndex(), paxos2->getLastLogIndex());
EXPECT_EQ(paxos1->getLastLogIndex(), paxos2->getLastLogIndex());
// memory usage not equal to 0
EXPECT_NE(easy_pool_alloc_byte, 0);
std::cout << "easy_pool_alloc_byte: " << easy_pool_alloc_byte << std::endl;
delete paxos1;
delete paxos2;
delete paxos3;
// memory usage go back to 0
EXPECT_EQ(easy_pool_alloc_byte, 0);
std::cout << "easy_pool_alloc_byte: " << easy_pool_alloc_byte << std::endl;
deleteDir("paxosLogTestDir1");
deleteDir("paxosLogTestDir2");
deleteDir("paxosLogTestDir3");
}
TEST(consensus, paxos_force_promote) {
std::vector<std::string> strConfig;
strConfig.emplace_back("127.0.0.1:11001");
strConfig.emplace_back("127.0.0.1:11002");
strConfig.emplace_back("127.0.0.1:11003");
uint64_t timeout= 10000;
std::shared_ptr<PaxosLog> rlog;
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir1", true, 4 * 1024 * 1024);
Paxos *paxos1= new Paxos(timeout, rlog, 3000);
paxos1->init(strConfig, 1, NULL);
paxos1->initAutoPurgeLog(false, false, NULL); // disable autoPurge
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir2", true, 4 * 1024 * 1024);
Paxos *paxos2= new Paxos(timeout, rlog, 3000);
paxos2->init(strConfig, 2, NULL);
paxos2->initAutoPurgeLog(false, false, NULL); // disable autoPurge
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir3", true, 4 * 1024 * 1024);
Paxos *paxos3= new Paxos(timeout, rlog, 3000);
paxos3->init(strConfig, 3, NULL);
std::string learnerAddr = "127.0.0.1:11004";
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir4", true, 4 * 1024 * 1024);
Paxos *paxos4= new Paxos(timeout, rlog, 3000);
paxos4->initAsLearner(learnerAddr);
sleep(3);
paxos1->requestVote();
sleep(1);
EXPECT_EQ(paxos1->getState(), Paxos::LEADER);
LogEntry le;
le.set_index(0);
le.set_optype(0);
le.set_value("aaa");
paxos1->replicateLog(le);
sleep(1);
std::vector<std::string> vec;
vec.push_back(learnerAddr);
paxos1->changeLearners(Paxos::CCAddNode, vec);
sleep(1);
EXPECT_EQ(paxos1->getConfig()->learnersToString(), std::string("127.0.0.1:11004$00"));
/* learner forcePromote: do nothing */
paxos4->forcePromote();
sleep(1);
EXPECT_EQ(paxos4->getState(), Paxos::LEARNER);
/* follower forcePromote: become new leader */
paxos2->forcePromote();
sleep(1);
EXPECT_EQ(paxos2->getState(), Paxos::LEADER);
EXPECT_EQ(paxos1->getState(), Paxos::FOLLOWER);
delete paxos1;
delete paxos2;
delete paxos3;
delete paxos4;
deleteDir("paxosLogTestDir1");
deleteDir("paxosLogTestDir2");
deleteDir("paxosLogTestDir3");
deleteDir("paxosLogTestDir4");
}
TEST(consensus, extra_info) {
std::vector<std::string> strConfig;
strConfig.emplace_back("127.0.0.1:11001");
strConfig.emplace_back("127.0.0.1:11002");
strConfig.emplace_back("127.0.0.1:11003");
uint64_t timeout= 5000;
std::shared_ptr<PaxosLog> rlog;
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir1", true, 4 * 1024 * 1024);
Paxos *paxos1= new Paxos(timeout, rlog);
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir2", true, 4 * 1024 * 1024);
Paxos *paxos2= new Paxos(timeout, rlog);
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir3", true, 4 * 1024 * 1024);
Paxos *paxos3= new Paxos(timeout, rlog);
class MockExtraStore: public ExtraStore {
public:
MockExtraStore(uint p) : port(p), isLeader(0) {}
virtual std::string getRemote() { return data; }
virtual void setRemote(const std::string &d) { data = d; }
/* local info to send to others */
virtual std::string getLocal() { return isLeader? std::to_string(port): ""; }
uint getRemotePort() { return data != ""? stoul(data): 0; }
void setIsLeader(bool b) { isLeader = b; }
private:
uint port;
std::string data;
bool isLeader; /* maintained by rds server level */
};
paxos1->init(strConfig, 1);
paxos2->init(strConfig, 2);
paxos3->init(strConfig, 3);
paxos1->setExtraStore(std::make_shared<MockExtraStore>(paxos1->getPort()-8000));
paxos2->setExtraStore(std::make_shared<MockExtraStore>(paxos2->getPort()-8000));
paxos3->setExtraStore(std::make_shared<MockExtraStore>(paxos3->getPort()-8000));
sleep(3);
paxos1->requestVote(1);
sleep(1);
EXPECT_EQ(paxos1->getState(), Paxos::LEADER);
std::dynamic_pointer_cast<MockExtraStore>(paxos1->getExtraStore())->setIsLeader(1);
std::dynamic_pointer_cast<MockExtraStore>(paxos2->getExtraStore())->setIsLeader(0);
std::dynamic_pointer_cast<MockExtraStore>(paxos3->getExtraStore())->setIsLeader(0);
LogEntry le;
le.set_index(0);
le.set_optype(0);
le.set_value("aaa");
paxos1->replicateLog(le);
sleep(1);
/* every follower will have port-8000 from leader paxos1 */
EXPECT_EQ(std::dynamic_pointer_cast<MockExtraStore>(paxos1->getExtraStore())->getRemotePort(), 0);
EXPECT_EQ(std::dynamic_pointer_cast<MockExtraStore>(paxos2->getExtraStore())->getRemotePort(), paxos1->getPort()-8000);
EXPECT_EQ(std::dynamic_pointer_cast<MockExtraStore>(paxos3->getExtraStore())->getRemotePort(), paxos1->getPort()-8000);
paxos2->requestVote(1);
sleep(1);
EXPECT_EQ(paxos2->getState(), Paxos::LEADER);
std::dynamic_pointer_cast<MockExtraStore>(paxos1->getExtraStore())->setIsLeader(0);
std::dynamic_pointer_cast<MockExtraStore>(paxos2->getExtraStore())->setIsLeader(1);
std::dynamic_pointer_cast<MockExtraStore>(paxos3->getExtraStore())->setIsLeader(0);
paxos2->replicateLog(le);
sleep(1);
/* every follower will have port-8000 from new leader paxos2 */
EXPECT_EQ(std::dynamic_pointer_cast<MockExtraStore>(paxos1->getExtraStore())->getRemotePort(), paxos2->getPort()-8000);
EXPECT_EQ(std::dynamic_pointer_cast<MockExtraStore>(paxos2->getExtraStore())->getRemotePort(), 0);
EXPECT_EQ(std::dynamic_pointer_cast<MockExtraStore>(paxos3->getExtraStore())->getRemotePort(), paxos2->getPort()-8000);
delete paxos1;
delete paxos2;
delete paxos3;
deleteDir("paxosLogTestDir1");
deleteDir("paxosLogTestDir2");
deleteDir("paxosLogTestDir3");
}