func (pd *ProposerDispatcher) TwoBTxnVotesReceived(sender common.RMId, twoBTxnVotes *msgs.TwoBTxnVotes) { var txnId *common.TxnId switch twoBTxnVotes.Which() { case msgs.TWOBTXNVOTES_FAILURES: txnId = common.MakeTxnId(twoBTxnVotes.Failures().TxnId()) case msgs.TWOBTXNVOTES_OUTCOME: txnId = common.MakeTxnId(twoBTxnVotes.Outcome().Txn().Id()) default: panic(fmt.Sprintf("Unexpected 2BVotes type: %v", twoBTxnVotes.Which())) } pd.withProposerManager(txnId, func(pm *ProposerManager) { pm.TwoBTxnVotesReceived(sender, txnId, twoBTxnVotes) }) }
// from network func (pm *ProposerManager) TwoBTxnVotesReceived(sender common.RMId, txnId *common.TxnId, twoBTxnVotes *msgs.TwoBTxnVotes) { instId := instanceIdPrefix([instanceIdPrefixLen]byte{}) instIdSlice := instId[:] copy(instIdSlice, txnId[:]) switch twoBTxnVotes.Which() { case msgs.TWOBTXNVOTES_FAILURES: failures := twoBTxnVotes.Failures() server.Log(txnId, "2B received from", sender, "; instance:", common.RMId(failures.RmId())) binary.BigEndian.PutUint32(instIdSlice[common.KeyLen:], failures.RmId()) if prop, found := pm.proposals[instId]; found { prop.TwoBFailuresReceived(sender, &failures) } case msgs.TWOBTXNVOTES_OUTCOME: binary.BigEndian.PutUint32(instIdSlice[common.KeyLen:], uint32(pm.RMId)) outcome := twoBTxnVotes.Outcome() if proposer, found := pm.proposers[*txnId]; found { server.Log(txnId, "2B outcome received from", sender, "(known active)") proposer.BallotOutcomeReceived(sender, &outcome) return } txnCap := outcome.Txn() alloc := AllocForRMId(&txnCap, pm.RMId) if alloc.Active() != 0 { // We have no record of this, but we were active - we must // have died and recovered (or we may have never received // this yet - see above - if we were down, other proposers // may have started abort proposers). Thus this could be // abort (abort proposers out there) or commit (we previously // voted, and that vote got recorded, but we have since died // and restarted). server.Log(txnId, "2B outcome received from", sender, "(unknown active)") // There's a possibility the acceptor that sent us this 2B is // one of only a few acceptors that got enough 2As to // determine the outcome. We must set up new paxos instances // to ensure the result is propogated to all. All we need to // do is to start a proposal for our own vars. The proposal // itself will detect any further absences and take care of // them. acceptors := GetAcceptorsFromTxn(&txnCap) server.Log(txnId, "Starting abort proposals with acceptors", acceptors) fInc := int(txnCap.FInc()) ballots := MakeAbortBallots(&txnCap, alloc) pm.NewPaxosProposals(txnId, &txnCap, fInc, ballots, acceptors, pm.RMId, false) proposer := NewProposer(pm, txnId, &txnCap, ProposerActiveLearner, pm.topology) pm.proposers[*txnId] = proposer proposer.Start() proposer.BallotOutcomeReceived(sender, &outcome) } else { // Not active, so we are a learner if outcome.Which() == msgs.OUTCOME_COMMIT { server.Log(txnId, "2B outcome received from", sender, "(unknown learner)") // we must be a learner. proposer := NewProposer(pm, txnId, &txnCap, ProposerPassiveLearner, pm.topology) pm.proposers[*txnId] = proposer proposer.Start() proposer.BallotOutcomeReceived(sender, &outcome) } else { // Whilst it's an abort now, at some point in the past it // was a commit and as such we received that // outcome. However, we must have since died and so lost // that state/proposer. We should now immediately reply // with a TLC. server.Log(txnId, "Sending immediate TLC for unknown abort learner") // We have no state here, and if we receive further 2Bs // from the repeating sender at the acceptor then we will // send further TLCs. So the use of OSS here is correct. NewOneShotSender(MakeTxnLocallyCompleteMsg(txnId), pm, sender) } } default: panic(fmt.Sprintf("Unexpected 2BVotes type: %v", twoBTxnVotes.Which())) } }