func (c *cache) updateFromTxnCommit(txn *msgs.ClientTxn, txnId *common.TxnId) { actions := txn.Actions() c.Lock() defer c.Unlock() for idx, l := 0, actions.Len(); idx < l; idx++ { action := actions.At(idx) vUUId := common.MakeVarUUId(action.VarId()) switch action.Which() { case msgs.CLIENTACTION_WRITE: write := action.Write() refs := write.References() c.updateFromWrite(txnId, vUUId, write.Value(), &refs) case msgs.CLIENTACTION_READWRITE: rw := action.Readwrite() refs := rw.References() c.updateFromWrite(txnId, vUUId, rw.Value(), &refs) case msgs.CLIENTACTION_CREATE: create := action.Create() refs := create.References() c.updateFromWrite(txnId, vUUId, create.Value(), &refs) case msgs.CLIENTACTION_READ: // do nothing } } }
func (cr *connectionRun) clientTxnError(ctxn *cmsgs.ClientTxn, err error, origTxnId *common.TxnId) error { seg := capn.NewBuffer(nil) msg := cmsgs.NewRootClientMessage(seg) outcome := cmsgs.NewClientTxnOutcome(seg) msg.SetClientTxnOutcome(outcome) if origTxnId == nil { outcome.SetId(ctxn.Id()) } else { outcome.SetId(origTxnId[:]) } outcome.SetFinalId(ctxn.Id()) outcome.SetError(err.Error()) return cr.sendMessage(server.SegToBytes(seg)) }
func (sts *SimpleTxnSubmitter) clientToServerTxn(clientTxnCap *cmsgs.ClientTxn, topologyVersion uint32) (*msgs.Txn, []common.RMId, []common.RMId, error) { outgoingSeg := capn.NewBuffer(nil) txnCap := msgs.NewTxn(outgoingSeg) txnCap.SetId(clientTxnCap.Id()) txnCap.SetRetry(clientTxnCap.Retry()) txnCap.SetSubmitter(uint32(sts.rmId)) txnCap.SetSubmitterBootCount(sts.bootCount) txnCap.SetFInc(sts.topology.FInc) txnCap.SetTopologyVersion(topologyVersion) clientActions := clientTxnCap.Actions() actions := msgs.NewActionList(outgoingSeg, clientActions.Len()) txnCap.SetActions(actions) picker := ch.NewCombinationPicker(int(sts.topology.FInc), sts.disabledHashCodes) rmIdToActionIndices, err := sts.translateActions(outgoingSeg, picker, &actions, &clientActions) if err != nil { return nil, nil, nil, err } // NB: we're guaranteed that activeRMs and passiveRMs are // disjoint. Thus there is no RM that has some active and some // passive actions. activeRMs, passiveRMs, err := picker.Choose() if err != nil { return nil, nil, nil, err } allocations := msgs.NewAllocationList(outgoingSeg, len(activeRMs)+len(passiveRMs)) txnCap.SetAllocations(allocations) sts.setAllocations(0, rmIdToActionIndices, &allocations, outgoingSeg, true, activeRMs) sts.setAllocations(len(activeRMs), rmIdToActionIndices, &allocations, outgoingSeg, false, passiveRMs) return &txnCap, activeRMs, passiveRMs, nil }
func (cts *ClientTxnSubmitter) SubmitClientTransaction(ctxnCap *cmsgs.ClientTxn, continuation ClientTxnCompletionConsumer) { if cts.txnLive { continuation(nil, fmt.Errorf("Cannot submit client as a live txn already exists")) return } seg := capn.NewBuffer(nil) clientOutcome := cmsgs.NewClientTxnOutcome(seg) clientOutcome.SetId(ctxnCap.Id()) curTxnId := common.MakeTxnId(ctxnCap.Id()) delay := time.Duration(0) retryCount := 0 var cont TxnCompletionConsumer cont = func(txnId *common.TxnId, outcome *msgs.Outcome, err error) { if outcome == nil || err != nil { // node is shutting down or error cts.txnLive = false continuation(nil, err) return } switch outcome.Which() { case msgs.OUTCOME_COMMIT: cts.versionCache.UpdateFromCommit(txnId, outcome) clientOutcome.SetFinalId(txnId[:]) clientOutcome.SetCommit() cts.addCreatesToCache(outcome) cts.txnLive = false continuation(&clientOutcome, nil) return default: abort := outcome.Abort() resubmit := abort.Which() == msgs.OUTCOMEABORT_RESUBMIT if !resubmit { updates := abort.Rerun() validUpdates := cts.versionCache.UpdateFromAbort(&updates) server.Log("Updates:", updates.Len(), "; valid: ", len(validUpdates)) resubmit = len(validUpdates) == 0 if !resubmit { clientOutcome.SetFinalId(txnId[:]) clientOutcome.SetAbort(cts.translateUpdates(seg, validUpdates)) cts.txnLive = false continuation(&clientOutcome, nil) return } } server.Log("Resubmitting", txnId, "; orig resubmit?", abort.Which() == msgs.OUTCOMEABORT_RESUBMIT) retryCount++ switch { case retryCount == server.SubmissionInitialAttempts: delay = server.SubmissionInitialBackoff case retryCount > server.SubmissionInitialAttempts: delay = delay + time.Duration(cts.rng.Intn(int(delay))) if delay > server.SubmissionMaxSubmitDelay { delay = time.Duration(cts.rng.Intn(int(server.SubmissionMaxSubmitDelay))) } } curTxnIdNum := binary.BigEndian.Uint64(txnId[:8]) curTxnIdNum += 1 + uint64(cts.rng.Intn(8)) binary.BigEndian.PutUint64(curTxnId[:8], curTxnIdNum) ctxnCap.SetId(curTxnId[:]) cts.SimpleTxnSubmitter.SubmitClientTransaction(ctxnCap, cont, delay, false) } } cts.txnLive = true cts.SimpleTxnSubmitter.SubmitClientTransaction(ctxnCap, cont, 0, false) }