在工程应用环境中,一个新启动的节点须要可以从其它节点进行状态同步,或者叫作实例的对齐(Learn)。该节说明了C的数据能够从B学习,可是在一个具体的环境中,当一个节点须要学习时,它具体应该如何选择,以哪个为准,这里并无后详细说明清楚,这个就须要结合代码来看一下。node
在实例类Instance启动的时候,它首先启动定时器,定时尝试向同组中的全部机器学习:
int Instance :: Init()
{
……
m_oLearner.Reset_AskforLearn_Noop();机器学习
PLGImp("OK");函数
return 0;
}oop
void Learner :: AskforLearn_Noop(const bool bIsStart)
{
Reset_AskforLearn_Noop();学习
m_bIsIMLearning = false;ui
m_poCheckpointMgr->ExitCheckpointMode();spa
AskforLearn();
if (bIsStart)
{
AskforLearn();
}
}对象
向系统广播 MsgType_PaxosLearner_AskforLearn 消息,全部收到该消息的节点经过MsgType_PaxosLearner_SendNowInstanceID协议返回本身本地最大的实例号。
void Learner :: AskforCheckpoint(const nodeid_t iSendNodeID)
{
PLGHead("START");get
int ret = m_poCheckpointMgr->PrepareForAskforCheckpoint(iSendNodeID);
if (ret != 0)
{
return;
}cmd
PaxosMsg oPaxosMsg;
oPaxosMsg.set_instanceid(GetInstanceID());
oPaxosMsg.set_nodeid(m_poConfig->GetMyNodeID());
oPaxosMsg.set_msgtype(MsgType_PaxosLearner_AskforCheckpoint);
PLGHead("END InstanceID %lu MyNodeID %lu", GetInstanceID(), oPaxosMsg.nodeid());
SendMessage(iSendNodeID, oPaxosMsg);
}
leaner执行AskforCheckpoint函数准备学习,可是在PrepareForAskforCheckpoint函数中会判断当前是否已经收到半数以上的节点回复,而且经过m_bInAskforCheckpointMode标志位进入checkpointmode
int CheckpointMgr :: PrepareForAskforCheckpoint(const nodeid_t iSendNodeID)
{
if (m_setNeedAsk.find(iSendNodeID) == m_setNeedAsk.end())
{
m_setNeedAsk.insert(iSendNodeID);
}
if (m_llLastAskforCheckpointTime == 0)
{
m_llLastAskforCheckpointTime = Time::GetSteadyClockMS();
}
uint64_t llNowTime = Time::GetSteadyClockMS();
if (llNowTime > m_llLastAskforCheckpointTime + 60000)
{
PLGImp("no majority reply, just ask for checkpoint");
}
else
{
if ((int)m_setNeedAsk.size() < m_poConfig->GetMajorityCount())
{
PLGImp("Need more other tell us need to askforcheckpoint");
return -2;
}
}
m_llLastAskforCheckpointTime = 0;
m_bInAskforCheckpointMode = true;
return 0;
}
4、有其它节点的MsgType_PaxosLearner_SendNowInstanceID包如何处理
从代码上看,当开始学习以后,就是一个专心致志的过程,那最开广播的消息,其它节点回包也是知足PrepareForAskforCheckpoint函数的半数以上条件,那会不会它们都会被同步过来呢?
void Instance :: OnReceive(const std::string & sBuffer)
{
BP->GetInstanceBP()->OnReceive();
……
int iCmd = oHeader.cmdid();
if (iCmd == MsgCmd_PaxosMsg)
{
if (m_oCheckpointMgr.InAskforcheckpointMode())
{
PLGImp("in ask for checkpoint mode, ignord paxosmsg");
return;
}
……
OnReceivePaxosMsg(oPaxosMsg);
}
……
}
因为发送学习checkpoint以后就经过m_bInAskforCheckpointMode进入了checkpoint模式,而MsgType_PaxosLearner_SendNowInstanceID回包是一个paxos类型的回包,因此要通过if (m_oCheckpointMgr.InAskforcheckpointMode())的过滤,而且当前处于checkpoint学习模式时,这个消息会被忽略。
const bool CheckpointMgr :: InAskforcheckpointMode() const
{
return m_bInAskforCheckpointMode;
}
5、总结
具体的学习对象是从第一个超过半数的节点学习。在CheckpointMgr :: PrepareForAskforCheckpoint函数中的m_setNeedAsk并无在学习以后清零,多是因为checkpoint同步以后系统就会重启,因此不须要清零吧。