2329 lines
74 KiB
C++
2329 lines
74 KiB
C++
/************************************************************************
|
|
*
|
|
* Copyright (c) 2017 Alibaba.com, Inc. All Rights Reserved
|
|
* $Id: consensus1-t.cc,v 1.0 03/21/2017 09:19:25 PM yingqiang.zyq(yingqiang.zyq@alibaba-inc.com) $
|
|
*
|
|
************************************************************************/
|
|
|
|
/**
|
|
* @file consensus-learner-t.cc
|
|
* @author yingqiang.zyq(yingqiang.zyq@alibaba-inc.com)
|
|
* @date 03/21/2017 09:19:25 PM
|
|
* @version 1.0
|
|
* @brief
|
|
*
|
|
**/
|
|
|
|
#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, learnerSource)
|
|
{
|
|
std::vector<std::string> strConfig;
|
|
LogEntry le;
|
|
le.set_term(1);
|
|
le.set_index(1);
|
|
le.set_optype(kMock);
|
|
strConfig.emplace_back("127.0.0.1:11001");
|
|
strConfig.emplace_back("127.0.0.1:11002");
|
|
strConfig.emplace_back("127.0.0.1:11003");
|
|
std::string strTmp3("127.0.0.1:11004");
|
|
std::string strTmp4("127.0.0.1:11005");
|
|
std::string strTmp5("127.0.0.1:11006");
|
|
|
|
const uint64_t timeout= 2000;
|
|
std::shared_ptr<PaxosLog> rlog, rlog1;
|
|
rlog1= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir11", true, 4 * 1024 * 1024);
|
|
// We init log with mock log in index 1 to make error happend when we send log entry 1 to learner!
|
|
rlog->append(le);
|
|
Paxos *paxos1= new Paxos(timeout, rlog);
|
|
paxos1->init(strConfig, 1);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir12", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos2= new Paxos(timeout, rlog);
|
|
paxos2->init(strConfig, 2);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir13", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos3= new Paxos(timeout, rlog);
|
|
paxos3->init(strConfig, 3);
|
|
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir14", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos4= new Paxos(timeout, rlog);
|
|
paxos4->initAsLearner(strTmp3);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir15", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos5= new Paxos(timeout, rlog);
|
|
paxos5->initAsLearner(strTmp4);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir16", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos6= new Paxos(timeout, rlog);
|
|
paxos6->initAsLearner(strTmp5);
|
|
|
|
const Paxos::StatsType &stats= paxos2->getStats();
|
|
|
|
sleep(3);
|
|
paxos1->requestVote();
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(paxos1->getState(), Paxos::LEADER);
|
|
|
|
strConfig.clear();
|
|
strConfig.push_back(strTmp3);
|
|
strConfig.push_back(strTmp4);
|
|
|
|
paxos1->changeLearners(Paxos::CCAddNode, strConfig);
|
|
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(paxos1->getConfig()->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(paxos1->getConfig()->learnersToString(), std::string("127.0.0.1:11004$00;127.0.0.1:11005$00"));
|
|
|
|
|
|
/* extra safety test */
|
|
EXPECT_EQ(paxos1->configureMember(100, true, 9), PE_WEIGHTLEARNER);
|
|
EXPECT_STREQ(pxserror(paxos1->configureMember("127.0.0.1:11004", true, 9)), "Configure forcesync or weight to a learner is not allowed.");
|
|
|
|
paxos1->configureLearner(100, 2);
|
|
|
|
sleep(1);
|
|
EXPECT_EQ(paxos1->getConfig()->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(paxos1->getConfig()->learnersToString(), std::string("127.0.0.1:11004$02;127.0.0.1:11005$00"));
|
|
EXPECT_EQ(paxos2->getConfig()->learnersToString(), std::string("127.0.0.1:11004$02;127.0.0.1:11005$00"));
|
|
EXPECT_EQ(paxos2->getConfig()->getServer(100)->learnerSource, 2);
|
|
/* test getServerIdFromAddr */
|
|
EXPECT_EQ(paxos1->getServerIdFromAddr("127.0.0.1:11001"), 1);
|
|
EXPECT_EQ(paxos1->getServerIdFromAddr("127.0.0.1:11002"), 2);
|
|
EXPECT_EQ(paxos1->getServerIdFromAddr("127.0.0.1:11003"), 3);
|
|
EXPECT_EQ(paxos1->getServerIdFromAddr("127.0.0.1:11004"), 100);
|
|
EXPECT_EQ(paxos1->getServerIdFromAddr("127.0.0.1:11005"), 101);
|
|
paxos2->clearStats();
|
|
|
|
le.set_index(0);
|
|
le.set_optype(0);
|
|
le.set_value("aaa");
|
|
paxos1->replicateLog(le);
|
|
|
|
sleep(1);
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
|
|
sleep(2);
|
|
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;
|
|
EXPECT_EQ(stats.countMsgAppendLog, 2);
|
|
|
|
EXPECT_EQ(paxos4->getCurrentLeader(), 2);
|
|
EXPECT_EQ(paxos5->getCurrentLeader(), 1);
|
|
|
|
EXPECT_EQ(paxos4->getLastLogIndex(), paxos1->getLastLogIndex());
|
|
EXPECT_EQ(paxos5->getLastLogIndex(), paxos1->getLastLogIndex());
|
|
|
|
std::vector<Paxos::ClusterInfoType> cis;
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
EXPECT_EQ(cis[3].learnerSource, 2);
|
|
EXPECT_EQ(cis[4].learnerSource, 0);
|
|
EXPECT_EQ(cis[0].learnerSource, 0);
|
|
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(1);
|
|
cis.clear();
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
EXPECT_TRUE(cis[3].matchIndex <= cis[1].matchIndex);
|
|
EXPECT_TRUE(cis[3].matchIndex >= cis[1].matchIndex - 2);
|
|
EXPECT_TRUE(cis[3].nextIndex <= cis[1].nextIndex);
|
|
EXPECT_TRUE(cis[3].nextIndex >= cis[1].nextIndex - 2);
|
|
|
|
paxos1->configureLearner(100, 3);
|
|
sleep(1);
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(2);
|
|
|
|
EXPECT_EQ(paxos4->getCurrentLeader(), 3);
|
|
EXPECT_EQ(paxos4->getLastLogIndex(), paxos1->getLastLogIndex());
|
|
|
|
cis.clear();
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
EXPECT_TRUE(cis[3].matchIndex <= cis[1].matchIndex);
|
|
EXPECT_TRUE(cis[3].matchIndex >= cis[1].matchIndex - 2);
|
|
EXPECT_TRUE(cis[3].nextIndex <= cis[1].nextIndex);
|
|
EXPECT_TRUE(cis[3].nextIndex >= cis[1].nextIndex - 2);
|
|
|
|
paxos1->configureLearner(100, 0);
|
|
sleep(1);
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(paxos4->getCurrentLeader(), 1);
|
|
EXPECT_EQ(paxos4->getLastLogIndex(), paxos1->getLastLogIndex());
|
|
|
|
// Already fixed! Error may happy when server 1 is leader, and we change learnerSource from 1 to 0.
|
|
paxos1->configureLearner(100, 1);
|
|
sleep(1);
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(paxos4->getCurrentLeader(), 1);
|
|
EXPECT_EQ(paxos4->getLastLogIndex(), paxos1->getLastLogIndex());
|
|
|
|
paxos1->configureLearner(100, 0);
|
|
sleep(1);
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(paxos4->getCurrentLeader(), 1);
|
|
EXPECT_EQ(paxos4->getLastLogIndex(), paxos1->getLastLogIndex());
|
|
|
|
// set the learnerSource to another learner
|
|
paxos1->configureLearner(100, 101);
|
|
sleep(1);
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(paxos4->getCurrentLeader(), 101);
|
|
EXPECT_EQ(paxos4->getLastLogIndex(), paxos1->getLastLogIndex());
|
|
|
|
uint64_t tmpInt= 0;
|
|
std::cout<<"Cluster Info for server "<<paxos1->getLocalServer()->serverId<<std::endl<<std::flush;
|
|
cis.clear();
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
tmpInt= cis[0].matchIndex;
|
|
std::cout<<"Cluster Info for server "<<paxos5->getLocalServer()->serverId<<std::endl<<std::flush;
|
|
cis.clear();
|
|
paxos5->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
EXPECT_EQ(tmpInt, cis[1].matchIndex);
|
|
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(1);
|
|
|
|
std::cout<<"Cluster Info for server "<<paxos1->getLocalServer()->serverId<<std::endl<<std::flush;
|
|
cis.clear();
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
EXPECT_LE(tmpInt, cis[3].matchIndex);
|
|
std::cout<<"Cluster Info for server "<<paxos5->getLocalServer()->serverId<<std::endl<<std::flush;
|
|
cis.clear();
|
|
paxos5->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
|
|
|
|
// check if the new added member has the forceSync electionWeight and learnerSource info.
|
|
paxos1->configureMember(2, false, 8);
|
|
sleep(1);
|
|
paxos1->configureLearner(100, 2);
|
|
sleep(1);
|
|
|
|
strConfig.clear();
|
|
strConfig.push_back(strTmp5);
|
|
|
|
paxos1->changeLearners(Paxos::CCAddNode, strConfig);
|
|
paxos1->changeMember(Paxos::CCAddNode, strTmp5);
|
|
|
|
sleep(5);
|
|
EXPECT_EQ(paxos6->getCurrentLeader(), 1);
|
|
EXPECT_EQ(paxos6->getLastLogIndex(), paxos1->getLastLogIndex());
|
|
|
|
cis.clear();
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
cis.clear();
|
|
paxos6->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
EXPECT_EQ(cis[1].electionWeight, 8);
|
|
EXPECT_EQ(cis[4].learnerSource, 2);
|
|
|
|
|
|
delete paxos6;
|
|
delete paxos5;
|
|
delete paxos4;
|
|
delete paxos3;
|
|
delete paxos2;
|
|
delete paxos1;
|
|
|
|
deleteDir("paxosLogTestDir11");
|
|
deleteDir("paxosLogTestDir12");
|
|
deleteDir("paxosLogTestDir13");
|
|
deleteDir("paxosLogTestDir14");
|
|
deleteDir("paxosLogTestDir15");
|
|
deleteDir("paxosLogTestDir16");
|
|
}
|
|
|
|
|
|
TEST(consensus, follower2learner)
|
|
{
|
|
std::vector<std::string> strConfig;
|
|
LogEntry le;
|
|
le.set_term(1);
|
|
le.set_index(1);
|
|
le.set_optype(kMock);
|
|
strConfig.emplace_back("127.0.0.1:11001");
|
|
strConfig.emplace_back("127.0.0.1:11002");
|
|
strConfig.emplace_back("127.0.0.1:11003");
|
|
std::string strTmp3("127.0.0.1:11004");
|
|
std::string strTmp4("127.0.0.1:11005");
|
|
|
|
const uint64_t timeout= 2000;
|
|
std::shared_ptr<PaxosLog> rlog, rlog1, rlog4;
|
|
rlog1= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir11", true, 4 * 1024 * 1024);
|
|
// We init log with mock log in index 1 to make error happend when we send log entry 1 to learner!
|
|
rlog->append(le);
|
|
Paxos *paxos1= new Paxos(timeout, rlog);
|
|
paxos1->init(strConfig, 1);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir12", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos2= new Paxos(timeout, rlog);
|
|
paxos2->init(strConfig, 2);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir13", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos3= new Paxos(timeout, rlog);
|
|
paxos3->init(strConfig, 3);
|
|
|
|
rlog4= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir14", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos4= new Paxos(timeout, rlog);
|
|
paxos4->initAsLearner(strTmp3);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir15", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos5= new Paxos(timeout, rlog);
|
|
paxos5->initAsLearner(strTmp4);
|
|
|
|
le.set_optype(0);
|
|
|
|
//const Paxos::StatsType &stats= paxos2->getStats();
|
|
|
|
sleep(3);
|
|
paxos1->requestVote();
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(paxos1->getState(), Paxos::LEADER);
|
|
|
|
strConfig.clear();
|
|
strConfig.push_back(strTmp3);
|
|
strConfig.push_back(strTmp4);
|
|
|
|
paxos1->changeLearners(Paxos::CCAddNode, strConfig);
|
|
sleep(1);
|
|
EXPECT_EQ(0, paxos1->changeMember(Paxos::CCAddNode, strTmp3));
|
|
sleep(1);
|
|
EXPECT_EQ(0, paxos1->changeMember(Paxos::CCAddNode, strTmp4));
|
|
sleep(1);
|
|
auto config1= std::dynamic_pointer_cast<StableConfiguration>(paxos1->getConfig());
|
|
EXPECT_EQ(config1->membersToString(("127.0.0.1:11001")), std::string("127.0.0.1:11001#5N;127.0.0.1:11002#5N;127.0.0.1:11003#5N;127.0.0.1:11004#5N;127.0.0.1:11005#5N@1"));
|
|
std::vector<Paxos::ClusterInfoType> cis;
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
|
|
|
|
EXPECT_EQ(0, paxos1->downgradeMember(4));
|
|
sleep(2);
|
|
cis.clear();
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
cis.clear();
|
|
paxos2->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
cis.clear();
|
|
paxos4->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
EXPECT_EQ(Paxos::LEARNER, paxos4->getState());
|
|
std::string tmpStr;
|
|
rlog4->getMetaData(std::string(Paxos::keyMemberConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("127.0.0.1:11004#5N"));
|
|
rlog4->getMetaData(std::string(Paxos::keyLearnerConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("127.0.0.1:11004$00"));
|
|
|
|
|
|
sleep(1);
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(1);
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(1);
|
|
|
|
cis.clear();
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(0, paxos1->changeMember(Paxos::CCAddNode, strTmp3));
|
|
sleep(1);
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(1);
|
|
cis.clear();
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(0, paxos1->downgradeMember(4));
|
|
sleep(1);
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(1);
|
|
cis.clear();
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
EXPECT_EQ(100, cis[4].serverId);
|
|
EXPECT_EQ("127.0.0.1:11004", cis[4].ipPort);
|
|
sleep(1);
|
|
|
|
std::cout<<"strTmp3:"<<strTmp3<<std::endl<<std::flush;
|
|
cis.clear();
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
EXPECT_EQ(0, paxos1->changeMember(Paxos::CCAddNode, strTmp3));
|
|
sleep(1);
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(1);
|
|
cis.clear();
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
sleep(1);
|
|
|
|
// can't downgrade a learner
|
|
EXPECT_EQ(PaxosErrorCode::PE_DOWNGRADLEARNER, paxos1->downgradeMember(100));
|
|
cis.clear();
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
EXPECT_EQ(5, cis.size());
|
|
|
|
// when a node change from follower => learner => follower, this node can't create connect to other node.
|
|
// That means can't became leader.
|
|
sleep(1);
|
|
paxos1->leaderTransfer(4);
|
|
sleep(6);
|
|
EXPECT_EQ(paxos4->getState(), Paxos::LEADER);
|
|
|
|
|
|
sleep(1);
|
|
cis.clear();
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
|
|
delete paxos5;
|
|
delete paxos4;
|
|
delete paxos3;
|
|
delete paxos2;
|
|
delete paxos1;
|
|
|
|
deleteDir("paxosLogTestDir11");
|
|
deleteDir("paxosLogTestDir12");
|
|
deleteDir("paxosLogTestDir13");
|
|
deleteDir("paxosLogTestDir14");
|
|
deleteDir("paxosLogTestDir15");
|
|
|
|
}
|
|
|
|
TEST(consensus, downgrade_follower_donnot_recieve_msg)
|
|
{
|
|
std::vector<std::string> strConfig;
|
|
LogEntry le;
|
|
le.set_term(1);
|
|
le.set_index(1);
|
|
le.set_optype(kMock);
|
|
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>("paxosLogTestDir11", true, 4 * 1024 * 1024);
|
|
// We init log with mock log in index 1 to make error happend when we send log entry 1 to learner!
|
|
rlog->append(le);
|
|
Paxos *paxos1= new Paxos(timeout, rlog);
|
|
paxos1->init(strConfig, 1);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir12", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos2= new Paxos(timeout, rlog);
|
|
paxos2->init(strConfig, 2);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir13", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos3= new Paxos(timeout, rlog);
|
|
paxos3->init(strConfig, 3);
|
|
|
|
le.set_optype(0);
|
|
|
|
//const Paxos::StatsType &stats= paxos2->getStats();
|
|
|
|
sleep(3);
|
|
paxos1->requestVote();
|
|
for (uint i = 0; i < 30; ++i) {
|
|
if (paxos1->getState() != Paxos::LEADER)
|
|
sleep(1);
|
|
else
|
|
break;
|
|
}
|
|
ASSERT_TRUE(paxos1->getState() == Paxos::LEADER);
|
|
|
|
std::vector<Paxos::ClusterInfoType> cis;
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
|
|
ASSERT_TRUE(0 == paxos1->downgradeMember(2));
|
|
auto s100= paxos1->getConfig()->getServer(100);
|
|
ASSERT_TRUE(s100 != 0);
|
|
s100->disconnect(nullptr);
|
|
paxos2->requestVote(false);
|
|
|
|
sleep(1);
|
|
cis.clear();
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
EXPECT_EQ(cis[2].serverId, 100);
|
|
EXPECT_EQ(cis[1].serverId, 3);
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
|
|
sleep(2);
|
|
EXPECT_EQ(paxos2->getCurrentLeader(), 1);
|
|
EXPECT_EQ(paxos2->getState(), Paxos::LEARNER);
|
|
EXPECT_EQ(paxos2->getLastLogIndex(), paxos1->getLastLogIndex());
|
|
|
|
delete paxos3;
|
|
delete paxos2;
|
|
delete paxos1;
|
|
|
|
deleteDir("paxosLogTestDir11");
|
|
deleteDir("paxosLogTestDir12");
|
|
deleteDir("paxosLogTestDir13");
|
|
}
|
|
|
|
TEST(consensus, restart_learner)
|
|
{
|
|
std::vector<std::string> strConfig;
|
|
std::string tmpStr;
|
|
LogEntry le;
|
|
le.set_term(1);
|
|
le.set_index(1);
|
|
le.set_optype(kMock);
|
|
strConfig.emplace_back("127.0.0.1:11001");
|
|
strConfig.emplace_back("127.0.0.1:11002");
|
|
strConfig.emplace_back("127.0.0.1:11003");
|
|
std::string strTmp3("127.0.0.1:11004");
|
|
std::string strTmp4("127.0.0.1:11005");
|
|
std::vector<Paxos::ClusterInfoType> cis;
|
|
|
|
const uint64_t timeout= 2000;
|
|
std::shared_ptr<PaxosLog> rlog, rlog1, rlog4;
|
|
rlog1= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir11", true, 4 * 1024 * 1024);
|
|
// We init log with mock log in index 1 to make error happend when we send log entry 1 to learner!
|
|
rlog->append(le);
|
|
Paxos *paxos1= new Paxos(timeout, rlog);
|
|
paxos1->init(strConfig, 1);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir12", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos2= new Paxos(timeout, rlog);
|
|
paxos2->init(strConfig, 2);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir13", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos3= new Paxos(timeout, rlog);
|
|
paxos3->init(strConfig, 3);
|
|
|
|
rlog4= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir14", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos4= new Paxos(timeout, rlog);
|
|
paxos4->initAsLearner(strTmp3);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir15", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos5= new Paxos(timeout, rlog);
|
|
paxos5->initAsLearner(strTmp4);
|
|
|
|
|
|
le.set_optype(0);
|
|
sleep(3);
|
|
paxos1->requestVote();
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(paxos1->getState(), Paxos::LEADER);
|
|
|
|
strConfig.clear();
|
|
strConfig.push_back(strTmp3);
|
|
|
|
paxos1->changeLearners(Paxos::CCAddNode, strConfig);
|
|
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(paxos1->getConfig()->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(paxos1->getConfig()->learnersToString(), std::string("127.0.0.1:11004$00;127.0.0.1:11005$00"));
|
|
EXPECT_EQ(paxos1->getConfig()->learnersToString(), std::string("127.0.0.1:11004$00"));
|
|
|
|
sleep(1);
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
|
|
cis.clear();
|
|
paxos4->getClusterInfo(cis);
|
|
sleep(1);
|
|
Paxos::printClusterInfo(cis);
|
|
|
|
std::cout<< "11004 restart"<< std::endl<< std::flush;
|
|
delete paxos4;
|
|
sleep(2);
|
|
paxos4= new Paxos(timeout, rlog4);
|
|
std::string emptryString("");
|
|
paxos4->initAsLearner(emptryString);
|
|
rlog4->getMetaData(std::string(Paxos::keyLearnerConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("127.0.0.1:11004$00"));
|
|
rlog4->getMetaData(std::string(Paxos::keyMemberConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("127.0.0.1:11004#5N"));
|
|
cis.clear();
|
|
paxos4->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
sleep(2);
|
|
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(1);
|
|
EXPECT_EQ(paxos4->getLastLogIndex(), paxos1->getLastLogIndex());
|
|
|
|
strConfig.clear();
|
|
strConfig.push_back(strTmp4);
|
|
paxos1->changeLearners(Paxos::CCAddNode, strConfig);
|
|
sleep(1);
|
|
|
|
std::cout<< "11004 restart"<< std::endl<< std::flush;
|
|
delete paxos4;
|
|
sleep(1);
|
|
paxos4= new Paxos(timeout, rlog4);
|
|
paxos4->initAsLearner(emptryString);
|
|
sleep(1);
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(2);
|
|
rlog4->getMetaData(std::string(Paxos::keyLearnerConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("127.0.0.1:11004$00;127.0.0.1:11005$00"));
|
|
rlog4->getMetaData(std::string(Paxos::keyMemberConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("127.0.0.1:11004#5N"));
|
|
cis.clear();
|
|
paxos4->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
|
|
|
|
delete paxos4;
|
|
delete paxos5;
|
|
delete paxos3;
|
|
delete paxos2;
|
|
delete paxos1;
|
|
|
|
deleteDir("paxosLogTestDir11");
|
|
deleteDir("paxosLogTestDir12");
|
|
deleteDir("paxosLogTestDir13");
|
|
deleteDir("paxosLogTestDir14");
|
|
deleteDir("paxosLogTestDir15");
|
|
}
|
|
|
|
TEST(consensus, restart_follower)
|
|
{
|
|
std::vector<std::string> strConfig;
|
|
std::string tmpStr;
|
|
LogEntry le;
|
|
le.set_term(1);
|
|
le.set_index(1);
|
|
le.set_optype(kMock);
|
|
strConfig.emplace_back("127.0.0.1:11001");
|
|
strConfig.emplace_back("127.0.0.1:11002");
|
|
strConfig.emplace_back("127.0.0.1:11003");
|
|
std::vector<Paxos::ClusterInfoType> cis;
|
|
|
|
const uint64_t timeout= 2000;
|
|
std::shared_ptr<PaxosLog> rlog, rlog1, rlog2;
|
|
rlog1= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir11", true, 4 * 1024 * 1024);
|
|
// We init log with mock log in index 1 to make error happend when we send log entry 1 to learner!
|
|
rlog->append(le);
|
|
Paxos *paxos1= new Paxos(timeout, rlog);
|
|
paxos1->init(strConfig, 1);
|
|
rlog2= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir12", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos2= new Paxos(timeout, rlog);
|
|
paxos2->init(strConfig, 2);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir13", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos3= new Paxos(timeout, rlog);
|
|
paxos3->init(strConfig, 3);
|
|
|
|
|
|
le.set_optype(0);
|
|
sleep(3);
|
|
paxos3->requestVote();
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(paxos3->getState(), Paxos::LEADER);
|
|
|
|
EXPECT_EQ(paxos3->getConfig()->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(paxos3->getConfig()->learnersToString(), std::string("127.0.0.1:11004$00;127.0.0.1:11005$00"));
|
|
EXPECT_EQ(paxos3->getConfig()->learnersToString(), std::string(""));
|
|
|
|
sleep(1);
|
|
le.clear_term();
|
|
paxos3->replicateLog(le);
|
|
|
|
cis.clear();
|
|
paxos3->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
|
|
ASSERT_TRUE(0 == paxos3->downgradeMember(1));
|
|
sleep(1);
|
|
EXPECT_EQ(paxos1->getState(), Paxos::LEARNER);
|
|
cis.clear();
|
|
paxos3->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
|
|
std::cout<< "11002 restart"<< std::endl<< std::flush;
|
|
delete paxos2;
|
|
sleep(2);
|
|
paxos2= new Paxos(timeout, rlog2);
|
|
strConfig.clear();
|
|
paxos2->init(strConfig, 0);
|
|
sleep(2);
|
|
rlog2->getMetaData(std::string(Paxos::keyLearnerConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("127.0.0.1:11001$00"));
|
|
rlog2->getMetaData(std::string(Paxos::keyMemberConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("0;127.0.0.1:11002#5N;127.0.0.1:11003#5N@2"));
|
|
cis.clear();
|
|
paxos2->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
sleep(2);
|
|
|
|
le.clear_term();
|
|
paxos3->replicateLog(le);
|
|
sleep(1);
|
|
|
|
delete paxos3;
|
|
delete paxos2;
|
|
delete paxos1;
|
|
|
|
deleteDir("paxosLogTestDir11");
|
|
deleteDir("paxosLogTestDir12");
|
|
deleteDir("paxosLogTestDir13");
|
|
}
|
|
|
|
TEST(consensus, configureChange_affect_learner_meta)
|
|
{
|
|
std::vector<std::string> strConfig;
|
|
LogEntry le;
|
|
le.set_term(1);
|
|
le.set_index(1);
|
|
le.set_optype(kMock);
|
|
strConfig.emplace_back("127.0.0.1:11001");
|
|
strConfig.emplace_back("127.0.0.1:11002");
|
|
strConfig.emplace_back("127.0.0.1:11003");
|
|
std::string strTmp3("127.0.0.1:11004");
|
|
std::string strTmp4("127.0.0.1:11005");
|
|
std::string strTmp6("127.0.0.1:11006");
|
|
|
|
const uint64_t timeout= 2000;
|
|
std::shared_ptr<PaxosLog> rlog, rlog1, rlog2, rlog4, rlog5, rlog6;
|
|
rlog1= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir11", true, 4 * 1024 * 1024);
|
|
// We init log with mock log in index 1 to make error happend when we send log entry 1 to learner!
|
|
rlog->append(le);
|
|
Paxos *paxos1= new Paxos(timeout, rlog);
|
|
paxos1->init(strConfig, 1);
|
|
rlog2= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir12", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos2= new Paxos(timeout, rlog);
|
|
paxos2->init(strConfig, 2);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir13", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos3= new Paxos(timeout, rlog);
|
|
paxos3->init(strConfig, 3);
|
|
|
|
rlog4= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir14", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos4= new Paxos(timeout, rlog);
|
|
paxos4->initAsLearner(strTmp3);
|
|
rlog5= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir15", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos5= new Paxos(timeout, rlog);
|
|
paxos5->initAsLearner(strTmp4);
|
|
rlog6= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir16", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos6= new Paxos(timeout, rlog);
|
|
paxos6->initAsLearner(strTmp6);
|
|
|
|
le.set_optype(0);
|
|
|
|
//const Paxos::StatsType &stats= paxos2->getStats();
|
|
|
|
sleep(3);
|
|
paxos1->requestVote();
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(paxos1->getState(), Paxos::LEADER);
|
|
|
|
strConfig.clear();
|
|
strConfig.push_back(strTmp3);
|
|
paxos1->changeLearners(Paxos::CCAddNode, strConfig);
|
|
sleep(1);
|
|
|
|
strConfig.clear();
|
|
strConfig.push_back(strTmp4);
|
|
paxos1->changeLearners(Paxos::CCAddNode, strConfig);
|
|
sleep(1);
|
|
|
|
auto config1= std::dynamic_pointer_cast<StableConfiguration>(paxos1->getConfig());
|
|
EXPECT_EQ(config1->membersToString(("127.0.0.1:11001")), std::string("127.0.0.1:11001#5N;127.0.0.1:11002#5N;127.0.0.1:11003#5N@1"));
|
|
EXPECT_EQ(config1->learnersToString(), std::string("127.0.0.1:11004$00;127.0.0.1:11005$00"));
|
|
std::vector<Paxos::ClusterInfoType> cis;
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
std::string tmpStr;
|
|
rlog4->getMetaData(std::string(Paxos::keyMemberConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("127.0.0.1:11004#5N"));
|
|
rlog4->getMetaData(std::string(Paxos::keyLearnerConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("127.0.0.1:11004$00;127.0.0.1:11005$00"));
|
|
|
|
|
|
// follower -> learner
|
|
EXPECT_EQ(0, paxos1->downgradeMember(2));
|
|
sleep(2);
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(1);
|
|
|
|
std::cout<< "s1:"<< std::endl<< std::flush;
|
|
cis.clear();
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
std::cout<< "s2:"<< std::endl<< std::flush;
|
|
cis.clear();
|
|
paxos2->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
cis.clear();
|
|
std::cout<< "s4:"<< std::endl<< std::flush;
|
|
paxos4->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
EXPECT_EQ(Paxos::LEARNER, paxos4->getState());
|
|
rlog4->getMetaData(std::string(Paxos::keyMemberConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("127.0.0.1:11004#5N"));
|
|
rlog2->getMetaData(std::string(Paxos::keyLearnerConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("127.0.0.1:11004$00;127.0.0.1:11005$00;127.0.0.1:11002$00"));
|
|
rlog4->getMetaData(std::string(Paxos::keyLearnerConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("127.0.0.1:11004$00;127.0.0.1:11005$00;127.0.0.1:11002$00"));
|
|
rlog5->getMetaData(std::string(Paxos::keyLearnerConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("127.0.0.1:11004$00;127.0.0.1:11005$00;127.0.0.1:11002$00"));
|
|
|
|
|
|
// learner -> follower
|
|
EXPECT_EQ(0, paxos1->changeMember(Paxos::CCAddNode, strTmp3));
|
|
sleep(1);
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(1);
|
|
|
|
std::cout<< "s1:"<< std::endl<< std::flush;
|
|
cis.clear();
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
std::cout<< "s2:"<< std::endl<< std::flush;
|
|
cis.clear();
|
|
paxos2->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
cis.clear();
|
|
std::cout<< "s4:"<< std::endl<< std::flush;
|
|
paxos4->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
EXPECT_EQ(Paxos::FOLLOWER, paxos4->getState());
|
|
rlog4->getMetaData(std::string(Paxos::keyMemberConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("127.0.0.1:11001#5N;127.0.0.1:11004#5N;127.0.0.1:11003#5N@2"));
|
|
rlog2->getMetaData(std::string(Paxos::keyLearnerConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("0;127.0.0.1:11005$00;127.0.0.1:11002$00"));
|
|
rlog4->getMetaData(std::string(Paxos::keyLearnerConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("0;127.0.0.1:11005$00;127.0.0.1:11002$00"));
|
|
rlog5->getMetaData(std::string(Paxos::keyLearnerConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("0;127.0.0.1:11005$00;127.0.0.1:11002$00"));
|
|
|
|
|
|
// follower -> learner
|
|
EXPECT_EQ(0, paxos1->downgradeMember(3));
|
|
sleep(1);
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(1);
|
|
|
|
std::cout<< "s1:"<< std::endl<< std::flush;
|
|
cis.clear();
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
std::cout<< "s2:"<< std::endl<< std::flush;
|
|
cis.clear();
|
|
paxos2->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
cis.clear();
|
|
std::cout<< "s4:"<< std::endl<< std::flush;
|
|
paxos4->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
EXPECT_EQ(Paxos::FOLLOWER, paxos4->getState());
|
|
rlog4->getMetaData(std::string(Paxos::keyMemberConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("127.0.0.1:11001#5N;127.0.0.1:11004#5N@2"));
|
|
rlog2->getMetaData(std::string(Paxos::keyLearnerConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("127.0.0.1:11003$00;127.0.0.1:11005$00;127.0.0.1:11002$00"));
|
|
rlog4->getMetaData(std::string(Paxos::keyLearnerConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("127.0.0.1:11003$00;127.0.0.1:11005$00;127.0.0.1:11002$00"));
|
|
rlog5->getMetaData(std::string(Paxos::keyLearnerConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("127.0.0.1:11003$00;127.0.0.1:11005$00;127.0.0.1:11002$00"));
|
|
|
|
|
|
// configureLearner
|
|
paxos1->configureLearner(100, 102);
|
|
for (int i=0; i< 7; ++i)
|
|
{
|
|
// add 103-109
|
|
strConfig.clear();
|
|
strConfig.push_back("127.0.0.1:1200" + std::to_string(i));
|
|
paxos1->changeLearners(Paxos::CCAddNode, strConfig);
|
|
}
|
|
// add 110
|
|
strConfig.clear();
|
|
strConfig.push_back(strTmp6);
|
|
paxos1->changeLearners(Paxos::CCAddNode, strConfig);
|
|
for (int i=0; i< 7; ++i)
|
|
{
|
|
// delete 103-109
|
|
strConfig.clear();
|
|
strConfig.push_back("127.0.0.1:1200" + std::to_string(i));
|
|
paxos1->changeLearners(Paxos::CCDelNode, strConfig);
|
|
}
|
|
paxos1->configureLearner(101, 110);
|
|
sleep(1);
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(1);
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(1);
|
|
|
|
std::cout<< "s1:"<< std::endl<< std::flush;
|
|
cis.clear();
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
std::cout<< "s2:"<< std::endl<< std::flush;
|
|
cis.clear();
|
|
paxos2->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
cis.clear();
|
|
std::cout<< "s4:"<< std::endl<< std::flush;
|
|
paxos4->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
EXPECT_EQ(Paxos::FOLLOWER, paxos4->getState());
|
|
rlog4->getMetaData(std::string(Paxos::keyMemberConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("127.0.0.1:11001#5N;127.0.0.1:11004#5N@2"));
|
|
rlog2->getMetaData(std::string(Paxos::keyLearnerConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("127.0.0.1:11003$:2;127.0.0.1:11005$;0;127.0.0.1:11002$00;0;0;0;0;0;0;0;127.0.0.1:11006$00"));
|
|
rlog4->getMetaData(std::string(Paxos::keyLearnerConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("127.0.0.1:11003$:2;127.0.0.1:11005$;0;127.0.0.1:11002$00;0;0;0;0;0;0;0;127.0.0.1:11006$00"));
|
|
rlog5->getMetaData(std::string(Paxos::keyLearnerConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("127.0.0.1:11003$:2;127.0.0.1:11005$;0;127.0.0.1:11002$00;0;0;0;0;0;0;0;127.0.0.1:11006$00"));
|
|
|
|
|
|
//restart learner
|
|
std::cout<< "11005 restart"<< std::endl<< std::flush;
|
|
delete paxos5;
|
|
sleep(2);
|
|
paxos5= new Paxos(timeout, rlog5);
|
|
std::string emptryString("");
|
|
paxos5->initAsLearner(emptryString);
|
|
rlog5->getMetaData(std::string(Paxos::keyLearnerConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("127.0.0.1:11003$:2;127.0.0.1:11005$;0;127.0.0.1:11002$00;0;0;0;0;0;0;0;127.0.0.1:11006$00"));
|
|
rlog5->getMetaData(std::string(Paxos::keyMemberConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("127.0.0.1:11005#5N"));
|
|
cis.clear();
|
|
std::cout<< "s5:"<< std::endl<< std::flush;
|
|
paxos5->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
sleep(2);
|
|
|
|
|
|
delete paxos6;
|
|
delete paxos5;
|
|
delete paxos4;
|
|
delete paxos3;
|
|
delete paxos2;
|
|
delete paxos1;
|
|
|
|
deleteDir("paxosLogTestDir11");
|
|
deleteDir("paxosLogTestDir12");
|
|
deleteDir("paxosLogTestDir13");
|
|
deleteDir("paxosLogTestDir14");
|
|
deleteDir("paxosLogTestDir15");
|
|
deleteDir("paxosLogTestDir16");
|
|
}
|
|
|
|
TEST(consensus, learner_old_meta_new_version)
|
|
{
|
|
std::vector<std::string> strConfig;
|
|
std::string tmpStr;
|
|
LogEntry le;
|
|
le.set_term(1);
|
|
le.set_index(1);
|
|
le.set_optype(kMock);
|
|
strConfig.emplace_back("127.0.0.1:11001");
|
|
strConfig.emplace_back("127.0.0.1:11002");
|
|
strConfig.emplace_back("127.0.0.1:11003");
|
|
std::string strTmp3("127.0.0.1:11004");
|
|
std::vector<Paxos::ClusterInfoType> cis;
|
|
|
|
const uint64_t timeout= 2000;
|
|
std::shared_ptr<PaxosLog> rlog, rlog1, rlog4;
|
|
rlog1= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir11", true, 4 * 1024 * 1024);
|
|
// We init log with mock log in index 1 to make error happend when we send log entry 1 to learner!
|
|
rlog->append(le);
|
|
Paxos *paxos1= new Paxos(timeout, rlog);
|
|
paxos1->init(strConfig, 1);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir12", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos2= new Paxos(timeout, rlog);
|
|
paxos2->init(strConfig, 2);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir13", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos3= new Paxos(timeout, rlog);
|
|
paxos3->init(strConfig, 3);
|
|
|
|
rlog4= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir14", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos4= new Paxos(timeout, rlog);
|
|
paxos4->initAsLearner(strTmp3);
|
|
|
|
|
|
le.set_optype(0);
|
|
sleep(3);
|
|
paxos1->requestVote();
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(paxos1->getState(), Paxos::LEADER);
|
|
|
|
strConfig.clear();
|
|
strConfig.push_back(strTmp3);
|
|
|
|
paxos1->changeLearners(Paxos::CCAddNode, strConfig);
|
|
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(paxos1->getConfig()->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(paxos1->getConfig()->learnersToString(), std::string("127.0.0.1:11004$00"));
|
|
|
|
sleep(1);
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
|
|
cis.clear();
|
|
paxos4->getClusterInfo(cis);
|
|
sleep(1);
|
|
Paxos::printClusterInfo(cis);
|
|
|
|
std::cout<< "11004 restart"<< std::endl<< std::flush;
|
|
delete paxos4;
|
|
sleep(2);
|
|
|
|
//change meta to old format
|
|
rlog4->getMetaData(std::string(Paxos::keyMemberConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("127.0.0.1:11004#5N"));
|
|
rlog4->getMetaData(std::string(Paxos::keyLearnerConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("127.0.0.1:11004$00"));
|
|
rlog4->setMetaData(std::string(Paxos::keyMemberConfigure), std::string(""));
|
|
|
|
|
|
paxos4= new Paxos(timeout, rlog4);
|
|
std::string emptryString("");
|
|
paxos4->initAsLearner(emptryString);
|
|
sleep(2);
|
|
rlog4->getMetaData(std::string(Paxos::keyLearnerConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string(""));
|
|
rlog4->getMetaData(std::string(Paxos::keyMemberConfigure), tmpStr);
|
|
EXPECT_EQ(tmpStr, std::string("127.0.0.1:11004#5N"));
|
|
cis.clear();
|
|
paxos4->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
sleep(2);
|
|
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(1);
|
|
EXPECT_EQ(paxos4->getLastLogIndex(), paxos1->getLastLogIndex());
|
|
|
|
|
|
|
|
delete paxos4;
|
|
delete paxos3;
|
|
delete paxos2;
|
|
delete paxos1;
|
|
|
|
deleteDir("paxosLogTestDir11");
|
|
deleteDir("paxosLogTestDir12");
|
|
deleteDir("paxosLogTestDir13");
|
|
deleteDir("paxosLogTestDir14");
|
|
}
|
|
|
|
TEST(consensus, SyncLearnerAll)
|
|
{
|
|
std::vector<std::string> strConfig;
|
|
LogEntry le;
|
|
le.set_term(1);
|
|
le.set_index(1);
|
|
le.set_optype(kMock);
|
|
strConfig.emplace_back("127.0.0.1:11001");
|
|
strConfig.emplace_back("127.0.0.1:11002");
|
|
strConfig.emplace_back("127.0.0.1:11003");
|
|
std::string strTmp3("127.0.0.1:11004");
|
|
std::string strTmp4("127.0.0.1:11005");
|
|
std::string strTmp5("127.0.0.1:11006");
|
|
|
|
const uint64_t timeout= 2000;
|
|
std::shared_ptr<PaxosLog> rlog, rlog1, rlog6;
|
|
rlog1= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir11", true, 4 * 1024 * 1024);
|
|
// We init log with mock log in index 1 to make error happend when we send log entry 1 to learner!
|
|
rlog->append(le);
|
|
Paxos *paxos1= new Paxos(timeout, rlog);
|
|
paxos1->init(strConfig, 1);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir12", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos2= new Paxos(timeout, rlog);
|
|
paxos2->init(strConfig, 2);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir13", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos3= new Paxos(timeout, rlog);
|
|
paxos3->init(strConfig, 3);
|
|
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir14", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos4= new Paxos(timeout, rlog);
|
|
paxos4->initAsLearner(strTmp3);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir15", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos5= new Paxos(timeout, rlog);
|
|
paxos5->initAsLearner(strTmp4);
|
|
rlog6= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir16", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos6= new Paxos(timeout, rlog);
|
|
paxos6->initAsLearner(strTmp5);
|
|
|
|
const Paxos::StatsType &stats= paxos2->getStats();
|
|
|
|
sleep(3);
|
|
paxos1->requestVote();
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(paxos1->getState(), Paxos::LEADER);
|
|
|
|
strConfig.clear();
|
|
strConfig.push_back(strTmp3);
|
|
strConfig.push_back(strTmp4);
|
|
|
|
paxos1->changeLearners(Paxos::CCAddNode, strConfig);
|
|
|
|
sleep(1);
|
|
|
|
std::vector<Paxos::ClusterInfoType> cis;
|
|
cis.clear();
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
EXPECT_EQ(paxos1->getConfig()->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(paxos1->getConfig()->learnersToString(), std::string("127.0.0.1:11004$00;127.0.0.1:11005$00"));
|
|
|
|
le.set_index(0);
|
|
le.set_optype(0);
|
|
le.set_value("aaa");
|
|
paxos1->replicateLog(le);
|
|
sleep(1);
|
|
|
|
|
|
auto lli= paxos1->getLastLogIndex();
|
|
le.set_optype(kMock);
|
|
for (uint i= 2; i <= lli-1; ++i)
|
|
{
|
|
le.set_index(2);
|
|
rlog6->append(le);
|
|
}
|
|
le.set_optype(0);
|
|
EXPECT_EQ(lli-1, rlog6->getLastLogIndex());
|
|
|
|
|
|
strConfig.clear();
|
|
strConfig.push_back(strTmp5);
|
|
paxos1->changeLearners(Paxos::CCAddNode, strConfig);
|
|
sleep(2);
|
|
EXPECT_EQ(paxos6->getConfig()->learnersToString(), std::string("127.0.0.1:11004$00;127.0.0.1:11005$00;127.0.0.1:11006$00"));
|
|
|
|
|
|
/* for old added learner to sync meta */
|
|
std::vector<std::string> tmp;
|
|
paxos1->changeLearners(Paxos::CCSyncLearnerAll, tmp);
|
|
sleep(2);
|
|
EXPECT_EQ(paxos6->getConfig()->learnersToString(), std::string("127.0.0.1:11004$00;127.0.0.1:11005$00;127.0.0.1:11006$00"));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
paxos1->configureLearner(100, 2);
|
|
|
|
sleep(1);
|
|
EXPECT_EQ(paxos1->getConfig()->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(paxos1->getConfig()->learnersToString(), std::string("127.0.0.1:11004$02;127.0.0.1:11005$00"));
|
|
EXPECT_EQ(paxos2->getConfig()->learnersToString(), std::string("127.0.0.1:11004$02;127.0.0.1:11005$00"));
|
|
EXPECT_EQ(paxos2->getConfig()->getServer(100)->learnerSource, 2);
|
|
paxos2->clearStats();
|
|
|
|
le.set_index(0);
|
|
le.set_optype(0);
|
|
le.set_value("aaa");
|
|
paxos1->replicateLog(le);
|
|
|
|
sleep(1);
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
|
|
sleep(2);
|
|
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;
|
|
EXPECT_EQ(stats.countMsgAppendLog, 2);
|
|
|
|
EXPECT_EQ(paxos4->getCurrentLeader(), 2);
|
|
EXPECT_EQ(paxos5->getCurrentLeader(), 1);
|
|
|
|
EXPECT_EQ(paxos4->getLastLogIndex(), paxos1->getLastLogIndex());
|
|
EXPECT_EQ(paxos5->getLastLogIndex(), paxos1->getLastLogIndex());
|
|
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
EXPECT_EQ(cis[3].learnerSource, 2);
|
|
EXPECT_EQ(cis[4].learnerSource, 0);
|
|
EXPECT_EQ(cis[0].learnerSource, 0);
|
|
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(1);
|
|
cis.clear();
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
EXPECT_TRUE(cis[3].matchIndex <= cis[1].matchIndex);
|
|
EXPECT_TRUE(cis[3].matchIndex >= cis[1].matchIndex - 2);
|
|
EXPECT_TRUE(cis[3].nextIndex <= cis[1].nextIndex);
|
|
EXPECT_TRUE(cis[3].nextIndex >= cis[1].nextIndex - 2);
|
|
|
|
paxos1->configureLearner(100, 3);
|
|
sleep(1);
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(2);
|
|
|
|
EXPECT_EQ(paxos4->getCurrentLeader(), 3);
|
|
EXPECT_EQ(paxos4->getLastLogIndex(), paxos1->getLastLogIndex());
|
|
|
|
cis.clear();
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
EXPECT_TRUE(cis[3].matchIndex <= cis[1].matchIndex);
|
|
EXPECT_TRUE(cis[3].matchIndex >= cis[1].matchIndex - 2);
|
|
EXPECT_TRUE(cis[3].nextIndex <= cis[1].nextIndex);
|
|
EXPECT_TRUE(cis[3].nextIndex >= cis[1].nextIndex - 2);
|
|
|
|
paxos1->configureLearner(100, 0);
|
|
sleep(1);
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(paxos4->getCurrentLeader(), 1);
|
|
EXPECT_EQ(paxos4->getLastLogIndex(), paxos1->getLastLogIndex());
|
|
|
|
// Already fixed! Error may happy when server 1 is leader, and we change learnerSource from 1 to 0.
|
|
paxos1->configureLearner(100, 1);
|
|
sleep(1);
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(paxos4->getCurrentLeader(), 1);
|
|
EXPECT_EQ(paxos4->getLastLogIndex(), paxos1->getLastLogIndex());
|
|
|
|
paxos1->configureLearner(100, 0);
|
|
sleep(1);
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(paxos4->getCurrentLeader(), 1);
|
|
EXPECT_EQ(paxos4->getLastLogIndex(), paxos1->getLastLogIndex());
|
|
|
|
// set the learnerSource to another learner
|
|
paxos1->configureLearner(100, 101);
|
|
sleep(1);
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(paxos4->getCurrentLeader(), 101);
|
|
EXPECT_EQ(paxos4->getLastLogIndex(), paxos1->getLastLogIndex());
|
|
|
|
uint64_t tmpInt= 0;
|
|
std::cout<<"Cluster Info for server "<<paxos1->getLocalServer()->serverId<<std::endl<<std::flush;
|
|
cis.clear();
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
tmpInt= cis[0].matchIndex;
|
|
std::cout<<"Cluster Info for server "<<paxos5->getLocalServer()->serverId<<std::endl<<std::flush;
|
|
cis.clear();
|
|
paxos5->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
EXPECT_EQ(tmpInt, cis[1].matchIndex);
|
|
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(1);
|
|
|
|
std::cout<<"Cluster Info for server "<<paxos1->getLocalServer()->serverId<<std::endl<<std::flush;
|
|
cis.clear();
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
EXPECT_LE(tmpInt, cis[3].matchIndex);
|
|
std::cout<<"Cluster Info for server "<<paxos5->getLocalServer()->serverId<<std::endl<<std::flush;
|
|
cis.clear();
|
|
paxos5->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
|
|
|
|
// check if the new added member has the forceSync electionWeight and learnerSource info.
|
|
paxos1->configureMember(2, false, 8);
|
|
sleep(1);
|
|
paxos1->configureLearner(100, 2);
|
|
sleep(1);
|
|
|
|
strConfig.clear();
|
|
strConfig.push_back(strTmp5);
|
|
|
|
paxos1->changeLearners(Paxos::CCAddNode, strConfig);
|
|
paxos1->changeMember(Paxos::CCAddNode, strTmp5);
|
|
|
|
sleep(1);
|
|
EXPECT_EQ(paxos6->getCurrentLeader(), 1);
|
|
EXPECT_EQ(paxos6->getLastLogIndex(), paxos1->getLastLogIndex());
|
|
|
|
cis.clear();
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
cis.clear();
|
|
paxos6->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
EXPECT_EQ(cis[1].electionWeight, 8);
|
|
EXPECT_EQ(cis[4].learnerSource, 2);
|
|
*/
|
|
|
|
|
|
delete paxos6;
|
|
delete paxos5;
|
|
delete paxos4;
|
|
delete paxos3;
|
|
delete paxos2;
|
|
delete paxos1;
|
|
|
|
deleteDir("paxosLogTestDir11");
|
|
deleteDir("paxosLogTestDir12");
|
|
deleteDir("paxosLogTestDir13");
|
|
deleteDir("paxosLogTestDir14");
|
|
deleteDir("paxosLogTestDir15");
|
|
deleteDir("paxosLogTestDir16");
|
|
}
|
|
|
|
TEST(consensus, cctimeout)
|
|
{
|
|
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");
|
|
std::string strTmp3("127.0.0.1:11004");
|
|
|
|
const uint64_t timeout= 2000;
|
|
std::shared_ptr<PaxosLog> rlog, rlog1;
|
|
rlog1= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir11", true, 4 * 1024 * 1024);
|
|
Paxos *paxos1= new Paxos(timeout, rlog);
|
|
paxos1->init(strConfig, 1);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir12", true, 4 * 1024 * 1024);
|
|
Paxos *paxos2= new Paxos(timeout, rlog);
|
|
paxos2->init(strConfig, 2);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir13", true, 4 * 1024 * 1024);
|
|
Paxos *paxos3= new Paxos(timeout, rlog);
|
|
paxos3->init(strConfig, 3);
|
|
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir14", true, 4 * 1024 * 1024);
|
|
Paxos *paxos4= new Paxos(timeout, rlog);
|
|
paxos4->initAsLearner(strTmp3);
|
|
|
|
sleep(3);
|
|
paxos1->requestVote();
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(paxos1->getState(), Paxos::LEADER);
|
|
|
|
strConfig.clear();
|
|
strConfig.push_back(strTmp3);
|
|
|
|
paxos1->setConfigureChangeTimeout(1000);
|
|
EXPECT_EQ(paxos1->changeLearners(Paxos::CCAddNode, strConfig), 0);
|
|
delete paxos2;
|
|
delete paxos3;
|
|
|
|
easy_error_log("start changeMember");
|
|
EXPECT_EQ(paxos1->changeMember(Paxos::CCAddNode, strTmp3), PaxosErrorCode::PE_TIMEOUT);
|
|
easy_error_log("changeMember timeout");
|
|
|
|
delete paxos1;
|
|
delete paxos4;
|
|
deleteDir("paxosLogTestDir11");
|
|
deleteDir("paxosLogTestDir12");
|
|
deleteDir("paxosLogTestDir13");
|
|
deleteDir("paxosLogTestDir14");
|
|
}
|
|
|
|
static void msleep(uint64_t t)
|
|
{
|
|
struct timeval sleeptime;
|
|
if (t == 0)
|
|
return;
|
|
sleeptime.tv_sec= t / 1000;
|
|
sleeptime.tv_usec= (t - (sleeptime.tv_sec * 1000)) * 1000;
|
|
select(0, 0, 0, 0, &sleeptime);
|
|
}
|
|
TEST(consensus, learnerSource4)
|
|
{
|
|
std::vector<std::string> strConfig;
|
|
LogEntry le;
|
|
le.set_term(1);
|
|
le.set_index(1);
|
|
le.set_optype(kMock);
|
|
strConfig.emplace_back("127.0.0.1:11001");
|
|
strConfig.emplace_back("127.0.0.1:11002");
|
|
strConfig.emplace_back("127.0.0.1:11003");
|
|
std::string strTmp3("127.0.0.1:11004");
|
|
std::string strTmp4("127.0.0.1:11005");
|
|
std::string strTmp5("127.0.0.1:11006");
|
|
std::string strTmp6("127.0.0.1:11007");
|
|
std::string strTmp7("127.0.0.1:11008");
|
|
|
|
const uint64_t timeout= 2000;
|
|
std::shared_ptr<PaxosLog> rlog, rlog1;
|
|
rlog1= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir11", true, 4 * 1024 * 1024);
|
|
// We init log with mock log in index 1 to make error happend when we send log entry 1 to learner!
|
|
rlog->append(le);
|
|
Paxos *paxos1= new Paxos(timeout, rlog);
|
|
paxos1->init(strConfig, 1);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir12", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos2= new Paxos(timeout, rlog);
|
|
paxos2->init(strConfig, 2);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir13", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos3= new Paxos(timeout, rlog);
|
|
paxos3->init(strConfig, 3);
|
|
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir14", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos4= new Paxos(timeout, rlog);
|
|
paxos4->initAsLearner(strTmp3);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir15", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos5= new Paxos(timeout, rlog);
|
|
paxos5->initAsLearner(strTmp4);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir16", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos6= new Paxos(timeout, rlog);
|
|
paxos6->initAsLearner(strTmp5);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir17", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos7= new Paxos(timeout, rlog);
|
|
paxos7->initAsLearner(strTmp6);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir18", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos8= new Paxos(timeout, rlog);
|
|
paxos8->initAsLearner(strTmp7);
|
|
|
|
le.set_optype(0);
|
|
|
|
paxos2->setMaxMergeReportTimeout(500);
|
|
paxos4->setMaxMergeReportTimeout(500);
|
|
paxos5->setMaxMergeReportTimeout(500);
|
|
paxos6->setMaxMergeReportTimeout(500);
|
|
paxos7->setMaxMergeReportTimeout(500);
|
|
paxos8->setMaxMergeReportTimeout(500);
|
|
|
|
const Paxos::StatsType &stats= paxos2->getStats();
|
|
|
|
sleep(3);
|
|
paxos1->requestVote();
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(paxos1->getState(), Paxos::LEADER);
|
|
|
|
strConfig.clear();
|
|
strConfig.push_back(strTmp3);
|
|
strConfig.push_back(strTmp4);
|
|
strConfig.push_back(strTmp5);
|
|
strConfig.push_back(strTmp6);
|
|
strConfig.push_back(strTmp7);
|
|
|
|
paxos1->changeLearners(Paxos::CCAddNode, strConfig);
|
|
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(paxos1->getConfig()->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(paxos1->getConfig()->learnersToString(), std::string("127.0.0.1:11004$00;127.0.0.1:11005$00;127.0.0.1:11006$00;127.0.0.1:11007$00;127.0.0.1:11008$00"));
|
|
|
|
|
|
paxos1->configureLearner(100, 2);
|
|
sleep(1);
|
|
paxos1->configureLearner(101, 100);
|
|
sleep(1);
|
|
paxos1->configureLearner(102, 101);
|
|
sleep(1);
|
|
paxos1->configureLearner(103, 102);
|
|
sleep(1);
|
|
paxos1->configureLearner(104, 103);
|
|
|
|
sleep(2);
|
|
EXPECT_EQ(paxos1->getConfig()->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(paxos1->getConfig()->learnersToString(), std::string("127.0.0.1:11004$02;127.0.0.1:11005$:0;127.0.0.1:11006$:1;127.0.0.1:11007$:2;127.0.0.1:11008$:3"));
|
|
EXPECT_EQ(paxos2->getConfig()->learnersToString(), std::string("127.0.0.1:11004$02;127.0.0.1:11005$:0;127.0.0.1:11006$:1;127.0.0.1:11007$:2;127.0.0.1:11008$:3"));
|
|
EXPECT_EQ(paxos2->getConfig()->getServer(100)->learnerSource, 2);
|
|
EXPECT_EQ(paxos2->getConfig()->getServer(101)->learnerSource, 100);
|
|
EXPECT_EQ(paxos2->getConfig()->getServer(102)->learnerSource, 101);
|
|
EXPECT_EQ(paxos2->getConfig()->getServer(103)->learnerSource, 102);
|
|
EXPECT_EQ(paxos2->getConfig()->getServer(104)->learnerSource, 103);
|
|
paxos2->clearStats();
|
|
|
|
std::vector<Paxos::ClusterInfoType> cis;
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
EXPECT_EQ(cis[3].learnerSource, 2);
|
|
EXPECT_EQ(cis[4].learnerSource, 100);
|
|
EXPECT_EQ(cis[0].learnerSource, 0);
|
|
|
|
auto index= paxos1->getLastLogIndex();
|
|
le.set_index(0);
|
|
le.set_optype(0);
|
|
le.set_value("aaa");
|
|
paxos1->replicateLog(le);
|
|
|
|
|
|
for (uint64_t i= 0; i<14; ++i)
|
|
{
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
msleep(200);
|
|
}
|
|
|
|
sleep(2);
|
|
|
|
std::cout<< "paxos1:"<<std::endl<< std::flush;
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
std::cout<< "paxos2:"<<std::endl<< std::flush;
|
|
paxos2->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
std::cout<< "paxos4(100):"<<std::endl<< std::flush;
|
|
paxos4->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
std::cout<< "paxos5(101):"<<std::endl<< std::flush;
|
|
paxos5->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
std::cout<< "paxos6(102):"<<std::endl<< std::flush;
|
|
paxos6->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
std::cout<< "paxos7(103):"<<std::endl<< std::flush;
|
|
paxos7->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
|
|
EXPECT_EQ(index+15, paxos1->getLastLogIndex());
|
|
EXPECT_EQ(index+15, paxos4->getLastLogIndex());
|
|
EXPECT_EQ(index+15, paxos5->getLastLogIndex());
|
|
|
|
//change learnersource
|
|
paxos1->configureLearner(103, 2);
|
|
sleep(1);
|
|
EXPECT_EQ(paxos2->getConfig()->getServer(103)->learnerSource, 2);
|
|
|
|
index= paxos1->getLastLogIndex();
|
|
le.set_index(0);
|
|
le.set_optype(0);
|
|
le.set_value("aaa");
|
|
paxos1->replicateLog(le);
|
|
|
|
|
|
for (uint64_t i= 0; i<14; ++i)
|
|
{
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
msleep(200);
|
|
}
|
|
|
|
sleep(2);
|
|
|
|
std::cout<< "paxos1:"<<std::endl<< std::flush;
|
|
paxos1->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
std::cout<< "paxos2:"<<std::endl<< std::flush;
|
|
paxos2->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
std::cout<< "paxos4(100):"<<std::endl<< std::flush;
|
|
paxos4->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
std::cout<< "paxos5(101):"<<std::endl<< std::flush;
|
|
paxos5->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
std::cout<< "paxos6(102):"<<std::endl<< std::flush;
|
|
paxos6->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
std::cout<< "paxos7(103):"<<std::endl<< std::flush;
|
|
paxos7->getClusterInfo(cis);
|
|
Paxos::printClusterInfo(cis);
|
|
|
|
EXPECT_EQ(index+15, paxos1->getLastLogIndex());
|
|
EXPECT_EQ(index+15, paxos4->getLastLogIndex());
|
|
EXPECT_EQ(index+15, paxos5->getLastLogIndex());
|
|
|
|
|
|
|
|
|
|
delete paxos8;
|
|
delete paxos7;
|
|
delete paxos6;
|
|
delete paxos5;
|
|
delete paxos4;
|
|
delete paxos3;
|
|
delete paxos2;
|
|
delete paxos1;
|
|
|
|
deleteDir("paxosLogTestDir11");
|
|
deleteDir("paxosLogTestDir12");
|
|
deleteDir("paxosLogTestDir13");
|
|
deleteDir("paxosLogTestDir14");
|
|
deleteDir("paxosLogTestDir15");
|
|
deleteDir("paxosLogTestDir16");
|
|
deleteDir("paxosLogTestDir17");
|
|
deleteDir("paxosLogTestDir18");
|
|
}
|
|
|
|
/**
|
|
* bug: concurrent configureChange may clear other's flag,
|
|
* cause later configureChange hang
|
|
*/
|
|
TEST(consensus, concurrent_cc)
|
|
{
|
|
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>("paxosLogTestDir11", true, 4 * 1024 * 1024);
|
|
Paxos *paxos1= new Paxos(timeout, rlog);
|
|
paxos1->init(strConfig, 1);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir12", true, 4 * 1024 * 1024);
|
|
Paxos *paxos2= new Paxos(timeout, rlog);
|
|
paxos2->init(strConfig, 2);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir13", 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::thread op1([paxos1](){
|
|
std::vector<std::string> strConfig;
|
|
strConfig.push_back("127.0.0.1:11004");
|
|
paxos1->changeLearners(Paxos::CCAddNode, strConfig);
|
|
});
|
|
std::thread op2([paxos1](){
|
|
std::vector<std::string> strConfig;
|
|
strConfig.push_back("127.0.0.1:11005");
|
|
paxos1->changeLearners(Paxos::CCAddNode, strConfig);
|
|
});
|
|
std::thread op3([paxos1](){
|
|
std::vector<std::string> strConfig;
|
|
strConfig.push_back("127.0.0.1:11006");
|
|
paxos1->changeLearners(Paxos::CCAddNode, strConfig);
|
|
});
|
|
op1.join();
|
|
op2.join();
|
|
op3.join();
|
|
|
|
paxos1->setConfigureChangeTimeout(5*1000); //5s
|
|
delete paxos2;
|
|
delete paxos3;
|
|
std::thread op4([paxos1](){
|
|
std::vector<std::string> strConfig;
|
|
strConfig.push_back("127.0.0.1:11007");
|
|
paxos1->changeLearners(Paxos::CCAddNode, strConfig); // timeout
|
|
});
|
|
std::thread op5([paxos1](){
|
|
std::vector<std::string> strConfig;
|
|
strConfig.push_back("127.0.0.1:11008");
|
|
paxos1->changeLearners(Paxos::CCAddNode, strConfig); // timeout
|
|
});
|
|
op4.join();
|
|
op5.join();
|
|
|
|
delete paxos1;
|
|
deleteDir("paxosLogTestDir11");
|
|
deleteDir("paxosLogTestDir12");
|
|
deleteDir("paxosLogTestDir13");
|
|
}
|
|
|
|
TEST(consensus, learner_downgrade_term)
|
|
{
|
|
std::vector<std::string> strConfig;
|
|
LogEntry le;
|
|
le.set_term(1);
|
|
le.set_index(1);
|
|
le.set_optype(kMock);
|
|
strConfig.emplace_back("127.0.0.1:11001");
|
|
strConfig.emplace_back("127.0.0.1:11002");
|
|
strConfig.emplace_back("127.0.0.1:11003");
|
|
std::string strTmp3("127.0.0.1:11004");
|
|
std::vector<Paxos::ClusterInfoType> cis;
|
|
|
|
const uint64_t timeout= 2000;
|
|
std::shared_ptr<PaxosLog> rlog, rlog1, rlog4;
|
|
rlog1= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir11", true, 4 * 1024 * 1024);
|
|
// We init log with mock log in index 1 to make error happend when we send log entry 1 to learner!
|
|
rlog->append(le);
|
|
Paxos *paxos1= new Paxos(timeout, rlog);
|
|
paxos1->init(strConfig, 1);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir12", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos2= new Paxos(timeout, rlog);
|
|
paxos2->init(strConfig, 2);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir13", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos3= new Paxos(timeout, rlog);
|
|
paxos3->init(strConfig, 3);
|
|
|
|
rlog4= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir14", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos4= new Paxos(timeout, rlog);
|
|
paxos4->initAsLearner(strTmp3);
|
|
|
|
|
|
le.set_optype(0);
|
|
sleep(3);
|
|
paxos1->requestVote();
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(paxos1->getState(), Paxos::LEADER);
|
|
|
|
strConfig.clear();
|
|
strConfig.push_back(strTmp3);
|
|
|
|
paxos1->changeLearners(Paxos::CCAddNode, strConfig);
|
|
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(paxos1->getConfig()->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(paxos1->getConfig()->learnersToString(), std::string("127.0.0.1:11004$00"));
|
|
|
|
sleep(1);
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
|
|
cis.clear();
|
|
paxos4->getClusterInfo(cis);
|
|
sleep(1);
|
|
Paxos::printClusterInfo(cis);
|
|
|
|
std::cout<< "11004 restart"<< std::endl<< std::flush;
|
|
delete paxos4;
|
|
sleep(2);
|
|
|
|
//force to give learner a larger term
|
|
uint64_t cterm1 = 0, cterm2 = 0;
|
|
rlog4->getMetaData(std::string(Paxos::keyCurrentTerm), &cterm1);
|
|
rlog1->getMetaData(std::string(Paxos::keyCurrentTerm), &cterm2);
|
|
EXPECT_EQ(cterm1, cterm2);
|
|
rlog4->setMetaData(std::string(Paxos::keyCurrentTerm), cterm1 + 10);
|
|
|
|
paxos4= new Paxos(timeout, rlog4);
|
|
std::string emptryString("");
|
|
paxos4->initAsLearner(emptryString);
|
|
sleep(2);
|
|
rlog4->getMetaData(std::string(Paxos::keyCurrentTerm), &cterm1);
|
|
// check term downgrade successfully
|
|
EXPECT_EQ(cterm1, cterm2);
|
|
|
|
le.clear_term();
|
|
paxos1->replicateLog(le);
|
|
sleep(1);
|
|
// check log replicate is normal
|
|
EXPECT_EQ(paxos4->getLastLogIndex(), paxos1->getLastLogIndex());
|
|
|
|
delete paxos4;
|
|
delete paxos3;
|
|
delete paxos2;
|
|
delete paxos1;
|
|
|
|
deleteDir("paxosLogTestDir11");
|
|
deleteDir("paxosLogTestDir12");
|
|
deleteDir("paxosLogTestDir13");
|
|
deleteDir("paxosLogTestDir14");
|
|
}
|
|
|
|
TEST(consensus, learner_heartbeat)
|
|
{
|
|
std::vector<std::string> strConfig;
|
|
LogEntry le;
|
|
le.set_term(1);
|
|
le.set_index(1);
|
|
le.set_optype(kMock);
|
|
strConfig.emplace_back("127.0.0.1:11001");
|
|
std::string strTmp3("127.0.0.1:11004");
|
|
std::vector<Paxos::ClusterInfoType> cis;
|
|
|
|
const uint64_t timeout= 5000;
|
|
std::shared_ptr<PaxosLog> rlog1, rlog4;
|
|
rlog1= std::make_shared<RDPaxosLog>("paxosLogTestDir11", true, 4 * 1024 * 1024);
|
|
// We init log with mock log in index 1 to make error happend when we send log entry 1 to learner!
|
|
rlog1->append(le);
|
|
Paxos *paxos1= new Paxos(timeout, rlog1);
|
|
paxos1->init(strConfig, 1);
|
|
|
|
rlog4= std::make_shared<RDPaxosLog>("paxosLogTestDir14", true, 4 * 1024 * 1024);
|
|
rlog4->append(le);
|
|
Paxos *paxos4= new Paxos(timeout, rlog4);
|
|
paxos4->initAsLearner(strTmp3);
|
|
|
|
le.set_optype(0);
|
|
sleep(3);
|
|
paxos1->requestVote();
|
|
sleep(1);
|
|
EXPECT_EQ(paxos1->getState(), Paxos::LEADER);
|
|
strConfig.clear();
|
|
strConfig.push_back(strTmp3);
|
|
paxos1->changeLearners(Paxos::CCAddNode, strConfig);
|
|
|
|
/* now we have 1 leader and 1 learner*/
|
|
const Paxos::StatsType &stats= paxos1->getStats();
|
|
uint64_t tmp = 0;
|
|
sleep(2);
|
|
EXPECT_EQ(stats.countHeartbeat, 0);
|
|
paxos1->changeMember(Paxos::CCAddNode, strConfig[0]);
|
|
while (rlog1->getLastLogIndex() != rlog4->getLastLogIndex()) {}
|
|
tmp = stats.countHeartbeat;
|
|
sleep(2);
|
|
EXPECT_GT(stats.countHeartbeat, tmp);
|
|
paxos1->downgradeMember(strConfig[0]);
|
|
while (rlog1->getLastLogIndex() != rlog4->getLastLogIndex()) {}
|
|
tmp = stats.countHeartbeat;
|
|
sleep(2);
|
|
EXPECT_EQ(stats.countHeartbeat, tmp);
|
|
paxos1->changeLearners(Paxos::CCDelNode, strConfig);
|
|
paxos1->setEnableLearnerHeartbeat(true);
|
|
paxos1->changeLearners(Paxos::CCAddNode, strConfig);
|
|
while (rlog1->getLastLogIndex() != rlog4->getLastLogIndex()) {}
|
|
tmp = stats.countHeartbeat;
|
|
sleep(2);
|
|
EXPECT_GT(stats.countHeartbeat, tmp);
|
|
paxos1->changeMember(Paxos::CCAddNode, strConfig[0]);
|
|
while (rlog1->getLastLogIndex() != rlog4->getLastLogIndex()) {}
|
|
tmp = stats.countHeartbeat;
|
|
sleep(2);
|
|
EXPECT_GT(stats.countHeartbeat, tmp);
|
|
paxos1->downgradeMember(strConfig[0]);
|
|
while (rlog1->getLastLogIndex() != rlog4->getLastLogIndex()) {}
|
|
tmp = stats.countHeartbeat;
|
|
sleep(2);
|
|
EXPECT_GT(stats.countHeartbeat, tmp);
|
|
|
|
delete paxos4;
|
|
delete paxos1;
|
|
|
|
deleteDir("paxosLogTestDir11");
|
|
deleteDir("paxosLogTestDir14");
|
|
}
|
|
|
|
/* change learnerSource use the address as argument */
|
|
TEST(consensus, learnersource_addr)
|
|
{
|
|
std::vector<std::string> strConfig;
|
|
LogEntry le;
|
|
le.set_term(1);
|
|
le.set_index(1);
|
|
le.set_optype(kMock);
|
|
strConfig.emplace_back("127.0.0.1:11001");
|
|
strConfig.emplace_back("127.0.0.1:11002");
|
|
strConfig.emplace_back("127.0.0.1:11003");
|
|
std::string strTmp3("127.0.0.1:11004");
|
|
std::vector<Paxos::ClusterInfoType> cis;
|
|
|
|
const uint64_t timeout= 2000;
|
|
std::shared_ptr<PaxosLog> rlog, rlog1, rlog4;
|
|
rlog1= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir11", true, 4 * 1024 * 1024);
|
|
// We init log with mock log in index 1 to make error happend when we send log entry 1 to learner!
|
|
rlog->append(le);
|
|
Paxos *paxos1= new Paxos(timeout, rlog);
|
|
paxos1->init(strConfig, 1);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir12", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos2= new Paxos(timeout, rlog);
|
|
paxos2->init(strConfig, 2);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir13", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos3= new Paxos(timeout, rlog);
|
|
paxos3->init(strConfig, 3);
|
|
|
|
rlog4= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir14", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos4= new Paxos(timeout, rlog);
|
|
paxos4->initAsLearner(strTmp3);
|
|
|
|
|
|
le.set_optype(0);
|
|
sleep(3);
|
|
paxos1->requestVote();
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(paxos1->getState(), Paxos::LEADER);
|
|
|
|
strConfig.clear();
|
|
strConfig.push_back(strTmp3);
|
|
|
|
paxos1->changeLearners(Paxos::CCAddNode, strConfig);
|
|
sleep(1);
|
|
EXPECT_EQ(paxos1->getConfig()->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(paxos1->getConfig()->learnersToString(), std::string("127.0.0.1:11004$00"));
|
|
|
|
// cannot configure follower
|
|
EXPECT_EQ(paxos1->configureLearner("127.0.0.1:11002", "127.0.0.1:11002"), PaxosErrorCode::PE_NOTFOUND);
|
|
// cannot configure not-exist node
|
|
EXPECT_EQ(paxos1->configureLearner("127.0.0.1:11005", "127.0.0.1:11002"), PaxosErrorCode::PE_NOTFOUND);
|
|
EXPECT_EQ(paxos1->configureLearner("127.0.0.1:11004", "127.0.0.1:11005"), PaxosErrorCode::PE_NOTFOUND);
|
|
// success case
|
|
EXPECT_EQ(paxos1->configureLearner("127.0.0.1:11004", "127.0.0.1:11003"), PaxosErrorCode::PE_NONE);
|
|
sleep(1);
|
|
EXPECT_EQ(paxos1->getConfig()->learnersToString(), std::string("127.0.0.1:11004$03"));
|
|
// reset to 0
|
|
EXPECT_EQ(paxos1->configureLearner("127.0.0.1:11004", "127.0.0.1:11004"), PaxosErrorCode::PE_NONE);
|
|
sleep(1);
|
|
EXPECT_EQ(paxos1->getConfig()->learnersToString(), std::string("127.0.0.1:11004$00"));
|
|
|
|
delete paxos4;
|
|
delete paxos3;
|
|
delete paxos2;
|
|
delete paxos1;
|
|
|
|
deleteDir("paxosLogTestDir11");
|
|
deleteDir("paxosLogTestDir12");
|
|
deleteDir("paxosLogTestDir13");
|
|
deleteDir("paxosLogTestDir14");
|
|
}
|
|
|
|
TEST(consensus, enable_learner_auto_reset_match_index)
|
|
{
|
|
std::vector<std::string> strConfig;
|
|
LogEntry le;
|
|
le.set_term(1);
|
|
le.set_index(1);
|
|
le.set_optype(kNormal);
|
|
strConfig.emplace_back("127.0.0.1:11001");
|
|
strConfig.emplace_back("127.0.0.1:11002");
|
|
strConfig.emplace_back("127.0.0.1:11003");
|
|
std::string strTmp3("127.0.0.1:11004");
|
|
std::vector<Paxos::ClusterInfoType> cis;
|
|
|
|
const uint64_t timeout= 2000;
|
|
std::shared_ptr<PaxosLog> rlog, rlog1, rlog2, rlog4;
|
|
rlog1= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir11", true, 4 * 1024 * 1024);
|
|
// We init log with mock log in index 1 to make error happend when we send log entry 1 to learner!
|
|
rlog->append(le);
|
|
Paxos *paxos1= new Paxos(timeout, rlog);
|
|
paxos1->init(strConfig, 1);
|
|
rlog2= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir12", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos2= new Paxos(timeout, rlog);
|
|
paxos2->init(strConfig, 2);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir13", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos3= new Paxos(timeout, rlog);
|
|
paxos3->init(strConfig, 3);
|
|
|
|
rlog4= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir14", true, 4 * 1024 * 1024);
|
|
rlog->append(le);
|
|
Paxos *paxos4= new Paxos(timeout, rlog);
|
|
paxos4->initAsLearner(strTmp3);
|
|
|
|
|
|
le.set_optype(0);
|
|
sleep(3);
|
|
paxos1->requestVote();
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(paxos1->getState(), Paxos::LEADER);
|
|
|
|
strConfig.clear();
|
|
strConfig.push_back(strTmp3);
|
|
|
|
paxos1->changeLearners(Paxos::CCAddNode, strConfig);
|
|
sleep(1);
|
|
EXPECT_EQ(paxos1->getConfig()->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(paxos1->getConfig()->learnersToString(), std::string("127.0.0.1:11004$00"));
|
|
|
|
EXPECT_EQ(paxos4->getLastLogIndex(), 3);
|
|
|
|
std::cout<< "shutdown learner"<< std::endl;
|
|
delete paxos4;
|
|
sleep(1);
|
|
|
|
paxos2->requestVote(true);
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(paxos2->getState(), Paxos::LEADER);
|
|
EXPECT_EQ(paxos2->getLastLogIndex(), 4);
|
|
|
|
// new leader's index 4 term should be 3
|
|
{
|
|
LogEntry le;
|
|
rlog2->getEntry(4, le);
|
|
EXPECT_EQ(le.term(), 3);
|
|
}
|
|
|
|
// learner's index 4 term should be 2
|
|
{
|
|
LogEntry le;
|
|
le.set_term(2);
|
|
le.set_optype(kNormal);
|
|
rlog4->append(le);
|
|
rlog4->getEntry(4, le);
|
|
EXPECT_EQ(le.term(), 2);
|
|
}
|
|
{
|
|
LogEntry le;
|
|
le.set_term(2);
|
|
le.set_optype(kNormal);
|
|
rlog4->append(le);
|
|
rlog4->getEntry(5, le);
|
|
EXPECT_EQ(le.term(), 2);
|
|
}
|
|
|
|
paxos2->changeLearners(Paxos::CCDelNode, strConfig);
|
|
sleep(1);
|
|
EXPECT_EQ(paxos2->getConfig()->learnersToString(), std::string(""));
|
|
|
|
paxos2->changeLearners(Paxos::CCAddNode, strConfig);
|
|
sleep(1);
|
|
EXPECT_EQ(paxos2->getConfig()->learnersToString(), std::string("127.0.0.1:11004$00"));
|
|
|
|
EXPECT_EQ(paxos2->getLastLogIndex(), 6);
|
|
|
|
std::cout<< "restart learner"<< std::endl;
|
|
paxos4= new Paxos(timeout, rlog4);
|
|
paxos4->initAsLearner(strTmp3);
|
|
|
|
sleep(3);
|
|
|
|
EXPECT_EQ(paxos2->getEnableLearnerAutoResetMatchIndex(), false);
|
|
// log can not be replicated
|
|
{
|
|
LogEntry le;
|
|
rlog4->getEntry(4, le);
|
|
EXPECT_EQ(le.term(), 2);
|
|
}
|
|
|
|
paxos2->setEnableLearnerAutoResetMatchIndex(true);
|
|
EXPECT_EQ(paxos2->getEnableLearnerAutoResetMatchIndex(), true);
|
|
|
|
{
|
|
LogEntry le;
|
|
le.set_term(3);
|
|
le.set_optype(kNormal);
|
|
paxos2->replicateLog(le);
|
|
}
|
|
|
|
sleep(5);
|
|
|
|
// log can be replicated
|
|
EXPECT_EQ(paxos4->getLastLogIndex(), 7);
|
|
{
|
|
LogEntry le;
|
|
rlog4->getEntry(4, le);
|
|
EXPECT_EQ(le.term(), 3);
|
|
}
|
|
|
|
delete paxos4;
|
|
delete paxos3;
|
|
delete paxos2;
|
|
delete paxos1;
|
|
|
|
deleteDir("paxosLogTestDir11");
|
|
deleteDir("paxosLogTestDir12");
|
|
deleteDir("paxosLogTestDir13");
|
|
deleteDir("paxosLogTestDir14");
|
|
}
|
|
|
|
// test force single learner
|
|
// after a node becomes a single learner, it can be added back to a new cluster,
|
|
// and its log position will be automatically matched.
|
|
TEST(consensus, force_single_learner)
|
|
{
|
|
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");
|
|
std::string strTmp3("127.0.0.1:11004");
|
|
std::vector<Paxos::ClusterInfoType> cis;
|
|
|
|
const uint64_t timeout= 5000;
|
|
std::shared_ptr<PaxosLog> rlog, rlog1, rlog2, rlog4;
|
|
rlog1= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir11", true, 4 * 1024 * 1024);
|
|
Paxos *paxos1= new Paxos(timeout, rlog);
|
|
paxos1->init(strConfig, 1);
|
|
rlog2= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir12", true, 4 * 1024 * 1024);
|
|
auto localServer = std::make_shared<alisql::LocalServer>(0);
|
|
Paxos *paxos2= new Paxos(timeout, rlog);
|
|
paxos2->init(strConfig, 2, 0, 4, 4, localServer);
|
|
rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir13", true, 4 * 1024 * 1024);
|
|
Paxos *paxos3= new Paxos(timeout, rlog);
|
|
paxos3->init(strConfig, 3);
|
|
|
|
rlog4= rlog= std::make_shared<RDPaxosLog>("paxosLogTestDir14", true, 4 * 1024 * 1024);
|
|
Paxos *paxos4= new Paxos(timeout, rlog);
|
|
paxos4->initAsLearner(strTmp3);
|
|
|
|
paxos1->setEnableLearnerAutoResetMatchIndex(true);
|
|
paxos2->setEnableLearnerAutoResetMatchIndex(true);
|
|
paxos3->setEnableLearnerAutoResetMatchIndex(true);
|
|
paxos4->setEnableLearnerAutoResetMatchIndex(true);
|
|
|
|
// get standard learner meta info
|
|
EXPECT_EQ(paxos4->getConfig()->membersToString(), std::string("127.0.0.1:11004#5N"));
|
|
EXPECT_EQ(paxos4->getConfig()->learnersToString(), std::string(""));
|
|
|
|
sleep(1);
|
|
paxos1->requestVote();
|
|
sleep(1);
|
|
|
|
EXPECT_EQ(paxos1->getState(), Paxos::LEADER);
|
|
|
|
strConfig.clear();
|
|
strConfig.push_back(strTmp3);
|
|
|
|
paxos1->changeLearners(Paxos::CCAddNode, strConfig);
|
|
sleep(3);
|
|
EXPECT_EQ(paxos1->getConfig()->membersToString(("127.0.0.1:11001")), std::string("127.0.0.1:11001#5N;127.0.0.1:11002#5N;127.0.0.1:11003#5N@1"));
|
|
EXPECT_EQ(paxos1->getConfig()->learnersToString(), std::string("127.0.0.1:11004$00"));
|
|
|
|
EXPECT_EQ(paxos2->getCommitIndex(), 2);
|
|
EXPECT_EQ(paxos3->getCommitIndex(), 2);
|
|
EXPECT_EQ(paxos4->getCommitIndex(), 2);
|
|
|
|
// does not work for learner
|
|
EXPECT_EQ(paxos4->forceSingleLearner(), 1);
|
|
EXPECT_EQ(paxos4->getConfig()->membersToString(), std::string("127.0.0.1:11004#5N"));
|
|
EXPECT_EQ(paxos4->getConfig()->learnersToString(), std::string("127.0.0.1:11004$00"));
|
|
|
|
// make learner single leader
|
|
paxos4->forceSingleLeader();
|
|
paxos4->requestVote();
|
|
LogEntry le;
|
|
le.set_optype(0);
|
|
le.set_ikey("a");
|
|
paxos4->replicateLog(le);
|
|
EXPECT_EQ(paxos4->getCommitIndex(), 4);
|
|
{
|
|
LogEntry le;
|
|
rlog4->getEntry(3, le);
|
|
EXPECT_EQ(le.term(), 3);
|
|
}
|
|
|
|
le.set_ikey("b");
|
|
paxos1->replicateLog(le);
|
|
sleep(3);
|
|
EXPECT_EQ(paxos1->getCommitIndex(), 3);
|
|
EXPECT_EQ(paxos2->getCommitIndex(), 3);
|
|
EXPECT_EQ(paxos3->getCommitIndex(), 3);
|
|
{
|
|
LogEntry le;
|
|
rlog1->getEntry(3, le);
|
|
EXPECT_EQ(le.term(), 2);
|
|
}
|
|
{
|
|
LogEntry le;
|
|
rlog2->getEntry(3, le);
|
|
EXPECT_EQ(le.term(), 2);
|
|
}
|
|
|
|
// generate bigger term log to test learner auto reset match index
|
|
paxos2->requestVote();
|
|
sleep(1);
|
|
EXPECT_EQ(paxos2->getState(), Paxos::LEADER);
|
|
paxos1->requestVote();
|
|
sleep(3);
|
|
EXPECT_EQ(paxos1->getState(), Paxos::LEADER);
|
|
EXPECT_EQ(paxos1->getCommitIndex(), 5);
|
|
EXPECT_EQ(paxos2->getCommitIndex(), 5);
|
|
EXPECT_EQ(paxos3->getCommitIndex(), 5);
|
|
|
|
// change follower to single learner
|
|
EXPECT_EQ(paxos2->getConfig()->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(paxos2->getConfig()->learnersToString(), std::string("127.0.0.1:11004$00"));
|
|
EXPECT_EQ(paxos2->forceSingleLearner(), 0);
|
|
EXPECT_EQ(paxos2->getConfig()->membersToString(), std::string("0;127.0.0.1:11002#5N"));
|
|
EXPECT_EQ(paxos2->getConfig()->learnersToString(), std::string(""));
|
|
|
|
// change leader to single learner
|
|
EXPECT_EQ(paxos1->getConfig()->membersToString(("127.0.0.1:11001")), std::string("127.0.0.1:11001#5N;127.0.0.1:11002#5N;127.0.0.1:11003#5N@1"));
|
|
EXPECT_EQ(paxos1->getConfig()->learnersToString(), std::string("127.0.0.1:11004$00"));
|
|
EXPECT_EQ(paxos1->forceSingleLearner(), 0);
|
|
EXPECT_EQ(paxos1->getConfig()->membersToString(), std::string("127.0.0.1:11001#5N"));
|
|
EXPECT_EQ(paxos1->getConfig()->learnersToString(), std::string(""));
|
|
|
|
// add paxos 1 as learner
|
|
strConfig.clear();
|
|
strConfig.push_back("127.0.0.1:11001");
|
|
paxos4->changeLearners(Paxos::CCAddNode, strConfig);
|
|
sleep(3);
|
|
EXPECT_EQ(paxos4->getCommitIndex(), 5);
|
|
EXPECT_EQ(paxos1->getCommitIndex(), 5);
|
|
EXPECT_EQ(paxos4->getConfig()->membersToString(("127.0.0.1:11004")), std::string("127.0.0.1:11004#5N@1"));
|
|
EXPECT_EQ(paxos4->getConfig()->learnersToString(), std::string("127.0.0.1:11001$00"));
|
|
EXPECT_EQ(paxos1->getConfig()->membersToString(), std::string("127.0.0.1:11001#5N"));
|
|
EXPECT_EQ(paxos1->getConfig()->learnersToString(), std::string("127.0.0.1:11001$00"));
|
|
|
|
le.set_optype(0);
|
|
paxos4->replicateLog(le);
|
|
sleep(3);
|
|
EXPECT_EQ(paxos4->getCommitIndex(), 6);
|
|
EXPECT_EQ(paxos1->getCommitIndex(), 6);
|
|
|
|
// add paxos 2 as learner
|
|
strConfig.clear();
|
|
strConfig.push_back("127.0.0.1:11002");
|
|
paxos4->changeLearners(Paxos::CCAddNode, strConfig);
|
|
sleep(3);
|
|
EXPECT_EQ(paxos4->getCommitIndex(), 7);
|
|
EXPECT_EQ(paxos2->getCommitIndex(), 7);
|
|
EXPECT_EQ(paxos4->getConfig()->membersToString(("127.0.0.1:11004")), std::string("127.0.0.1:11004#5N@1"));
|
|
EXPECT_EQ(paxos4->getConfig()->learnersToString(), std::string("127.0.0.1:11001$00;127.0.0.1:11002$00"));
|
|
EXPECT_EQ(paxos2->getConfig()->membersToString(), std::string("0;127.0.0.1:11002#5N"));
|
|
EXPECT_EQ(paxos2->getConfig()->learnersToString(), std::string("127.0.0.1:11001$00;127.0.0.1:11002$00"));
|
|
|
|
le.set_optype(0);
|
|
paxos4->replicateLog(le);
|
|
sleep(3);
|
|
EXPECT_EQ(paxos4->getCommitIndex(), 8);
|
|
EXPECT_EQ(paxos2->getCommitIndex(), 8);
|
|
|
|
{
|
|
// upgrade paxos 1 to follower
|
|
std::string s("127.0.0.1:11001");
|
|
paxos4->changeMember(Paxos::CCAddNode, s);
|
|
sleep(3);
|
|
EXPECT_EQ(paxos4->getCommitIndex(), 9);
|
|
EXPECT_EQ(paxos1->getCommitIndex(), 9);
|
|
EXPECT_EQ(paxos4->getConfig()->membersToString(("127.0.0.1:11004")), std::string("127.0.0.1:11004#5N;127.0.0.1:11001#5N@1"));
|
|
EXPECT_EQ(paxos4->getConfig()->learnersToString(), std::string("0;127.0.0.1:11002$00"));
|
|
EXPECT_EQ(paxos1->getConfig()->membersToString(("127.0.0.1:11001")), std::string("127.0.0.1:11004#5N;127.0.0.1:11001#5N@2"));
|
|
EXPECT_EQ(paxos1->getConfig()->learnersToString(), std::string("0;127.0.0.1:11002$00"));
|
|
}
|
|
|
|
le.set_optype(0);
|
|
paxos4->replicateLog(le);
|
|
sleep(3);
|
|
EXPECT_EQ(paxos4->getCommitIndex(), 10);
|
|
EXPECT_EQ(paxos2->getCommitIndex(), 10);
|
|
|
|
{
|
|
// upgrade paxos 2 to follower
|
|
std::string s("127.0.0.1:11002");
|
|
paxos4->changeMember(Paxos::CCAddNode, s);
|
|
sleep(3);
|
|
EXPECT_EQ(paxos4->getCommitIndex(), 11);
|
|
EXPECT_EQ(paxos2->getCommitIndex(), 11);
|
|
EXPECT_EQ(paxos4->getConfig()->membersToString(("127.0.0.1:11004")), std::string("127.0.0.1:11004#5N;127.0.0.1:11001#5N;127.0.0.1:11002#5N@1"));
|
|
EXPECT_EQ(paxos4->getConfig()->learnersToString(), std::string(""));
|
|
EXPECT_EQ(paxos1->getConfig()->membersToString(("127.0.0.1:11002")), std::string("127.0.0.1:11004#5N;127.0.0.1:11001#5N;127.0.0.1:11002#5N@3"));
|
|
EXPECT_EQ(paxos1->getConfig()->learnersToString(), std::string(""));
|
|
}
|
|
|
|
le.set_optype(0);
|
|
paxos4->replicateLog(le);
|
|
sleep(3);
|
|
EXPECT_EQ(paxos4->getCommitIndex(), 12);
|
|
EXPECT_EQ(paxos2->getCommitIndex(), 12);
|
|
|
|
// since this function will break the protocol,
|
|
// logs might be different on every node
|
|
{
|
|
LogEntry le;
|
|
rlog1->getEntry(3, le);
|
|
EXPECT_TRUE(le.term() == 3 || le.term() == 2);
|
|
}
|
|
{
|
|
LogEntry le;
|
|
rlog2->getEntry(3, le);
|
|
EXPECT_TRUE(le.term() == 3 || le.term() == 2);
|
|
}
|
|
|
|
{
|
|
std::vector<Paxos::ClusterInfoType> cis;
|
|
paxos4->getClusterInfo(cis);
|
|
EXPECT_EQ(cis[2].matchIndex, 12);
|
|
}
|
|
|
|
{
|
|
paxos2->requestVote(true);
|
|
sleep(1);
|
|
EXPECT_EQ(paxos2->getState(), Paxos::LEADER);
|
|
LogEntry le;
|
|
le.set_optype(0);
|
|
le.set_term(paxos2->getTerm());
|
|
localServer->writeLog(le);
|
|
sleep(2);
|
|
std::vector<Paxos::ClusterInfoType> cis;
|
|
paxos2->getClusterInfo(cis);
|
|
EXPECT_EQ(paxos2->getCommitIndex(), 14);
|
|
// if bug exists, match index will be 13
|
|
EXPECT_EQ(cis[2].matchIndex, 14);
|
|
}
|
|
|
|
delete paxos4;
|
|
delete paxos3;
|
|
delete paxos2;
|
|
delete paxos1;
|
|
|
|
deleteDir("paxosLogTestDir11");
|
|
deleteDir("paxosLogTestDir12");
|
|
deleteDir("paxosLogTestDir13");
|
|
deleteDir("paxosLogTestDir14");
|
|
}
|
|
|