Skip to content

Commit d6578e5

Browse files
committed
sql: step read timestamp before RC statement retries
In `sql.(*connExecutor).dispatchReadCommittedStmtToExecutionEngine` we automatically retry statements under Read Committed isolation that fail with retryable errors. To give these retries a better chance of succeeding, step the read timestamp just before each retry. This should help the retried query see the results of the conflicting transactions that caused the failure and any other transactions that occurred in the meantime. Also step statement_timestamp so that any SQL using statement_timestamp() gets an up-to-date timestamp on each retry. Informs: #145377 Release note: None
1 parent a7a0b62 commit d6578e5

File tree

1 file changed

+29
-14
lines changed

1 file changed

+29
-14
lines changed

pkg/sql/conn_executor_exec.go

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2560,18 +2560,18 @@ func (ex *connExecutor) commitSQLTransactionInternal(ctx context.Context) (retEr
25602560

25612561
ex.extraTxnState.prepStmtsNamespace.closePortals(ctx, &ex.extraTxnState.prepStmtsNamespaceMemAcc)
25622562

2563-
// We need to step the transaction's internal read sequence before committing
2564-
// if it has stepping enabled. If it doesn't have stepping enabled, then we
2565-
// just set the stepping mode back to what it was.
2563+
// We need to step the transaction's read sequence before committing if it has
2564+
// stepping enabled. If it doesn't have stepping enabled, then we just set the
2565+
// stepping mode back to what it was.
25662566
//
2567-
// Even if we do step the transaction's internal read sequence, we do not
2568-
// advance its external read timestamp (applicable only to read committed
2569-
// transactions). This is because doing so is not needed before committing,
2570-
// and it would cause the transaction to commit at a higher timestamp than
2571-
// necessary. On heavily contended workloads like the one from #109628, this
2572-
// can cause unnecessary write-write contention between transactions by
2573-
// inflating the contention footprint of each transaction (i.e. the duration
2574-
// measured in MVCC time that the transaction holds locks).
2567+
// Even if we do step the transaction's read sequence, we do not advance its
2568+
// read timestamp (applicable only to read committed transactions). This is
2569+
// because doing so is not needed before committing, and it would cause the
2570+
// transaction to commit at a higher timestamp than necessary. On heavily
2571+
// contended workloads like the one from #109628, this can cause unnecessary
2572+
// write-write contention between transactions by inflating the contention
2573+
// footprint of each transaction (i.e. the duration measured in MVCC time that
2574+
// the transaction holds locks).
25752575
prevSteppingMode := ex.state.mu.txn.ConfigureStepping(ctx, kv.SteppingEnabled)
25762576
if prevSteppingMode == kv.SteppingEnabled {
25772577
if err := ex.state.mu.txn.Step(ctx, false /* allowReadTimestampStep */); err != nil {
@@ -2722,6 +2722,14 @@ func (ex *connExecutor) rollbackSQLTransaction(
27222722
func (ex *connExecutor) dispatchReadCommittedStmtToExecutionEngine(
27232723
ctx context.Context, p *planner, res RestrictedCommandResult,
27242724
) error {
2725+
if ex.executorType == executorTypeInternal {
2726+
// Because we step the read timestamp below, this is not safe to call within
2727+
// internal executor.
2728+
return errors.AssertionFailedf(
2729+
"call of dispatchReadCommittedStmtToExecutionEngine within internal executor",
2730+
)
2731+
}
2732+
27252733
getPausablePortalInfo := func() *portalPauseInfo {
27262734
if p != nil && p.pausablePortal != nil {
27272735
return p.pausablePortal.pauseInfo
@@ -2749,7 +2757,17 @@ func (ex *connExecutor) dispatchReadCommittedStmtToExecutionEngine(
27492757
ex.sessionTracing.TraceRetryInformation(
27502758
ctx, "statement", p.autoRetryStmtCounter, p.autoRetryStmtReason,
27512759
)
2760+
// Step both the sequence number and the read timestamp so that we can see
2761+
// the results of the conflicting transactions that caused us to fail and
2762+
// any other transactions that occurred in the meantime.
2763+
if err := ex.state.mu.txn.Step(ctx, true /* allowReadTimestampStep */); err != nil {
2764+
return err
2765+
}
2766+
// Also step statement_timestamp so that any SQL using it is up-to-date.
2767+
stmtTS := ex.server.cfg.Clock.PhysicalTime()
2768+
p.extendedEvalCtx.StmtTimestamp = stmtTS
27522769
}
2770+
27532771
bufferPos := res.BufferedResultsLen()
27542772
if err = ex.dispatchToExecutionEngine(ctx, p, res); err != nil {
27552773
return err
@@ -2802,9 +2820,6 @@ func (ex *connExecutor) dispatchReadCommittedStmtToExecutionEngine(
28022820
if err := ex.state.mu.txn.PrepareForPartialRetry(ctx); err != nil {
28032821
return err
28042822
}
2805-
if err := ex.state.mu.txn.Step(ctx, false /* allowReadTimestampStep */); err != nil {
2806-
return err
2807-
}
28082823
p.autoRetryStmtCounter++
28092824
p.autoRetryStmtReason = maybeRetriableErr
28102825
if ppInfo := getPausablePortalInfo(); ppInfo != nil {

0 commit comments

Comments
 (0)