func (vb *varBallot) CalculateResult(br badReads, clock *eng.VectorClock) { vb.result = eng.NewBallot(vb.vUUId, eng.Commit, eng.NewVectorClock()) for _, rmBal := range vb.rmToBallot { vb.combineVote(rmBal, br) } if !vb.result.Aborted() { clock.MergeInMax(vb.result.Clock) } }
func (br badReads) AddToSeg(seg *capn.Segment) msgs.Update_List { txnIdToBadReadActions := make(map[common.TxnId]*[]*badReadAction, len(br)) for _, bra := range br { if bras, found := txnIdToBadReadActions[*bra.txnId]; found { *bras = append(*bras, bra) } else { list := []*badReadAction{bra} txnIdToBadReadActions[*bra.txnId] = &list } } updates := msgs.NewUpdateList(seg, len(txnIdToBadReadActions)) idx := 0 for txnId, badReadActions := range txnIdToBadReadActions { update := updates.At(idx) idx++ update.SetTxnId(txnId[:]) actionList := msgs.NewActionList(seg, len(*badReadActions)) update.SetActions(actionList) clock := eng.NewVectorClock() for idy, bra := range *badReadActions { action := bra.action switch action.Which() { case msgs.ACTION_READ: newAction := actionList.At(idy) newAction.SetVarId(action.VarId()) newAction.SetMissing() case msgs.ACTION_WRITE: actionList.Set(idy, *action) case msgs.ACTION_READWRITE: readWrite := action.Readwrite() newAction := actionList.At(idy) newAction.SetVarId(action.VarId()) newAction.SetWrite() newWrite := newAction.Write() newWrite.SetValue(readWrite.Value()) newWrite.SetReferences(readWrite.References()) case msgs.ACTION_CREATE: create := action.Create() newAction := actionList.At(idy) newAction.SetVarId(action.VarId()) newAction.SetWrite() newWrite := newAction.Write() newWrite.SetValue(create.Value()) newWrite.SetReferences(create.References()) case msgs.ACTION_ROLL: roll := action.Roll() newAction := actionList.At(idy) newAction.SetVarId(action.VarId()) newAction.SetWrite() newWrite := newAction.Write() newWrite.SetValue(roll.Value()) newWrite.SetReferences(roll.References()) default: panic(fmt.Sprintf("Unexpected action type (%v) for badread of %v at %v", action.Which(), action.VarId(), txnId)) } clock.SetVarIdMax(*bra.vUUId, bra.clockElem) } update.SetClock(clock.AddToSeg(seg)) } return updates }
func (ba *BallotAccumulator) determineOutcome() *outcomeEqualId { // Even in the case of retries, we must wait until we have at least // F+1 results for one var, otherwise we run the risk of // timetravel: a slow learner could issue a badread based on not // being caught up. By waiting for at least F+1 ballots for a var // (they don't have to be the same ballot!), we avoid this as there // must be at least one voter who isn't in the past. if !(ba.dirty && (ba.incompleteVars == 0 || ba.Txn.Retry())) { return nil } ba.dirty = false combinedClock := eng.NewVectorClock() aborted, deadlock := false, false vUUIds := common.VarUUIds(make([]*common.VarUUId, 0, len(ba.vUUIdToBallots))) br := NewBadReads() server.Log(ba.txnId, "Calculating result") for _, vBallot := range ba.vUUIdToBallots { if len(vBallot.rmToBallot) < vBallot.voters { continue } vUUIds = append(vUUIds, vBallot.vUUId) if vBallot.result == nil { vBallot.CalculateResult(br, combinedClock) } aborted = aborted || vBallot.result.Aborted() deadlock = deadlock || vBallot.result.Vote == eng.AbortDeadlock } vUUIds.Sort() seg := capn.NewBuffer(nil) outcome := msgs.NewOutcome(seg) outcomeIdList := msgs.NewOutcomeIdList(seg, len(vUUIds)) outcome.SetId(outcomeIdList) for idx, vUUId := range vUUIds { outcomeId := outcomeIdList.At(idx) outcomeId.SetVarId(vUUId[:]) vBallot := ba.vUUIdToBallots[*vUUId] instanceIdList := msgs.NewAcceptedInstanceIdList(seg, len(vBallot.rmToBallot)) outcomeId.SetAcceptedInstances(instanceIdList) for idy, rmBal := range vBallot.rmToBallot { instanceId := instanceIdList.At(idy) instanceId.SetRmId(uint32(rmBal.instanceRMId)) instanceId.SetVote(rmBal.ballot.Vote.ToVoteEnum()) } } if aborted { deflatedTxn := deflateTxn(ba.Txn, seg) outcome.SetTxn(*deflatedTxn) outcome.SetAbort() abort := outcome.Abort() if deadlock { abort.SetResubmit() } else { abort.SetRerun(br.AddToSeg(seg)) } } else { outcome.SetTxn(*ba.Txn) outcome.SetCommit(combinedClock.AddToSeg(seg)) } ba.outcome = (*outcomeEqualId)(&outcome) return ba.outcome }