/************************************************************************ * * 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 #include #include #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 config= std::shared_ptr(new StableConfiguration()); EXPECT_TRUE(static_cast(config)); std::shared_ptr ptr; std::shared_ptr lptr; config->servers.push_back(lptr= std::make_shared(1)); lptr->strAddr= std::string("127.0.0.1:10001"); config->servers.push_back(ptr= std::make_shared(2)); ptr->matchIndex= 5; ptr->strAddr= std::string("127.0.0.1:10002"); config->servers.push_back(ptr= std::make_shared(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 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 config= std::shared_ptr(new StableConfiguration()); EXPECT_TRUE(static_cast(config)); std::shared_ptr ptr; std::shared_ptr lptr; config->servers.push_back(lptr= std::make_shared(1)); lptr->strAddr= std::string("127.0.0.1:10001"); config->servers.push_back(nullptr); config->servers.push_back(ptr= std::make_shared(3)); ptr->matchIndex= 5; ptr->strAddr= std::string("127.0.0.1:10002"); config->servers.push_back(ptr= std::make_shared(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 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 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 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(new Service(NULL)); EXPECT_TRUE(static_cast(srv)); srv->init(); srv->start(11001); auto ptr= std::make_shared(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 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 rlog; rlog= std::make_shared("paxosLogTestDir1", true, 4 * 1024 * 1024); Paxos *paxos1= new Paxos(timeout, rlog); paxos1->init(strConfig, 1); rlog= std::make_shared("paxosLogTestDir2", true, 4 * 1024 * 1024); Paxos *paxos2= new Paxos(timeout, rlog); paxos2->init(strConfig, 2); rlog= std::make_shared("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("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("paxosLogTestDir5", true, 4 * 1024 * 1024); Paxos *learner2= new Paxos(timeout, rlog); learner2->initAsLearner(strTmp2); rlog= std::make_shared("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(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 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 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 rlog1= std::make_shared("paxosLogTestDir11", true, 4 * 1024 * 1024); std::shared_ptr rlog2= std::make_shared("paxosLogTestDir12", true, 4 * 1024 * 1024); std::shared_ptr rlog3= std::make_shared("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 log= paxos->getLog(); for (i= 1; i <= paxos->getCommitIndex(); ++i) { LogEntry entry; log->getEntry(i, entry); std::cout<< "LogIndex "<getCommitIndex()<< " ."<waitCommitIndexUpdate(10, 3); EXPECT_LE(paxos->getCommitIndex(), 10); EXPECT_NE(paxos->getTerm(), 3); std::cout<< "ApplyThread: return because state changed."<getStats(); std::cout<< "countMsgAppendLog:"< 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 rlog; rlog= std::make_shared("paxosLogTestDir21", true, 4 * 1024 * 1024); ClientService *cs1= new ClientService(); Paxos *paxos1= new Paxos(timeout, rlog); paxos1->init(strConfig, 1, cs1); rlog= std::make_shared("paxosLogTestDir22", true, 4 * 1024 * 1024); ClientService *cs2= new ClientService(); Paxos *paxos2= new Paxos(timeout, rlog); paxos2->init(strConfig, 2, cs2); rlog= std::make_shared("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:"<replicateLog(le); //std::cout<< "countMsgAppendLog:"<replicateLog(le); //std::cout<< "countMsgAppendLog:"<replicateLog(le); //std::cout<< "countMsgAppendLog:"<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 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 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 aserver; std::shared_ptr aserver1= std::make_shared(1); std::shared_ptr rlog, rlog1; std::shared_ptr rdlog; rlog1= rlog= rdlog= std::make_shared("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(1)); rlog= rdlog= std::make_shared("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("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:"<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:"<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 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:"<replicateLog(le); std::cout<< "countMsgAppendLog:"<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 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 rlog; rlog= std::make_shared("paxosLogTestDir21", true, 4 * 1024 * 1024); Paxos *paxos1= new Paxos(timeout, rlog); paxos1->init(strConfig, 1); rlog= std::make_shared("paxosLogTestDir22", true, 4 * 1024 * 1024); Paxos *paxos2= new Paxos(timeout, rlog); paxos2->init(strConfig, 2); rlog= std::make_shared("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 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 rlog, rlog1; rlog1= rlog= std::make_shared("paxosLogTestDir1", true, 4 * 1024 * 1024); Paxos *paxos1= new Paxos(timeout, rlog); paxos1->init(strConfig, 1); rlog= std::make_shared("paxosLogTestDir2", true, 4 * 1024 * 1024); Paxos *paxos2= new Paxos(timeout, rlog); paxos2->init(strConfig, 2); rlog= std::make_shared("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("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 strConfig = { "127.0.0.1:11001", "127.0.0.1:11002", "127.0.0.1:11003" }; uint64_t timeout = 10000; std::shared_ptr rlog; rlog = std::make_shared("paxosLogTestDir1", true, 4 * 1024 * 1024); Paxos *paxos1 = new Paxos(timeout, rlog); paxos1->init(strConfig, 1, NULL); rlog = std::make_shared("paxosLogTestDir2", true, 4 * 1024 * 1024); Paxos *paxos2 = new Paxos(timeout, rlog); paxos2->init(strConfig, 2, NULL); rlog = std::make_shared("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 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 strConfig = { "127.0.0.1:11001", "127.0.0.1:11002", "127.0.0.1:11003" }; uint64_t timeout = 10000; std::shared_ptr rlog; rlog = std::make_shared("paxosLogTestDir1", true, 4 * 1024 * 1024); Paxos *paxos1 = new Paxos(timeout, rlog); paxos1->init(strConfig, 1, NULL); rlog = std::make_shared("paxosLogTestDir2", true, 4 * 1024 * 1024); Paxos *paxos2 = new Paxos(timeout, rlog); paxos2->init(strConfig, 2, NULL); rlog = std::make_shared("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 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 strConfig = { "127.0.0.1:11001", "127.0.0.1:11002", "127.0.0.1:11003" }; uint64_t timeout = 10000; std::shared_ptr rlog; rlog = std::make_shared("paxosLogTestDir1", true, 4 * 1024 * 1024); Paxos *paxos1 = new Paxos(timeout, rlog); paxos1->init(strConfig, 1, NULL); rlog = std::make_shared("paxosLogTestDir2", true, 4 * 1024 * 1024); Paxos *paxos2 = new Paxos(timeout, rlog); paxos2->init(strConfig, 2, NULL); rlog = std::make_shared("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 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 rlog; rlog = std::make_shared("paxosLogTestDir1", true, 4 * 1024 * 1024); Paxos *paxos1 = new Paxos(timeout, rlog); paxos1->init(strConfig, 1, NULL); rlog = std::make_shared("paxosLogTestDir2", true, 4 * 1024 * 1024); Paxos *paxos2 = new Paxos(timeout, rlog); paxos2->init(strConfig, 2, NULL); rlog = std::make_shared("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 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 rlog, rlog1; rlog1 = rlog = std::make_shared("paxosLogTestDir1", true, 4 * 1024 * 1024); Paxos *paxos1 = new Paxos(timeout, rlog1); paxos1->init(strConfig, 1, NULL, 4, 4, NULL, true); rlog = std::make_shared("paxosLogTestDir2", true, 4 * 1024 * 1024); Paxos *paxos2 = new Paxos(timeout, rlog); paxos2->init(strConfig, 2, NULL, 4, 4, NULL, true); rlog = std::make_shared("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 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 rlog; rlog= std::make_shared("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("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("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("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 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 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 rlog; rlog= std::make_shared("paxosLogTestDir1", true, 4 * 1024 * 1024); Paxos *paxos1= new Paxos(timeout, rlog); rlog= std::make_shared("paxosLogTestDir2", true, 4 * 1024 * 1024); Paxos *paxos2= new Paxos(timeout, rlog); rlog= std::make_shared("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(paxos1->getPort()-8000)); paxos2->setExtraStore(std::make_shared(paxos2->getPort()-8000)); paxos3->setExtraStore(std::make_shared(paxos3->getPort()-8000)); sleep(3); paxos1->requestVote(1); sleep(1); EXPECT_EQ(paxos1->getState(), Paxos::LEADER); std::dynamic_pointer_cast(paxos1->getExtraStore())->setIsLeader(1); std::dynamic_pointer_cast(paxos2->getExtraStore())->setIsLeader(0); std::dynamic_pointer_cast(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(paxos1->getExtraStore())->getRemotePort(), 0); EXPECT_EQ(std::dynamic_pointer_cast(paxos2->getExtraStore())->getRemotePort(), paxos1->getPort()-8000); EXPECT_EQ(std::dynamic_pointer_cast(paxos3->getExtraStore())->getRemotePort(), paxos1->getPort()-8000); paxos2->requestVote(1); sleep(1); EXPECT_EQ(paxos2->getState(), Paxos::LEADER); std::dynamic_pointer_cast(paxos1->getExtraStore())->setIsLeader(0); std::dynamic_pointer_cast(paxos2->getExtraStore())->setIsLeader(1); std::dynamic_pointer_cast(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(paxos1->getExtraStore())->getRemotePort(), paxos2->getPort()-8000); EXPECT_EQ(std::dynamic_pointer_cast(paxos2->getExtraStore())->getRemotePort(), 0); EXPECT_EQ(std::dynamic_pointer_cast(paxos3->getExtraStore())->getRemotePort(), paxos2->getPort()-8000); delete paxos1; delete paxos2; delete paxos3; deleteDir("paxosLogTestDir1"); deleteDir("paxosLogTestDir2"); deleteDir("paxosLogTestDir3"); }