void clsEntityWorker::CheckForCatchUp(EntityInfo_t *ptEntityInfo, uint32_t iGlobalMaxChosenEntry) { uint32_t iEntityID = ptEntityInfo->iEntityID; uint32_t iLocalMaxChosenEntry = ptEntityInfo->iMaxChosenEntry; CertainLogError("iEntityID %u iLocalMax %u iGlobalMax %u", iEntityID, iLocalMaxChosenEntry, iGlobalMaxChosenEntry); for (uint32_t iEntry = iLocalMaxChosenEntry + 1; iEntry <= iGlobalMaxChosenEntry; ++iEntry) { EntryInfo_t *ptInfo = m_poEntryMng->FindEntryInfo(iEntityID, iEntry); if (ptInfo == NULL) { ptInfo = m_poEntryMng->CreateEntryInfo(iEntityID, iEntry); assert(ptInfo != NULL); BroadcastToRemote(iEntityID, iEntry, NULL); } else { CertainLogDebug("EntryInfo Found: iEntityID %u iEntry %u", iEntityID, iEntry); } } }
void clsEntityWorker::Run() { SetThreadTitle("entity_%u_%u", m_iLocalAcceptorID, m_iWorkerID); CertainLogDebug("worker_id %u run", m_iWorkerID); while (1) { bool bHasWork = false; // 1.Do with IO request. clsCmdBase *poCmd = NULL; int iRet = m_poIOReqQueue->TakeByOneThread(&poCmd); if (iRet == 0) { assert(poCmd != NULL); bHasWork = true; iRet = DoWithIOReq(poCmd); if (iRet < 0) { CertainLogError("DoWithIOReq ret %d cmd %s", iRet, poCmd->GetTextCmd().c_str()); } // iRet = 1: reuse the ptr, use clsRefPtr in future if (iRet != 1) { delete poCmd, poCmd = NULL; } } // 2.Do with PLog response. clsPaxosCmd *poPaxosCmd; iRet = m_poPLogRspQueue->TakeByOneThread(&poPaxosCmd); if (iRet == 0) { bHasWork = true; iRet = DoWithPLogRsp(poPaxosCmd); if (iRet < 0) { const EntryRecord_t &tSrcRecord = poPaxosCmd->GetSrcRecord(); CertainLogError("DoWithPLogRsp ret %d record %s", iRet, EntryRecordToString(tSrcRecord).c_str()); } delete poPaxosCmd, poPaxosCmd = NULL; } // 3.Do with Timeout EntryState. iRet = DoWithTimeout(); AssertEqual(iRet, 0); if (!bHasWork) { usleep(1); } } }
// iPtr is for check only. int clsAsyncPipeMng::SyncWriteByPipeIdx(uint32_t iIdx, uintptr_t iPtr) { CertainLogDebug("iIdx %u iPtr %lu", iIdx, iPtr); AssertLess(iIdx, MAX_ASYNC_PIPE_NUM); int iOutFD = m_aaAsyncPipe[iIdx][1]; int iRet = write(iOutFD, &iPtr, sizeof(iPtr)); AssertEqual(iRet, sizeof(iPtr)); return 0; }
int clsAsyncPipeMng::SyncWaitByPipeIdx(uint32_t iIdx, uintptr_t iPtr) { CertainLogDebug("iIdx %u iPtr %lu", iIdx, iPtr); int iInFD = m_aaAsyncPipe[iIdx][0]; struct pollfd PollFd; PollFd.events = POLLIN | POLLERR; PollFd.fd = iInFD; int iEventCnt = 0; int iTimeout = 1000; int iTimeoutCnt = 0; while (true) { errno = 0; iEventCnt = poll(&PollFd, 1, iTimeout); if (errno == EINTR) { continue; } else if (iEventCnt > 0) { break; } else { iTimeoutCnt++; OSS::ReportPollTimeout(); // It won't be timeout forever. CertainLogError("iPtr %lu PipeIdx %u iTimeoutCnt %d", iPtr, iIdx, iTimeoutCnt); } } if (iEventCnt <= 0) { return -1; } uintptr_t iRetPtr; int iRet = read(iInFD, &iRetPtr, sizeof(iRetPtr)); AssertEqual(iRet, sizeof(iRetPtr)); if (iRetPtr != iPtr) { CertainLogFatal("BUG %lu %lu", iRetPtr, iPtr); return eRetCodePipePtrErr; } return 0; }
int clsConnWorker::RecvNegoMsg(clsNegoContext *poNegoCtx) { int iRet; const ConnInfo_t &tConnInfo = poNegoCtx->GetConnInfo(); int iFD = tConnInfo.iFD; uint8_t acNego[1]; while (1) { iRet = read(iFD, acNego, 1); if (iRet == -1) { if (errno == EAGAIN || errno == EINTR) { continue; } CertainLogError("fd %d errno %d", iFD, errno); return -1; } else if (iRet == 0) { Endpoint_t tPeerAddr = tConnInfo.tPeerAddr; CertainLogError("closed by peer %s:%hu fd %d", tPeerAddr.sIP, tPeerAddr.hPort, iFD); return -2; } else { AssertEqual(iRet, 1); break; } } // (TODO)rock: uncomment this //uint32_t iAcceptorID = uint32_t(acNego[0]); uint32_t iAcceptorID = uint32_t(acNego[0] - '0'); poNegoCtx->SetAcceptorID(iAcceptorID); CertainLogDebug("iFD %d local %s:%hu peer %s:%hu iAcceptorID %u", iFD, tConnInfo.tLocalAddr.sIP, tConnInfo.tLocalAddr.hPort, tConnInfo.tPeerAddr.sIP, tConnInfo.tPeerAddr.hPort, iAcceptorID); return 0; }
int clsEntityWorker::DoWithTimeout() { int iExpiredCnt = 0; EntryInfo_t *ptInfo; while ((ptInfo = m_poEntryMng->TakeTimeout()) != NULL) { uint32_t iEntityID = ptInfo->iEntityID; uint32_t iEntry = ptInfo->iEntry; if (ptInfo->bUncertain) { m_poEntryMng->AddTimeout(ptInfo, 10); CertainLogDebug("iEntityID %u iEntry %u wait 10ms for uncertain", iEntityID, iEntry); continue; } // (TODO)rock: it must retry, when it's uncertain EntityInfo_t *ptEntityInfo = m_poEntityMng->GetEntityInfo(iEntityID); if (ptInfo->bDBPending || ptEntityInfo->bDBPending) { assert(ptInfo->bDBPending && ptEntityInfo->bDBPending); ptInfo->bDBPending = false; ptEntityInfo->bDBPending = false; } if (ptEntityInfo->poClientCmd != NULL && ptEntityInfo->poClientCmd->GetEntry() == iEntry) { InvalidClientCmd(ptEntityInfo, " : Timeout"); } iExpiredCnt++; ActivateEntry(ptInfo); } if (iExpiredCnt > 0) { CertainLogError("iExpiredCnt %d", iExpiredCnt); } return 0; }
void clsEntityWorker::CleanUpEntry(EntityInfo_t *ptEntityInfo, EntryInfo_t *ptInfo) { uint32_t iEntityID = ptInfo->iEntityID; uint32_t iEntry = ptInfo->iEntry; CertainLogDebug("iEntityID %u iEntry %u", iEntityID, iEntry); if (ptEntityInfo->poClientCmd != NULL && ptEntityInfo->poClientCmd->GetEntry() == ptInfo->iEntry) { delete ptEntityInfo->poClientCmd; ptEntityInfo->poClientCmd = NULL; } m_poEntryMng->DestroyEntryInfo(ptInfo); }
void clsConnWorker::Run() { uint32_t iLocalAcceptorID = m_poConf->GetLocalAcceptorID(); SetThreadTitle("conn_%u", iLocalAcceptorID); CertainLogDebug("run"); int iRet = AddAllListen(); if (iRet != 0) { CertainLogError("AddAllListen ret %d", iRet); exit(-1); } while (1) { m_poEpollIO->RunOnce(-1); } }
void clsEntityWorker::SyncEntryRecord(EntryInfo_t *ptInfo, clsPaxosCmd *poPaxosCmd) { uint32_t iAcceptorID = poPaxosCmd->GetDestAcceptorID(); uint32_t iEntityID = ptInfo->iEntityID; uint32_t iEntry = ptInfo->iEntry; clsEntryStateMachine *poMachine = ptInfo->poMachine; const EntryRecord_t &tSrcRecord = poMachine->GetRecord(m_iLocalAcceptorID); CertainLogDebug("state %d bRemoteUpdated %u bBroadcast %u record %s", poMachine->GetEntryState(), ptInfo->bRemoteUpdated, ptInfo->bBroadcast, EntryRecordToString(tSrcRecord).c_str()); if (ptInfo->bBroadcast) { AssertEqual(iAcceptorID, INVALID_ACCEPTOR_ID); BroadcastToRemote(iEntityID, iEntry, poMachine); ptInfo->bBroadcast = false; ptInfo->bRemoteUpdated = false; } if (ptInfo->bRemoteUpdated) { AssertNotEqual(iAcceptorID, INVALID_ACCEPTOR_ID); const EntryRecord_t &tDestRecord = poMachine->GetRecord(iAcceptorID); // If dest has been chosen, SendDataPacket makes no matter. if (!tDestRecord.bChosen) { clsPaxosCmd *po = new clsPaxosCmd(m_iLocalAcceptorID, iEntityID, iEntry, &tSrcRecord, &tDestRecord); po->SetDestAcceptorID(iAcceptorID); m_poIOWorkerRouter->GoAndDeleteIfFailed(po); } ptInfo->bRemoteUpdated = false; } }
int clsConnWorker::AcceptOneFD(clsListenContext *poContext, ConnInfo_t &tConnInfo) { int iListenFD = poContext->GetFD(); struct sockaddr_in tSockAddr; socklen_t tLen = sizeof(tSockAddr); int iFD = accept(iListenFD, (struct sockaddr *)(&tSockAddr), &tLen); if (iFD == -1) { if (errno == EAGAIN) { return 1; } // (TODO)rock: close it CertainLogError("accept ret -1 errno %d", errno); return -1; } int iFlags = fcntl(iFD, F_GETFL, 0); int iRet = fcntl(iFD, F_SETFL, iFlags | O_NONBLOCK); AssertEqual(iRet, 0); Endpoint_t tPeerAddr; strcpy(tPeerAddr.sIP, inet_ntoa(tSockAddr.sin_addr)); tPeerAddr.hPort = ntohs(tSockAddr.sin_port); tConnInfo.tLocalAddr = poContext->GetLocalAddr(); tConnInfo.tPeerAddr = tPeerAddr; tConnInfo.iFD = iFD; CertainLogDebug("iFD %d local %s:%hu peer %s:%hu", iFD, tConnInfo.tLocalAddr.sIP, tConnInfo.tLocalAddr.hPort, tConnInfo.tPeerAddr.sIP, tConnInfo.tPeerAddr.hPort); return 0; }
int clsConnInfoMng::PutByOneThread(uint32_t iAcceptorID, const ConnInfo_t &tConnInfo) { AssertNotEqual(iAcceptorID, m_iLocalAcceptorID); CertainLogDebug("iAcceptorID %u local %s:%hu peer %s:%hu", iAcceptorID, tConnInfo.tLocalAddr.sIP, tConnInfo.tLocalAddr.hPort, tConnInfo.tPeerAddr.sIP, tConnInfo.tPeerAddr.hPort); clsThreadLock oLock(&m_oMutex); if (iAcceptorID == INVALID_ACCEPTOR_ID) { m_tExtConnQueue.push(tConnInfo); } else { AssertLess(iAcceptorID, m_iAcceptorNum); m_vecIntConnQueue[iAcceptorID].push(tConnInfo); } return 0; }
int clsEntityWorker::DoWithIOReq(clsCmdBase *poCmd) { CertainLogDebug("cmd: %s", poCmd->GetTextCmd().c_str()); clsPaxosCmd *poPaxosCmd = NULL; clsClientCmd *poClientCmd = NULL; switch (poCmd->GetCmdID()) { case kNoopCmd: case kSimpleCmd: poClientCmd = dynamic_cast<clsClientCmd *>(poCmd); return DoWithClientCmd(poClientCmd); case kPaxosCmd: poPaxosCmd = dynamic_cast<clsPaxosCmd *>(poCmd); return DoWithPaxosCmd(poPaxosCmd); default: CertainLogError("cmd: %s", poCmd->GetTextCmd().c_str()); assert(false); } return 0; }
int clsEntityWorker::DoWithPLogRsp(clsPaxosCmd *poPaxosCmd) { int iRet; uint32_t iEntityID = poPaxosCmd->GetEntityID(); uint32_t iEntry = poPaxosCmd->GetEntry(); CertainLogDebug("iEntityID %u iEntry %u", iEntityID, iEntry); EntityInfo_t *ptEntityInfo = m_poEntityMng->GetEntityInfo(iEntityID); assert(ptEntityInfo != NULL); EntryInfo_t *ptInfo = m_poEntryMng->FindEntryInfo(iEntityID, iEntry); assert(ptInfo != NULL); assert(ptInfo->bUncertain); ptInfo->bUncertain = false; SyncEntryRecord(ptInfo, poPaxosCmd); clsEntryStateMachine *poMachine = ptInfo->poMachine; const EntryRecord_t &tSrcRecord = poMachine->GetRecord(m_iLocalAcceptorID); if (CERTAIN_DEBUG) { string strInfoRecord = EntryRecordToString(poPaxosCmd->GetSrcRecord()); string strMachineRecord = EntryRecordToString(tSrcRecord); assert(strInfoRecord == strMachineRecord); } list<clsPaxosCmd *> tWaitingList; swap(*ptInfo->ptWaitingList, tWaitingList); if (tWaitingList.size() > 0) { CertainLogDebug("iEntityID %u iEntry %u tWaitingList.size() %lu", iEntityID, iEntry, tWaitingList.size()); } if (poMachine->GetEntryState() == kEntryStateChosen) { clsCmdFactory *poCmdFactory = clsCmdFactory::GetInstance(); // (TODO)rock: reduce PB once clsCmdBase *poCmd = poCmdFactory->CreateCmd( tSrcRecord.strValue.c_str(), tSrcRecord.strValue.size()); clsClientCmd *poClientCmd = ptEntityInfo->poClientCmd; clsClientCmd *poChosenCmd = dynamic_cast<clsClientCmd *>(poCmd); if (poClientCmd != NULL && poClientCmd->GetEntry() == iEntry) { CertainLogDebug("cli_cmd: %s chosen: %s", poClientCmd->GetTextCmd().c_str(), EntryRecordToString(tSrcRecord).c_str()); if (poClientCmd->GetUUID() == poChosenCmd->GetUUID()) { delete poChosenCmd, poChosenCmd = NULL; poChosenCmd = ptEntityInfo->poClientCmd; ptEntityInfo->poClientCmd = NULL; poChosenCmd->SetNeedRsp(true); if (ptEntityInfo->iMaxEntryChosenByLocal < iEntry) { ptEntityInfo->iMaxEntryChosenByLocal = iEntry; } } else { CertainLogError("uuid (%lu %lu) cmd %s", poClientCmd->GetUUID(), poChosenCmd->GetUUID(), poClientCmd->GetTextCmd().c_str()); InvalidClientCmd(ptEntityInfo); } } // (TODO)rock: Push Rsp here instead of in DB thread poChosenCmd->SetEntry(iEntry); iRet = m_poDBReqQueue->PushByMultiThread(poChosenCmd); AssertEqual(iRet, 0); // (TODO)rock: dbpending if (ptEntityInfo->iMaxChosenEntry < iEntry) { ptEntityInfo->iMaxChosenEntry = iEntry; } CleanUpEntry(ptEntityInfo, ptInfo); } iRet = DoWithWaitingList(&tWaitingList); if (iRet != 0) { CertainLogError("DoWithWaitingList ret %d", iRet); } return 0; }
int clsEntityWorker::DoWithPaxosCmd(clsPaxosCmd *poPaxosCmd) { int iRet; uint32_t iAcceptorID = poPaxosCmd->GetSrcAcceptorID(); uint32_t iEntityID = poPaxosCmd->GetEntityID(); uint32_t iEntry = poPaxosCmd->GetEntry(); AssertNotEqual(iAcceptorID, m_iLocalAcceptorID); EntityInfo_t *ptEntityInfo = m_poEntityMng->GetEntityInfo(iEntityID); assert(ptEntityInfo != NULL); CertainLogDebug("iAcceptorID %u iEntityID %u iEntry %u iMaxChosenEntry %u", iAcceptorID, iEntityID, iEntry, ptEntityInfo->iMaxChosenEntry); if (ptEntityInfo->iMaxChosenEntry >= iEntry) { EntryInfo_t *ptInfo = m_poEntryMng->FindEntryInfo(iEntityID, iEntry); const EntryRecord_t &tRecord = poPaxosCmd->GetSrcRecord(); // ptInfo == NULL means chosen, as ptInfo is cleanup once it's chosen. if (ptInfo == NULL) { if (tRecord.bChosen) { return 0; } clsPaxosCmd *po = new clsPaxosCmd(m_iLocalAcceptorID, iEntityID, iEntry); po->SetDestAcceptorID(iAcceptorID); po->SetForCatchUp(true); iRet = m_poPLogReqQueue->PushByOneThread(po); if (iRet != 0) { CertainLogError("PushByOneThread ret %d", iRet); delete po, po = NULL; return -1; } return 0; } CertainLogError("iEntityID %u iEntry %u iMaxChosenEntry %u", iEntityID, iEntry, ptEntityInfo->iMaxChosenEntry); } uint32_t iGlobalMaxChosenEntry = iEntry - 1; if (ptEntityInfo->iMaxChosenEntry < iGlobalMaxChosenEntry) { CheckForCatchUp(ptEntityInfo, iGlobalMaxChosenEntry); ptEntityInfo->iMaxChosenEntry = iGlobalMaxChosenEntry; } EntryInfo_t *ptInfo = m_poEntryMng->FindEntryInfo(iEntityID, iEntry); if (ptInfo == NULL) { ptInfo = m_poEntryMng->CreateEntryInfo(iEntityID, iEntry); assert(ptInfo != NULL); } if (ptInfo->bUncertain) { uint32_t iWaitingListSize = ptInfo->ptWaitingList->size(); if (iWaitingListSize > 10) { CertainLogError("iEntityID %u iEntry %u iWaitingListSize %u", iEntityID, iEntry, iWaitingListSize); return -2; } ptInfo->ptWaitingList->push_back(poPaxosCmd); return 1; } assert(ptInfo->poMachine->GetEntryState() != kEntryStateChosen); // It should have created the ptInfo for the entry not more than // iMaxChosenEntry, and it won't be cleanup until chosen. assert(ptInfo->poMachine->GetEntryState() != kEntryStateChosen); iRet = UpdateRecord(poPaxosCmd); if (iRet != 0) { CertainLogError("UpdateRecord ret %d", iRet); } return 0; }
int clsEntityWorker::UpdateRecord(clsPaxosCmd *poPaxosCmd) { uint32_t iAcceptorID = poPaxosCmd->GetSrcAcceptorID(); uint32_t iEntityID = poPaxosCmd->GetEntityID(); uint32_t iEntry = poPaxosCmd->GetEntry(); CertainLogDebug("iAcceptorID %u iEntityID %u iEntry %u", iAcceptorID, iEntityID, iEntry); EntityInfo_t *ptEntityInfo = m_poEntityMng->GetEntityInfo(iEntityID); assert(ptEntityInfo != NULL); EntryInfo_t *ptInfo = m_poEntryMng->FindEntryInfo(iEntityID, iEntry); assert(ptInfo != NULL); clsEntryStateMachine *poMachine = ptInfo->poMachine; const EntryRecord_t tOldRecord = poMachine->GetRecord(m_iLocalAcceptorID); CertainLogDebug("before update cmd: %s state %u", poPaxosCmd->GetTextCmd().c_str(), poMachine->GetEntryState()); const EntryRecord_t &tSrcRecord = poPaxosCmd->GetSrcRecord(); const EntryRecord_t &tDestRecord = poPaxosCmd->GetDestRecord(); poMachine->Update(m_iLocalAcceptorID, iAcceptorID, tSrcRecord); CertainLogDebug("after update cmd: %s state %u", poPaxosCmd->GetTextCmd().c_str(), poMachine->GetEntryState()); if (poMachine->GetEntryState() == kEntryStateMajorityPromise) { string strValue; if (ptEntityInfo->poClientCmd != NULL && ptEntityInfo->poClientCmd->GetEntry() == iEntry) { strValue = MakePaxosValue(ptEntityInfo->poClientCmd, true); } else { clsNoopCmd oNoopCmd(iEntityID, iEntry); strValue = MakePaxosValue(&oNoopCmd, false); } if (poMachine->AcceptOnMajorityPromise(m_iLocalAcceptorID, strValue)) { ptInfo->bBroadcast = true; } else { InvalidClientCmd(ptEntityInfo); } } if (poMachine->GetEntryState() == kEntryStateChosen) { if (!tSrcRecord.bChosen) { // only one proposer do broadcast for a proposal if (poMachine->IsLocalChosen(m_iLocalAcceptorID)) { ptInfo->bBroadcast = true; } } } const EntryRecord_t &tNewRecord = poMachine->GetRecord(m_iLocalAcceptorID); ptInfo->bRemoteUpdated = IsEntryRecordUpdated(tDestRecord, tNewRecord); bool bLocalUpdated = IsEntryRecordUpdated(tOldRecord, tNewRecord); clsPaxosCmd *po = new clsPaxosCmd(m_iLocalAcceptorID, iEntityID, iEntry, &tNewRecord); if (!ptInfo->bBroadcast) { po->SetDestAcceptorID(iAcceptorID); } if (bLocalUpdated) { int iRet = m_poPLogReqQueue->PushByOneThread(po); if (iRet != 0) { CertainLogError("PushByOneThread ret %d", iRet); delete po, po = NULL; return 0; } ptInfo->bUncertain = true; } else { clsAutoDelete<clsPaxosCmd> oAuto(po); if (poMachine->IsLocalEmpty()) { poMachine->SetCheckedEmpty(poPaxosCmd->GetSrcAcceptorID()); } if (ptEntityInfo->poClientCmd != NULL && ptEntityInfo->poClientCmd->IsReadOnly()) { if (poMachine->IsReadOK()) { m_poIOWorkerRouter->GoAndDeleteIfFailed( ptEntityInfo->poClientCmd); ptEntityInfo->poClientCmd = NULL; if (poMachine->IsLocalEmpty()) { CleanUpEntry(ptEntityInfo, ptInfo); } return 0; } else if (!poMachine->IsLocalEmpty()) { InvalidClientCmd(ptEntityInfo, " : ReadFail"); } } SyncEntryRecord(ptInfo, po); } return 0; }
int clsEntityWorker::DoWithClientCmd(clsClientCmd *poCmd) { int iRet; uint32_t iEntityID = poCmd->GetEntityID(); EntityInfo_t *ptEntityInfo = m_poEntityMng->GetEntityInfo(iEntityID); if (ptEntityInfo->poClientCmd != NULL || (!poCmd->IsEvalOnly() && ptEntityInfo->bDBPending)) { InvalidClientCmd(poCmd, " : TODO"); //iRet = AddWaitingCmd(poCmd); //if (iRet < 0) //{ // CertainLogError("poWaitingCmd->Add ret %d", iRet); // return -1; //} return 1; } if (poCmd->IsEvalOnly()) { if (poCmd->GetEntry() != ptEntityInfo->iMaxChosenEntry + 1) { InvalidClientCmd(poCmd, " : DISCARD"); return 1; } } assert(ptEntityInfo->poClientCmd == NULL); uint32_t iEntry = ptEntityInfo->iMaxChosenEntry + 1; EntryInfo_t *ptInfo = m_poEntryMng->FindEntryInfo(iEntityID, iEntry); if (ptInfo == NULL) { ptInfo = m_poEntryMng->CreateEntryInfo(iEntityID, iEntry); assert(ptInfo != NULL); } if (ptInfo->bUncertain) { InvalidClientCmd(poCmd, " : Uncertain"); return 1; } clsEntryStateMachine *poMachine = ptInfo->poMachine; int iEntryState = poMachine->GetEntryState(); CertainLogDebug("iEntityID %u iEntry %u state %d", iEntityID, iEntry, iEntryState); assert(!ptInfo->bRemoteUpdated); assert(!ptInfo->bBroadcast); // give in if has accepted remote if (poMachine->GetEntryState() == kEntryStateAcceptRemote) { InvalidClientCmd(poCmd, " : GiveIn"); return 1; } poCmd->SetEntry(iEntry); m_poEntryMng->AddTimeout(ptInfo, 50); if (m_poConf->GetPLogType() == kPLogTypeRes) { if (!poCmd->IsEvalOnly()) { assert(!poCmd->IsNeedRsp()); poCmd->SetEvalOnly(true); iRet = m_poDBReqQueue->PushByMultiThread(poCmd); if (iRet != 0) { CertainLogError("PushByMultiThread ret %d", iRet); return -1; } ptInfo->bDBPending = true; ptEntityInfo->bDBPending = true; return 1; } poCmd->SetEvalOnly(false); ptInfo->bDBPending = false; ptEntityInfo->bDBPending = false; } ptEntityInfo->poClientCmd = poCmd; if (m_poConf->IsEnableReadOpt() && poCmd->IsReadOnly() && poMachine->IsLocalEmpty()) { poMachine->ResetAllCheckedEmpty(); poMachine->SetCheckedEmpty(m_iLocalAcceptorID); BroadcastToRemote(iEntityID, iEntry, NULL, true); return 1; } uint32_t iProposalNum = poMachine->GetNextPreparedNum(m_iLocalAcceptorID); EntryRecord_t tTempRecord; InitEntryRecord(&tTempRecord); if (m_poConf->GetPaxosType() == kPaxosTypeMulti) { if (iProposalNum == m_iLocalAcceptorID + 1 && iEntry == ptEntityInfo->iMaxEntryChosenByLocal + 1) { tTempRecord.iAcceptedNum = iProposalNum; tTempRecord.iValueID = iProposalNum; tTempRecord.strValue = MakePaxosValue(poCmd, true); } else { iProposalNum = poMachine->GetNextPreparedNum(m_iLocalAcceptorID); } } tTempRecord.iPreparedNum = iProposalNum; tTempRecord.iPromisedNum = iProposalNum; iEntryState = poMachine->Update(m_iLocalAcceptorID, m_iLocalAcceptorID, tTempRecord); const EntryRecord_t &tUpdatedRecord = poMachine->GetRecord( m_iLocalAcceptorID); clsPaxosCmd *poPaxosCmd = new clsPaxosCmd(m_iLocalAcceptorID, iEntityID, iEntry, &tUpdatedRecord); CertainLogDebug("record: %s state %d", EntryRecordToString(tUpdatedRecord).c_str(), iEntryState); iRet = m_poPLogReqQueue->PushByOneThread(poPaxosCmd); if (iRet != 0) { CertainLogError("PushByOneThread ret %d", iRet); delete poPaxosCmd, poPaxosCmd = NULL; return -1; } // It's uncertain even if fail to push to PLogReqQueue. // It will retry when timeout, as this update has happened actually. ptInfo->bUncertain = true; ptInfo->bBroadcast = true; return 1; }