github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/replica_evaluate.go (about)

     1  // Copyright 2019 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package kvserver
    12  
    13  import (
    14  	"bytes"
    15  	"context"
    16  
    17  	"github.com/cockroachdb/cockroach/pkg/kv/kvserver/batcheval"
    18  	"github.com/cockroachdb/cockroach/pkg/kv/kvserver/batcheval/result"
    19  	"github.com/cockroachdb/cockroach/pkg/kv/kvserver/kvserverbase"
    20  	"github.com/cockroachdb/cockroach/pkg/kv/kvserver/spanset"
    21  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    22  	"github.com/cockroachdb/cockroach/pkg/storage"
    23  	"github.com/cockroachdb/cockroach/pkg/storage/enginepb"
    24  	"github.com/cockroachdb/cockroach/pkg/util/errorutil"
    25  	"github.com/cockroachdb/cockroach/pkg/util/hlc"
    26  	"github.com/cockroachdb/cockroach/pkg/util/log"
    27  	"github.com/cockroachdb/errors"
    28  	"github.com/kr/pretty"
    29  	"golang.org/x/time/rate"
    30  )
    31  
    32  var sentryIssue46720Limiter = rate.NewLimiter(0.1, 1) // 1 every 10s
    33  
    34  // optimizePuts searches for contiguous runs of Put & CPut commands in
    35  // the supplied request union. Any run which exceeds a minimum length
    36  // threshold employs a full order iterator to determine whether the
    37  // range of keys being written is empty. If so, then the run can be
    38  // set to put "blindly", meaning no iterator need be used to read
    39  // existing values during the MVCC write.
    40  // The caller should use the returned slice (which is either equal to
    41  // the input slice, or has been shallow-copied appropriately to avoid
    42  // mutating the original requests).
    43  func optimizePuts(
    44  	reader storage.Reader, origReqs []roachpb.RequestUnion, distinctSpans bool,
    45  ) []roachpb.RequestUnion {
    46  	var minKey, maxKey roachpb.Key
    47  	var unique map[string]struct{}
    48  	if !distinctSpans {
    49  		unique = make(map[string]struct{}, len(origReqs))
    50  	}
    51  	// Returns false on occurrence of a duplicate key.
    52  	maybeAddPut := func(key roachpb.Key) bool {
    53  		// Note that casting the byte slice key to a string does not allocate.
    54  		if unique != nil {
    55  			if _, ok := unique[string(key)]; ok {
    56  				return false
    57  			}
    58  			unique[string(key)] = struct{}{}
    59  		}
    60  		if minKey == nil || bytes.Compare(key, minKey) < 0 {
    61  			minKey = key
    62  		}
    63  		if maxKey == nil || bytes.Compare(key, maxKey) > 0 {
    64  			maxKey = key
    65  		}
    66  		return true
    67  	}
    68  
    69  	firstUnoptimizedIndex := len(origReqs)
    70  	for i, r := range origReqs {
    71  		switch t := r.GetInner().(type) {
    72  		case *roachpb.PutRequest:
    73  			if maybeAddPut(t.Key) {
    74  				continue
    75  			}
    76  		case *roachpb.ConditionalPutRequest:
    77  			if maybeAddPut(t.Key) {
    78  				continue
    79  			}
    80  		case *roachpb.InitPutRequest:
    81  			if maybeAddPut(t.Key) {
    82  				continue
    83  			}
    84  		}
    85  		firstUnoptimizedIndex = i
    86  		break
    87  	}
    88  
    89  	if firstUnoptimizedIndex < optimizePutThreshold { // don't bother if below this threshold
    90  		return origReqs
    91  	}
    92  	iter := reader.NewIterator(storage.IterOptions{
    93  		// We want to include maxKey in our scan. Since UpperBound is exclusive, we
    94  		// need to set it to the key after maxKey.
    95  		UpperBound: maxKey.Next(),
    96  	})
    97  	defer iter.Close()
    98  
    99  	// If there are enough puts in the run to justify calling seek,
   100  	// we can determine whether any part of the range being written
   101  	// is "virgin" and set the puts to write blindly.
   102  	// Find the first non-empty key in the run.
   103  	iter.SeekGE(storage.MakeMVCCMetadataKey(minKey))
   104  	var iterKey roachpb.Key
   105  	if ok, err := iter.Valid(); err != nil {
   106  		// TODO(bdarnell): return an error here instead of silently
   107  		// running without the optimization?
   108  		log.Errorf(context.TODO(), "Seek returned error; disabling blind-put optimization: %+v", err)
   109  		return origReqs
   110  	} else if ok && bytes.Compare(iter.Key().Key, maxKey) <= 0 {
   111  		iterKey = iter.Key().Key
   112  	}
   113  	// Set the prefix of the run which is being written to virgin
   114  	// keyspace to "blindly" put values.
   115  	reqs := append([]roachpb.RequestUnion(nil), origReqs...)
   116  	for i := range reqs[:firstUnoptimizedIndex] {
   117  		inner := reqs[i].GetInner()
   118  		if iterKey == nil || bytes.Compare(iterKey, inner.Header().Key) > 0 {
   119  			switch t := inner.(type) {
   120  			case *roachpb.PutRequest:
   121  				shallow := *t
   122  				shallow.Blind = true
   123  				reqs[i].MustSetInner(&shallow)
   124  			case *roachpb.ConditionalPutRequest:
   125  				shallow := *t
   126  				shallow.Blind = true
   127  				reqs[i].MustSetInner(&shallow)
   128  			case *roachpb.InitPutRequest:
   129  				shallow := *t
   130  				shallow.Blind = true
   131  				reqs[i].MustSetInner(&shallow)
   132  			default:
   133  				log.Fatalf(context.TODO(), "unexpected non-put request: %s", t)
   134  			}
   135  		}
   136  	}
   137  	return reqs
   138  }
   139  
   140  // evaluateBatch evaluates a batch request by splitting it up into its
   141  // individual commands, passing them to evaluateCommand, and combining
   142  // the results.
   143  func evaluateBatch(
   144  	ctx context.Context,
   145  	idKey kvserverbase.CmdIDKey,
   146  	readWriter storage.ReadWriter,
   147  	rec batcheval.EvalContext,
   148  	ms *enginepb.MVCCStats,
   149  	ba *roachpb.BatchRequest,
   150  	readOnly bool,
   151  ) (_ *roachpb.BatchResponse, _ result.Result, retErr *roachpb.Error) {
   152  
   153  	defer func() {
   154  		// Ensure that errors don't carry the WriteTooOld flag set. The client
   155  		// handles non-error responses with the WriteTooOld flag set, and errors
   156  		// with this flag set confuse it.
   157  		if retErr != nil && retErr.GetTxn() != nil {
   158  			retErr.GetTxn().WriteTooOld = false
   159  		}
   160  	}()
   161  
   162  	// NB: Don't mutate BatchRequest directly.
   163  	baReqs := ba.Requests
   164  	baHeader := ba.Header
   165  	br := ba.CreateReply()
   166  
   167  	// Optimize any contiguous sequences of put and conditional put ops.
   168  	if len(baReqs) >= optimizePutThreshold && !readOnly {
   169  		baReqs = optimizePuts(readWriter, baReqs, baHeader.DistinctSpans)
   170  	}
   171  
   172  	// Create a clone of the transaction to store the new txn state produced on
   173  	// the return/error path.
   174  	if baHeader.Txn != nil {
   175  		baHeader.Txn = baHeader.Txn.Clone()
   176  
   177  		// Check whether this transaction has been aborted, if applicable. This
   178  		// applies to reads and writes once a transaction that has begun to
   179  		// acquire locks (see #2231 for more about why we check for aborted
   180  		// transactions on reads). Note that 1PC transactions have had their
   181  		// transaction field cleared by this point so we do not execute this
   182  		// check in that case.
   183  		if baHeader.Txn.IsLocking() {
   184  			// We don't check the abort span for a couple of special requests:
   185  			// - if the request is asking to abort the transaction, then don't check the
   186  			// AbortSpan; we don't want the request to be rejected if the transaction
   187  			// has already been aborted.
   188  			// - heartbeats don't check the abort span. If the txn is aborted, they'll
   189  			// return an aborted proto in their otherwise successful response.
   190  			// TODO(nvanbenschoten): Let's remove heartbeats from this whitelist when
   191  			// we rationalize the TODO in txnHeartbeater.heartbeat.
   192  			if !ba.IsSingleAbortTxnRequest() && !ba.IsSingleHeartbeatTxnRequest() {
   193  				if pErr := checkIfTxnAborted(ctx, rec, readWriter, *baHeader.Txn); pErr != nil {
   194  					return nil, result.Result{}, pErr
   195  				}
   196  			}
   197  		}
   198  	}
   199  
   200  	var mergedResult result.Result
   201  
   202  	// WriteTooOldErrors have particular handling. When a request encounters the
   203  	// error, we'd like to lay down an intent in order to avoid writers being
   204  	// starved. So, for blind writes, we swallow the error and instead we set the
   205  	// WriteTooOld flag on the response. For non-blind writes (e.g. CPut), we
   206  	// can't do that and so we just return the WriteTooOldError - see note on
   207  	// IsRead() stanza below. Upon receiving either a WriteTooOldError or a
   208  	// response with the WriteTooOld flag set, the client will attempt to bump
   209  	// the txn's read timestamp through a refresh. If successful, the client
   210  	// will retry this batch (in both cases).
   211  	//
   212  	// In any case, evaluation of the current batch always continue after a
   213  	// WriteTooOldError in order to find out if there's more conflicts and chose
   214  	// a final write timestamp.
   215  	var writeTooOldState struct {
   216  		err *roachpb.WriteTooOldError
   217  		// cantDeferWTOE is set when a WriteTooOldError cannot be deferred past the
   218  		// end of the current batch.
   219  		cantDeferWTOE bool
   220  	}
   221  
   222  	for index, union := range baReqs {
   223  		// Execute the command.
   224  		args := union.GetInner()
   225  
   226  		if baHeader.Txn != nil {
   227  			// Set the Request's sequence number on the TxnMeta for this
   228  			// request. The MVCC layer (currently) uses TxnMeta to
   229  			// pass input arguments, such as the seqnum at which a
   230  			// request operates.
   231  			baHeader.Txn.Sequence = args.Header().Sequence
   232  		}
   233  
   234  		// Note that responses are populated even when an error is returned.
   235  		// TODO(tschottdorf): Change that. IIRC there is nontrivial use of it currently.
   236  		reply := br.Responses[index].GetInner()
   237  
   238  		var curResult result.Result
   239  		var pErr *roachpb.Error
   240  
   241  		curResult, pErr = evaluateCommand(
   242  			ctx, idKey, index, readWriter, rec, ms, baHeader, args, reply)
   243  
   244  		// If an EndTxn wants to restart because of a write too old, we
   245  		// might have a better error to return to the client.
   246  		retErr, ok := pErr.GetDetail().(*roachpb.TransactionRetryError)
   247  		if ok && retErr.Reason == roachpb.RETRY_WRITE_TOO_OLD &&
   248  			args.Method() == roachpb.EndTxn && writeTooOldState.err != nil {
   249  			pErr.SetDetail(writeTooOldState.err)
   250  			// Don't defer this error. We could perhaps rely on the client observing
   251  			// the WriteTooOld flag and retry the batch, but we choose not too.
   252  			writeTooOldState.cantDeferWTOE = true
   253  		}
   254  
   255  		if err := mergedResult.MergeAndDestroy(curResult); err != nil {
   256  			// TODO(tschottdorf): see whether we really need to pass nontrivial
   257  			// Result up on error and if so, formalize that.
   258  			log.Fatalf(
   259  				ctx,
   260  				"unable to absorb Result: %s\ndiff(new, old): %s",
   261  				err, pretty.Diff(curResult, mergedResult),
   262  			)
   263  		}
   264  
   265  		if pErr != nil {
   266  			// Initialize the error index.
   267  			pErr.SetErrorIndex(int32(index))
   268  
   269  			switch tErr := pErr.GetDetail().(type) {
   270  			case *roachpb.WriteTooOldError:
   271  				// We got a WriteTooOldError. We continue on to run all
   272  				// commands in the batch in order to determine the highest
   273  				// timestamp for more efficient retries. If the batch is
   274  				// transactional, we continue to lay down intents so that
   275  				// other concurrent overlapping transactions are forced
   276  				// through intent resolution and the chances of this batch
   277  				// succeeding when it will be retried are increased.
   278  				if writeTooOldState.err != nil {
   279  					writeTooOldState.err.ActualTimestamp.Forward(
   280  						tErr.ActualTimestamp)
   281  				} else {
   282  					writeTooOldState.err = tErr
   283  				}
   284  
   285  				// For read-write requests that observe key-value state, we don't have
   286  				// the option of leaving an intent behind when they encounter a
   287  				// WriteTooOldError, so we have to return an error instead of a response
   288  				// with the WriteTooOld flag set (which would also leave intents
   289  				// behind). These requests need to be re-evaluated at the bumped
   290  				// timestamp in order for their results to be valid. The current
   291  				// evaluation resulted in an result that could well be different from
   292  				// what the request would return if it were evaluated at the bumped
   293  				// timestamp, which would cause the request to be rejected if it were
   294  				// sent again with the same sequence number after a refresh.
   295  				//
   296  				// Similarly, for read-only requests that encounter a WriteTooOldError,
   297  				// we don't have the option of returning a response with the WriteTooOld
   298  				// flag set because a response is not even generated in tandem with the
   299  				// WriteTooOldError. We could fix this and then allow WriteTooOldErrors
   300  				// to be deferred in these cases, but doing so would buy more into the
   301  				// extremely error-prone approach of retuning responses and errors
   302  				// together throughout the MVCC read path. Doing so is not desirable as
   303  				// it has repeatedly caused bugs in the past. Instead, we'd like to get
   304  				// rid of this pattern entirely and instead address the TODO below.
   305  				//
   306  				// TODO(andrei): What we really want to do here is either speculatively
   307  				// evaluate the request at the bumped timestamp and return that
   308  				// speculative result, or leave behind an unreplicated lock that won't
   309  				// prevent the request for evaluating again at the same sequence number
   310  				// but at a bumped timestamp.
   311  				if !roachpb.IsBlindWrite(args) {
   312  					writeTooOldState.cantDeferWTOE = true
   313  				}
   314  
   315  				if baHeader.Txn != nil {
   316  					log.VEventf(ctx, 2, "setting WriteTooOld because of key: %s. wts: %s -> %s",
   317  						args.Header().Key, baHeader.Txn.WriteTimestamp, tErr.ActualTimestamp)
   318  					baHeader.Txn.WriteTimestamp.Forward(tErr.ActualTimestamp)
   319  					baHeader.Txn.WriteTooOld = true
   320  				} else {
   321  					// For non-transactional requests, there's nowhere to defer the error
   322  					// to. And the request has to fail because non-transactional batches
   323  					// should read and write at the same timestamp.
   324  					writeTooOldState.cantDeferWTOE = true
   325  				}
   326  
   327  				// Clear pErr; we're done processing the WTOE for now and we'll return
   328  				// to considering it below after we've evaluated all requests.
   329  				pErr = nil
   330  			default:
   331  				return nil, mergedResult, pErr
   332  			}
   333  		}
   334  
   335  		// If the last request was carried out with a limit, subtract the number
   336  		// of results from the limit going forward. Exhausting the limit results
   337  		// in a limit of -1. This makes sure that we still execute the rest of
   338  		// the batch, but with limit-aware operations returning no data.
   339  		if limit, retResults := baHeader.MaxSpanRequestKeys, reply.Header().NumKeys; limit > 0 {
   340  			if retResults > limit {
   341  				index, retResults, limit := index, retResults, limit // don't alloc unless branch taken
   342  				err := errorutil.UnexpectedWithIssueErrorf(46652,
   343  					"received %d results, limit was %d (original limit: %d, batch=%s idx=%d)",
   344  					errors.Safe(retResults), errors.Safe(limit),
   345  					errors.Safe(ba.Header.MaxSpanRequestKeys),
   346  					errors.Safe(ba.Summary()), errors.Safe(index))
   347  				if sentryIssue46720Limiter.Allow() {
   348  					log.Errorf(ctx, "%v", err)
   349  					errorutil.SendReport(ctx, &rec.ClusterSettings().SV, err)
   350  				}
   351  				return nil, mergedResult, roachpb.NewError(err)
   352  			} else if retResults < limit {
   353  				baHeader.MaxSpanRequestKeys -= retResults
   354  			} else {
   355  				// They were equal, so drop to -1 instead of zero (which would
   356  				// mean "no limit").
   357  				baHeader.MaxSpanRequestKeys = -1
   358  			}
   359  		} else if limit < 0 {
   360  			if retResults > 0 {
   361  				index, retResults := index, retResults // don't alloc unless branch taken
   362  				log.Fatalf(ctx,
   363  					"received %d results, limit was exhausted (original limit: %d, batch=%s idx=%d)",
   364  					errors.Safe(retResults), errors.Safe(ba.Header.MaxSpanRequestKeys),
   365  					errors.Safe(ba.Summary()), errors.Safe(index))
   366  			}
   367  		}
   368  		// Same as for MaxSpanRequestKeys above, keep track of the limit and
   369  		// make sure to fall through to -1 instead of hitting zero (which
   370  		// means no limit).
   371  		if baHeader.TargetBytes > 0 {
   372  			retBytes := reply.Header().NumBytes
   373  			if baHeader.TargetBytes > retBytes {
   374  				baHeader.TargetBytes -= retBytes
   375  			} else {
   376  				baHeader.TargetBytes = -1
   377  			}
   378  		}
   379  
   380  		// If transactional, we use ba.Txn for each individual command and
   381  		// accumulate updates to it. Once accumulated, we then remove the Txn
   382  		// from each individual response.
   383  		// TODO(spencer,tschottdorf): need copy-on-write behavior for the
   384  		//   updated batch transaction / timestamp.
   385  		if baHeader.Txn != nil {
   386  			if header := reply.Header(); header.Txn != nil {
   387  				baHeader.Txn.Update(header.Txn)
   388  				header.Txn = nil
   389  				reply.SetHeader(header)
   390  			}
   391  		}
   392  	}
   393  
   394  	if writeTooOldState.err != nil {
   395  		if baHeader.Txn != nil && baHeader.Txn.Status.IsCommittedOrStaging() {
   396  			log.Fatalf(ctx, "committed txn with writeTooOld err: %s", writeTooOldState.err)
   397  		}
   398  	}
   399  
   400  	// If there's a write too old error that we can't defer, return it.
   401  	if writeTooOldState.cantDeferWTOE {
   402  		return nil, mergedResult, roachpb.NewErrorWithTxn(writeTooOldState.err, baHeader.Txn)
   403  	}
   404  
   405  	// Update the batch response timestamp field to the timestamp at which the
   406  	// batch's reads were evaluated.
   407  	if baHeader.Txn != nil {
   408  		// If transactional, send out the final transaction entry with the reply.
   409  		br.Txn = baHeader.Txn
   410  		// Note that br.Txn.ReadTimestamp might be higher than baHeader.Timestamp if
   411  		// we had an EndTxn that decided that it can refresh to something higher
   412  		// than baHeader.Timestamp because there were no refresh spans.
   413  		if br.Txn.ReadTimestamp.Less(baHeader.Timestamp) {
   414  			log.Fatalf(ctx, "br.Txn.ReadTimestamp < ba.Timestamp (%s < %s). ba: %s",
   415  				br.Txn.ReadTimestamp, baHeader.Timestamp, ba)
   416  		}
   417  		br.Timestamp = br.Txn.ReadTimestamp
   418  	} else {
   419  		br.Timestamp = baHeader.Timestamp
   420  	}
   421  
   422  	return br, mergedResult, nil
   423  }
   424  
   425  // evaluateCommand delegates to the eval method for the given
   426  // roachpb.Request. The returned Result may be partially valid
   427  // even if an error is returned. maxKeys is the number of scan results
   428  // remaining for this batch (MaxInt64 for no limit).
   429  func evaluateCommand(
   430  	ctx context.Context,
   431  	raftCmdID kvserverbase.CmdIDKey,
   432  	index int,
   433  	readWriter storage.ReadWriter,
   434  	rec batcheval.EvalContext,
   435  	ms *enginepb.MVCCStats,
   436  	h roachpb.Header,
   437  	args roachpb.Request,
   438  	reply roachpb.Response,
   439  ) (result.Result, *roachpb.Error) {
   440  	// If a unittest filter was installed, check for an injected error; otherwise, continue.
   441  	if filter := rec.EvalKnobs().TestingEvalFilter; filter != nil {
   442  		filterArgs := kvserverbase.FilterArgs{
   443  			Ctx:   ctx,
   444  			CmdID: raftCmdID,
   445  			Index: index,
   446  			Sid:   rec.StoreID(),
   447  			Req:   args,
   448  			Hdr:   h,
   449  		}
   450  		if pErr := filter(filterArgs); pErr != nil {
   451  			if pErr.GetTxn() == nil {
   452  				pErr.SetTxn(h.Txn)
   453  			}
   454  			log.Infof(ctx, "test injecting error: %s", pErr)
   455  			return result.Result{}, pErr
   456  		}
   457  	}
   458  
   459  	var err error
   460  	var pd result.Result
   461  
   462  	if cmd, ok := batcheval.LookupCommand(args.Method()); ok {
   463  		cArgs := batcheval.CommandArgs{
   464  			EvalCtx: rec,
   465  			Header:  h,
   466  			Args:    args,
   467  			Stats:   ms,
   468  		}
   469  
   470  		if cmd.EvalRW != nil {
   471  			pd, err = cmd.EvalRW(ctx, readWriter, cArgs, reply)
   472  		} else {
   473  			pd, err = cmd.EvalRO(ctx, readWriter, cArgs, reply)
   474  		}
   475  	} else {
   476  		err = errors.Errorf("unrecognized command %s", args.Method())
   477  	}
   478  
   479  	if h.ReturnRangeInfo {
   480  		returnRangeInfo(reply, rec)
   481  	}
   482  
   483  	// TODO(peter): We'd like to assert that the hlc clock is always updated
   484  	// correctly, but various tests insert versioned data without going through
   485  	// the proper channels. See TestPushTxnUpgradeExistingTxn for an example.
   486  	//
   487  	// if header.Txn != nil && h.Timestamp.LessEq(header.Txn.Timestamp) {
   488  	// 	if now := r.store.Clock().Now(); now.Less(header.Txn.Timestamp) {
   489  	// 		log.Fatalf(ctx, "hlc clock not updated: %s < %s", now, header.Txn.Timestamp)
   490  	// 	}
   491  	// }
   492  
   493  	if log.V(2) {
   494  		log.Infof(ctx, "evaluated %s command %+v: %+v, err=%v", args.Method(), args, reply, err)
   495  	}
   496  
   497  	// Create a roachpb.Error by initializing txn from the request/response header.
   498  	var pErr *roachpb.Error
   499  	if err != nil {
   500  		txn := reply.Header().Txn
   501  		if txn == nil {
   502  			txn = h.Txn
   503  		}
   504  		pErr = roachpb.NewErrorWithTxn(err, txn)
   505  	}
   506  
   507  	return pd, pErr
   508  }
   509  
   510  // returnRangeInfo populates RangeInfos in the response if the batch
   511  // requested them.
   512  func returnRangeInfo(reply roachpb.Response, rec batcheval.EvalContext) {
   513  	header := reply.Header()
   514  	lease, _ := rec.GetLease()
   515  	desc := rec.Desc()
   516  	header.RangeInfos = []roachpb.RangeInfo{
   517  		{
   518  			Desc:  *desc,
   519  			Lease: lease,
   520  		},
   521  	}
   522  	reply.SetHeader(header)
   523  }
   524  
   525  // canDoServersideRetry looks at the error produced by evaluating ba (or the
   526  // WriteTooOldFlag in br.Txn if there's no error) and decides if it's possible
   527  // to retry the batch evaluation at a higher timestamp. Retrying is sometimes
   528  // possible in case of some retriable errors which ask for higher timestamps:
   529  // for transactional requests, retrying is possible if the transaction had not
   530  // performed any prior reads that need refreshing.
   531  //
   532  // deadline, if not nil, specifies the highest timestamp (exclusive) at which
   533  // the request can be evaluated. If ba is a transactional request, then dealine
   534  // cannot be specified; a transaction's deadline comes from it's EndTxn request.
   535  //
   536  // If true is returned, ba and ba.Txn will have been updated with the new
   537  // timestamp.
   538  func canDoServersideRetry(
   539  	ctx context.Context,
   540  	pErr *roachpb.Error,
   541  	ba *roachpb.BatchRequest,
   542  	br *roachpb.BatchResponse,
   543  	latchSpans *spanset.SpanSet,
   544  	deadline *hlc.Timestamp,
   545  ) bool {
   546  	if ba.Txn != nil {
   547  		if deadline != nil {
   548  			log.Fatal(ctx, "deadline passed for transactional request")
   549  		}
   550  		canFwdRTS := ba.CanForwardReadTimestamp
   551  		if etArg, ok := ba.GetArg(roachpb.EndTxn); ok {
   552  			// If the request provided an EndTxn request, also check its
   553  			// CanCommitAtHigherTimestamp flag. This ensures that we're backwards
   554  			// compatable and gives us a chance to make sure that these flags are
   555  			// in-sync until the CanCommitAtHigherTimestamp is migrated away.
   556  			et := etArg.(*roachpb.EndTxnRequest)
   557  			canFwdCTS := batcheval.CanForwardCommitTimestampWithoutRefresh(ba.Txn, et)
   558  			if canFwdRTS && !canFwdCTS {
   559  				log.Fatalf(ctx, "unexpected mismatch between Batch.CanForwardReadTimestamp "+
   560  					"(%+v) and EndTxn.CanCommitAtHigherTimestamp (%+v)", ba, et)
   561  			}
   562  			canFwdRTS = canFwdCTS
   563  			deadline = et.Deadline
   564  		}
   565  		if !canFwdRTS {
   566  			return false
   567  		}
   568  	}
   569  	var newTimestamp hlc.Timestamp
   570  
   571  	if pErr != nil {
   572  		switch tErr := pErr.GetDetail().(type) {
   573  		case *roachpb.WriteTooOldError:
   574  			// Locking scans hit WriteTooOld errors if they encounter values at
   575  			// timestamps higher than their read timestamps. The encountered
   576  			// timestamps are guaranteed to be greater than the txn's read
   577  			// timestamp, but not its write timestamp. So, when determining what
   578  			// the new timestamp should be, we make sure to not regress the
   579  			// txn's write timestamp.
   580  			newTimestamp = tErr.ActualTimestamp
   581  			if ba.Txn != nil {
   582  				newTimestamp.Forward(pErr.GetTxn().WriteTimestamp)
   583  			}
   584  		case *roachpb.TransactionRetryError:
   585  			if ba.Txn == nil {
   586  				// TODO(andrei): I don't know if TransactionRetryError is possible for
   587  				// non-transactional batches, but some tests inject them for 1PC
   588  				// transactions. I'm not sure how to deal with them, so let's not retry.
   589  				return false
   590  			}
   591  			newTimestamp = pErr.GetTxn().WriteTimestamp
   592  		default:
   593  			// TODO(andrei): Handle other retriable errors too.
   594  			return false
   595  		}
   596  	} else {
   597  		if !br.Txn.WriteTooOld {
   598  			log.Fatalf(ctx, "programming error: expected the WriteTooOld flag to be set")
   599  		}
   600  		newTimestamp = br.Txn.WriteTimestamp
   601  	}
   602  
   603  	if deadline != nil && deadline.LessEq(newTimestamp) {
   604  		return false
   605  	}
   606  	return tryBumpBatchTimestamp(ctx, ba, newTimestamp, latchSpans)
   607  }