@@ -20,6 +20,7 @@ import (
2020 "github.com/cockroachdb/cockroach/pkg/util/errorutil/unimplemented"
2121 "github.com/cockroachdb/cockroach/pkg/util/uuid"
2222 "github.com/cockroachdb/errors"
23+ "github.com/cockroachdb/redact"
2324)
2425
2526// savepoint captures the state in the TxnCoordSender necessary to restore that
@@ -121,15 +122,8 @@ func (tc *TxnCoordSender) RollbackToSavepoint(ctx context.Context, s kv.Savepoin
121122 }
122123
123124 sp := s .(* savepoint )
124- err := tc .checkSavepointLocked (sp )
125+ err := tc .checkSavepointLocked (sp , "rollback to" )
125126 if err != nil {
126- if errors .Is (err , errSavepointInvalidAfterTxnRestart ) {
127- err = kvpb .NewTransactionRetryWithProtoRefreshError (
128- "cannot rollback to savepoint after a transaction restart" ,
129- tc .mu .txn .ID ,
130- tc .mu .txn ,
131- )
132- }
133127 return err
134128 }
135129
@@ -165,15 +159,7 @@ func (tc *TxnCoordSender) ReleaseSavepoint(ctx context.Context, s kv.SavepointTo
165159 }
166160
167161 sp := s .(* savepoint )
168- err := tc .checkSavepointLocked (sp )
169- if errors .Is (err , errSavepointInvalidAfterTxnRestart ) {
170- err = kvpb .NewTransactionRetryWithProtoRefreshError (
171- "cannot release savepoint after a transaction restart" ,
172- tc .mu .txn .ID ,
173- tc .mu .txn ,
174- )
175- }
176- return err
162+ return tc .checkSavepointLocked (sp , "release" )
177163}
178164
179165type errSavepointOperationInErrorTxn struct {}
@@ -193,23 +179,22 @@ func (tc *TxnCoordSender) assertNotFinalized() error {
193179 return nil
194180}
195181
196- var errSavepointInvalidAfterTxnRestart = errors .New ("savepoint invalid after transaction restart" )
197-
198182// checkSavepointLocked checks whether the provided savepoint is still valid.
199- // Returns errSavepointInvalidAfterTxnRestart if the savepoint is not an
183+ // Returns a TransactionRetryWithProtoRefreshError if the savepoint is not an
200184// "initial" one and the transaction has restarted since the savepoint was
201185// created.
202- func (tc * TxnCoordSender ) checkSavepointLocked (s * savepoint ) error {
186+ func (tc * TxnCoordSender ) checkSavepointLocked (s * savepoint , op redact. SafeString ) error {
203187 // Only savepoints taken before any activity are allowed to be used after a
204188 // transaction restart.
205189 if s .Initial () {
206190 return nil
207191 }
208- if s .txnID != tc .mu .txn .ID {
209- return errSavepointInvalidAfterTxnRestart
210- }
211- if s .epoch != tc .mu .txn .Epoch {
212- return errSavepointInvalidAfterTxnRestart
192+ if s .txnID != tc .mu .txn .ID || s .epoch != tc .mu .txn .Epoch {
193+ return kvpb .NewTransactionRetryWithProtoRefreshError (
194+ redact .Sprintf ("cannot %s savepoint after a transaction restart" , op ),
195+ s .txnID ,
196+ tc .mu .txn ,
197+ )
213198 }
214199
215200 if s .seqNum < 0 || s .seqNum > tc .interceptorAlloc .txnSeqNumAllocator .writeSeq {
0 commit comments