github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/distsql/server.go (about) 1 // Copyright 2016 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 distsql 12 13 import ( 14 "context" 15 "io" 16 "sync" 17 "time" 18 19 "github.com/cockroachdb/cockroach/pkg/gossip" 20 "github.com/cockroachdb/cockroach/pkg/kv" 21 "github.com/cockroachdb/cockroach/pkg/roachpb" 22 "github.com/cockroachdb/cockroach/pkg/server/telemetry" 23 "github.com/cockroachdb/cockroach/pkg/sql/colflow" 24 "github.com/cockroachdb/cockroach/pkg/sql/execinfra" 25 "github.com/cockroachdb/cockroach/pkg/sql/execinfrapb" 26 "github.com/cockroachdb/cockroach/pkg/sql/flowinfra" 27 "github.com/cockroachdb/cockroach/pkg/sql/lex" 28 "github.com/cockroachdb/cockroach/pkg/sql/rowflow" 29 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 30 "github.com/cockroachdb/cockroach/pkg/sql/sessiondata" 31 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 32 "github.com/cockroachdb/cockroach/pkg/sql/sqltelemetry" 33 "github.com/cockroachdb/cockroach/pkg/sql/sqlutil" 34 "github.com/cockroachdb/cockroach/pkg/util/contextutil" 35 "github.com/cockroachdb/cockroach/pkg/util/envutil" 36 "github.com/cockroachdb/cockroach/pkg/util/log" 37 "github.com/cockroachdb/cockroach/pkg/util/mon" 38 "github.com/cockroachdb/cockroach/pkg/util/timeutil" 39 "github.com/cockroachdb/cockroach/pkg/util/tracing" 40 "github.com/cockroachdb/errors" 41 "github.com/cockroachdb/logtags" 42 "github.com/opentracing/opentracing-go" 43 ) 44 45 // minFlowDrainWait is the minimum amount of time a draining server allows for 46 // any incoming flows to be registered. It acts as a grace period in which the 47 // draining server waits for its gossiped draining state to be received by other 48 // nodes. 49 const minFlowDrainWait = 1 * time.Second 50 51 // MultiTenancyIssueNo is the issue tracking DistSQL's Gossip and 52 // NodeID dependencies. 53 // 54 // See https://github.com/cockroachdb/cockroach/issues/47900. 55 const MultiTenancyIssueNo = 47900 56 57 var noteworthyMemoryUsageBytes = envutil.EnvOrDefaultInt64("COCKROACH_NOTEWORTHY_DISTSQL_MEMORY_USAGE", 1024*1024 /* 1MB */) 58 59 // ServerImpl implements the server for the distributed SQL APIs. 60 type ServerImpl struct { 61 execinfra.ServerConfig 62 flowRegistry *flowinfra.FlowRegistry 63 flowScheduler *flowinfra.FlowScheduler 64 memMonitor mon.BytesMonitor 65 regexpCache *tree.RegexpCache 66 } 67 68 var _ execinfrapb.DistSQLServer = &ServerImpl{} 69 70 // NewServer instantiates a DistSQLServer. 71 func NewServer(ctx context.Context, cfg execinfra.ServerConfig) *ServerImpl { 72 ds := &ServerImpl{ 73 ServerConfig: cfg, 74 regexpCache: tree.NewRegexpCache(512), 75 flowRegistry: flowinfra.NewFlowRegistry(cfg.NodeID.SQLInstanceID()), 76 flowScheduler: flowinfra.NewFlowScheduler(cfg.AmbientContext, cfg.Stopper, cfg.Settings, cfg.Metrics), 77 memMonitor: mon.MakeMonitor( 78 "distsql", 79 mon.MemoryResource, 80 cfg.Metrics.CurBytesCount, 81 cfg.Metrics.MaxBytesHist, 82 -1, /* increment: use default block size */ 83 noteworthyMemoryUsageBytes, 84 cfg.Settings, 85 ), 86 } 87 ds.memMonitor.Start(ctx, cfg.ParentMemoryMonitor, mon.BoundAccount{}) 88 return ds 89 } 90 91 // Start launches workers for the server. 92 func (ds *ServerImpl) Start() { 93 // Gossip the version info so that other nodes don't plan incompatible flows 94 // for us. 95 if g, ok := ds.ServerConfig.Gossip.Optional(MultiTenancyIssueNo); ok { 96 if nodeID, ok := ds.ServerConfig.NodeID.OptionalNodeID(); ok { 97 if err := g.AddInfoProto( 98 gossip.MakeDistSQLNodeVersionKey(nodeID), 99 &execinfrapb.DistSQLVersionGossipInfo{ 100 Version: execinfra.Version, 101 MinAcceptedVersion: execinfra.MinAcceptedVersion, 102 }, 103 0, // ttl - no expiration 104 ); err != nil { 105 panic(err) 106 } 107 } 108 } 109 110 if err := ds.setDraining(false); err != nil { 111 panic(err) 112 } 113 114 ds.flowScheduler.Start() 115 } 116 117 // Drain changes the node's draining state through gossip and drains the 118 // server's flowRegistry. See flowRegistry.Drain for more details. 119 func (ds *ServerImpl) Drain( 120 ctx context.Context, flowDrainWait time.Duration, reporter func(int, string), 121 ) { 122 if err := ds.setDraining(true); err != nil { 123 log.Warningf(ctx, "unable to gossip distsql draining state: %s", err) 124 } 125 126 flowWait := flowDrainWait 127 minWait := minFlowDrainWait 128 if ds.ServerConfig.TestingKnobs.DrainFast { 129 flowWait = 0 130 minWait = 0 131 } else if g, ok := ds.Gossip.Optional(MultiTenancyIssueNo); !ok || len(g.Outgoing()) == 0 { 132 // If there is only one node in the cluster (us), there's no need to 133 // wait a minimum time for the draining state to be gossiped. 134 minWait = 0 135 } 136 ds.flowRegistry.Drain(flowWait, minWait, reporter) 137 } 138 139 // setDraining changes the node's draining state through gossip to the provided 140 // state. 141 func (ds *ServerImpl) setDraining(drain bool) error { 142 nodeID, ok := ds.ServerConfig.NodeID.OptionalNodeID() 143 if !ok { 144 // Ignore draining requests when running on behalf of a tenant. 145 // NB: intentionally swallow the error or the server will fatal. 146 _ = MultiTenancyIssueNo // related issue 147 return nil 148 } 149 if g, ok := ds.ServerConfig.Gossip.Optional(MultiTenancyIssueNo); ok { 150 return g.AddInfoProto( 151 gossip.MakeDistSQLDrainingKey(nodeID), 152 &execinfrapb.DistSQLDrainingInfo{ 153 Draining: drain, 154 }, 155 0, // ttl - no expiration 156 ) 157 } 158 return nil 159 } 160 161 // FlowVerIsCompatible checks a flow's version is compatible with this node's 162 // DistSQL version. 163 func FlowVerIsCompatible( 164 flowVer, minAcceptedVersion, serverVersion execinfrapb.DistSQLVersion, 165 ) bool { 166 return flowVer >= minAcceptedVersion && flowVer <= serverVersion 167 } 168 169 // setupFlow creates a Flow. 170 // 171 // Args: 172 // localState: Specifies if the flow runs entirely on this node and, if it does, 173 // specifies the txn and other attributes. 174 // 175 // Note: unless an error is returned, the returned context contains a span that 176 // must be finished through Flow.Cleanup. 177 func (ds *ServerImpl) setupFlow( 178 ctx context.Context, 179 parentSpan opentracing.Span, 180 parentMonitor *mon.BytesMonitor, 181 req *execinfrapb.SetupFlowRequest, 182 syncFlowConsumer execinfra.RowReceiver, 183 localState LocalState, 184 ) (context.Context, flowinfra.Flow, error) { 185 if !FlowVerIsCompatible(req.Version, execinfra.MinAcceptedVersion, execinfra.Version) { 186 err := errors.Errorf( 187 "version mismatch in flow request: %d; this node accepts %d through %d", 188 req.Version, execinfra.MinAcceptedVersion, execinfra.Version, 189 ) 190 log.Warningf(ctx, "%v", err) 191 return ctx, nil, err 192 } 193 194 const opName = "flow" 195 var sp opentracing.Span 196 if parentSpan == nil { 197 sp = ds.Tracer.(*tracing.Tracer).StartRootSpan( 198 opName, logtags.FromContext(ctx), tracing.NonRecordableSpan) 199 } else if localState.IsLocal { 200 // If we're a local flow, we don't need a "follows from" relationship: we're 201 // going to run this flow synchronously. 202 // TODO(andrei): localState.IsLocal is not quite the right thing to use. 203 // If that field is unset, we might still want to create a child span if 204 // this flow is run synchronously. 205 sp = tracing.StartChildSpan(opName, parentSpan, logtags.FromContext(ctx), false /* separateRecording */) 206 } else { 207 // We use FollowsFrom because the flow's span outlives the SetupFlow request. 208 // TODO(andrei): We should use something more efficient than StartSpan; we 209 // should use AmbientContext.AnnotateCtxWithSpan() but that interface 210 // doesn't currently support FollowsFrom relationships. 211 sp = ds.Tracer.StartSpan( 212 opName, 213 opentracing.FollowsFrom(parentSpan.Context()), 214 tracing.LogTagsFromCtx(ctx), 215 ) 216 } 217 // sp will be Finish()ed by Flow.Cleanup(). 218 ctx = opentracing.ContextWithSpan(ctx, sp) 219 220 // The monitor opened here is closed in Flow.Cleanup(). 221 monitor := mon.MakeMonitor( 222 "flow", 223 mon.MemoryResource, 224 ds.Metrics.CurBytesCount, 225 ds.Metrics.MaxBytesHist, 226 -1, /* use default block size */ 227 noteworthyMemoryUsageBytes, 228 ds.Settings, 229 ) 230 monitor.Start(ctx, parentMonitor, mon.BoundAccount{}) 231 232 makeLeaf := func(req *execinfrapb.SetupFlowRequest) (*kv.Txn, error) { 233 tis := req.LeafTxnInputState 234 if tis == nil { 235 // This must be a flow running for some bulk-io operation that doesn't use 236 // a txn. 237 return nil, nil 238 } 239 if tis.Txn.Status != roachpb.PENDING { 240 return nil, errors.AssertionFailedf("cannot create flow in non-PENDING txn: %s", 241 tis.Txn) 242 } 243 // The flow will run in a LeafTxn because we do not want each distributed 244 // Txn to heartbeat the transaction. 245 return kv.NewLeafTxn(ctx, ds.DB, req.Flow.Gateway, tis), nil 246 } 247 248 var evalCtx *tree.EvalContext 249 var leafTxn *kv.Txn 250 if localState.EvalContext != nil { 251 evalCtx = localState.EvalContext 252 evalCtx.Mon = &monitor 253 } else { 254 if localState.IsLocal { 255 return nil, nil, errors.AssertionFailedf( 256 "EvalContext expected to be populated when IsLocal is set") 257 } 258 259 location, err := timeutil.TimeZoneStringToLocation( 260 req.EvalContext.Location, 261 timeutil.TimeZoneStringToLocationISO8601Standard, 262 ) 263 if err != nil { 264 tracing.FinishSpan(sp) 265 return ctx, nil, err 266 } 267 268 var be lex.BytesEncodeFormat 269 switch req.EvalContext.BytesEncodeFormat { 270 case execinfrapb.BytesEncodeFormat_HEX: 271 be = lex.BytesEncodeHex 272 case execinfrapb.BytesEncodeFormat_ESCAPE: 273 be = lex.BytesEncodeEscape 274 case execinfrapb.BytesEncodeFormat_BASE64: 275 be = lex.BytesEncodeBase64 276 default: 277 return nil, nil, errors.AssertionFailedf("unknown byte encode format: %s", 278 errors.Safe(req.EvalContext.BytesEncodeFormat)) 279 } 280 sd := &sessiondata.SessionData{ 281 ApplicationName: req.EvalContext.ApplicationName, 282 Database: req.EvalContext.Database, 283 User: req.EvalContext.User, 284 SearchPath: sessiondata.MakeSearchPath(req.EvalContext.SearchPath).WithTemporarySchemaName(req.EvalContext.TemporarySchemaName), 285 SequenceState: sessiondata.NewSequenceState(), 286 DataConversion: sessiondata.DataConversionConfig{ 287 Location: location, 288 BytesEncodeFormat: be, 289 ExtraFloatDigits: int(req.EvalContext.ExtraFloatDigits), 290 }, 291 VectorizeMode: sessiondata.VectorizeExecMode(req.EvalContext.Vectorize), 292 } 293 ie := &lazyInternalExecutor{ 294 newInternalExecutor: func() sqlutil.InternalExecutor { 295 return ds.SessionBoundInternalExecutorFactory(ctx, sd) 296 }, 297 } 298 299 // It's important to populate evalCtx.Txn early. We'll write it again in the 300 // f.SetTxn() call below, but by then it will already have been captured by 301 // processors. 302 leafTxn, err = makeLeaf(req) 303 if err != nil { 304 return nil, nil, err 305 } 306 evalCtx = &tree.EvalContext{ 307 Settings: ds.ServerConfig.Settings, 308 SessionData: sd, 309 ClusterID: ds.ServerConfig.ClusterID.Get(), 310 ClusterName: ds.ServerConfig.ClusterName, 311 NodeID: ds.ServerConfig.NodeID, 312 Codec: ds.ServerConfig.Codec, 313 ReCache: ds.regexpCache, 314 Mon: &monitor, 315 // Most processors will override this Context with their own context in 316 // ProcessorBase. StartInternal(). 317 Context: ctx, 318 Planner: &sqlbase.DummyEvalPlanner{}, 319 PrivilegedAccessor: &sqlbase.DummyPrivilegedAccessor{}, 320 SessionAccessor: &sqlbase.DummySessionAccessor{}, 321 ClientNoticeSender: &sqlbase.DummyClientNoticeSender{}, 322 Sequence: &sqlbase.DummySequenceOperators{}, 323 Tenant: &sqlbase.DummyTenantOperator{}, 324 InternalExecutor: ie, 325 Txn: leafTxn, 326 } 327 evalCtx.SetStmtTimestamp(timeutil.Unix(0 /* sec */, req.EvalContext.StmtTimestampNanos)) 328 evalCtx.SetTxnTimestamp(timeutil.Unix(0 /* sec */, req.EvalContext.TxnTimestampNanos)) 329 var haveSequences bool 330 for _, seq := range req.EvalContext.SeqState.Seqs { 331 evalCtx.SessionData.SequenceState.RecordValue(seq.SeqID, seq.LatestVal) 332 haveSequences = true 333 } 334 if haveSequences { 335 evalCtx.SessionData.SequenceState.SetLastSequenceIncremented( 336 *req.EvalContext.SeqState.LastSeqIncremented) 337 } 338 } 339 340 // TODO(radu): we should sanity check some of these fields. 341 flowCtx := execinfra.FlowCtx{ 342 AmbientContext: ds.AmbientContext, 343 Cfg: &ds.ServerConfig, 344 ID: req.Flow.FlowID, 345 EvalCtx: evalCtx, 346 NodeID: ds.ServerConfig.NodeID, 347 TraceKV: req.TraceKV, 348 Local: localState.IsLocal, 349 } 350 // req always contains the desired vectorize mode, regardless of whether we 351 // have non-nil localState.EvalContext. We don't want to update EvalContext 352 // itself when the vectorize mode needs to be changed because we would need 353 // to restore the original value which can have data races under stress. 354 isVectorized := sessiondata.VectorizeExecMode(req.EvalContext.Vectorize) != sessiondata.VectorizeOff 355 f := newFlow(flowCtx, ds.flowRegistry, syncFlowConsumer, localState.LocalProcs, isVectorized) 356 opt := flowinfra.FuseNormally 357 if localState.IsLocal { 358 // If there's no remote flows, fuse everything. This is needed in order for 359 // us to be able to use the RootTxn for the flow 's execution; the RootTxn 360 // doesn't allow for concurrent operations. Local flows with mutations need 361 // to use the RootTxn. 362 opt = flowinfra.FuseAggressively 363 } 364 365 var err error 366 if ctx, err = f.Setup(ctx, &req.Flow, opt); err != nil { 367 log.Errorf(ctx, "error setting up flow: %s", err) 368 // Flow.Cleanup will not be called, so we have to close the memory monitor 369 // and finish the span manually. 370 monitor.Stop(ctx) 371 tracing.FinishSpan(sp) 372 ctx = opentracing.ContextWithSpan(ctx, nil) 373 return ctx, nil, err 374 } 375 if !f.IsLocal() { 376 flowCtx.AddLogTag("f", f.GetFlowCtx().ID.Short()) 377 flowCtx.AnnotateCtx(ctx) 378 telemetry.Inc(sqltelemetry.DistSQLExecCounter) 379 } 380 if f.IsVectorized() { 381 telemetry.Inc(sqltelemetry.VecExecCounter) 382 } 383 384 // Figure out what txn the flow needs to run in, if any. For gateway flows 385 // that have no remote flows and also no concurrency, the txn comes from 386 // localState.Txn. Otherwise, we create a txn based on the request's 387 // LeafTxnInputState. 388 var txn *kv.Txn 389 if localState.IsLocal && !f.ConcurrentExecution() { 390 txn = localState.Txn 391 } else { 392 // If I haven't created the leaf already, do it now. 393 if leafTxn == nil { 394 var err error 395 leafTxn, err = makeLeaf(req) 396 if err != nil { 397 return nil, nil, err 398 } 399 } 400 txn = leafTxn 401 } 402 // TODO(andrei): We're about to overwrite f.EvalCtx.Txn, but the existing 403 // field has already been captured by various processors and operators that 404 // have already made a copy of the EvalCtx. In case this is not the gateway, 405 // we had already set the LeafTxn on the EvalCtx above, so it's OK. In case 406 // this is the gateway, if we're running with the RootTxn, then again it was 407 // set above so it's fine. If we're using a LeafTxn on the gateway, though, 408 // then the processors have erroneously captured the Root. See #41992. 409 f.SetTxn(txn) 410 411 return ctx, f, nil 412 } 413 414 func newFlow( 415 flowCtx execinfra.FlowCtx, 416 flowReg *flowinfra.FlowRegistry, 417 syncFlowConsumer execinfra.RowReceiver, 418 localProcessors []execinfra.LocalProcessor, 419 isVectorized bool, 420 ) flowinfra.Flow { 421 base := flowinfra.NewFlowBase(flowCtx, flowReg, syncFlowConsumer, localProcessors) 422 if isVectorized { 423 return colflow.NewVectorizedFlow(base) 424 } 425 return rowflow.NewRowBasedFlow(base) 426 } 427 428 // SetupSyncFlow sets up a synchronous flow, connecting the sync response 429 // output stream to the given RowReceiver. The flow is not started. The flow 430 // will be associated with the given context. 431 // Note: the returned context contains a span that must be finished through 432 // Flow.Cleanup. 433 func (ds *ServerImpl) SetupSyncFlow( 434 ctx context.Context, 435 parentMonitor *mon.BytesMonitor, 436 req *execinfrapb.SetupFlowRequest, 437 output execinfra.RowReceiver, 438 ) (context.Context, flowinfra.Flow, error) { 439 ctx, f, err := ds.setupFlow(ds.AnnotateCtx(ctx), opentracing.SpanFromContext(ctx), parentMonitor, 440 req, output, LocalState{}) 441 if err != nil { 442 return nil, nil, err 443 } 444 return ctx, f, err 445 } 446 447 // LocalState carries information that is required to set up a flow with wrapped 448 // planNodes. 449 type LocalState struct { 450 EvalContext *tree.EvalContext 451 452 // IsLocal is set if the flow is running on the gateway and there are no 453 // remote flows. 454 IsLocal bool 455 456 // Txn is filled in on the gateway only. It is the RootTxn that the query is running in. 457 // This will be used directly by the flow if the flow has no concurrency and IsLocal is set. 458 // If there is concurrency, a LeafTxn will be created. 459 Txn *kv.Txn 460 461 ///////////////////////////////////////////// 462 // Fields below are empty if IsLocal == false 463 ///////////////////////////////////////////// 464 465 // LocalProcs is an array of planNodeToRowSource processors. It's in order and 466 // will be indexed into by the RowSourceIdx field in LocalPlanNodeSpec. 467 LocalProcs []execinfra.LocalProcessor 468 } 469 470 // SetupLocalSyncFlow sets up a synchronous flow on the current (planning) node. 471 // It's used by the gateway node to set up the flows local to it. 472 // It's the same as SetupSyncFlow except it takes the localState. 473 func (ds *ServerImpl) SetupLocalSyncFlow( 474 ctx context.Context, 475 parentMonitor *mon.BytesMonitor, 476 req *execinfrapb.SetupFlowRequest, 477 output execinfra.RowReceiver, 478 localState LocalState, 479 ) (context.Context, flowinfra.Flow, error) { 480 ctx, f, err := ds.setupFlow(ctx, opentracing.SpanFromContext(ctx), parentMonitor, req, output, 481 localState) 482 if err != nil { 483 return nil, nil, err 484 } 485 return ctx, f, err 486 } 487 488 // RunSyncFlow is part of the DistSQLServer interface. 489 func (ds *ServerImpl) RunSyncFlow(stream execinfrapb.DistSQL_RunSyncFlowServer) error { 490 // Set up the outgoing mailbox for the stream. 491 mbox := flowinfra.NewOutboxSyncFlowStream(stream) 492 493 firstMsg, err := stream.Recv() 494 if err != nil { 495 return err 496 } 497 if firstMsg.SetupFlowRequest == nil { 498 return errors.AssertionFailedf("first message in RunSyncFlow doesn't contain SetupFlowRequest") 499 } 500 req := firstMsg.SetupFlowRequest 501 ctx, f, err := ds.SetupSyncFlow(stream.Context(), &ds.memMonitor, req, mbox) 502 if err != nil { 503 return err 504 } 505 mbox.SetFlowCtx(f.GetFlowCtx()) 506 507 if err := ds.Stopper.RunTask(ctx, "distsql.ServerImpl: sync flow", func(ctx context.Context) { 508 ctx, ctxCancel := contextutil.WithCancel(ctx) 509 defer ctxCancel() 510 f.AddStartable(mbox) 511 ds.Metrics.FlowStart() 512 if err := f.Run(ctx, func() {}); err != nil { 513 log.Fatalf(ctx, "unexpected error from syncFlow.Start(): %s "+ 514 "The error should have gone to the consumer.", err) 515 } 516 f.Cleanup(ctx) 517 ds.Metrics.FlowStop() 518 }); err != nil { 519 return err 520 } 521 return mbox.Err() 522 } 523 524 // SetupFlow is part of the DistSQLServer interface. 525 func (ds *ServerImpl) SetupFlow( 526 ctx context.Context, req *execinfrapb.SetupFlowRequest, 527 ) (*execinfrapb.SimpleResponse, error) { 528 log.VEventf(ctx, 1, "received SetupFlow request from n%v for flow %v", req.Flow.Gateway, req.Flow.FlowID) 529 parentSpan := opentracing.SpanFromContext(ctx) 530 531 // Note: the passed context will be canceled when this RPC completes, so we 532 // can't associate it with the flow. 533 ctx = ds.AnnotateCtx(context.Background()) 534 ctx, f, err := ds.setupFlow(ctx, parentSpan, &ds.memMonitor, req, nil /* syncFlowConsumer */, LocalState{}) 535 if err == nil { 536 err = ds.flowScheduler.ScheduleFlow(ctx, f) 537 } 538 if err != nil { 539 // We return flow deployment errors in the response so that they are 540 // packaged correctly over the wire. If we return them directly to this 541 // function, they become part of an rpc error. 542 return &execinfrapb.SimpleResponse{Error: execinfrapb.NewError(ctx, err)}, nil 543 } 544 return &execinfrapb.SimpleResponse{}, nil 545 } 546 547 func (ds *ServerImpl) flowStreamInt( 548 ctx context.Context, stream execinfrapb.DistSQL_FlowStreamServer, 549 ) error { 550 // Receive the first message. 551 msg, err := stream.Recv() 552 if err != nil { 553 if err == io.EOF { 554 return errors.AssertionFailedf("missing header message") 555 } 556 return err 557 } 558 if msg.Header == nil { 559 return errors.AssertionFailedf("no header in first message") 560 } 561 flowID := msg.Header.FlowID 562 streamID := msg.Header.StreamID 563 if log.V(1) { 564 log.Infof(ctx, "connecting inbound stream %s/%d", flowID.Short(), streamID) 565 } 566 f, streamStrategy, cleanup, err := ds.flowRegistry.ConnectInboundStream( 567 ctx, flowID, streamID, stream, flowinfra.SettingFlowStreamTimeout.Get(&ds.Settings.SV), 568 ) 569 if err != nil { 570 return err 571 } 572 defer cleanup() 573 log.VEventf(ctx, 1, "connected inbound stream %s/%d", flowID.Short(), streamID) 574 return streamStrategy.Run(f.AnnotateCtx(ctx), stream, msg, f) 575 } 576 577 // FlowStream is part of the DistSQLServer interface. 578 func (ds *ServerImpl) FlowStream(stream execinfrapb.DistSQL_FlowStreamServer) error { 579 ctx := ds.AnnotateCtx(stream.Context()) 580 err := ds.flowStreamInt(ctx, stream) 581 if err != nil && log.V(2) { 582 // flowStreamInt may return an error during normal operation (e.g. a flow 583 // was canceled as part of a graceful teardown). Log this error at the INFO 584 // level behind a verbose flag for visibility. 585 log.Infof(ctx, "%v", err) 586 } 587 return err 588 } 589 590 // lazyInternalExecutor is a tree.InternalExecutor that initializes 591 // itself only on the first call to QueryRow. 592 type lazyInternalExecutor struct { 593 // Set when an internal executor has been initialized. 594 sqlutil.InternalExecutor 595 596 // Used for initializing the internal executor exactly once. 597 once sync.Once 598 599 // newInternalExecutor must be set when instantiating a lazyInternalExecutor, 600 // it provides an internal executor to use when necessary. 601 newInternalExecutor func() sqlutil.InternalExecutor 602 } 603 604 var _ sqlutil.InternalExecutor = &lazyInternalExecutor{} 605 606 func (ie *lazyInternalExecutor) QueryRowEx( 607 ctx context.Context, 608 opName string, 609 txn *kv.Txn, 610 opts sqlbase.InternalExecutorSessionDataOverride, 611 stmt string, 612 qargs ...interface{}, 613 ) (tree.Datums, error) { 614 ie.once.Do(func() { 615 ie.InternalExecutor = ie.newInternalExecutor() 616 }) 617 return ie.InternalExecutor.QueryRowEx(ctx, opName, txn, opts, stmt, qargs...) 618 } 619 620 func (ie *lazyInternalExecutor) QueryRow( 621 ctx context.Context, opName string, txn *kv.Txn, stmt string, qargs ...interface{}, 622 ) (tree.Datums, error) { 623 ie.once.Do(func() { 624 ie.InternalExecutor = ie.newInternalExecutor() 625 }) 626 return ie.InternalExecutor.QueryRow(ctx, opName, txn, stmt, qargs...) 627 }