Coverage Report

Created: 2026-07-20 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/exec/scan/file_scanner.h
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
#pragma once
19
20
#include <stddef.h>
21
#include <stdint.h>
22
23
#include <memory>
24
#include <optional>
25
#include <string>
26
#include <unordered_map>
27
#include <unordered_set>
28
#include <vector>
29
30
#include "common/factory_creator.h"
31
#include "common/global_types.h"
32
#include "common/status.h"
33
#include "core/block/block.h"
34
#include "exec/operator/file_scan_operator.h"
35
#include "exec/scan/file_scan_io_context.h"
36
#include "exprs/vexpr_fwd.h"
37
#include "format/generic_reader.h"
38
#include "format/orc/vorc_reader.h"
39
#include "format/parquet/vparquet_reader.h"
40
#include "format/table/iceberg_reader.h"
41
#include "io/io_common.h"
42
#include "runtime/descriptors.h"
43
#include "runtime/runtime_profile.h"
44
#include "storage/olap_common.h"
45
#include "storage/olap_scan_common.h"
46
#include "storage/segment/adaptive_block_size_predictor.h"
47
#include "storage/segment/condition_cache.h"
48
49
namespace doris {
50
class RuntimeState;
51
class TFileRangeDesc;
52
class TFileScanRange;
53
class TFileScanRangeParams;
54
55
class ShardedKVCache;
56
class VExpr;
57
class VExprContext;
58
} // namespace doris
59
60
namespace doris {
61
62
class FileScanner : public Scanner {
63
    ENABLE_FACTORY_CREATOR(FileScanner);
64
65
public:
66
    static constexpr const char* NAME = "FileScanner";
67
    static constexpr size_t ADAPTIVE_BATCH_INITIAL_PROBE_ROWS = 32;
68
69
    // sub profile name (for parquet/orc)
70
    static const std::string FileReadBytesProfile;
71
    static const std::string FileReadTimeProfile;
72
73
#ifdef BE_TEST
74
    void TEST_init_runtime_filter_partition_prune_ctxs(
75
            const VExprContextSPtrs& conjuncts,
76
            const std::unordered_map<SlotId, int>& partition_slot_index_map) {
77
        _conjuncts = conjuncts;
78
        _partition_slot_index_map = partition_slot_index_map;
79
        _init_runtime_filter_partition_prune_ctxs();
80
    }
81
    const VExprContextSPtrs& TEST_runtime_filter_partition_prune_ctxs() const {
82
        return _runtime_filter_partition_prune_ctxs;
83
    }
84
    static TPushAggOp::type TEST_effective_push_down_agg_type(
85
            TPushAggOp::type agg_type, const std::optional<std::vector<int32_t>>& count_slot_ids) {
86
        return _effective_push_down_agg_type(agg_type, count_slot_ids);
87
    }
88
#endif
89
90
    FileScanner(RuntimeState* state, FileScanLocalState* parent, int64_t limit,
91
                std::shared_ptr<SplitSourceConnector> split_source, RuntimeProfile* profile,
92
                ShardedKVCache* kv_cache,
93
                const std::unordered_map<std::string, int>* colname_to_slot_id);
94
95
    Status _open_impl(RuntimeState* state) override;
96
97
    Status close(RuntimeState* state) override;
98
99
    void try_stop() override;
100
101
    Status init(RuntimeState* state, const VExprContextSPtrs& conjuncts) override;
102
103
0
    std::string get_name() override { return FileScanner::NAME; }
104
105
22
    std::string get_current_scan_range_name() override { return _current_range_path; }
106
107
    //only used for read one line.
108
    FileScanner(RuntimeState* state, RuntimeProfile* profile, const TFileScanRangeParams* params,
109
                const std::unordered_map<std::string, int>* colname_to_slot_id,
110
                TupleDescriptor* tuple_desc)
111
3.20k
            : Scanner(state, profile),
112
3.20k
              _params(params),
113
3.20k
              _col_name_to_slot_id(colname_to_slot_id),
114
3.20k
              _real_tuple_desc(tuple_desc) {
115
3.20k
        _configure_file_scan_handlers();
116
3.20k
    };
117
118
    Status read_lines_from_range(const TFileRangeDesc& range, const std::list<int64_t>& row_ids,
119
                                 Block* result_block, const ExternalFileMappingInfo& external_info,
120
                                 int64_t* init_reader_ms, int64_t* get_block_ms);
121
122
    Status prepare_for_read_lines(const TFileRangeDesc& range);
123
124
    void update_realtime_counters() override;
125
126
protected:
127
    Status _get_block_impl(RuntimeState* state, Block* block, bool* eof) override;
128
129
    Status _get_block_wrapped(RuntimeState* state, Block* block, bool* eof);
130
131
    Status _get_next_reader();
132
133
    // Build a ReaderInitContext with shared fields from FileScanner members.
134
    void _fill_base_init_context(ReaderInitContext* ctx);
135
136
    // TODO: cast input block columns type to string.
137
0
    Status _cast_src_block(Block* block) { return Status::OK(); }
138
139
    void _collect_profile_before_close() override;
140
141
    bool _should_update_load_counters() const override;
142
143
    // fe will add skip_bitmap_col to _input_tuple_desc iff the target olaptable has skip_bitmap_col
144
    // and the current load is a flexible partial update
145
9.12k
    bool _should_process_skip_bitmap_col() const { return _skip_bitmap_col_idx != -1; }
146
147
protected:
148
    const TFileScanRangeParams* _params = nullptr;
149
    std::shared_ptr<SplitSourceConnector> _split_source;
150
    bool _first_scan_range = false;
151
    TFileRangeDesc _current_range;
152
153
    std::unique_ptr<GenericReader> _cur_reader;
154
    bool _cur_reader_eof = false;
155
    // File source slot descriptors
156
    std::vector<SlotDescriptor*> _file_slot_descs;
157
    // Unified column descriptors for init_reader (includes file, partition, missing, synthesized cols)
158
    std::vector<ColumnDescriptor> _column_descs;
159
160
    // Partition slot id to partition key index (for matching columns_from_path)
161
    std::unordered_map<SlotId, int> _partition_slot_index_map;
162
    // created from param.expr_of_dest_slot
163
    // For query, it saves default value expr of all dest columns, or nullptr for NULL.
164
    // For load, it saves conversion expr/default value of all dest columns.
165
    VExprContextSPtrs _dest_vexpr_ctx;
166
    // dest slot name to index in _dest_vexpr_ctx;
167
    std::unordered_map<std::string, int> _dest_slot_name_to_idx;
168
    // col name to default value expr
169
    // TODO: only used by json reader. Could we delete this?
170
    std::unordered_map<std::string, VExprContextSPtr> _col_default_value_ctx;
171
    // the map values of dest slot id to src slot desc
172
    // if there is not key of dest slot id in dest_sid_to_src_sid_without_trans, it will be set to nullptr
173
    std::vector<SlotDescriptor*> _src_slot_descs_order_by_dest;
174
    // dest slot desc index to src slot desc index
175
    std::unordered_map<int, int> _dest_slot_to_src_slot_index;
176
177
    std::unordered_map<std::string, uint32_t> _src_block_name_to_idx;
178
179
    // Get from GenericReader, save the existing columns in file to their type.
180
    std::unordered_map<std::string, DataTypePtr> _slot_lower_name_to_col_type;
181
    // Get from GenericReader, save columns that required by scan but not exist in file.
182
183
    // The col lowercase name of source file to type of source file.
184
    std::map<std::string, DataTypePtr> _source_file_col_name_types;
185
186
    // For load task
187
    VExprContextSPtrs _pre_conjunct_ctxs;
188
    std::unique_ptr<RowDescriptor> _src_row_desc;
189
    std::unique_ptr<RowDescriptor> _dest_row_desc;
190
    // row desc for default exprs
191
    std::unique_ptr<RowDescriptor> _default_val_row_desc;
192
    // owned by scan node
193
    ShardedKVCache* _kv_cache = nullptr;
194
195
    std::set<TSlotId> _is_file_slot;
196
    bool _scanner_eof = false;
197
    int _rows = 0;
198
    int _num_of_columns_from_file;
199
200
    bool _src_block_mem_reuse = false;
201
    bool _strict_mode;
202
203
    bool _src_block_init = false;
204
    Block* _src_block_ptr = nullptr;
205
    Block _src_block;
206
207
    VExprContextSPtrs _push_down_conjuncts;
208
    VExprContextSPtrs _runtime_filter_partition_prune_ctxs;
209
    Block _runtime_filter_partition_prune_block;
210
211
    std::unique_ptr<io::FileCacheStatistics> _file_cache_statistics;
212
    std::unique_ptr<io::FileReaderStats> _file_reader_stats;
213
    std::shared_ptr<io::IOContext> _io_ctx;
214
215
    // Whether to fill partition columns from path, default is true.
216
    std::unordered_map<std::string, std::tuple<std::string, const SlotDescriptor*>>
217
            _partition_col_descs;
218
    std::unordered_map<std::string, bool> _partition_value_is_null;
219
220
    // idx of skip_bitmap_col in _input_tuple_desc
221
    int32_t _skip_bitmap_col_idx {-1};
222
    int32_t _sequence_map_col_uid {-1};
223
    int32_t _sequence_col_uid {-1};
224
225
private:
226
    RuntimeProfile::Counter* _get_block_timer = nullptr;
227
    RuntimeProfile::Counter* _cast_to_input_block_timer = nullptr;
228
    RuntimeProfile::Counter* _fill_missing_columns_timer = nullptr;
229
    RuntimeProfile::Counter* _pre_filter_timer = nullptr;
230
    RuntimeProfile::Counter* _convert_to_output_block_timer = nullptr;
231
    RuntimeProfile::Counter* _runtime_filter_partition_prune_timer = nullptr;
232
    RuntimeProfile::Counter* _empty_file_counter = nullptr;
233
    RuntimeProfile::Counter* _not_found_file_counter = nullptr;
234
    RuntimeProfile::Counter* _fully_skipped_file_counter = nullptr;
235
    RuntimeProfile::Counter* _file_counter = nullptr;
236
    RuntimeProfile::Counter* _file_read_bytes_counter = nullptr;
237
    RuntimeProfile::Counter* _file_read_calls_counter = nullptr;
238
    RuntimeProfile::Counter* _file_read_time_counter = nullptr;
239
    RuntimeProfile::Counter* _runtime_filter_partition_pruned_range_counter = nullptr;
240
    RuntimeProfile::Counter* _adaptive_batch_predicted_rows_counter = nullptr;
241
    RuntimeProfile::Counter* _adaptive_batch_actual_bytes_before_truncate_counter = nullptr;
242
    RuntimeProfile::Counter* _adaptive_batch_actual_bytes_after_truncate_counter = nullptr;
243
    RuntimeProfile::Counter* _adaptive_batch_probe_count_counter = nullptr;
244
245
    const std::unordered_map<std::string, int>* _col_name_to_slot_id = nullptr;
246
    // single slot filter conjuncts
247
    std::unordered_map<int, VExprContextSPtrs> _slot_id_to_filter_conjuncts;
248
    // not single(zero or multi) slot filter conjuncts
249
    VExprContextSPtrs _not_single_slot_filter_conjuncts;
250
    // save the path of current scan range
251
    std::string _current_range_path = "";
252
253
    // Only for load scan node.
254
    const TupleDescriptor* _input_tuple_desc = nullptr;
255
    // If _input_tuple_desc is set,
256
    // the _real_tuple_desc will point to _input_tuple_desc,
257
    // otherwise, point to _output_tuple_desc
258
    const TupleDescriptor* _real_tuple_desc = nullptr;
259
260
    int64_t _last_bytes_read_from_local = 0;
261
    int64_t _last_bytes_read_from_remote = 0;
262
263
    Status (FileScanner::*_init_src_block_handler)(Block* block) = nullptr;
264
    Status (FileScanner::*_process_src_block_after_read_handler)(Block* block) = nullptr;
265
    bool (FileScanner::*_should_push_down_predicates_handler)(
266
            TFileFormatType::type format_type) const = nullptr;
267
    bool (FileScanner::*_should_enable_condition_cache_handler)() const = nullptr;
268
269
    // Condition cache for external tables
270
    uint64_t _condition_cache_digest = 0;
271
    segment_v2::ConditionCache::ExternalCacheKey _condition_cache_key;
272
    std::shared_ptr<std::vector<bool>> _condition_cache;
273
    std::shared_ptr<ConditionCacheContext> _condition_cache_ctx;
274
    int64_t _condition_cache_hit_count = 0;
275
    std::unique_ptr<AdaptiveBlockSizePredictor> _block_size_predictor;
276
277
    void _configure_file_scan_handlers();
278
279
    Status _init_expr_ctxes();
280
    Status _init_src_block(Block* block);
281
    Status _init_src_block_for_load(Block* block);
282
    Status _init_src_block_for_query(Block* block);
283
    Status _process_src_block_after_read(Block* block);
284
    Status _process_src_block_after_read_for_load(Block* block);
285
    Status _process_src_block_after_read_for_query(Block* block);
286
    Status _check_output_block_types();
287
    Status _cast_to_input_block(Block* block);
288
    Status _pre_filter_src_block();
289
    Status _convert_to_output_block(Block* block);
290
    Status _truncate_char_or_varchar_columns(Block* block);
291
    void _truncate_char_or_varchar_column(Block* block, int idx, int len);
292
    Status _generate_partition_columns();
293
294
    bool _check_partition_prune_expr(const VExprSPtr& expr);
295
    bool _contains_runtime_filter(const VExprContextSPtrs& conjuncts) const;
296
    void _init_runtime_filter_partition_prune_ctxs();
297
    void _init_runtime_filter_partition_prune_block();
298
    Status _process_runtime_filters_partition_prune(bool& is_partition_pruned);
299
    Status _process_conjuncts();
300
    Status _process_late_arrival_conjuncts();
301
    void _get_slot_ids(VExpr* expr, std::vector<int>* slot_ids);
302
    Status _generate_truncate_columns(bool need_to_get_parsed_schema);
303
    Status _set_fill_or_truncate_columns(bool need_to_get_parsed_schema);
304
    Status _init_orc_reader(FileMetaCache* file_meta_cache_ptr,
305
                            std::unique_ptr<OrcReader> orc_reader = nullptr);
306
    Status _init_parquet_reader(FileMetaCache* file_meta_cache_ptr,
307
                                std::unique_ptr<ParquetReader> parquet_reader = nullptr);
308
    std::shared_ptr<segment_v2::RowIdColumnIteratorV2> _create_row_id_column_iterator();
309
310
72.1k
    TFileFormatType::type _get_current_format_type() {
311
        // for compatibility, if format_type is not set in range, use the format type of params
312
72.1k
        const TFileRangeDesc& range = _current_range;
313
72.1k
        return range.__isset.format_type ? range.format_type : _params->format_type;
314
72.1k
    };
315
316
22.1k
    Status _init_io_ctx() {
317
22.1k
        _io_ctx = create_file_scan_io_context(_state);
318
22.1k
        return Status::OK();
319
22.1k
    };
320
321
0
    void _reset_counter() {
322
0
        _counter.num_rows_unselected = 0;
323
0
        _counter.num_rows_filtered = 0;
324
0
    }
325
326
    bool _should_enable_condition_cache();
327
    bool _should_enable_condition_cache_for_load() const;
328
    bool _should_enable_condition_cache_for_query() const;
329
    bool _should_push_down_predicates(TFileFormatType::type format_type) const;
330
    bool _should_push_down_predicates_for_load(TFileFormatType::type format_type) const;
331
    bool _should_push_down_predicates_for_query(TFileFormatType::type format_type) const;
332
    void _init_reader_condition_cache();
333
    void _finalize_reader_condition_cache();
334
    void _reset_adaptive_batch_size_state();
335
    void _init_adaptive_batch_size_state(TFileFormatType::type format_type);
336
    bool _should_enable_adaptive_batch_size(TFileFormatType::type format_type) const;
337
    bool _should_run_adaptive_batch_size() const;
338
    size_t _predict_reader_batch_rows();
339
    void _update_adaptive_batch_size_before_truncate(const Block& block);
340
    void _update_adaptive_batch_size_after_truncate(const Block& block);
341
342
    static TPushAggOp::type _effective_push_down_agg_type(
343
441k
            TPushAggOp::type agg_type, const std::optional<std::vector<int32_t>>& count_slot_ids) {
344
441k
        if (agg_type != TPushAggOp::type::COUNT) {
345
436k
            return agg_type;
346
436k
        }
347
        // V1's CountReader receives only the file's total row count and emits that many synthetic
348
        // rows. This is exact for COUNT(*)/COUNT(1), but it has no column metadata for NULL or CAST
349
        // semantics. For example, a 10,000-row file with 9,015 non-null values must return 10,000
350
        // for COUNT(*) and 9,015 for COUNT(nullable_col); CountReader can produce only the former.
351
        // Therefore a non-empty argument list must use the normal reader. nullopt is an old FE plan
352
        // that predates the argument field; treating it as empty would silently reinterpret unknown
353
        // semantics as COUNT(*).
354
5.84k
        return count_slot_ids.has_value() && count_slot_ids->empty() ? TPushAggOp::type::COUNT
355
18.4E
                                                                     : TPushAggOp::type::NONE;
356
441k
    }
357
358
454k
    TPushAggOp::type _get_push_down_agg_type() const {
359
454k
        if (_local_state == nullptr) {
360
12.3k
            return TPushAggOp::type::NONE;
361
12.3k
        }
362
442k
        return _effective_push_down_agg_type(_local_state->get_push_down_agg_type(),
363
442k
                                             _local_state->get_push_down_count_slot_ids());
364
454k
    }
365
366
    // enable the file meta cache only when
367
    // 1. max_external_file_meta_cache_num is > 0
368
    // 2. the file number is less than 1/3 of cache's capacibility
369
    // Otherwise, the cache miss rate will be high
370
58.1k
    bool _should_enable_file_meta_cache() {
371
58.1k
        return ExecEnv::GetInstance()->file_meta_cache()->enabled() &&
372
58.1k
               _split_source->num_scan_ranges() < config::max_external_file_meta_cache_num / 3;
373
58.1k
    }
374
};
375
} // namespace doris