Line | Count | Source |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | |
18 | | #include "exec/scan/olap_scanner.h" |
19 | | |
20 | | #include <gen_cpp/Descriptors_types.h> |
21 | | #include <gen_cpp/PlanNodes_types.h> |
22 | | #include <gen_cpp/Types_types.h> |
23 | | #include <glog/logging.h> |
24 | | #include <stdlib.h> |
25 | | #include <thrift/protocol/TDebugProtocol.h> |
26 | | |
27 | | #include <algorithm> |
28 | | #include <atomic> |
29 | | #include <iterator> |
30 | | #include <ostream> |
31 | | #include <set> |
32 | | |
33 | | #include "cloud/cloud_storage_engine.h" |
34 | | #include "cloud/cloud_tablet_hotspot.h" |
35 | | #include "cloud/config.h" |
36 | | #include "common/config.h" |
37 | | #include "common/consts.h" |
38 | | #include "common/logging.h" |
39 | | #include "common/metrics/doris_metrics.h" |
40 | | #include "core/block/block.h" |
41 | | #include "core/data_type/data_type_number.h" |
42 | | #include "exec/common/variant_util.h" |
43 | | #include "exec/operator/olap_scan_operator.h" |
44 | | #include "exec/scan/scan_node.h" |
45 | | #include "exprs/function_filter.h" |
46 | | #include "exprs/vexpr.h" |
47 | | #include "exprs/vexpr_context.h" |
48 | | #include "io/cache/block_file_cache_profile.h" |
49 | | #include "io/io_common.h" |
50 | | #include "runtime/descriptors.h" |
51 | | #include "runtime/exec_env.h" |
52 | | #include "runtime/query_context.h" |
53 | | #include "runtime/runtime_profile.h" |
54 | | #include "runtime/runtime_state.h" |
55 | | #include "service/backend_options.h" |
56 | | #include "storage/binlog.h" |
57 | | #include "storage/id_manager.h" |
58 | | #include "storage/index/inverted/inverted_index_profile.h" |
59 | | #include "storage/iterator/block_reader.h" |
60 | | #include "storage/olap_common.h" |
61 | | #include "storage/olap_tuple.h" |
62 | | #include "storage/olap_utils.h" |
63 | | #include "storage/predicate/predicate_creator.h" |
64 | | #include "storage/storage_engine.h" |
65 | | #include "storage/tablet/tablet_schema.h" |
66 | | #ifndef NDEBUG |
67 | | #include "util/debug_points.h" |
68 | | #endif |
69 | | #include "util/json/path_in_data.h" |
70 | | |
71 | | namespace doris { |
72 | | #include "common/compile_check_avoid_begin.h" |
73 | | |
74 | | using ReadSource = TabletReadSource; |
75 | | |
76 | | OlapScanner::OlapScanner(ScanLocalStateBase* parent, OlapScanner::Params&& params) |
77 | 1.27M | : Scanner(params.state, parent, params.limit, params.profile), |
78 | 1.27M | _key_ranges(std::move(params.key_ranges)), |
79 | 1.27M | _tablet_reader_params({.tablet = std::move(params.tablet), |
80 | 1.27M | .tablet_schema {}, |
81 | 1.27M | .reader_type = params.read_row_binlog ? ReaderType::READER_BINLOG |
82 | 1.27M | : ReaderType::READER_QUERY, |
83 | 1.27M | .aggregation = params.aggregation, |
84 | 1.27M | .version = {0, params.version}, |
85 | 1.27M | .start_key {}, |
86 | 1.27M | .end_key {}, |
87 | 1.27M | .predicates {}, |
88 | 1.27M | .function_filters {}, |
89 | 1.27M | .delete_predicates {}, |
90 | 1.27M | .target_cast_type_for_variants {}, |
91 | 1.27M | .all_access_paths {}, |
92 | 1.27M | .predicate_access_paths {}, |
93 | 1.27M | .rs_splits {}, |
94 | 1.27M | .return_columns {}, |
95 | 1.27M | .tso_predicate_column_id {}, |
96 | 1.27M | .output_columns {}, |
97 | 1.27M | .extra_columns {}, |
98 | 1.27M | .profile = nullptr, |
99 | 1.27M | .runtime_state = nullptr, |
100 | 1.27M | .table_name = std::move(params.table_name), |
101 | 1.27M | .partition_name = std::move(params.partition_name), |
102 | 1.27M | .origin_return_columns = nullptr, |
103 | 1.27M | .tablet_columns_convert_to_null_set = nullptr, |
104 | 1.27M | .push_down_agg_type_opt = TPushAggOp::NONE, |
105 | 1.27M | .common_expr_ctxs_push_down {}, |
106 | 1.27M | .topn_filter_source_node_ids {}, |
107 | 1.27M | .key_group_cluster_key_idxes {}, |
108 | 1.27M | .virtual_column_exprs {}, |
109 | 1.27M | .score_runtime {}, |
110 | 1.27M | .collection_statistics {}, |
111 | 1.27M | .ann_topn_runtime {}, |
112 | 1.27M | .condition_cache_digest = parent->get_condition_cache_digest(), |
113 | 1.27M | .binlog_scan_type = params.binlog_scan_type}), |
114 | 1.27M | _start_tso(params.start_tso), |
115 | 1.27M | _end_tso(params.end_tso), |
116 | 1.27M | _initial_file_cache_stats(std::move(params.initial_file_cache_stats)) { |
117 | 1.27M | _tablet_reader_params.set_read_source(std::move(params.read_source), |
118 | 1.27M | _state->skip_delete_bitmap()); |
119 | 1.27M | _has_prepared = false; |
120 | 1.27M | _vector_search_params = params.state->get_vector_search_params(); |
121 | 1.27M | } |
122 | | |
123 | | static std::string read_columns_to_string(TabletSchemaSPtr tablet_schema, |
124 | 4.81k | const std::vector<uint32_t>& read_columns) { |
125 | | // avoid too long for one line, |
126 | | // it is hard to display in `show profile` stmt if one line is too long. |
127 | 4.81k | const int col_per_line = 10; |
128 | 4.81k | int i = 0; |
129 | 4.81k | std::string read_columns_string; |
130 | 4.81k | read_columns_string += "["; |
131 | 20.8k | for (auto it = read_columns.cbegin(); it != read_columns.cend(); it++) { |
132 | 16.0k | if (it != read_columns.cbegin()) { |
133 | 11.2k | read_columns_string += ", "; |
134 | 11.2k | } |
135 | 16.0k | read_columns_string += tablet_schema->columns().at(*it)->name(); |
136 | 16.0k | if (i >= col_per_line) { |
137 | 13 | read_columns_string += "\n"; |
138 | 13 | i = 0; |
139 | 15.9k | } else { |
140 | 15.9k | ++i; |
141 | 15.9k | } |
142 | 16.0k | } |
143 | 4.81k | read_columns_string += "]"; |
144 | 4.81k | return read_columns_string; |
145 | 4.81k | } |
146 | | |
147 | 2.60M | static bool has_file_cache_statistics(const io::FileCacheStatistics& stats) { |
148 | 2.60M | return stats.num_local_io_total != 0 || stats.num_remote_io_total != 0 || |
149 | 2.60M | stats.num_peer_io_total != 0 || stats.local_io_timer != 0 || |
150 | 2.60M | stats.bytes_read_from_local != 0 || stats.bytes_read_from_remote != 0 || |
151 | 2.60M | stats.bytes_read_from_peer != 0 || stats.remote_io_timer != 0 || |
152 | 2.60M | stats.peer_io_timer != 0 || stats.remote_wait_timer != 0 || |
153 | 2.60M | stats.write_cache_io_timer != 0 || stats.bytes_write_into_cache != 0 || |
154 | 2.60M | stats.num_skip_cache_io_total != 0 || stats.read_cache_file_directly_timer != 0 || |
155 | 2.60M | stats.cache_get_or_set_timer != 0 || stats.lock_wait_timer != 0 || |
156 | 2.60M | stats.get_timer != 0 || stats.set_timer != 0 || |
157 | 2.60M | stats.inverted_index_num_local_io_total != 0 || |
158 | 2.60M | stats.inverted_index_num_remote_io_total != 0 || |
159 | 2.60M | stats.inverted_index_num_peer_io_total != 0 || |
160 | 2.60M | stats.inverted_index_bytes_read_from_local != 0 || |
161 | 2.60M | stats.inverted_index_bytes_read_from_remote != 0 || |
162 | 2.60M | stats.inverted_index_bytes_read_from_peer != 0 || |
163 | 2.60M | stats.inverted_index_local_io_timer != 0 || stats.inverted_index_remote_io_timer != 0 || |
164 | 2.60M | stats.inverted_index_peer_io_timer != 0 || stats.inverted_index_io_timer != 0; |
165 | 2.60M | } |
166 | | |
167 | | io::IOContext build_score_runtime_collection_io_context(RuntimeState* state, ReaderType reader_type, |
168 | | int64_t expiration_time, |
169 | 42 | io::FileCacheStatistics* file_cache_stats) { |
170 | 42 | io::IOContext io_ctx { |
171 | 42 | .reader_type = reader_type, |
172 | 42 | .expiration_time = expiration_time, |
173 | 42 | .query_id = &state->query_id(), |
174 | 42 | .file_cache_stats = file_cache_stats, |
175 | 42 | .is_inverted_index = true, |
176 | 42 | .table_name = "", |
177 | 42 | .partition_name = "", |
178 | 42 | }; |
179 | 42 | if (auto* query_ctx = state->get_query_ctx(); query_ctx != nullptr) { |
180 | 41 | io_ctx.remote_scan_cache_write_limiter = query_ctx->remote_scan_cache_write_limiter(); |
181 | 41 | } |
182 | 42 | return io_ctx; |
183 | 42 | } |
184 | | |
185 | 1.27M | Status OlapScanner::_prepare_impl() { |
186 | 1.27M | auto* local_state = static_cast<OlapScanLocalState*>(_local_state); |
187 | 1.27M | auto& tablet = _tablet_reader_params.tablet; |
188 | 1.27M | auto& tablet_schema = _tablet_reader_params.tablet_schema; |
189 | 1.27M | DBUG_EXECUTE_IF("CloudTablet.capture_rs_readers.return.e-230", { |
190 | 1.27M | LOG_WARNING("CloudTablet.capture_rs_readers.return e-230 init") |
191 | 1.27M | .tag("tablet_id", tablet->tablet_id()); |
192 | 1.27M | return Status::Error<false>(-230, "injected error"); |
193 | 1.27M | }); |
194 | | |
195 | 1.27M | for (auto& ctx : local_state->_common_expr_ctxs_push_down) { |
196 | 21.6k | VExprContextSPtr context; |
197 | 21.6k | RETURN_IF_ERROR(ctx->clone(_state, context)); |
198 | 21.6k | _common_expr_ctxs_push_down.emplace_back(context); |
199 | 21.6k | context->prepare_ann_range_search(_vector_search_params); |
200 | 21.6k | } |
201 | | |
202 | 1.27M | for (auto pair : local_state->_slot_id_to_virtual_column_expr) { |
203 | | // Scanner will be executed in a different thread, so we need to clone the context. |
204 | 502 | VExprContextSPtr context; |
205 | 502 | RETURN_IF_ERROR(pair.second->clone(_state, context)); |
206 | 502 | _slot_id_to_virtual_column_expr[pair.first] = context; |
207 | 502 | } |
208 | | |
209 | 1.27M | _score_runtime = local_state->_score_runtime; |
210 | | // All scanners share the same ann_topn_runtime. |
211 | 1.27M | _ann_topn_runtime = local_state->_ann_topn_runtime; |
212 | | |
213 | | // set limit to reduce end of rowset and segment mem use |
214 | 1.27M | _tablet_reader = std::make_unique<BlockReader>(); |
215 | | // batch size is passed down to segment iterator, use _state->batch_size() |
216 | | // instead of _parent->limit(), because if _parent->limit() is a very small |
217 | | // value (e.g. select a from t where a .. and b ... limit 1), |
218 | | // it will be very slow when reading data in segment iterator |
219 | 1.27M | _tablet_reader->set_batch_size(_state->batch_size()); |
220 | | // Adaptive batch size: pass byte-budget settings to the storage reader. |
221 | | // The reader still uses batch_size() as the row ceiling. |
222 | 1.27M | _tablet_reader->set_preferred_block_size_bytes(_state->preferred_block_size_bytes()); |
223 | 1.27M | { |
224 | 1.27M | TOlapScanNode& olap_scan_node = local_state->olap_scan_node(); |
225 | 1.27M | TabletSchemaSPtr source_tablet_schema = |
226 | 1.27M | _tablet_reader_params.reader_type == ReaderType::READER_BINLOG |
227 | 1.27M | ? tablet->row_binlog_tablet_schema() |
228 | 1.27M | : tablet->tablet_schema(); |
229 | | |
230 | 1.27M | tablet_schema = std::make_shared<TabletSchema>(); |
231 | 1.27M | tablet_schema->copy_from(*source_tablet_schema); |
232 | 1.27M | if (olap_scan_node.__isset.columns_desc && !olap_scan_node.columns_desc.empty() && |
233 | 1.27M | olap_scan_node.columns_desc[0].col_unique_id >= 0) { |
234 | 1.27M | tablet_schema->clear_columns(); |
235 | 20.4M | for (const auto& column_desc : olap_scan_node.columns_desc) { |
236 | 20.4M | tablet_schema->append_column(TabletColumn(column_desc)); |
237 | 20.4M | } |
238 | 1.27M | if (olap_scan_node.__isset.schema_version) { |
239 | 1.27M | tablet_schema->set_schema_version(olap_scan_node.schema_version); |
240 | 1.27M | } |
241 | 1.27M | } |
242 | 1.27M | if (olap_scan_node.__isset.indexes_desc) { |
243 | 1.27M | tablet_schema->update_indexes_from_thrift(olap_scan_node.indexes_desc); |
244 | 1.27M | } |
245 | | |
246 | 1.27M | if (_tablet_reader_params.rs_splits.empty()) { |
247 | | // Non-pipeline mode, Tablet : Scanner = 1 : 1 |
248 | | // acquire tablet rowset readers at the beginning of the scan node |
249 | | // to prevent this case: when there are lots of olap scanners to run for example 10000 |
250 | | // the rowsets maybe compacted when the last olap scanner starts |
251 | 0 | ReadSource read_source; |
252 | |
|
253 | 0 | if (config::is_cloud_mode()) { |
254 | | // FIXME(plat1ko): Avoid pointer cast |
255 | 0 | ExecEnv::GetInstance()->storage_engine().to_cloud().tablet_hotspot().count(*tablet); |
256 | 0 | } |
257 | |
|
258 | 0 | auto maybe_read_source = tablet->capture_read_source( |
259 | 0 | _tablet_reader_params.version, |
260 | 0 | { |
261 | 0 | .skip_missing_versions = _state->skip_missing_version(), |
262 | 0 | .enable_fetch_rowsets_from_peers = |
263 | 0 | config::enable_fetch_rowsets_from_peer_replicas, |
264 | 0 | .capture_row_binlog = |
265 | 0 | _tablet_reader_params.reader_type == ReaderType::READER_BINLOG, |
266 | 0 | .enable_prefer_cached_rowset = |
267 | 0 | config::is_cloud_mode() ? _state->enable_prefer_cached_rowset() |
268 | 0 | : false, |
269 | 0 | .query_freshness_tolerance_ms = |
270 | 0 | config::is_cloud_mode() ? _state->query_freshness_tolerance_ms() |
271 | 0 | : -1, |
272 | 0 | }); |
273 | 0 | if (!maybe_read_source) { |
274 | 0 | LOG(WARNING) << "fail to init reader. res=" << maybe_read_source.error(); |
275 | 0 | return maybe_read_source.error(); |
276 | 0 | } |
277 | 0 | read_source = std::move(maybe_read_source.value()); |
278 | |
|
279 | 0 | if (config::enable_mow_verbose_log && tablet->enable_unique_key_merge_on_write()) { |
280 | 0 | LOG_INFO("finish capture_rs_readers for tablet={}, query_id={}", |
281 | 0 | tablet->tablet_id(), print_id(_state->query_id())); |
282 | 0 | } |
283 | |
|
284 | 0 | if (!_state->skip_delete_predicate()) { |
285 | 0 | read_source.fill_delete_predicates(); |
286 | 0 | } |
287 | 0 | _tablet_reader_params.set_read_source(std::move(read_source)); |
288 | 0 | } |
289 | | |
290 | | // Initialize tablet_reader_params |
291 | 1.27M | RETURN_IF_ERROR(_init_tablet_reader_params( |
292 | 1.27M | local_state->_parent->cast<OlapScanOperatorX>()._slot_id_to_slot_desc, _key_ranges, |
293 | 1.27M | local_state->_slot_id_to_predicates, local_state->_push_down_functions)); |
294 | 1.27M | } |
295 | | |
296 | | // add read columns in profile |
297 | 1.27M | if (_state->enable_profile()) { |
298 | 4.82k | _profile->add_info_string("ReadColumns", |
299 | 4.82k | read_columns_to_string(tablet_schema, _return_columns)); |
300 | 4.82k | } |
301 | | |
302 | 1.27M | if (_tablet_reader_params.score_runtime) { |
303 | 40 | SCOPED_TIMER(local_state->_statistics_collect_timer); |
304 | 40 | _tablet_reader_params.collection_statistics = std::make_shared<CollectionStatistics>(); |
305 | | |
306 | 40 | auto io_ctx = build_score_runtime_collection_io_context( |
307 | 40 | _state, _tablet_reader_params.reader_type, tablet->ttl_seconds(), |
308 | 40 | &_tablet_reader->mutable_stats()->file_cache_stats); |
309 | 40 | io_ctx.table_name = _tablet_reader_params.table_name; |
310 | 40 | io_ctx.partition_name = _tablet_reader_params.partition_name; |
311 | | |
312 | 40 | RETURN_IF_ERROR(_tablet_reader_params.collection_statistics->collect( |
313 | 40 | _state, _tablet_reader_params.rs_splits, _tablet_reader_params.tablet_schema, |
314 | 40 | _tablet_reader_params.common_expr_ctxs_push_down, &io_ctx)); |
315 | 40 | } |
316 | | |
317 | 1.27M | _has_prepared = true; |
318 | 1.27M | return Status::OK(); |
319 | 1.27M | } |
320 | | |
321 | 1.27M | Status OlapScanner::_open_impl(RuntimeState* state) { |
322 | 1.27M | RETURN_IF_ERROR(Scanner::_open_impl(state)); |
323 | 1.27M | SCOPED_TIMER(_local_state->cast<OlapScanLocalState>()._reader_init_timer); |
324 | | |
325 | 1.27M | auto res = _tablet_reader->init(_tablet_reader_params); |
326 | 1.27M | if (!res.ok()) { |
327 | | // init() also runs the eager first-row read that evaluates pushed-down expressions, |
328 | | // so res may be a data/expression error rather than a storage failure. Keep its own |
329 | | // message and only append the tablet/backend, without a misleading storage wording. |
330 | 62 | res.append(". tablet=" + std::to_string(_tablet_reader_params.tablet->tablet_id()) + |
331 | 62 | ", backend=" + BackendOptions::get_localhost()); |
332 | 62 | return res; |
333 | 62 | } |
334 | 1.27M | _tablet_reader->mutable_stats()->file_cache_stats.merge_from(_initial_file_cache_stats); |
335 | | |
336 | | // Do not hold rs_splits any more to release memory. |
337 | 1.27M | _tablet_reader_params.rs_splits.clear(); |
338 | | |
339 | 1.27M | return Status::OK(); |
340 | 1.27M | } |
341 | | |
342 | | // For binlog partition-based incremental read. Pushes down [start_tso, end_tso] range |
343 | | // predicates onto the TSO column. If the TSO column is not already returned, pass it as |
344 | | // a storage-only predicate column instead of widening scan output. |
345 | 1.27M | Status OlapScanner::_init_tso_predicates() { |
346 | 1.27M | if (!_start_tso.has_value() && !_end_tso.has_value()) { |
347 | 1.27M | return Status::OK(); |
348 | 1.27M | } |
349 | | |
350 | 18.4E | auto& tablet_schema = _tablet_reader_params.tablet_schema; |
351 | 18.4E | int32_t tso_index = _tablet_reader_params.reader_type == ReaderType::READER_BINLOG |
352 | 18.4E | ? tablet_schema->binlog_tso_col_idx() |
353 | 18.4E | : tablet_schema->commit_tso_col_idx(); |
354 | 18.4E | const std::string& column_name = _tablet_reader_params.reader_type == ReaderType::READER_BINLOG |
355 | 18.4E | ? BINLOG_TSO_COL |
356 | 18.4E | : COMMIT_TSO_COL; |
357 | 18.4E | if (tso_index < 0) { |
358 | 0 | return Status::InternalError("Column {} not found in tablet schema after append", |
359 | 0 | column_name); |
360 | 0 | } |
361 | | |
362 | 18.4E | auto data_type = std::make_shared<DataTypeInt64>(); |
363 | 18.4E | if (_start_tso.has_value()) { |
364 | 0 | Field start_value = Field::create_field<TYPE_BIGINT>(*_start_tso); |
365 | 0 | _tablet_reader_params.predicates.push_back(create_comparison_predicate<PredicateType::GT>( |
366 | 0 | tso_index, column_name, data_type, start_value, false)); |
367 | 0 | } |
368 | 18.4E | if (_end_tso.has_value()) { |
369 | 0 | Field end_value = Field::create_field<TYPE_BIGINT>(*_end_tso); |
370 | 0 | _tablet_reader_params.predicates.push_back(create_comparison_predicate<PredicateType::LE>( |
371 | 0 | tso_index, column_name, data_type, end_value, false)); |
372 | 0 | } |
373 | | |
374 | | // The storage-layer statistics fast path (VStatisticsIterator, picked when |
375 | | // push_down_agg_type is COUNT/MINMAX) bypasses SegmentIterator and returns raw |
376 | | // segment row counts without applying any column predicate. The commit-tso |
377 | | // predicate injected above is row-level, so the fast path would both miscount |
378 | | // (ignoring commit_tso <= snapshot_tso) and crash on a column-count DCHECK when |
379 | | // the tso predicate column is not in return_columns. Disable it here, matching |
380 | | // the binlog DETAIL/MIN_DELTA handling. |
381 | 18.4E | _tablet_reader_params.push_down_agg_type_opt = TPushAggOp::NONE; |
382 | | |
383 | 18.4E | if (std::find(_tablet_reader_params.return_columns.begin(), |
384 | 18.4E | _tablet_reader_params.return_columns.end(), |
385 | 18.4E | tso_index) == _tablet_reader_params.return_columns.end()) { |
386 | 0 | _tablet_reader_params.tso_predicate_column_id = static_cast<ColumnId>(tso_index); |
387 | 0 | } |
388 | | |
389 | 18.4E | return Status::OK(); |
390 | 18.4E | } |
391 | | |
392 | | // it will be called under tablet read lock because capture rs readers need |
393 | | Status OlapScanner::_init_tablet_reader_params( |
394 | | const phmap::flat_hash_map<int, SlotDescriptor*>& slot_id_to_slot_desc, |
395 | | const std::vector<OlapScanRange*>& key_ranges, |
396 | | const phmap::flat_hash_map<int, std::vector<std::shared_ptr<ColumnPredicate>>>& |
397 | | slot_to_predicates, |
398 | 1.27M | const std::vector<FunctionFilter>& function_filters) { |
399 | | // if the table with rowset [0-x] or [0-1] [2-y], and [0-1] is empty |
400 | 1.27M | const bool single_version = _tablet_reader_params.has_single_version(); |
401 | | |
402 | 1.27M | auto* olap_local_state = static_cast<OlapScanLocalState*>(_local_state); |
403 | 1.27M | bool read_mor_as_dup = olap_local_state->olap_scan_node().__isset.read_mor_as_dup && |
404 | 1.27M | olap_local_state->olap_scan_node().read_mor_as_dup; |
405 | 1.27M | if (_state->skip_storage_engine_merge() || read_mor_as_dup) { |
406 | 43 | _tablet_reader_params.direct_mode = true; |
407 | 43 | _tablet_reader_params.aggregation = true; |
408 | 1.27M | } else { |
409 | 1.27M | auto push_down_agg_type = _local_state->get_push_down_agg_type(); |
410 | 1.27M | _tablet_reader_params.direct_mode = _tablet_reader_params.aggregation || single_version || |
411 | 1.27M | (push_down_agg_type != TPushAggOp::NONE && |
412 | 10.6k | push_down_agg_type != TPushAggOp::COUNT_ON_INDEX); |
413 | 1.27M | } |
414 | | |
415 | 1.27M | RETURN_IF_ERROR(_init_variant_columns()); |
416 | 1.27M | RETURN_IF_ERROR(_init_return_columns()); |
417 | | |
418 | 1.27M | _tablet_reader_params.push_down_agg_type_opt = _local_state->get_push_down_agg_type(); |
419 | | |
420 | | // Binlog DETAIL/MIN_DELTA scans widen `return_columns` with key/tso/op/before |
421 | | // columns to drive the row-level merge in BlockReader. The storage-layer |
422 | | // statistics fast path (VStatisticsIterator, picked when push_down_agg_type |
423 | | // is COUNT/MINMAX) bypasses SegmentIterator entirely, returning raw segment |
424 | | // row counts without binlog op filtering and with a schema that does not |
425 | | // match the widened read schema. The result is both wrong (raw segment |
426 | | // count != binlog row count) and unsafe (column-count DCHECK fires inside |
427 | | // VStatisticsIterator::next_batch). Disable the fast path for these scans. |
428 | 1.27M | if (_tablet_reader_params.binlog_scan_type == TBinlogScanType::DETAIL || |
429 | 1.27M | _tablet_reader_params.binlog_scan_type == TBinlogScanType::MIN_DELTA) { |
430 | 0 | _tablet_reader_params.push_down_agg_type_opt = TPushAggOp::NONE; |
431 | 0 | } |
432 | | |
433 | 1.27M | _tablet_reader_params.common_expr_ctxs_push_down = _common_expr_ctxs_push_down; |
434 | 1.27M | _tablet_reader_params.virtual_column_exprs = _virtual_column_exprs; |
435 | 1.27M | _tablet_reader_params.score_runtime = _score_runtime; |
436 | 1.27M | _tablet_reader_params.output_columns = olap_local_state->_output_column_ids; |
437 | 1.27M | _tablet_reader_params.ann_topn_runtime = _ann_topn_runtime; |
438 | 1.27M | for (const auto& ele : olap_local_state->_cast_types_for_variants) { |
439 | 1.40k | _tablet_reader_params.target_cast_type_for_variants[ele.first] = ele.second; |
440 | 1.40k | }; |
441 | 1.27M | auto& tablet_schema = _tablet_reader_params.tablet_schema; |
442 | 10.4M | for (auto& predicates : slot_to_predicates) { |
443 | 10.4M | const int sid = predicates.first; |
444 | 10.4M | DCHECK(slot_id_to_slot_desc.contains(sid)); |
445 | 10.4M | int32_t index = |
446 | 10.4M | tablet_schema->field_index(slot_id_to_slot_desc.find(sid)->second->col_name()); |
447 | 10.4M | if (index < 0) { |
448 | 0 | throw Exception( |
449 | 0 | Status::InternalError("Column {} not found in tablet schema", |
450 | 0 | slot_id_to_slot_desc.find(sid)->second->col_name())); |
451 | 0 | } |
452 | 10.4M | for (auto& predicate : predicates.second) { |
453 | 1.01M | _tablet_reader_params.predicates.push_back(predicate->clone(index)); |
454 | 1.01M | } |
455 | 10.4M | } |
456 | | |
457 | 1.27M | std::copy(function_filters.cbegin(), function_filters.cend(), |
458 | 1.27M | std::inserter(_tablet_reader_params.function_filters, |
459 | 1.27M | _tablet_reader_params.function_filters.begin())); |
460 | | |
461 | | // Merge the columns in delete predicate that not in latest schema in to current tablet schema |
462 | 1.27M | for (auto& del_pred : _tablet_reader_params.delete_predicates) { |
463 | 6.22k | tablet_schema->merge_dropped_columns(*del_pred->tablet_schema()); |
464 | 6.22k | } |
465 | | |
466 | | // Push key ranges to the tablet reader. |
467 | | // Skip the "full scan" placeholder (has_lower_bound == false) — when no key |
468 | | // predicates exist, start_key/end_key remain empty and the reader does a full scan. |
469 | 1.82M | for (auto* key_range : key_ranges) { |
470 | 1.82M | if (!key_range->has_lower_bound) { |
471 | 153k | continue; |
472 | 153k | } |
473 | | |
474 | 1.67M | _tablet_reader_params.start_key_include = key_range->begin_include; |
475 | 1.67M | _tablet_reader_params.end_key_include = key_range->end_include; |
476 | | |
477 | 1.67M | _tablet_reader_params.start_key.push_back(key_range->begin_scan_range); |
478 | 1.67M | _tablet_reader_params.end_key.push_back(key_range->end_scan_range); |
479 | 1.67M | } |
480 | | |
481 | 1.27M | _tablet_reader_params.profile = _local_state->custom_profile(); |
482 | 1.27M | _tablet_reader_params.runtime_state = _state; |
483 | 1.27M | { |
484 | 1.27M | auto* olap_scan_local_state = &_local_state->cast<OlapScanLocalState>(); |
485 | 1.27M | TOlapScanNode& olap_scan_node = olap_scan_local_state->olap_scan_node(); |
486 | 1.27M | if (_tablet_reader_params.table_name.empty() && olap_scan_node.__isset.table_name) { |
487 | 3 | _tablet_reader_params.table_name = olap_scan_node.table_name; |
488 | 3 | } |
489 | 1.27M | if (_tablet_reader_params.partition_name.empty() && olap_scan_node.__isset.partition_name) { |
490 | 3 | _tablet_reader_params.partition_name = olap_scan_node.partition_name; |
491 | 3 | } |
492 | 1.27M | } |
493 | | |
494 | 1.27M | _tablet_reader_params.origin_return_columns = &_return_columns; |
495 | 1.27M | _tablet_reader_params.tablet_columns_convert_to_null_set = &_tablet_columns_convert_to_null_set; |
496 | | |
497 | 1.27M | auto add_return_column_if_absent = [&](uint32_t cid) { |
498 | 0 | if (std::find(_tablet_reader_params.return_columns.begin(), |
499 | 0 | _tablet_reader_params.return_columns.end(), |
500 | 0 | cid) == _tablet_reader_params.return_columns.end()) { |
501 | 0 | _tablet_reader_params.return_columns.push_back(cid); |
502 | 0 | } |
503 | 0 | }; |
504 | | |
505 | | // For row-binlog scans that emit BEFORE/AFTER pairs (MIN_DELTA / DETAIL), we must read |
506 | | // every key column, every requested value column, the binlog meta columns (tso / op) |
507 | | // and their __BEFORE__ mirrors, so the BlockReader can reconstruct change rows. |
508 | 1.27M | const bool need_before_columns = |
509 | 1.27M | _tablet_reader_params.binlog_scan_type == TBinlogScanType::MIN_DELTA || |
510 | 1.27M | _tablet_reader_params.binlog_scan_type == TBinlogScanType::DETAIL; |
511 | 1.27M | if (need_before_columns) { |
512 | 0 | for (size_t i = 0; i < tablet_schema->num_key_columns(); ++i) { |
513 | 0 | add_return_column_if_absent(static_cast<uint32_t>(i)); |
514 | 0 | } |
515 | 0 | for (auto cid : _return_columns) { |
516 | 0 | add_return_column_if_absent(cid); |
517 | 0 | } |
518 | |
|
519 | 0 | if (int32_t tso_idx = tablet_schema->binlog_tso_col_idx(); tso_idx >= 0) { |
520 | 0 | add_return_column_if_absent(static_cast<uint32_t>(tso_idx)); |
521 | 0 | } |
522 | 0 | if (int32_t op_idx = tablet_schema->binlog_op_col_idx(); op_idx >= 0) { |
523 | 0 | add_return_column_if_absent(static_cast<uint32_t>(op_idx)); |
524 | 0 | } |
525 | |
|
526 | 0 | for (auto cid : _return_columns) { |
527 | 0 | if (cid >= tablet_schema->num_key_columns()) { |
528 | 0 | const auto& col_name = tablet_schema->column(cid).name(); |
529 | 0 | std::string before_col_name; |
530 | 0 | before_col_name.append("__BEFORE__"); |
531 | 0 | before_col_name.append(col_name); |
532 | 0 | before_col_name.append("__"); |
533 | 0 | if (int32_t before_idx = tablet_schema->field_index(before_col_name); |
534 | 0 | before_idx >= 0) { |
535 | 0 | add_return_column_if_absent(static_cast<uint32_t>(before_idx)); |
536 | 0 | } |
537 | 0 | } |
538 | 0 | } |
539 | 1.27M | } else if (_tablet_reader_params.direct_mode) { |
540 | 1.26M | _tablet_reader_params.return_columns = _return_columns; |
541 | 1.26M | } else { |
542 | | // we need to fetch all key columns to do the right aggregation on storage engine side. |
543 | 40.1k | for (size_t i = 0; i < tablet_schema->num_key_columns(); ++i) { |
544 | 28.2k | _tablet_reader_params.return_columns.push_back(i); |
545 | 28.2k | } |
546 | 60.0k | for (auto index : _return_columns) { |
547 | 60.0k | if (tablet_schema->column(index).is_key()) { |
548 | 28.1k | continue; |
549 | 28.1k | } |
550 | 31.8k | _tablet_reader_params.return_columns.push_back(index); |
551 | 31.8k | } |
552 | | // expand the sequence column |
553 | 11.9k | if (tablet_schema->has_sequence_col() || tablet_schema->has_seq_map()) { |
554 | 39 | bool has_replace_col = false; |
555 | 91 | for (auto col : _return_columns) { |
556 | 91 | if (tablet_schema->column(col).aggregation() == |
557 | 91 | FieldAggregationMethod::OLAP_FIELD_AGGREGATION_REPLACE) { |
558 | 40 | has_replace_col = true; |
559 | 40 | break; |
560 | 40 | } |
561 | 91 | } |
562 | 39 | if (auto sequence_col_idx = tablet_schema->sequence_col_idx(); |
563 | 40 | has_replace_col && tablet_schema->has_sequence_col() && |
564 | 39 | std::find(_return_columns.begin(), _return_columns.end(), sequence_col_idx) == |
565 | 28 | _return_columns.end()) { |
566 | 16 | _tablet_reader_params.return_columns.push_back(sequence_col_idx); |
567 | 16 | } |
568 | 40 | if (has_replace_col) { |
569 | 40 | const auto& val_to_seq = tablet_schema->value_col_idx_to_seq_col_idx(); |
570 | 40 | std::set<uint32_t> return_seq_columns; |
571 | | |
572 | 241 | for (auto col : _tablet_reader_params.return_columns) { |
573 | | // we need to add the necessary sequence column in _return_columns, and |
574 | | // Avoid adding the same seq column twice |
575 | 241 | const auto val_iter = val_to_seq.find(col); |
576 | 241 | if (val_iter != val_to_seq.end()) { |
577 | 42 | auto seq = val_iter->second; |
578 | 42 | if (std::find(_tablet_reader_params.return_columns.begin(), |
579 | 42 | _tablet_reader_params.return_columns.end(), |
580 | 42 | seq) == _tablet_reader_params.return_columns.end()) { |
581 | 4 | return_seq_columns.insert(seq); |
582 | 4 | } |
583 | 42 | } |
584 | 241 | } |
585 | 40 | _tablet_reader_params.return_columns.insert( |
586 | 40 | std::end(_tablet_reader_params.return_columns), |
587 | 40 | std::begin(return_seq_columns), std::end(return_seq_columns)); |
588 | 40 | } |
589 | 39 | } |
590 | 11.9k | } |
591 | | |
592 | 1.27M | RETURN_IF_ERROR(_init_tso_predicates()); |
593 | | |
594 | | // For any row-binlog scan, force the storage layer to deliver rows strictly in primary-key |
595 | | // order so the BlockReader can group consecutive same-key changes (MIN_DELTA) or emit |
596 | | // BEFORE/AFTER pairs in deterministic order (DETAIL). Disable ORDER BY / TopN pushdowns |
597 | | // and reset their related params, since they would otherwise re-order the stream. |
598 | 1.27M | if (_tablet_reader_params.binlog_scan_type != TBinlogScanType::NONE) { |
599 | 0 | _tablet_reader_params.read_orderby_key = true; |
600 | 0 | _tablet_reader_params.read_orderby_key_reverse = false; |
601 | 0 | _tablet_reader_params.read_orderby_key_num_prefix_columns = 0; |
602 | 0 | _tablet_reader_params.read_orderby_key_limit = 0; |
603 | 0 | _tablet_reader_params.force_key_ordered_read = true; |
604 | 0 | _tablet_reader_params.topn_filter_source_node_ids.clear(); |
605 | 0 | } |
606 | | |
607 | 1.27M | _tablet_reader_params.use_page_cache = _state->enable_page_cache(); |
608 | | |
609 | 1.27M | DBUG_EXECUTE_IF("NewOlapScanner::_init_tablet_reader_params.block", DBUG_BLOCK); |
610 | | |
611 | 1.27M | if (!_state->skip_storage_engine_merge()) { |
612 | 1.27M | auto* olap_scan_local_state = &_local_state->cast<OlapScanLocalState>(); |
613 | 1.27M | TOlapScanNode& olap_scan_node = olap_scan_local_state->olap_scan_node(); |
614 | | |
615 | | // Set MOR value predicate pushdown flag |
616 | 1.27M | if (olap_scan_node.__isset.enable_mor_value_predicate_pushdown && |
617 | 1.27M | olap_scan_node.enable_mor_value_predicate_pushdown) { |
618 | 25 | _tablet_reader_params.enable_mor_value_predicate_pushdown = true; |
619 | 25 | } |
620 | | |
621 | 1.27M | const bool has_key_topn = |
622 | 1.27M | olap_scan_node.__isset.sort_info && !olap_scan_node.sort_info.is_asc_order.empty(); |
623 | 1.27M | if (has_key_topn) { |
624 | 3.58k | _limit = _local_state->limit_per_scanner(); |
625 | 3.58k | } |
626 | | |
627 | 1.27M | const bool no_runtime_filters = _total_rf_num == 0; |
628 | 1.27M | const bool segment_limit_enabled = _state->enable_segment_limit_pushdown(); |
629 | 1.27M | const bool storage_no_merge = olap_scan_local_state->_storage_no_merge(); |
630 | | |
631 | 1.27M | if (_limit > 0 && no_runtime_filters && segment_limit_enabled && storage_no_merge) { |
632 | 3.35k | for (const auto& conjunct : _conjuncts) { |
633 | 0 | DORIS_CHECK(!olap_scan_local_state->_check_expr_storage_filter( |
634 | 0 | conjunct->root(), OlapScanLocalState::ExprStorageFilterCheckMode:: |
635 | 0 | HAS_SEGMENT_EVALUABLE_EXPR)); |
636 | 0 | } |
637 | 3.35k | } |
638 | | |
639 | | // Segment LIMIT has only two legal states: completely disabled, or enabled after every |
640 | | // row-filtering conjunct has become a storage predicate or SegmentIterator common expr. |
641 | 1.27M | const bool can_push_down_segment_limit = _limit > 0 && no_runtime_filters && |
642 | 1.27M | _conjuncts.empty() && segment_limit_enabled && |
643 | 1.27M | storage_no_merge; |
644 | 1.27M | if (can_push_down_segment_limit) { |
645 | 3.36k | if (has_key_topn) { |
646 | 2.83k | _tablet_reader_params.read_orderby_key = true; |
647 | 2.83k | if (!olap_scan_node.sort_info.is_asc_order[0]) { |
648 | 242 | _tablet_reader_params.read_orderby_key_reverse = true; |
649 | 242 | } |
650 | 2.83k | _tablet_reader_params.read_orderby_key_num_prefix_columns = |
651 | 2.83k | olap_scan_node.sort_info.is_asc_order.size(); |
652 | 2.83k | _tablet_reader_params.read_orderby_key_limit = _limit; |
653 | 2.83k | } else { |
654 | 527 | _tablet_reader_params.general_read_limit = _limit; |
655 | 527 | } |
656 | 3.36k | } |
657 | | |
658 | 1.27M | if (_tablet_reader_params.read_orderby_key_limit > 0 || |
659 | 1.27M | _tablet_reader_params.general_read_limit > 0) { |
660 | 3.35k | DORIS_CHECK(can_push_down_segment_limit); |
661 | 3.35k | DORIS_CHECK(_conjuncts.empty()); |
662 | 3.35k | } |
663 | | |
664 | | // A key TopN scan cannot share the plain LIMIT early-stop counter. If |
665 | | // storage TopN is pushed down, each scanner must produce its full local |
666 | | // candidates. If it is not pushed down for any reason, the upper TopN |
667 | | // still needs all rows from the scan. |
668 | 1.27M | if (has_key_topn) { |
669 | 3.59k | _shared_scan_limit = nullptr; |
670 | 3.59k | if (_tablet_reader_params.read_orderby_key_limit == 0) { |
671 | 762 | _limit = -1; |
672 | 762 | } |
673 | 3.59k | } |
674 | | // Note: _shared_scan_limit is intentionally not pushed into the |
675 | | // storage layer. SegmentIterator's _process_eof() is irreversible, |
676 | | // so a concurrently-decremented atomic could reach 0 while a segment |
677 | | // still has data needed by other scanners. |
678 | | |
679 | | // set push down topn filter |
680 | 1.27M | _tablet_reader_params.topn_filter_source_node_ids = |
681 | 1.27M | olap_scan_local_state->get_topn_filter_source_node_ids(_state, true); |
682 | 1.27M | if (!_tablet_reader_params.topn_filter_source_node_ids.empty()) { |
683 | 6.27k | _tablet_reader_params.topn_filter_target_node_id = |
684 | 6.27k | olap_scan_local_state->parent()->node_id(); |
685 | 6.27k | } |
686 | 1.27M | } |
687 | | |
688 | | // If this is a Two-Phase read query, and we need to delay the release of Rowset |
689 | | // by rowset->update_delayed_expired_timestamp().This could expand the lifespan of Rowset |
690 | 1.27M | if (tablet_schema->field_index(BeConsts::ROWID_COL) >= 0) { |
691 | 0 | constexpr static int delayed_s = 60; |
692 | 0 | for (auto rs_reader : _tablet_reader_params.rs_splits) { |
693 | 0 | uint64_t delayed_expired_timestamp = |
694 | 0 | UnixSeconds() + _tablet_reader_params.runtime_state->execution_timeout() + |
695 | 0 | delayed_s; |
696 | 0 | rs_reader.rs_reader->rowset()->update_delayed_expired_timestamp( |
697 | 0 | delayed_expired_timestamp); |
698 | 0 | ExecEnv::GetInstance()->storage_engine().add_quering_rowset( |
699 | 0 | rs_reader.rs_reader->rowset()); |
700 | 0 | } |
701 | 0 | } |
702 | | |
703 | 1.27M | if (tablet_schema->has_global_row_id()) { |
704 | 9.05k | auto& id_file_map = _state->get_id_file_map(); |
705 | 15.9k | for (auto rs_reader : _tablet_reader_params.rs_splits) { |
706 | 15.9k | id_file_map->add_temp_rowset(rs_reader.rs_reader->rowset()); |
707 | 15.9k | } |
708 | 9.05k | } |
709 | | |
710 | 1.27M | return Status::OK(); |
711 | 1.27M | } |
712 | | |
713 | 1.27M | Status OlapScanner::_init_variant_columns() { |
714 | 1.27M | auto& tablet_schema = _tablet_reader_params.tablet_schema; |
715 | 1.27M | if (tablet_schema->num_variant_columns() == 0) { |
716 | 1.26M | return Status::OK(); |
717 | 1.26M | } |
718 | | // Parent column has path info to distinction from each other |
719 | 15.0k | for (auto* slot : _output_tuple_desc->slots()) { |
720 | 15.0k | if (slot->type()->get_primitive_type() == PrimitiveType::TYPE_VARIANT) { |
721 | | // Such columns are not exist in frontend schema info, so we need to |
722 | | // add them into tablet_schema for later column indexing. |
723 | 7.10k | const auto& dt_variant = |
724 | 7.10k | assert_cast<const DataTypeVariant&>(*remove_nullable(slot->type())); |
725 | 7.10k | TabletColumn subcol = TabletColumn::create_materialized_variant_column( |
726 | 7.10k | tablet_schema->column_by_uid(slot->col_unique_id()).name_lower_case(), |
727 | 7.10k | slot->column_paths(), slot->col_unique_id(), |
728 | 7.10k | dt_variant.variant_max_subcolumns_count(), dt_variant.enable_doc_mode()); |
729 | 7.10k | if (tablet_schema->field_index(*subcol.path_info_ptr()) < 0) { |
730 | 5.55k | tablet_schema->append_column(subcol, TabletSchema::ColumnType::VARIANT); |
731 | 5.55k | } |
732 | 7.10k | } |
733 | 15.0k | } |
734 | 5.96k | variant_util::inherit_column_attributes(tablet_schema); |
735 | 5.96k | return Status::OK(); |
736 | 1.27M | } |
737 | | |
738 | 1.27M | Status OlapScanner::_init_return_columns() { |
739 | | // For OLAP scan, _output_tuple_desc is the storage-aligned scan tuple |
740 | | // descriptor. extra_key_column_slot_ids marks extra key slots that are |
741 | | // present only for scan-schema alignment. For example, on an AGG table with |
742 | | // keys (k1, k2), a query returning only k2 may still scan (k1, k2); k1 is |
743 | | // an extra column and can be removed by the projection output tuple. |
744 | 13.7M | for (auto* slot : _output_tuple_desc->slots()) { |
745 | | // variant column using path to index a column |
746 | 13.7M | int32_t index = 0; |
747 | 13.7M | auto& tablet_schema = _tablet_reader_params.tablet_schema; |
748 | 13.7M | if (slot->type()->get_primitive_type() == PrimitiveType::TYPE_VARIANT) { |
749 | 7.10k | index = tablet_schema->field_index(PathInData( |
750 | 7.10k | tablet_schema->column_by_uid(slot->col_unique_id()).name_lower_case(), |
751 | 7.10k | slot->column_paths())); |
752 | 13.7M | } else { |
753 | 13.7M | index = slot->col_unique_id() >= 0 ? tablet_schema->field_index(slot->col_unique_id()) |
754 | 18.4E | : tablet_schema->field_index(slot->col_name()); |
755 | 13.7M | } |
756 | | |
757 | 13.7M | if (index < 0) { |
758 | 0 | return Status::InternalError( |
759 | 0 | "field name is invalid. field={}, field_name_to_index={}, col_unique_id={}", |
760 | 0 | slot->col_name(), tablet_schema->get_all_field_names(), slot->col_unique_id()); |
761 | 0 | } |
762 | | |
763 | 13.7M | if (slot->get_virtual_column_expr()) { |
764 | 498 | _virtual_column_exprs[index] = _slot_id_to_virtual_column_expr[slot->id()]; |
765 | | |
766 | 498 | VLOG_DEBUG << fmt::format("Virtual column, slot id: {}, cid {}, type: {}", slot->id(), |
767 | 1 | index, slot->get_data_type_ptr()->get_name()); |
768 | 498 | } |
769 | | |
770 | 13.7M | const auto& column = tablet_schema->column(index); |
771 | 13.7M | auto* olap_local_state = static_cast<OlapScanLocalState*>(_local_state); |
772 | 13.7M | const auto& olap_scan_node = olap_local_state->olap_scan_node(); |
773 | 13.7M | if (olap_scan_node.__isset.extra_key_column_slot_ids && |
774 | 13.7M | olap_scan_node.extra_key_column_slot_ids.contains(slot->id())) { |
775 | 126k | DORIS_CHECK(column.is_key()); |
776 | 126k | if (_tablet_reader_params.direct_mode) { |
777 | | // Direct readers can synthesize extra storage keys because they are only |
778 | | // placeholders before the scan projection removes them. Merge/aggregation |
779 | | // readers must still read real key values to preserve storage semantics. |
780 | 117k | _tablet_reader_params.extra_columns.insert(index); |
781 | 117k | } |
782 | 126k | } |
783 | 13.7M | int32_t unique_id = |
784 | 13.7M | column.unique_id() >= 0 ? column.unique_id() : column.parent_unique_id(); |
785 | 13.7M | if (!slot->all_access_paths().empty()) { |
786 | 85.5k | _tablet_reader_params.all_access_paths.insert({unique_id, slot->all_access_paths()}); |
787 | 85.5k | } |
788 | | |
789 | 13.7M | if (!slot->predicate_access_paths().empty()) { |
790 | 7.56k | _tablet_reader_params.predicate_access_paths.insert( |
791 | 7.56k | {unique_id, slot->predicate_access_paths()}); |
792 | 7.56k | } |
793 | | |
794 | 13.7M | if ((slot->type()->get_primitive_type() == PrimitiveType::TYPE_STRUCT || |
795 | 13.7M | slot->type()->get_primitive_type() == PrimitiveType::TYPE_MAP || |
796 | 13.7M | slot->type()->get_primitive_type() == PrimitiveType::TYPE_ARRAY) && |
797 | 13.7M | !slot->all_access_paths().empty()) { |
798 | 77.9k | tablet_schema->add_pruned_columns_data_type(column.unique_id(), slot->type()); |
799 | 77.9k | } |
800 | | |
801 | 13.7M | _return_columns.push_back(index); |
802 | 13.7M | if (slot->is_nullable() && !tablet_schema->column(index).is_nullable()) { |
803 | 0 | _tablet_columns_convert_to_null_set.emplace(index); |
804 | 13.7M | } else if (!slot->is_nullable() && tablet_schema->column(index).is_nullable()) { |
805 | 0 | return Status::Error<ErrorCode::INVALID_SCHEMA>( |
806 | 0 | "slot(id: {}, name: {})'s nullable does not match " |
807 | 0 | "column(tablet id: {}, index: {}, name: {}) ", |
808 | 0 | slot->id(), slot->col_name(), tablet_schema->table_id(), index, |
809 | 0 | tablet_schema->column(index).name()); |
810 | 0 | } |
811 | 13.7M | } |
812 | | |
813 | 1.27M | if (_return_columns.empty()) { |
814 | 0 | return Status::InternalError("failed to build storage scanner, no materialized slot!"); |
815 | 0 | } |
816 | | |
817 | 1.27M | return Status::OK(); |
818 | 1.27M | } |
819 | | |
820 | 2.64M | bool OlapScanner::check_partition_pruned() const { |
821 | 2.64M | if (!_local_state) { |
822 | 0 | return false; |
823 | 0 | } |
824 | 2.64M | return _local_state->is_partition_pruned(_tablet_reader_params.tablet->partition_id()); |
825 | 2.64M | } |
826 | | |
827 | 1.32M | doris::TabletStorageType OlapScanner::get_storage_type() { |
828 | 1.32M | if (config::is_cloud_mode()) { |
829 | | // we don't have cold storage in cloud mode, all storage is treated as local |
830 | 896k | return doris::TabletStorageType::STORAGE_TYPE_LOCAL; |
831 | 896k | } |
832 | 429k | int local_reader = 0; |
833 | 856k | for (const auto& reader : _tablet_reader_params.rs_splits) { |
834 | 856k | local_reader += reader.rs_reader->rowset()->is_local(); |
835 | 856k | } |
836 | 429k | int total_reader = _tablet_reader_params.rs_splits.size(); |
837 | | |
838 | 429k | if (local_reader == total_reader) { |
839 | 429k | return doris::TabletStorageType::STORAGE_TYPE_LOCAL; |
840 | 429k | } else if (local_reader == 0) { |
841 | 0 | return doris::TabletStorageType::STORAGE_TYPE_REMOTE; |
842 | 0 | } |
843 | 0 | return doris::TabletStorageType::STORAGE_TYPE_REMOTE_AND_LOCAL; |
844 | 429k | } |
845 | | |
846 | 1.62M | Status OlapScanner::_get_block_impl(RuntimeState* state, Block* block, bool* eof) { |
847 | | // Read one block from block reader |
848 | | // ATTN: Here we need to let the _get_block_impl method guarantee the semantics of the interface, |
849 | | // that is, eof can be set to true only when the returned block is empty. |
850 | 1.62M | RETURN_IF_ERROR(_tablet_reader->next_block_with_aggregation(block, eof)); |
851 | 1.62M | if (block->rows() > 0) { |
852 | 351k | _tablet_reader_params.tablet->read_block_count.fetch_add(1, std::memory_order_relaxed); |
853 | 351k | *eof = false; |
854 | 351k | } |
855 | 1.62M | #ifndef NDEBUG |
856 | 1.62M | RETURN_IF_ERROR(_check_ann_cache_hit_debug_points(_tablet_reader->stats())); |
857 | 1.62M | #endif |
858 | 1.62M | return Status::OK(); |
859 | 1.62M | } |
860 | | |
861 | 1.28M | Status OlapScanner::close(RuntimeState* state) { |
862 | 1.28M | if (!_try_close()) { |
863 | 150 | return Status::OK(); |
864 | 150 | } |
865 | 1.28M | RETURN_IF_ERROR(Scanner::close(state)); |
866 | 1.28M | return Status::OK(); |
867 | 1.28M | } |
868 | | |
869 | 1.32M | void OlapScanner::update_realtime_counters() { |
870 | 1.32M | if (!_has_prepared) { |
871 | | // Counter update need prepare successfully, or it maybe core. For example, olap scanner |
872 | | // will open tablet reader during prepare, if not prepare successfully, tablet reader == nullptr. |
873 | 0 | return; |
874 | 0 | } |
875 | 1.32M | OlapScanLocalState* local_state = static_cast<OlapScanLocalState*>(_local_state); |
876 | 1.32M | const OlapReaderStatistics& stats = _tablet_reader->stats(); |
877 | 1.32M | COUNTER_UPDATE(local_state->_read_compressed_counter, stats.compressed_bytes_read); |
878 | 1.32M | COUNTER_UPDATE(local_state->_read_uncompressed_counter, stats.uncompressed_bytes_read); |
879 | 1.32M | COUNTER_UPDATE(local_state->_scan_bytes, stats.uncompressed_bytes_read); |
880 | 1.32M | COUNTER_UPDATE(local_state->_scan_rows, stats.raw_rows_read); |
881 | | |
882 | | // Make sure the scan bytes and scan rows counter in audit log is the same as the counter in |
883 | | // doris metrics. |
884 | | // ScanBytes is the uncompressed bytes read from local + remote |
885 | | // bytes_read_from_local is the compressed bytes read from local |
886 | | // bytes_read_from_remote is the compressed bytes read from remote |
887 | | // scan bytes > bytes_read_from_local + bytes_read_from_remote |
888 | 1.32M | _state->get_query_ctx()->resource_ctx()->io_context()->update_scan_rows(stats.raw_rows_read); |
889 | 1.32M | _state->get_query_ctx()->resource_ctx()->io_context()->update_scan_bytes( |
890 | 1.32M | stats.uncompressed_bytes_read); |
891 | | |
892 | | // In case of no cache, we still need to update the IO stats. uncompressed bytes read == local + remote |
893 | 1.32M | if (stats.file_cache_stats.bytes_read_from_local == 0 && |
894 | 1.32M | stats.file_cache_stats.bytes_read_from_remote == 0) { |
895 | 1.09M | _state->get_query_ctx()->resource_ctx()->io_context()->update_scan_bytes_from_local_storage( |
896 | 1.09M | stats.compressed_bytes_read); |
897 | 1.09M | DorisMetrics::instance()->query_scan_bytes_from_local->increment( |
898 | 1.09M | stats.compressed_bytes_read); |
899 | 1.09M | } else { |
900 | 228k | _state->get_query_ctx()->resource_ctx()->io_context()->update_scan_bytes_from_local_storage( |
901 | 228k | stats.file_cache_stats.bytes_read_from_local); |
902 | 228k | _state->get_query_ctx() |
903 | 228k | ->resource_ctx() |
904 | 228k | ->io_context() |
905 | 228k | ->update_scan_bytes_from_remote_storage( |
906 | 228k | stats.file_cache_stats.bytes_read_from_remote); |
907 | | |
908 | 228k | DorisMetrics::instance()->query_scan_bytes_from_local->increment( |
909 | 228k | stats.file_cache_stats.bytes_read_from_local); |
910 | 228k | DorisMetrics::instance()->query_scan_bytes_from_remote->increment( |
911 | 228k | stats.file_cache_stats.bytes_read_from_remote); |
912 | 228k | } |
913 | | |
914 | 1.32M | if (has_file_cache_statistics(stats.file_cache_stats)) { |
915 | 230k | io::FileCacheProfileReporter cache_profile(local_state->_segment_profile.get()); |
916 | 230k | cache_profile.update(&stats.file_cache_stats); |
917 | 230k | _state->get_query_ctx()->resource_ctx()->io_context()->update_bytes_write_into_cache( |
918 | 230k | stats.file_cache_stats.bytes_write_into_cache); |
919 | 230k | } |
920 | | |
921 | 1.32M | _tablet_reader->mutable_stats()->compressed_bytes_read = 0; |
922 | 1.32M | _tablet_reader->mutable_stats()->uncompressed_bytes_read = 0; |
923 | 1.32M | _tablet_reader->mutable_stats()->raw_rows_read = 0; |
924 | 1.32M | _tablet_reader->mutable_stats()->file_cache_stats = {}; |
925 | 1.32M | } |
926 | | |
927 | 1.27M | void OlapScanner::_collect_profile_before_close() { |
928 | | // Please don't directly enable the profile here, we need to set QueryStatistics using the counter inside. |
929 | 1.27M | if (_has_updated_counter) { |
930 | 0 | return; |
931 | 0 | } |
932 | 1.27M | _has_updated_counter = true; |
933 | 1.27M | _tablet_reader->update_profile(_profile); |
934 | | |
935 | 1.27M | Scanner::_collect_profile_before_close(); |
936 | | |
937 | | // Update counters for OlapScanner |
938 | | // Update counters from tablet reader's stats |
939 | 1.27M | auto& stats = _tablet_reader->stats(); |
940 | 1.27M | auto* local_state = &_local_state->cast<OlapScanLocalState>(); |
941 | 1.27M | COUNTER_UPDATE(local_state->_io_timer, stats.io_ns); |
942 | 1.27M | COUNTER_UPDATE(local_state->_read_compressed_counter, stats.compressed_bytes_read); |
943 | 1.27M | COUNTER_UPDATE(local_state->_scan_bytes, stats.uncompressed_bytes_read); |
944 | 1.27M | COUNTER_UPDATE(local_state->_decompressor_timer, stats.decompress_ns); |
945 | 1.27M | COUNTER_UPDATE(local_state->_read_uncompressed_counter, stats.uncompressed_bytes_read); |
946 | 1.27M | COUNTER_UPDATE(local_state->_block_load_timer, stats.block_load_ns); |
947 | 1.27M | COUNTER_UPDATE(local_state->_block_load_counter, stats.blocks_load); |
948 | 1.27M | COUNTER_UPDATE(local_state->_block_fetch_timer, stats.block_fetch_ns); |
949 | 1.27M | COUNTER_UPDATE(local_state->_delete_bitmap_get_agg_timer, stats.delete_bitmap_get_agg_ns); |
950 | 1.27M | COUNTER_UPDATE(local_state->_scan_rows, stats.raw_rows_read); |
951 | 1.27M | COUNTER_UPDATE(local_state->_vec_cond_timer, stats.vec_cond_ns); |
952 | 1.27M | COUNTER_UPDATE(local_state->_short_cond_timer, stats.short_cond_ns); |
953 | 1.27M | COUNTER_UPDATE(local_state->_expr_filter_timer, stats.expr_filter_ns); |
954 | 1.27M | COUNTER_UPDATE(local_state->_block_init_timer, stats.block_init_ns); |
955 | 1.27M | COUNTER_UPDATE(local_state->_block_init_seek_timer, stats.block_init_seek_ns); |
956 | 1.27M | COUNTER_UPDATE(local_state->_block_init_seek_counter, stats.block_init_seek_num); |
957 | 1.27M | COUNTER_UPDATE(local_state->_segment_generate_row_range_by_keys_timer, |
958 | 1.27M | stats.generate_row_ranges_by_keys_ns); |
959 | 1.27M | COUNTER_UPDATE(local_state->_segment_generate_row_range_by_column_conditions_timer, |
960 | 1.27M | stats.generate_row_ranges_by_column_conditions_ns); |
961 | 1.27M | COUNTER_UPDATE(local_state->_segment_generate_row_range_by_bf_timer, |
962 | 1.27M | stats.generate_row_ranges_by_bf_ns); |
963 | 1.27M | COUNTER_UPDATE(local_state->_collect_iterator_merge_next_timer, |
964 | 1.27M | stats.collect_iterator_merge_next_timer); |
965 | 1.27M | COUNTER_UPDATE(local_state->_segment_generate_row_range_by_zonemap_timer, |
966 | 1.27M | stats.generate_row_ranges_by_zonemap_ns); |
967 | 1.27M | COUNTER_UPDATE(local_state->_segment_generate_row_range_by_dict_timer, |
968 | 1.27M | stats.generate_row_ranges_by_dict_ns); |
969 | 1.27M | COUNTER_UPDATE(local_state->_predicate_column_read_timer, stats.predicate_column_read_ns); |
970 | 1.27M | COUNTER_UPDATE(local_state->_non_predicate_column_read_timer, stats.non_predicate_read_ns); |
971 | 1.27M | COUNTER_UPDATE(local_state->_predicate_column_read_seek_timer, |
972 | 1.27M | stats.predicate_column_read_seek_ns); |
973 | 1.27M | COUNTER_UPDATE(local_state->_predicate_column_read_seek_counter, |
974 | 1.27M | stats.predicate_column_read_seek_num); |
975 | 1.27M | COUNTER_UPDATE(local_state->_lazy_read_timer, stats.lazy_read_ns); |
976 | 1.27M | COUNTER_UPDATE(local_state->_lazy_read_pruned_timer, stats.lazy_read_pruned_ns); |
977 | 1.27M | COUNTER_UPDATE(local_state->_lazy_read_seek_timer, stats.block_lazy_read_seek_ns); |
978 | 1.27M | COUNTER_UPDATE(local_state->_lazy_read_seek_counter, stats.block_lazy_read_seek_num); |
979 | 1.27M | COUNTER_UPDATE(local_state->_output_col_timer, stats.output_col_ns); |
980 | 1.27M | COUNTER_UPDATE(local_state->_rows_vec_cond_filtered_counter, stats.rows_vec_cond_filtered); |
981 | 1.27M | COUNTER_UPDATE(local_state->_rows_short_circuit_cond_filtered_counter, |
982 | 1.27M | stats.rows_short_circuit_cond_filtered); |
983 | 1.27M | COUNTER_UPDATE(local_state->_rows_expr_cond_filtered_counter, stats.rows_expr_cond_filtered); |
984 | 1.27M | COUNTER_UPDATE(local_state->_rows_vec_cond_input_counter, stats.vec_cond_input_rows); |
985 | 1.27M | COUNTER_UPDATE(local_state->_rows_short_circuit_cond_input_counter, |
986 | 1.27M | stats.short_circuit_cond_input_rows); |
987 | 1.27M | COUNTER_UPDATE(local_state->_rows_expr_cond_input_counter, stats.expr_cond_input_rows); |
988 | 1.27M | COUNTER_UPDATE(local_state->_stats_filtered_counter, stats.rows_stats_filtered); |
989 | 1.27M | COUNTER_UPDATE(local_state->_stats_rp_filtered_counter, stats.rows_stats_rp_filtered); |
990 | 1.27M | COUNTER_UPDATE(local_state->_expr_zonemap_filtered_segment_counter, |
991 | 1.27M | stats.expr_zonemap_filtered_segments); |
992 | 1.27M | COUNTER_UPDATE(local_state->_expr_zonemap_filtered_page_counter, |
993 | 1.27M | stats.expr_zonemap_filtered_pages); |
994 | 1.27M | COUNTER_UPDATE(local_state->_expr_zonemap_unusable_counter, stats.expr_zonemap_unusable_evals); |
995 | 1.27M | COUNTER_UPDATE(local_state->_in_zonemap_point_check_counter, |
996 | 1.27M | stats.in_zonemap_point_check_count); |
997 | 1.27M | COUNTER_UPDATE(local_state->_in_zonemap_range_only_counter, stats.in_zonemap_range_only_count); |
998 | 1.27M | COUNTER_UPDATE(local_state->_dict_filtered_counter, stats.segment_dict_filtered); |
999 | 1.27M | COUNTER_UPDATE(local_state->_bf_filtered_counter, stats.rows_bf_filtered); |
1000 | 1.27M | COUNTER_UPDATE(local_state->_del_filtered_counter, stats.rows_del_filtered); |
1001 | 1.27M | COUNTER_UPDATE(local_state->_del_filtered_counter, stats.rows_del_by_bitmap); |
1002 | 1.27M | COUNTER_UPDATE(local_state->_del_filtered_counter, stats.rows_vec_del_cond_filtered); |
1003 | 1.27M | COUNTER_UPDATE(local_state->_conditions_filtered_counter, stats.rows_conditions_filtered); |
1004 | 1.27M | COUNTER_UPDATE(local_state->_key_range_filtered_counter, stats.rows_key_range_filtered); |
1005 | 1.27M | COUNTER_UPDATE(local_state->_total_pages_num_counter, stats.total_pages_num); |
1006 | 1.27M | COUNTER_UPDATE(local_state->_cached_pages_num_counter, stats.cached_pages_num); |
1007 | 1.27M | COUNTER_UPDATE(local_state->_inverted_index_filter_counter, stats.rows_inverted_index_filtered); |
1008 | 1.27M | COUNTER_UPDATE(local_state->_inverted_index_filter_timer, stats.inverted_index_filter_timer); |
1009 | 1.27M | COUNTER_UPDATE(local_state->_inverted_index_query_cache_hit_counter, |
1010 | 1.27M | stats.inverted_index_query_cache_hit); |
1011 | 1.27M | COUNTER_UPDATE(local_state->_inverted_index_query_cache_miss_counter, |
1012 | 1.27M | stats.inverted_index_query_cache_miss); |
1013 | 1.27M | COUNTER_UPDATE(local_state->_inverted_index_query_timer, stats.inverted_index_query_timer); |
1014 | 1.27M | COUNTER_UPDATE(local_state->_inverted_index_query_null_bitmap_timer, |
1015 | 1.27M | stats.inverted_index_query_null_bitmap_timer); |
1016 | 1.27M | COUNTER_UPDATE(local_state->_inverted_index_query_bitmap_copy_timer, |
1017 | 1.27M | stats.inverted_index_query_bitmap_copy_timer); |
1018 | 1.27M | COUNTER_UPDATE(local_state->_inverted_index_searcher_open_timer, |
1019 | 1.27M | stats.inverted_index_searcher_open_timer); |
1020 | 1.27M | COUNTER_UPDATE(local_state->_inverted_index_searcher_search_timer, |
1021 | 1.27M | stats.inverted_index_searcher_search_timer); |
1022 | 1.27M | COUNTER_UPDATE(local_state->_inverted_index_searcher_search_init_timer, |
1023 | 1.27M | stats.inverted_index_searcher_search_init_timer); |
1024 | 1.27M | COUNTER_UPDATE(local_state->_inverted_index_searcher_search_exec_timer, |
1025 | 1.27M | stats.inverted_index_searcher_search_exec_timer); |
1026 | 1.27M | COUNTER_UPDATE(local_state->_inverted_index_searcher_cache_hit_counter, |
1027 | 1.27M | stats.inverted_index_searcher_cache_hit); |
1028 | 1.27M | COUNTER_UPDATE(local_state->_inverted_index_searcher_cache_miss_counter, |
1029 | 1.27M | stats.inverted_index_searcher_cache_miss); |
1030 | 1.27M | COUNTER_UPDATE(local_state->_inverted_index_downgrade_count_counter, |
1031 | 1.27M | stats.inverted_index_downgrade_count); |
1032 | 1.27M | COUNTER_UPDATE(local_state->_inverted_index_analyzer_timer, |
1033 | 1.27M | stats.inverted_index_analyzer_timer); |
1034 | 1.27M | COUNTER_UPDATE(local_state->_inverted_index_lookup_timer, stats.inverted_index_lookup_timer); |
1035 | 1.27M | COUNTER_UPDATE(local_state->_variant_scan_sparse_column_timer, |
1036 | 1.27M | stats.variant_scan_sparse_column_timer_ns); |
1037 | 1.27M | COUNTER_UPDATE(local_state->_variant_scan_sparse_column_bytes, |
1038 | 1.27M | stats.variant_scan_sparse_column_bytes); |
1039 | 1.27M | COUNTER_UPDATE(local_state->_variant_fill_path_from_sparse_column_timer, |
1040 | 1.27M | stats.variant_fill_path_from_sparse_column_timer_ns); |
1041 | 1.27M | COUNTER_UPDATE(local_state->_variant_subtree_default_iter_count, |
1042 | 1.27M | stats.variant_subtree_default_iter_count); |
1043 | 1.27M | COUNTER_UPDATE(local_state->_variant_subtree_leaf_iter_count, |
1044 | 1.27M | stats.variant_subtree_leaf_iter_count); |
1045 | 1.27M | COUNTER_UPDATE(local_state->_variant_subtree_hierarchical_iter_count, |
1046 | 1.27M | stats.variant_subtree_hierarchical_iter_count); |
1047 | 1.27M | COUNTER_UPDATE(local_state->_variant_subtree_sparse_iter_count, |
1048 | 1.27M | stats.variant_subtree_sparse_iter_count); |
1049 | 1.27M | COUNTER_UPDATE(local_state->_variant_doc_value_column_iter_count, |
1050 | 1.27M | stats.variant_doc_value_column_iter_count); |
1051 | | |
1052 | 1.27M | if (stats.adaptive_batch_size_predict_max_rows > 0) { |
1053 | 1.00M | local_state->_adaptive_batch_predict_min_rows_counter->set( |
1054 | 1.00M | stats.adaptive_batch_size_predict_min_rows); |
1055 | 1.00M | local_state->_adaptive_batch_predict_max_rows_counter->set( |
1056 | 1.00M | stats.adaptive_batch_size_predict_max_rows); |
1057 | 1.00M | } |
1058 | | |
1059 | 1.27M | InvertedIndexProfileReporter inverted_index_profile; |
1060 | 1.27M | inverted_index_profile.update(local_state->_index_filter_profile.get(), |
1061 | 1.27M | &stats.inverted_index_stats); |
1062 | | |
1063 | 1.27M | if (has_file_cache_statistics(stats.file_cache_stats)) { |
1064 | 0 | io::FileCacheProfileReporter cache_profile(local_state->_segment_profile.get()); |
1065 | 0 | cache_profile.update(&stats.file_cache_stats); |
1066 | 0 | _state->get_query_ctx()->resource_ctx()->io_context()->update_bytes_write_into_cache( |
1067 | 0 | stats.file_cache_stats.bytes_write_into_cache); |
1068 | 0 | } |
1069 | 1.27M | COUNTER_UPDATE(local_state->_output_index_result_column_timer, |
1070 | 1.27M | stats.output_index_result_column_timer); |
1071 | 1.27M | COUNTER_UPDATE(local_state->_filtered_segment_counter, stats.filtered_segment_number); |
1072 | 1.27M | COUNTER_UPDATE(local_state->_total_segment_counter, stats.total_segment_number); |
1073 | 1.27M | COUNTER_UPDATE(local_state->_condition_cache_hit_counter, stats.condition_cache_hit_seg_nums); |
1074 | 1.27M | COUNTER_UPDATE(local_state->_condition_cache_filtered_rows_counter, |
1075 | 1.27M | stats.condition_cache_filtered_rows); |
1076 | | |
1077 | 1.27M | COUNTER_UPDATE(local_state->_tablet_reader_init_timer, stats.tablet_reader_init_timer_ns); |
1078 | 1.27M | COUNTER_UPDATE(local_state->_tablet_reader_capture_rs_readers_timer, |
1079 | 1.27M | stats.tablet_reader_capture_rs_readers_timer_ns); |
1080 | 1.27M | COUNTER_UPDATE(local_state->_tablet_reader_init_return_columns_timer, |
1081 | 1.27M | stats.tablet_reader_init_return_columns_timer_ns); |
1082 | 1.27M | COUNTER_UPDATE(local_state->_tablet_reader_init_keys_param_timer, |
1083 | 1.27M | stats.tablet_reader_init_keys_param_timer_ns); |
1084 | 1.27M | COUNTER_UPDATE(local_state->_tablet_reader_init_orderby_keys_param_timer, |
1085 | 1.27M | stats.tablet_reader_init_orderby_keys_param_timer_ns); |
1086 | 1.27M | COUNTER_UPDATE(local_state->_tablet_reader_init_conditions_param_timer, |
1087 | 1.27M | stats.tablet_reader_init_conditions_param_timer_ns); |
1088 | 1.27M | COUNTER_UPDATE(local_state->_tablet_reader_init_delete_condition_param_timer, |
1089 | 1.27M | stats.tablet_reader_init_delete_condition_param_timer_ns); |
1090 | 1.27M | COUNTER_UPDATE(local_state->_block_reader_vcollect_iter_init_timer, |
1091 | 1.27M | stats.block_reader_vcollect_iter_init_timer_ns); |
1092 | 1.27M | COUNTER_UPDATE(local_state->_block_reader_rs_readers_init_timer, |
1093 | 1.27M | stats.block_reader_rs_readers_init_timer_ns); |
1094 | 1.27M | COUNTER_UPDATE(local_state->_block_reader_build_heap_init_timer, |
1095 | 1.27M | stats.block_reader_build_heap_init_timer_ns); |
1096 | | |
1097 | 1.27M | COUNTER_UPDATE(local_state->_rowset_reader_get_segment_iterators_timer, |
1098 | 1.27M | stats.rowset_reader_get_segment_iterators_timer_ns); |
1099 | 1.27M | COUNTER_UPDATE(local_state->_rowset_reader_create_iterators_timer, |
1100 | 1.27M | stats.rowset_reader_create_iterators_timer_ns); |
1101 | 1.27M | COUNTER_UPDATE(local_state->_rowset_reader_init_iterators_timer, |
1102 | 1.27M | stats.rowset_reader_init_iterators_timer_ns); |
1103 | 1.27M | COUNTER_UPDATE(local_state->_rowset_reader_load_segments_timer, |
1104 | 1.27M | stats.rowset_reader_load_segments_timer_ns); |
1105 | | |
1106 | 1.27M | COUNTER_UPDATE(local_state->_segment_iterator_init_timer, stats.segment_iterator_init_timer_ns); |
1107 | 1.27M | COUNTER_UPDATE(local_state->_segment_iterator_init_return_column_iterators_timer, |
1108 | 1.27M | stats.segment_iterator_init_return_column_iterators_timer_ns); |
1109 | 1.27M | COUNTER_UPDATE(local_state->_segment_iterator_init_index_iterators_timer, |
1110 | 1.27M | stats.segment_iterator_init_index_iterators_timer_ns); |
1111 | 1.27M | COUNTER_UPDATE(local_state->_segment_iterator_init_segment_prefetchers_timer, |
1112 | 1.27M | stats.segment_iterator_init_segment_prefetchers_timer_ns); |
1113 | | |
1114 | 1.27M | COUNTER_UPDATE(local_state->_segment_create_column_readers_timer, |
1115 | 1.27M | stats.segment_create_column_readers_timer_ns); |
1116 | 1.27M | COUNTER_UPDATE(local_state->_segment_load_index_timer, stats.segment_load_index_timer_ns); |
1117 | | |
1118 | | // Update metrics |
1119 | 1.27M | DorisMetrics::instance()->query_scan_bytes->increment( |
1120 | 1.27M | local_state->_read_uncompressed_counter->value()); |
1121 | 1.27M | DorisMetrics::instance()->query_scan_rows->increment(local_state->_scan_rows->value()); |
1122 | 1.27M | auto& tablet = _tablet_reader_params.tablet; |
1123 | 1.27M | tablet->query_scan_bytes->increment(local_state->_read_uncompressed_counter->value()); |
1124 | 1.27M | tablet->query_scan_rows->increment(local_state->_scan_rows->value()); |
1125 | 1.27M | tablet->query_scan_count->increment(1); |
1126 | | |
1127 | 1.27M | COUNTER_UPDATE(local_state->_ann_range_search_filter_counter, |
1128 | 1.27M | stats.rows_ann_index_range_filtered); |
1129 | 1.27M | COUNTER_UPDATE(local_state->_ann_topn_filter_counter, stats.rows_ann_index_topn_filtered); |
1130 | 1.27M | COUNTER_UPDATE(local_state->_ann_index_load_costs, stats.ann_index_load_ns); |
1131 | 1.27M | COUNTER_UPDATE(local_state->_ann_ivf_on_disk_load_costs, stats.ann_ivf_on_disk_load_ns); |
1132 | 1.27M | COUNTER_UPDATE(local_state->_ann_ivf_on_disk_cache_hit_cnt, |
1133 | 1.27M | stats.ann_ivf_on_disk_cache_hit_cnt); |
1134 | 1.27M | COUNTER_UPDATE(local_state->_ann_ivf_on_disk_cache_miss_cnt, |
1135 | 1.27M | stats.ann_ivf_on_disk_cache_miss_cnt); |
1136 | 1.27M | COUNTER_UPDATE(local_state->_ann_range_search_costs, stats.ann_index_range_search_ns); |
1137 | 1.27M | COUNTER_UPDATE(local_state->_ann_range_search_cnt, stats.ann_index_range_search_cnt); |
1138 | 1.27M | COUNTER_UPDATE(local_state->_ann_range_engine_search_costs, stats.ann_range_engine_search_ns); |
1139 | | // Engine prepare before search |
1140 | 1.27M | COUNTER_UPDATE(local_state->_ann_range_pre_process_costs, stats.ann_range_pre_process_ns); |
1141 | | // Post process parent: Doris result process + engine convert |
1142 | 1.27M | COUNTER_UPDATE(local_state->_ann_range_post_process_costs, |
1143 | 1.27M | stats.ann_range_result_convert_ns + stats.ann_range_engine_convert_ns); |
1144 | | // Engine convert (child under post-process) |
1145 | 1.27M | COUNTER_UPDATE(local_state->_ann_range_engine_convert_costs, stats.ann_range_engine_convert_ns); |
1146 | | // Doris-side result convert (child under post-process) |
1147 | 1.27M | COUNTER_UPDATE(local_state->_ann_range_result_convert_costs, stats.ann_range_result_convert_ns); |
1148 | | |
1149 | 1.27M | COUNTER_UPDATE(local_state->_ann_topn_search_costs, stats.ann_topn_search_ns); |
1150 | 1.27M | COUNTER_UPDATE(local_state->_ann_topn_search_cnt, stats.ann_index_topn_search_cnt); |
1151 | 1.27M | COUNTER_UPDATE(local_state->_ann_cache_hit_cnt, stats.ann_index_cache_hits); |
1152 | 1.27M | COUNTER_UPDATE(local_state->_ann_range_cache_hit_cnt, stats.ann_index_range_cache_hits); |
1153 | | |
1154 | | // Detailed ANN timers |
1155 | | // ANN TopN timers with hierarchy |
1156 | | // Engine search time (FAISS) |
1157 | 1.27M | COUNTER_UPDATE(local_state->_ann_topn_engine_search_costs, |
1158 | 1.27M | stats.ann_index_topn_engine_search_ns); |
1159 | | // Engine prepare time (allocations/buffer setup before search) |
1160 | 1.27M | COUNTER_UPDATE(local_state->_ann_topn_pre_process_costs, |
1161 | 1.27M | stats.ann_index_topn_engine_prepare_ns); |
1162 | | // Post process parent includes Doris result processing + engine convert |
1163 | 1.27M | COUNTER_UPDATE(local_state->_ann_topn_post_process_costs, |
1164 | 1.27M | stats.ann_index_topn_result_process_ns + stats.ann_index_topn_engine_convert_ns); |
1165 | | // Engine-side conversion time inside FAISS wrappers (child under post-process) |
1166 | 1.27M | COUNTER_UPDATE(local_state->_ann_topn_engine_convert_costs, |
1167 | 1.27M | stats.ann_index_topn_engine_convert_ns); |
1168 | | |
1169 | | // Doris-side result convert costs (show separately as another child counter); use pure process time |
1170 | 1.27M | COUNTER_UPDATE(local_state->_ann_topn_result_convert_costs, |
1171 | 1.27M | stats.ann_index_topn_result_process_ns); |
1172 | | |
1173 | 1.27M | COUNTER_UPDATE(local_state->_ann_fallback_brute_force_cnt, stats.ann_fall_back_brute_force_cnt); |
1174 | 1.27M | COUNTER_UPDATE(local_state->_ann_topn_fallback_by_small_candidate_cnt, |
1175 | 1.27M | stats.ann_topn_fallback_by_small_candidate_cnt); |
1176 | 1.27M | COUNTER_UPDATE(local_state->_ann_topn_fallback_small_candidate_rows, |
1177 | 1.27M | stats.ann_topn_fallback_small_candidate_rows); |
1178 | 1.27M | COUNTER_UPDATE(local_state->_ann_range_fallback_by_small_candidate_cnt, |
1179 | 1.27M | stats.ann_range_fallback_by_small_candidate_cnt); |
1180 | 1.27M | COUNTER_UPDATE(local_state->_ann_range_fallback_small_candidate_rows, |
1181 | 1.27M | stats.ann_range_fallback_small_candidate_rows); |
1182 | | |
1183 | | // Overhead counter removed; precise instrumentation is reported via engine_prepare above. |
1184 | 1.27M | } |
1185 | | |
1186 | | #ifndef NDEBUG |
1187 | 1.62M | Status OlapScanner::_check_ann_cache_hit_debug_points(const OlapReaderStatistics& stats) { |
1188 | 1.62M | DBUG_EXECUTE_IF("olap_scanner.ann_topn_cache_hits", { |
1189 | 1.62M | auto expected_hits = dp->param<int32_t>("expected_hits", -1); |
1190 | 1.62M | auto min_hits = dp->param<int32_t>("min_hits", -1); |
1191 | 1.62M | if (expected_hits >= 0 && stats.ann_index_cache_hits != expected_hits) { |
1192 | 1.62M | return Status::Error<ErrorCode::INTERNAL_ERROR>( |
1193 | 1.62M | "ann_index_cache_hits: {} not equal to expected: {}", |
1194 | 1.62M | stats.ann_index_cache_hits, expected_hits); |
1195 | 1.62M | } |
1196 | 1.62M | if (min_hits >= 0 && stats.ann_index_cache_hits < min_hits) { |
1197 | 1.62M | return Status::Error<ErrorCode::INTERNAL_ERROR>( |
1198 | 1.62M | "ann_index_cache_hits: {} less than expected min: {}", |
1199 | 1.62M | stats.ann_index_cache_hits, min_hits); |
1200 | 1.62M | } |
1201 | 1.62M | }) |
1202 | 1.62M | DBUG_EXECUTE_IF("olap_scanner.ann_range_cache_hits", { |
1203 | 1.62M | auto expected_hits = dp->param<int32_t>("expected_hits", -1); |
1204 | 1.62M | auto min_hits = dp->param<int32_t>("min_hits", -1); |
1205 | 1.62M | if (expected_hits >= 0 && stats.ann_index_range_cache_hits != expected_hits) { |
1206 | 1.62M | return Status::Error<ErrorCode::INTERNAL_ERROR>( |
1207 | 1.62M | "ann_index_range_cache_hits: {} not equal to expected: {}", |
1208 | 1.62M | stats.ann_index_range_cache_hits, expected_hits); |
1209 | 1.62M | } |
1210 | 1.62M | if (min_hits >= 0 && stats.ann_index_range_cache_hits < min_hits) { |
1211 | 1.62M | return Status::Error<ErrorCode::INTERNAL_ERROR>( |
1212 | 1.62M | "ann_index_range_cache_hits: {} less than expected min: {}", |
1213 | 1.62M | stats.ann_index_range_cache_hits, min_hits); |
1214 | 1.62M | } |
1215 | 1.62M | }) |
1216 | 1.62M | return Status::OK(); |
1217 | 1.62M | } |
1218 | | #endif |
1219 | | |
1220 | | #include "common/compile_check_avoid_end.h" |
1221 | | } // namespace doris |