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 (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) }