Coverage Report

Created: 2026-11-03 19:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/storage/iterators.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 <cstddef>
21
#include <memory>
22
#include <set>
23
24
#include "agent/be_exec_version_manager.h"
25
#include "common/status.h"
26
#include "core/block/block.h"
27
#include "exprs/score_runtime.h"
28
#include "exprs/vexpr.h"
29
#include "io/io_common.h"
30
#include "runtime/runtime_state.h"
31
#include "storage/index/ann/ann_topn_runtime.h"
32
#include "storage/olap_common.h"
33
#include "storage/predicate/block_column_predicate.h"
34
#include "storage/predicate/column_predicate.h"
35
#include "storage/row_cursor.h"
36
#include "storage/segment/row_ranges.h"
37
#include "storage/segment/variant/variant_compaction_paths.h"
38
#include "storage/tablet/tablet_schema.h"
39
40
namespace doris {
41
42
class ReadSchema;
43
class ColumnPredicate;
44
45
struct IteratorRowRef;
46
47
class StorageReadOptions {
48
public:
49
    // Every storage read needs a statistics sink. Deleting the default constructor keeps copied
50
    // options valid from creation; for example, SegmentIterator stores a copy and later
51
    // dereferences stats while reading pages.
52
    StorageReadOptions() = delete;
53
54
6.51M
    explicit StorageReadOptions(OlapReaderStatistics& stats_) noexcept : stats(&stats_) {}
55
56
    // Query reads use their RuntimeState; background reads without one use the newest version.
57
17.6M
    int get_be_exec_version() const {
58
17.6M
        return runtime_state != nullptr ? runtime_state->be_exec_version()
59
17.6M
                                        : BeExecVersionManager::get_newest_version();
60
17.6M
    }
61
62
    struct KeyRange {
63
        KeyRange()
64
                : lower_key(nullptr),
65
                  include_lower(false),
66
                  upper_key(nullptr),
67
0
                  include_upper(false) {}
68
69
        KeyRange(const RowCursor* lower_key_, bool include_lower_, const RowCursor* upper_key_,
70
                 bool include_upper_)
71
3.70M
                : lower_key(lower_key_),
72
3.70M
                  include_lower(include_lower_),
73
3.70M
                  upper_key(upper_key_),
74
3.70M
                  include_upper(include_upper_) {}
75
76
        // the lower bound of the range, nullptr if not existed
77
        const RowCursor* lower_key = nullptr;
78
        // whether `lower_key` is included in the range
79
        bool include_lower;
80
        // the upper bound of the range, nullptr if not existed
81
        const RowCursor* upper_key = nullptr;
82
        // whether `upper_key` is included in the range
83
        bool include_upper;
84
85
3.57M
        uint64_t get_digest(uint64_t seed) const {
86
3.58M
            if (lower_key != nullptr) {
87
3.58M
                auto key_str = lower_key->to_string();
88
3.58M
                seed = HashUtil::hash64(key_str.c_str(), key_str.size(), seed);
89
3.58M
                seed = HashUtil::hash64(&include_lower, sizeof(include_lower), seed);
90
3.58M
            }
91
92
3.59M
            if (upper_key != nullptr) {
93
3.59M
                auto key_str = upper_key->to_string();
94
3.59M
                seed = HashUtil::hash64(key_str.c_str(), key_str.size(), seed);
95
3.59M
                seed = HashUtil::hash64(&include_upper, sizeof(include_upper), seed);
96
3.59M
            }
97
98
3.57M
            return seed;
99
3.57M
        }
100
    };
101
102
    // reader's key ranges, empty if not existed.
103
    // used by short key index to filter row blocks
104
    std::vector<KeyRange> key_ranges;
105
106
    // For unique-key merge-on-write, the effect is similar to delete_conditions
107
    // that filters out rows that are deleted in realtime.
108
    // For a particular row, if delete_bitmap.contains(rowid) means that row is
109
    // marked deleted and invisible to user anymore.
110
    // segment_id -> roaring::Roaring*
111
    std::unordered_map<uint32_t, std::shared_ptr<roaring::Roaring>> delete_bitmap;
112
113
    std::shared_ptr<AndBlockColumnPredicate> delete_condition_predicates =
114
            AndBlockColumnPredicate::create_shared();
115
    // reader's column predicate, nullptr if not existed
116
    // used to fiter rows in row block
117
    std::vector<std::shared_ptr<ColumnPredicate>> column_predicates;
118
    std::unordered_map<int32_t, std::shared_ptr<AndBlockColumnPredicate>> col_id_to_predicates;
119
    std::unordered_map<int32_t, std::vector<std::shared_ptr<const ColumnPredicate>>>
120
            del_predicates_for_zone_map;
121
    TPushAggOp::type push_down_agg_type_opt = TPushAggOp::NONE;
122
    // Non-key columns whose predicates were proven always true by the segment zone map and then
123
    // removed from column_predicates. SegmentIterator can skip reading these non-output columns,
124
    // or COUNT_ON_INDEX columns, because the column values no longer affect filtering or counting.
125
    std::set<uint32_t> zonemap_always_true_pred_cols;
126
127
    // Non-owning and initialized to a valid object by the constructor.
128
    OlapReaderStatistics* stats;
129
    bool use_page_cache = false;
130
    uint32_t block_row_max = 4096 - 32; // see https://github.com/apache/doris/pull/11816
131
    // Effective adaptive batch size byte budget.
132
    size_t preferred_block_size_bytes = 8388608UL;
133
134
    // Whether the tablet schema this read targets materializes variant subcolumns as extracted
135
    // columns. A compaction read then takes them as flat leaves.
136
    bool tablet_has_extracted_variant_columns = false;
137
    // The compaction output schema's variant path layout; null outside a variant compaction.
138
    VariantCompactionPathsSPtr variant_compaction_paths;
139
    bool enable_unique_key_merge_on_write = false;
140
    std::vector<int> topn_filter_source_node_ids;
141
    // used for special optimization for query : ORDER BY key DESC LIMIT n
142
    bool read_orderby_key_reverse = false;
143
    // For rows with the same key, use ascending order (small-to-large) for tie-breakers.
144
    // For example, use lower rowset version / segment id first.
145
    bool use_insert_order_when_same = false;
146
    bool read_changelog = false;
147
    int changelog_tso_idx = -1;
148
    // columns for orderby keys
149
    std::vector<uint32_t>* read_orderby_key_columns = nullptr;
150
    io::IOContext io_ctx;
151
    VExprContextSPtrs common_expr_ctxs_push_down;
152
    const std::set<int32_t>* output_columns = nullptr;
153
    // Extra storage key columns that are included only to keep the scan schema
154
    // aligned with the storage key prefix. SegmentIterator can synthesize
155
    // placeholders only after proving predicates, delete conditions, and
156
    // expressions do not need their real values.
157
    std::set<ColumnId> extra_columns;
158
    // runtime state
159
    RuntimeState* runtime_state = nullptr;
160
    RowsetId rowset_id;
161
    Version version;
162
    TsoRange commit_tso;
163
    int64_t tablet_id = 0;
164
    // slots that cast may be eliminated in storage layer
165
    std::map<std::string, DataTypePtr> target_cast_type_for_variants;
166
    RowRanges row_ranges;
167
168
    // Per-segment row budget pushed down from the scanner (topn or general
169
    // limit). SegmentIterator applies it after predicate/common-expr filtering;
170
    // _can_opt_limit_reads() only decides whether the pre-filter read can also
171
    // be capped. 0 disables the optimization.
172
    size_t read_limit = 0;
173
174
    std::map<ColumnId, VExprContextSPtr> virtual_column_exprs;
175
    std::shared_ptr<segment_v2::AnnTopNRuntime> ann_topn_runtime;
176
177
    std::map<int32_t, TColumnAccessPaths> all_access_paths;
178
    std::map<int32_t, TColumnAccessPaths> predicate_access_paths;
179
180
    std::shared_ptr<ScoreRuntime> score_runtime;
181
    CollectionStatisticsPtr collection_statistics;
182
183
    uint64_t condition_cache_digest = 0;
184
};
185
186
struct CompactionSampleInfo {
187
    int64_t bytes = 0;
188
    int64_t rows = 0;
189
    int64_t group_data_size = 0;
190
    int64_t null_count = 0; // Number of NULL cells in this column group
191
};
192
193
struct BlockWithSameBit {
194
    Block* block;
195
    std::vector<bool>& same_bit;
196
197
201
    bool empty() const { return block->rows() == 0; }
198
};
199
200
class RowwiseIterator;
201
using RowwiseIteratorUPtr = std::unique_ptr<RowwiseIterator>;
202
class RowwiseIterator {
203
public:
204
4.14M
    RowwiseIterator() = default;
205
4.16M
    virtual ~RowwiseIterator() = default;
206
207
    // Initialize this iterator and make it ready to read with
208
    // input options.
209
    // Input options may contain scan range in which this scan.
210
    // Return Status::OK() if init successfully,
211
    // Return other error otherwise
212
0
    virtual Status init(const StorageReadOptions& opts) {
213
0
        return Status::InternalError("to be implemented, current class: " +
214
0
                                     demangle(typeid(*this).name()));
215
0
    }
216
217
0
    virtual Status init(const StorageReadOptions& opts, CompactionSampleInfo* sample_info) {
218
0
        return Status::InternalError("should not reach here, current class: " +
219
0
                                     demangle(typeid(*this).name()));
220
0
    }
221
222
    // If there is any valid data, this function will load data
223
    // into input batch with Status::OK() returned
224
    // If there is no data to read, will return Status::EndOfFile.
225
    // If other error happens, other error code will be returned.
226
0
    virtual Status next_batch(Block* block) {
227
0
        return Status::InternalError("should not reach here, current class: " +
228
0
                                     demangle(typeid(*this).name()));
229
0
    }
230
231
0
    virtual Status next_batch(BlockWithSameBit* block_with_same_bit) {
232
0
        return Status::InternalError("should not reach here, current class: " +
233
0
                                     demangle(typeid(*this).name()));
234
0
    }
235
236
0
    virtual Status next_batch(BlockView* block_view) {
237
0
        return Status::InternalError("should not reach here, current class: " +
238
0
                                     demangle(typeid(*this).name()));
239
0
    }
240
241
0
    virtual Status next_row(IteratorRowRef* ref) {
242
0
        return Status::InternalError("should not reach here, current class: " +
243
0
                                     demangle(typeid(*this).name()));
244
0
    }
245
0
    virtual Status unique_key_next_row(IteratorRowRef* ref) {
246
0
        return Status::InternalError("should not reach here, current class: " +
247
0
                                     demangle(typeid(*this).name()));
248
0
    }
249
250
0
    virtual bool is_merge_iterator() const { return false; }
251
252
    // return schema for this Iterator
253
    virtual const ReadSchema& schema() const = 0;
254
255
    // Return the data id such as segment id, used for keep the insert order when do
256
    // merge sort in priority queue
257
26.0k
    virtual uint64_t data_id() const { return 0; }
258
259
5.59k
    virtual void update_profile(RuntimeProfile* profile) {}
260
    // return rows merged count by iterator
261
0
    virtual uint64_t merged_rows() const { return 0; }
262
263
    // return if it's an empty iterator
264
1.40M
    virtual bool empty() const { return false; }
265
};
266
267
} // namespace doris