예제 #1
0
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) })
}
예제 #2
0
// 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()))
	}
}