@@ -994,15 +994,17 @@ func (txn *Txn) exec(ctx context.Context, fn func(context.Context, *Txn) error)
994994 break
995995 }
996996
997- txn .PrepareForRetry (ctx )
997+ if err := txn .PrepareForRetry (ctx ); err != nil {
998+ return err
999+ }
9981000 }
9991001
10001002 return err
10011003}
10021004
10031005// PrepareForRetry needs to be called before a retry to perform some
10041006// book-keeping and clear errors when possible.
1005- func (txn * Txn ) PrepareForRetry (ctx context.Context ) {
1007+ func (txn * Txn ) PrepareForRetry (ctx context.Context ) error {
10061008 // Reset commit triggers. These must be reconfigured by the client during the
10071009 // next retry.
10081010 txn .commitTriggers = nil
@@ -1012,11 +1014,11 @@ func (txn *Txn) PrepareForRetry(ctx context.Context) {
10121014
10131015 retryErr := txn .mu .sender .GetTxnRetryableErr (ctx )
10141016 if retryErr == nil {
1015- return
1017+ return nil
10161018 }
10171019 if txn .typ != RootTxn {
1018- panic ( errors .WithContextTags (errors .NewAssertionErrorWithWrappedErrf (
1019- retryErr , "PrepareForRetry() called on leaf txn" ), ctx ))
1020+ return errors .WithContextTags (errors .NewAssertionErrorWithWrappedErrf (
1021+ retryErr , "PrepareForRetry() called on leaf txn" ), ctx )
10201022 }
10211023 log .VEventf (ctx , 2 , "retrying transaction: %s because of a retryable error: %s" ,
10221024 txn .debugNameLocked (), retryErr )
@@ -1029,23 +1031,24 @@ func (txn *Txn) PrepareForRetry(ctx context.Context) {
10291031 // txn IDs. However, at no point can both the old and new incarnation of a
10301032 // transaction be active at the same time -- this would constitute a
10311033 // programming error.
1032- log .Fatalf (
1033- ctx ,
1034- "unexpected retryable error for old incarnation of the transaction %s; current incarnation %s" ,
1035- retryErr .TxnID ,
1036- txn .mu .ID ,
1037- )
1034+ return errors .WithContextTags (
1035+ errors .NewAssertionErrorWithWrappedErrf (
1036+ retryErr ,
1037+ "unexpected retryable error for old incarnation of the transaction %s; current incarnation %s" ,
1038+ retryErr .TxnID ,
1039+ txn .mu .ID ,
1040+ ), ctx )
10381041 }
10391042
10401043 if ! retryErr .PrevTxnAborted () {
10411044 // If the retryable error doesn't correspond to an aborted transaction,
10421045 // there's no need to switch out the transaction. We simply clear the
10431046 // retryable error and proceed.
10441047 txn .mu .sender .ClearTxnRetryableErr (ctx )
1045- return
1048+ return nil
10461049 }
10471050
1048- txn .handleTransactionAbortedErrorLocked (ctx , retryErr )
1051+ return txn .handleTransactionAbortedErrorLocked (ctx , retryErr )
10491052}
10501053
10511054// Send runs the specified calls synchronously in a single batch and
@@ -1354,10 +1357,11 @@ func (txn *Txn) UpdateStateOnRemoteRetryableErr(ctx context.Context, pErr *kvpb.
13541357// the current one with it.
13551358func (txn * Txn ) handleTransactionAbortedErrorLocked (
13561359 ctx context.Context , retryErr * kvpb.TransactionRetryWithProtoRefreshError ,
1357- ) {
1360+ ) error {
13581361 if ! retryErr .PrevTxnAborted () {
13591362 // Sanity check we're dealing with a TransactionAbortedError.
1360- log .Fatalf (ctx , "cannot replace root sender if txn not aborted: %v" , retryErr )
1363+ return errors .WithContextTags (errors .NewAssertionErrorWithWrappedErrf (
1364+ retryErr , "cannot replace root sender if txn not aborted" ), ctx )
13611365 }
13621366
13631367 // The transaction we had been using thus far has been aborted. The proto
@@ -1368,6 +1372,7 @@ func (txn *Txn) handleTransactionAbortedErrorLocked(
13681372 prevSteppingMode := txn .mu .sender .GetSteppingMode (ctx )
13691373 txn .mu .sender = txn .db .factory .RootTransactionalSender (newTxn , txn .mu .userPriority )
13701374 txn .mu .sender .ConfigureStepping (ctx , prevSteppingMode )
1375+ return nil
13711376}
13721377
13731378// SetFixedTimestamp makes the transaction run in an unusual way, at a "fixed
0 commit comments