Skip to content

Commit 663fd06

Browse files
craig[bot]ZhouXing19
andcommitted
Merge #155669
155669: sql: add safety gates for pausable portal cleanup and flow invalidation r=ZhouXing19 a=ZhouXing19 Informs: https://github.com/cockroachlabs/support/issues/3463 When a pausable portal encounters an error during execution, two issues can lead to panics on subsequent resume attempts: 1. The underlying FlowBase gets reset to nil during cleanup, but the portal's flow reference remains non-nil, causing hasFlowForPausablePortal() to incorrectly return true. 2. Errored portals are not removed from the portal map because deletion only occurs when execStmt() returns a non-nil fsm.Event. This change adds two defensive checks: - Nil the whole flow object hanging off the `portalInfo` while cleaning up the flow. - Ensure errored portals are properly cleaned up regardless of event state These gates prevent nil pointer dereferences when resuming portals that have been partially cleaned up due to errors. Release note: None Co-authored-by: ZhouXing19 <zhouxing@uchicago.edu>
2 parents 48e15d6 + 9a13f8e commit 663fd06

File tree

2 files changed

+15
-13
lines changed

2 files changed

+15
-13
lines changed

pkg/sql/conn_executor.go

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2598,8 +2598,6 @@ func (ex *connExecutor) execCmd() (retErr error) {
25982598
panic(errors.AssertionFailedf("unsupported command type: %T", cmd))
25992599
}
26002600

2601-
var advInfo advanceInfo
2602-
26032601
// We close all pausable portals and cursors when we encounter err payload,
26042602
// otherwise there will be leftover bytes.
26052603
shouldClosePausablePortalsAndCursors := func(payload fsm.EventPayload) bool {
@@ -2611,18 +2609,19 @@ func (ex *connExecutor) execCmd() (retErr error) {
26112609
}
26122610
}
26132611

2612+
if shouldClosePausablePortalsAndCursors(payload) {
2613+
// We need this as otherwise, there'll be leftover bytes when
2614+
// txnState.finishSQLTxn() is being called, as the underlying resources of
2615+
// pausable portals hasn't been cleared yet.
2616+
ex.extraTxnState.prepStmtsNamespace.closeAllPausablePortals(ctx, &ex.extraTxnState.prepStmtsNamespaceMemAcc)
2617+
if err := ex.extraTxnState.sqlCursors.closeAll(&ex.planner, cursorCloseForTxnRollback); err != nil {
2618+
log.Dev.Warningf(ctx, "error closing cursors: %v", err)
2619+
}
2620+
}
2621+
2622+
var advInfo advanceInfo
26142623
// If an event was generated, feed it to the state machine.
26152624
if ev != nil {
2616-
var err error
2617-
if shouldClosePausablePortalsAndCursors(payload) {
2618-
// We need this as otherwise, there'll be leftover bytes when
2619-
// txnState.finishSQLTxn() is being called, as the underlying resources of
2620-
// pausable portals hasn't been cleared yet.
2621-
ex.extraTxnState.prepStmtsNamespace.closeAllPausablePortals(ctx, &ex.extraTxnState.prepStmtsNamespaceMemAcc)
2622-
if err := ex.extraTxnState.sqlCursors.closeAll(&ex.planner, cursorCloseForTxnRollback); err != nil {
2623-
log.Dev.Warningf(ctx, "error closing cursors: %v", err)
2624-
}
2625-
}
26262625
advInfo, err = ex.txnStateTransitionsApplyWrapper(ev, payload, res, pos)
26272626
if err != nil {
26282627
return err

pkg/sql/distsql_running.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2019,7 +2019,10 @@ func (dsp *DistSQLPlanner) PlanAndRunAll(
20192019
}
20202020
if !p.resumableFlow.cleanup.isComplete {
20212021
p.resumableFlow.cleanup.appendFunc(func(ctx context.Context) {
2022-
p.resumableFlow.flow.Cleanup(ctx)
2022+
if p.resumableFlow.flow != nil {
2023+
p.resumableFlow.flow.Cleanup(ctx)
2024+
p.resumableFlow.flow = nil
2025+
}
20232026
})
20242027
}
20252028
}

0 commit comments

Comments
 (0)