@@ -56,7 +56,12 @@ ScannerContext::ScannerContext(
5656 RuntimeState* state, pipeline::ScanLocalStateBase* local_state,
5757 const TupleDescriptor* output_tuple_desc, const RowDescriptor* output_row_descriptor,
5858 const std::list<std::shared_ptr<vectorized::ScannerDelegate>>& scanners, int64_t limit_,
59- std::shared_ptr<pipeline::Dependency> dependency, int parallism_of_scan_operator)
59+ std::shared_ptr<pipeline::Dependency> dependency
60+ #ifdef BE_TEST
61+ ,
62+ int num_parallel_instances
63+ #endif
64+ )
6065 : HasTaskExecutionCtx(state),
6166 _state (state),
6267 _local_state(local_state),
@@ -67,9 +72,20 @@ ScannerContext::ScannerContext(
6772 _batch_size(state->batch_size ()),
6873 limit(limit_),
6974 _all_scanners(scanners.begin(), scanners.end()),
70- _parallism_of_scan_operator(parallism_of_scan_operator),
71- _min_scan_concurrency_of_scan_scheduler(_state->min_scan_concurrency_of_scan_scheduler ()),
72- _min_scan_concurrency(_state->min_scan_concurrency_of_scanner ()) {
75+ #ifndef BE_TEST
76+ _scanner_scheduler (local_state->scan_scheduler (state)),
77+ _min_scan_concurrency_of_scan_scheduler(local_state->min_scanners_concurrency (state)),
78+ _max_scan_concurrency(std::min(local_state->max_scanners_concurrency (state),
79+ cast_set<int>(scanners.size()))),
80+ #else
81+ _scanner_scheduler (state->get_query_ctx ()->get_scan_scheduler()),
82+ _min_scan_concurrency_of_scan_scheduler(0 ),
83+ _max_scan_concurrency(num_parallel_instances),
84+ #endif
85+ _min_scan_concurrency (local_state->should_run_serial ()
86+ ? 1
87+ : std::min(_state->min_scan_concurrency_of_scanner (),
88+ _max_scan_concurrency)) {
7389 DCHECK (_state != nullptr );
7490 DCHECK (_output_row_descriptor == nullptr ||
7591 _output_row_descriptor->tuple_descriptors ().size () == 1 );
@@ -106,14 +122,6 @@ Status ScannerContext::init() {
106122 auto scanner = _all_scanners.front ().lock ();
107123 DCHECK (scanner != nullptr );
108124
109- // TODO: Maybe need refactor.
110- // A query could have remote scan task and local scan task at the same time.
111- // So we need to compute the _scanner_scheduler in each scan operator instead of query context.
112- if (scanner->_scanner ->get_storage_type () == TabletStorageType::STORAGE_TYPE_LOCAL) {
113- _scanner_scheduler = _state->get_query_ctx ()->get_scan_scheduler ();
114- } else {
115- _scanner_scheduler = _state->get_query_ctx ()->get_remote_scan_scheduler ();
116- }
117125 if (auto * task_executor_scheduler =
118126 dynamic_cast <TaskExecutorSimplifiedScanScheduler*>(_scanner_scheduler)) {
119127 std::shared_ptr<TaskExecutor> task_executor = task_executor_scheduler->task_executor ();
@@ -132,43 +140,11 @@ Status ScannerContext::init() {
132140 // Provide more memory for wide tables, increase proportionally by multiples of 300
133141 _max_bytes_in_queue *= _output_tuple_desc->slots ().size () / 300 + 1 ;
134142
135- if (_min_scan_concurrency_of_scan_scheduler == 0 ) {
136- // _scanner_scheduler->get_max_threads() is setted by workload group.
137- _min_scan_concurrency_of_scan_scheduler = 2 * _scanner_scheduler->get_max_threads ();
138- }
139-
140143 if (_all_scanners.empty ()) {
141144 _is_finished = true ;
142145 _set_scanner_done ();
143146 }
144147
145- // The overall target of our system is to make full utilization of the resources.
146- // At the same time, we dont want too many tasks are queued by scheduler, that is not necessary.
147- // Each scan operator can submit _max_scan_concurrency scanner to scheduelr if scheduler has enough resource.
148- // So that for a single query, we can make sure it could make full utilization of the resource.
149- _max_scan_concurrency = _state->num_scanner_threads ();
150- if (_max_scan_concurrency == 0 ) {
151- // Why this is safe:
152- /*
153- 1. If num cpu cores is less than or equal to 24:
154- _max_concurrency_of_scan_scheduler will be 96. _parallism_of_scan_operator will be 1 or C/2.
155- so _max_scan_concurrency will be 96 or (96 * 2 / C).
156- For a single scan node, most scanner it can submit will be 96 or (96 * 2 / C) * (C / 2) which is 96 too.
157- So a single scan node could make full utilization of the resource without sumbiting all its tasks.
158- 2. If num cpu cores greater than 24:
159- _max_concurrency_of_scan_scheduler will be 4 * C. _parallism_of_scan_operator will be 1 or C/2.
160- so _max_scan_concurrency will be 4 * C or (4 * C * 2 / C).
161- For a single scan node, most scanner it can submit will be 4 * C or (4 * C * 2 / C) * (C / 2) which is 4 * C too.
162-
163- So, in all situations, when there is only one scan node, it could make full utilization of the resource.
164- */
165- _max_scan_concurrency =
166- _min_scan_concurrency_of_scan_scheduler / _parallism_of_scan_operator;
167- _max_scan_concurrency = _max_scan_concurrency == 0 ? 1 : _max_scan_concurrency;
168- }
169-
170- _max_scan_concurrency = std::min (_max_scan_concurrency, (int32_t )_pending_scanners.size ());
171-
172148 // when user not specify scan_thread_num, so we can try downgrade _max_thread_num.
173149 // becaue we found in a table with 5k columns, column reader may ocuppy too much memory.
174150 // you can refer https://github.com/apache/doris/issues/35340 for details.
@@ -191,15 +167,6 @@ Status ScannerContext::init() {
191167 }
192168 }
193169
194- // For select * from table limit 10; should just use one thread.
195- if (_local_state->should_run_serial ()) {
196- _max_scan_concurrency = 1 ;
197- _min_scan_concurrency = 1 ;
198- }
199-
200- // Avoid corner case.
201- _min_scan_concurrency = std::min (_min_scan_concurrency, _max_scan_concurrency);
202-
203170 COUNTER_SET (_local_state->_max_scan_concurrency , (int64_t )_max_scan_concurrency);
204171 COUNTER_SET (_local_state->_min_scan_concurrency , (int64_t )_min_scan_concurrency);
205172
0 commit comments