Skip to content

Commit 3ebecc8

Browse files
authored
Merge pull request cockroachdb#156501 from yuzefovich/backport25.3-155824-156110
release-25.3: sql: fix top-level query stats when "inner" plans are present
2 parents 4be487c + 295d471 commit 3ebecc8

14 files changed

+395
-76
lines changed

pkg/sql/apply_join.go

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
"github.com/cockroachdb/cockroach/pkg/sql/catalog/colinfo"
1313
"github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb"
14+
"github.com/cockroachdb/cockroach/pkg/sql/distsql"
1415
"github.com/cockroachdb/cockroach/pkg/sql/opt/exec"
1516
"github.com/cockroachdb/cockroach/pkg/sql/sem/eval"
1617
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
@@ -35,6 +36,10 @@ type applyJoinNode struct {
3536
// The data source with no outer columns.
3637
singleInputPlanNode
3738

39+
// forwarder allows propagating the ProducerMetadata towards the
40+
// DistSQLReceiver.
41+
forwarder metadataForwarder
42+
3843
// pred represents the join predicate.
3944
pred *joinPredicate
4045

@@ -248,12 +253,13 @@ func (a *applyJoinNode) runNextRightSideIteration(params runParams, leftRow tree
248253
}
249254
plan := p.(*planComponents)
250255
rowResultWriter := NewRowResultWriter(&a.run.rightRows)
251-
if err := runPlanInsidePlan(
252-
ctx, params, plan, rowResultWriter,
253-
nil /* deferredRoutineSender */, "", /* stmtForDistSQLDiagram */
254-
); err != nil {
256+
queryStats, err := runPlanInsidePlan(
257+
ctx, params, plan, rowResultWriter, nil /* deferredRoutineSender */, "", /* stmtForDistSQLDiagram */
258+
)
259+
if err != nil {
255260
return err
256261
}
262+
forwardInnerQueryStats(a.forwarder, queryStats)
257263
a.run.rightRowsIterator = newRowContainerIterator(ctx, a.run.rightRows)
258264
return nil
259265
}
@@ -267,7 +273,7 @@ func runPlanInsidePlan(
267273
resultWriter rowResultWriter,
268274
deferredRoutineSender eval.DeferredRoutineSender,
269275
stmtForDistSQLDiagram string,
270-
) error {
276+
) (topLevelQueryStats, error) {
271277
defer plan.close(ctx)
272278
execCfg := params.ExecCfg()
273279
recv := MakeDistSQLReceiver(
@@ -286,6 +292,11 @@ func runPlanInsidePlan(
286292
// before we can produce any "outer" rows to be returned to the client, so
287293
// we make sure to unset pausablePortal field on the planner.
288294
plannerCopy.pausablePortal = nil
295+
// Avoid any possible metadata confusion by unsetting the
296+
// routineMetadataForwarder (if there is a routine in the inner plan that
297+
// needs it, then the plannerCopy will be updated during the inner plan
298+
// setup).
299+
plannerCopy.routineMetadataForwarder = nil
289300

290301
// planner object embeds the extended eval context, so we will modify that
291302
// (which won't affect the outer planner's extended eval context), and we'll
@@ -301,6 +312,8 @@ func runPlanInsidePlan(
301312
// return from this method (after the main query is executed).
302313
subqueryResultMemAcc := params.p.Mon().MakeBoundAccount()
303314
defer subqueryResultMemAcc.Close(ctx)
315+
// Note that planAndRunSubquery updates recv.stats with top-level
316+
// subquery stats.
304317
if !execCfg.DistSQLPlanner.PlanAndRunSubqueries(
305318
ctx,
306319
&plannerCopy,
@@ -309,9 +322,9 @@ func runPlanInsidePlan(
309322
recv,
310323
&subqueryResultMemAcc,
311324
false, /* skipDistSQLDiagramGeneration */
312-
params.p.mustUseLeafTxn(),
325+
params.p.innerPlansMustUseLeafTxn(),
313326
) {
314-
return resultWriter.Err()
327+
return recv.stats, resultWriter.Err()
315328
}
316329
}
317330

@@ -324,7 +337,9 @@ func runPlanInsidePlan(
324337
planCtx := execCfg.DistSQLPlanner.NewPlanningCtx(ctx, evalCtx, &plannerCopy, plannerCopy.txn, distributeType)
325338
planCtx.distSQLProhibitedErr = distSQLProhibitedErr
326339
planCtx.stmtType = recv.stmtType
327-
planCtx.mustUseLeafTxn = params.p.mustUseLeafTxn()
340+
if params.p.innerPlansMustUseLeafTxn() {
341+
planCtx.flowConcurrency = distsql.ConcurrencyWithOuterPlan
342+
}
328343
planCtx.stmtForDistSQLDiagram = stmtForDistSQLDiagram
329344

330345
// Wrap PlanAndRun in a function call so that we clean up immediately.
@@ -338,10 +353,10 @@ func runPlanInsidePlan(
338353

339354
// Check if there was an error interacting with the resultWriter.
340355
if recv.commErr != nil {
341-
return recv.commErr
356+
return recv.stats, recv.commErr
342357
}
343358
if resultWriter.Err() != nil {
344-
return resultWriter.Err()
359+
return recv.stats, resultWriter.Err()
345360
}
346361

347362
plannerCopy.autoCommit = false
@@ -358,10 +373,10 @@ func runPlanInsidePlan(
358373
// need to update the plan for cleanup purposes before proceeding.
359374
*plan = plannerCopy.curPlan.planComponents
360375
if recv.commErr != nil {
361-
return recv.commErr
376+
return recv.stats, recv.commErr
362377
}
363378

364-
return resultWriter.Err()
379+
return recv.stats, resultWriter.Err()
365380
}
366381

367382
func (a *applyJoinNode) Values() tree.Datums {

pkg/sql/conn_executor.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3961,6 +3961,7 @@ func (ex *connExecutor) initPlanner(ctx context.Context, p *planner) {
39613961
p.noticeSender = nil
39623962
p.preparedStatements = ex.getPrepStmtsAccessor()
39633963
p.sqlCursors = ex.getCursorAccessor()
3964+
p.routineMetadataForwarder = nil
39643965
p.storedProcTxnState = ex.getStoredProcTxnStateAccessor()
39653966
p.createdSequences = ex.getCreatedSequencesAccessor()
39663967

pkg/sql/conn_executor_exec.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3507,6 +3507,8 @@ type topLevelQueryStats struct {
35073507
// client receiving the PGWire protocol messages (as well as construcing
35083508
// those messages).
35093509
clientTime time.Duration
3510+
// NB: when adding another field here, consider whether
3511+
// forwardInnerQueryStats method needs an adjustment.
35103512
}
35113513

35123514
func (s *topLevelQueryStats) add(other *topLevelQueryStats) {

pkg/sql/distsql/server.go

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,28 @@ func newFlow(
533533
return rowflow.NewRowBasedFlow(base)
534534
}
535535

536+
// ConcurrencyKind indicates which concurrency type is present within the local
537+
// DistSQL flow. Note that inter-node concurrency (i.e. whether we have a
538+
// distributed plan) is not reflected here.
539+
type ConcurrencyKind uint32
540+
541+
const (
542+
// ConcurrencyHasParallelProcessors, if set, indicates that we have multiple
543+
// processors running for the same plan stage.
544+
ConcurrencyHasParallelProcessors ConcurrencyKind = (1 << iota)
545+
// ConcurrencyStreamer, if set, indicates we have concurrency due to usage
546+
// of the Streamer API.
547+
ConcurrencyStreamer
548+
// ConcurrencyParallelChecks, if set, indicates that we're running
549+
// post-query CHECKs in parallel with each other (i.e. the concurrency is
550+
// with _other_ local flows).
551+
ConcurrencyParallelChecks
552+
// ConcurrencyWithOuterPlan, if set, indicates that - if we're running an
553+
// "inner" plan (like an apply-join iteration or a routine) - we might have
554+
// concurrency with the "outer" plan.
555+
ConcurrencyWithOuterPlan
556+
)
557+
536558
// LocalState carries information that is required to set up a flow with wrapped
537559
// planNodes.
538560
type LocalState struct {
@@ -547,13 +569,9 @@ type LocalState struct {
547569
// remote flows.
548570
IsLocal bool
549571

550-
// HasConcurrency indicates whether the local flow uses multiple goroutines.
551-
HasConcurrency bool
552-
553-
// MustUseLeaf indicates whether the local flow must use the LeafTxn even if
554-
// there is no concurrency in the flow on its own because there would be
555-
// concurrency with other flows which prohibits the usage of the RootTxn.
556-
MustUseLeaf bool
572+
// concurrency tracks the types of concurrency present when accessing the
573+
// Txn.
574+
concurrency ConcurrencyKind
557575

558576
// Txn is filled in on the gateway only. It is the RootTxn that the query is running in.
559577
// This will be used directly by the flow if the flow has no concurrency and IsLocal is set.
@@ -570,10 +588,22 @@ type LocalState struct {
570588
LocalVectorSources map[int32]any
571589
}
572590

591+
// AddConcurrency marks the given concurrency kinds as present in the local
592+
// flow.
593+
func (l *LocalState) AddConcurrency(kind ConcurrencyKind) {
594+
l.concurrency |= kind
595+
}
596+
597+
// GetConcurrency returns the bit-mask representing all concurrency kinds
598+
// present in the local flow.
599+
func (l LocalState) GetConcurrency() ConcurrencyKind {
600+
return l.concurrency
601+
}
602+
573603
// MustUseLeafTxn returns true if a LeafTxn must be used. It is valid to call
574-
// this method only after IsLocal and HasConcurrency have been set correctly.
604+
// this method only after IsLocal and all concurrency kinds have been set.
575605
func (l LocalState) MustUseLeafTxn() bool {
576-
return !l.IsLocal || l.HasConcurrency || l.MustUseLeaf
606+
return !l.IsLocal || l.concurrency != 0
577607
}
578608

579609
// SetupLocalSyncFlow sets up a synchronous flow on the current (planning) node,

pkg/sql/distsql_physical_planner.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -989,7 +989,8 @@ type PlanningCtx struct {
989989
// isLocal is set to true if we're planning this query on a single node.
990990
isLocal bool
991991
// distSQLProhibitedErr, if set, indicates why the plan couldn't be
992-
// distributed.
992+
// distributed. If any part of the plan isn't distributable, then this is
993+
// guaranteed to be non-nil.
993994
distSQLProhibitedErr error
994995
planner *planner
995996

@@ -1031,11 +1032,11 @@ type PlanningCtx struct {
10311032
// query).
10321033
subOrPostQuery bool
10331034

1034-
// mustUseLeafTxn, if set, indicates that this PlanningCtx is used to handle
1035+
// flowConcurrency will be non-zero when this PlanningCtx is used to handle
10351036
// one of the plans that will run in parallel with other plans. As such, the
10361037
// DistSQL planner will need to use the LeafTxn (even if it's not needed
10371038
// based on other "regular" factors).
1038-
mustUseLeafTxn bool
1039+
flowConcurrency distsql.ConcurrencyKind
10391040

10401041
// onFlowCleanup contains non-nil functions that will be called after the
10411042
// local flow finished running and is being cleaned up. It allows us to
@@ -4371,7 +4372,7 @@ func (dsp *DistSQLPlanner) wrapPlan(
43714372
// expecting is in fact RowsAffected. RowsAffected statements return a single
43724373
// row with the number of rows affected by the statement, and are the only
43734374
// types of statement where it's valid to invoke a plan's fast path.
4374-
wrapper := newPlanNodeToRowSource(
4375+
wrapper, err := newPlanNodeToRowSource(
43754376
n,
43764377
runParams{
43774378
extendedEvalCtx: &evalCtx,
@@ -4380,6 +4381,9 @@ func (dsp *DistSQLPlanner) wrapPlan(
43804381
useFastPath,
43814382
firstNotWrapped,
43824383
)
4384+
if err != nil {
4385+
return nil, err
4386+
}
43834387

43844388
localProcIdx := p.AddLocalProcessor(wrapper)
43854389
var input []execinfrapb.InputSyncSpec

0 commit comments

Comments
 (0)