Skip to content

Commit

Permalink
kv: avoid retry error allocation on each Txn.exec call
Browse files Browse the repository at this point in the history
This commit updates `Txn.exec` to only call `errors.As` if the error from the
transaction execution was non-nil. This avoids a heap allocation of a
`TransactionRetryWithProtoRefreshError` on each call to `Txn.exec`, which was
originally introduced in a8ae1bf.

In kv100 (100% reads), this is responsible for **0.36%** of total CPU usage.
  • Loading branch information
nvanbenschoten committed Dec 30, 2021
1 parent cc22c45 commit 1f021e4
Showing 1 changed file with 17 additions and 16 deletions.
33 changes: 17 additions & 16 deletions pkg/kv/txn.go
Original file line number Diff line number Diff line change
Expand Up @@ -978,23 +978,24 @@ func (txn *Txn) exec(ctx context.Context, fn func(context.Context, *Txn) error)
}

var retryable bool
if errors.HasType(err, (*roachpb.UnhandledRetryableError)(nil)) {
if txn.typ == RootTxn {
// We sent transactional requests, so the TxnCoordSender was supposed to
// turn retryable errors into TransactionRetryWithProtoRefreshError. Note that this
// applies only in the case where this is the root transaction.
log.Fatalf(ctx, "unexpected UnhandledRetryableError at the txn.exec() level: %s", err)
}

} else if t := (*roachpb.TransactionRetryWithProtoRefreshError)(nil); errors.As(err, &t) {
if !txn.IsRetryableErrMeantForTxn(*t) {
// Make sure the txn record that err carries is for this txn.
// If it's not, we terminate the "retryable" character of the error. We
// might get a TransactionRetryWithProtoRefreshError if the closure ran another
// transaction internally and let the error propagate upwards.
return errors.Wrapf(err, "retryable error from another txn")
if err != nil {
if errors.HasType(err, (*roachpb.UnhandledRetryableError)(nil)) {
if txn.typ == RootTxn {
// We sent transactional requests, so the TxnCoordSender was supposed to
// turn retryable errors into TransactionRetryWithProtoRefreshError. Note that this
// applies only in the case where this is the root transaction.
log.Fatalf(ctx, "unexpected UnhandledRetryableError at the txn.exec() level: %s", err)
}
} else if t := (*roachpb.TransactionRetryWithProtoRefreshError)(nil); errors.As(err, &t) {
if !txn.IsRetryableErrMeantForTxn(*t) {
// Make sure the txn record that err carries is for this txn.
// If it's not, we terminate the "retryable" character of the error. We
// might get a TransactionRetryWithProtoRefreshError if the closure ran another
// transaction internally and let the error propagate upwards.
return errors.Wrapf(err, "retryable error from another txn")
}
retryable = true
}
retryable = true
}

if !retryable {
Expand Down

0 comments on commit 1f021e4

Please sign in to comment.