MCPcopy Create free account
hub / github.com/ClickHouse/ClickHouse / initializeExecution

Method initializeExecution

src/Processors/Executors/PipelineExecutor.cpp:578–627  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

576}
577
578void PipelineExecutor::initializeExecution(size_t num_threads, bool concurrency_control)
579{
580 is_execution_initialized = true;
581 tryUpdateExecutionStatus(ExecutionStatus::NotStarted, ExecutionStatus::Executing);
582
583 /// Capture the ceiling so the upscaling block can cap `setMax` at this value.
584 max_pipeline_threads = num_threads;
585
586 /// Read the flag ONCE. A config reload mid-initialization would otherwise split a
587 /// single query between lazy and eager strategies (e.g. allocate lazy with max=1 but
588 /// then initialize desired_threads=num_threads, stranding subsequent setMax as a no-op).
589 const bool lazy_allocation = ConcurrencyControl::instance().getLazyAllocation();
590
591 cpu_slots = allocateCPU(num_threads, concurrency_control, lazy_allocation);
592
593 /// If rollback flag is off, we used eager allocate(1, num_threads) and will not call
594 /// setMax in the upscaling block (nothing to grow). Initialize desired_threads
595 /// to the full ceiling so the growth check in the block becomes a no-op.
596 desired_threads = lazy_allocation ? 1 : num_threads;
597
598 Queue queue;
599 Queue async_queue;
600 graph->initializeExecution(queue, async_queue);
601
602 /// use_threads should reflect number of thread spawned and can grow with tasks.upscale(...).
603 /// Starting from 1 instead of 0 is to tackle the single thread scenario, where no upscale() will
604 /// be invoked but actually 1 thread used.
605 tasks.init(num_threads, 1, cpu_slots, profile_processors, trace_processors, read_progress_callback.get());
606 const size_t initial_parallel = tasks.fill(queue, async_queue);
607
608 /// Initial queued parallelism never routes through `pushTasks`, so size setMax here to
609 /// cover it. For multi-source pipelines (e.g. UNION ALL of N subqueries) this prevents
610 /// the pipeline from being stuck single-threaded if the master's first task happens not
611 /// to push more work. Only matters on the lazy path; the eager path already has the full
612 /// ceiling. `initial_parallel` is the total target — the master thread is one of its
613 /// consumers, no +1 needed.
614 if (lazy_allocation && initial_parallel > 1)
615 {
616 std::lock_guard lock(spawn_mutex);
617 const size_t target = std::min<size_t>(max_pipeline_threads, initial_parallel);
618 if (target > desired_threads)
619 {
620 desired_threads = target;
621 cpu_slots->setMax(target);
622 }
623 }
624
625 if (num_threads > 1)
626 pool = std::make_unique<ThreadPool>(CurrentMetrics::QueryPipelineExecutorThreads, CurrentMetrics::QueryPipelineExecutorThreadsActive, CurrentMetrics::QueryPipelineExecutorThreadsScheduled, num_threads);
627}
628
629void PipelineExecutor::spawnThreads(AcquiredSlotPtr slot)
630{

Callers

nothing calls this directly

Calls 5

getLazyAllocationMethod · 0.80
initMethod · 0.45
getMethod · 0.45
fillMethod · 0.45
setMaxMethod · 0.45

Tested by

no test coverage detected