Coverage Report

Created: 2026-10-26 10:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/storage/olap_common.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 <gen_cpp/Types_types.h>
21
#include <netinet/in.h>
22
23
#include <atomic>
24
#include <charconv>
25
#include <cstdint>
26
#include <functional>
27
#include <list>
28
#include <map>
29
#include <memory>
30
#include <ostream>
31
#include <sstream>
32
#include <string>
33
#include <typeinfo>
34
#include <unordered_map>
35
#include <unordered_set>
36
#include <utility>
37
38
#include "common/cast_set.h"
39
#include "common/config.h"
40
#include "common/exception.h"
41
#include "core/extended_types.h"
42
#include "io/io_common.h"
43
#include "storage/field_type.h"
44
#include "storage/index/inverted/common/inverted_index_stats.h"
45
#include "storage/index/inverted/common/snii_query_stats.h"
46
#include "storage/olap_define.h"
47
#include "storage/rowset/rowset_fwd.h"
48
#include "storage/rowset_id.h"
49
#include "util/hash_util.hpp"
50
#include "util/time.h"
51
#include "util/uid_util.h"
52
53
namespace doris {
54
namespace io {
55
struct ReadAheadStatistics;
56
}
57
58
using SchemaHash = int32_t;
59
60
using TabletUid = UniqueId;
61
62
enum class CompactionType {
63
    BASE_COMPACTION = 1,
64
    CUMULATIVE_COMPACTION = 2,
65
    FULL_COMPACTION = 3,
66
    // Only used by scheduler to route changelog tablets to the changelog thread pool.
67
    CHANGELOG_COMPACTION = 4
68
};
69
70
inline constexpr CompactionType BASE_COMPACTION = CompactionType::BASE_COMPACTION;
71
inline constexpr CompactionType CUMULATIVE_COMPACTION = CompactionType::CUMULATIVE_COMPACTION;
72
inline constexpr CompactionType FULL_COMPACTION = CompactionType::FULL_COMPACTION;
73
inline constexpr CompactionType CHANGELOG_COMPACTION = CompactionType::CHANGELOG_COMPACTION;
74
75
66
inline std::ostream& operator<<(std::ostream& os, CompactionType type) {
76
66
    return os << static_cast<int>(type);
77
66
}
78
79
struct CompactionScoreStats {
80
    int64_t max_score = 0;
81
    int64_t size_based_max_score = 0;
82
    int64_t time_series_max_score = 0;
83
    bool scanned = false;
84
};
85
86
enum class DataDirType {
87
    SPILL_DISK_DIR,
88
    OLAP_DATA_DIR,
89
    DATA_CACHE_DIR,
90
};
91
92
struct DataDirInfo {
93
    std::string path;
94
    size_t path_hash = 0;
95
    int64_t disk_capacity = 1; // actual disk capacity
96
    int64_t available = 0;     // available space, in bytes unit
97
    int64_t local_used_capacity = 0;
98
    int64_t remote_used_capacity = 0;
99
    int64_t trash_used_capacity = 0;
100
    bool is_used = false;                                      // whether available mark
101
    TStorageMedium::type storage_medium = TStorageMedium::HDD; // Storage medium type: SSD|HDD
102
    DataDirType data_dir_type = DataDirType::OLAP_DATA_DIR;
103
    std::string metric_name;
104
};
105
106
// Sort DataDirInfo by available space.
107
struct DataDirInfoLessAvailability {
108
23
    bool operator()(const DataDirInfo& left, const DataDirInfo& right) const {
109
23
        return left.available < right.available;
110
23
    }
111
};
112
113
struct TabletInfo {
114
    TabletInfo(TTabletId in_tablet_id, UniqueId in_uid)
115
1.94M
            : tablet_id(in_tablet_id), tablet_uid(in_uid) {}
116
117
10.7M
    bool operator<(const TabletInfo& right) const {
118
10.7M
        if (tablet_id != right.tablet_id) {
119
10.7M
            return tablet_id < right.tablet_id;
120
10.7M
        } else {
121
13.1k
            return tablet_uid < right.tablet_uid;
122
13.1k
        }
123
10.7M
    }
124
125
69
    std::string to_string() const {
126
69
        std::stringstream ss;
127
69
        ss << tablet_id << "." << tablet_uid.to_string();
128
69
        return ss.str();
129
69
    }
130
131
    TTabletId tablet_id;
132
    UniqueId tablet_uid;
133
};
134
135
struct TabletSize {
136
    TabletSize(TTabletId in_tablet_id, size_t in_tablet_size)
137
0
            : tablet_id(in_tablet_id), tablet_size(in_tablet_size) {}
138
139
    TTabletId tablet_id;
140
    size_t tablet_size;
141
};
142
143
// FieldType moved to storage/field_type.h (included above) so that
144
// data-type headers can name storage cell types without pulling in the
145
// whole of olap_common.h.
146
147
// Define all aggregation methods supported by TabletColumn
148
// Note that in practice, not all types can use all the following aggregation methods
149
// For example, it is meaningless to use SUM for the string type (but it will not cause the program to crash)
150
// The implementation of the TabletColumn class does not perform such checks, and should be constrained when creating the table
151
enum class FieldAggregationMethod {
152
    OLAP_FIELD_AGGREGATION_NONE = 0,
153
    OLAP_FIELD_AGGREGATION_SUM = 1,
154
    OLAP_FIELD_AGGREGATION_MIN = 2,
155
    OLAP_FIELD_AGGREGATION_MAX = 3,
156
    OLAP_FIELD_AGGREGATION_REPLACE = 4,
157
    OLAP_FIELD_AGGREGATION_HLL_UNION = 5,
158
    OLAP_FIELD_AGGREGATION_UNKNOWN = 6,
159
    OLAP_FIELD_AGGREGATION_BITMAP_UNION = 7,
160
    // Replace if and only if added value is not null
161
    OLAP_FIELD_AGGREGATION_REPLACE_IF_NOT_NULL = 8,
162
    OLAP_FIELD_AGGREGATION_QUANTILE_UNION = 9,
163
    OLAP_FIELD_AGGREGATION_GENERIC = 10
164
};
165
166
enum class PushType {
167
    PUSH_NORMAL = 1,          // for broker/hadoop load, not used any more
168
    PUSH_FOR_DELETE = 2,      // for delete
169
    PUSH_FOR_LOAD_DELETE = 3, // not used any more
170
    PUSH_NORMAL_V2 = 4,       // for spark load
171
};
172
173
// <start_version_id, end_version_id>, such as <100, 110>
174
//using Version = std::pair<TupleVersion, TupleVersion>;
175
176
struct Version {
177
    int64_t first;
178
    int64_t second;
179
180
93.4M
    Version(int64_t first_, int64_t second_) : first(first_), second(second_) {}
181
10.0M
    Version() : first(0), second(0) {}
182
183
8.48k
    static Version mock() {
184
        // Every time SchemaChange is used for external rowing, some temporary versions (such as 999, 1000, 1001) will be written, in order to avoid Cache conflicts, temporary
185
        // The version number takes a BIG NUMBER plus the version number of the current SchemaChange
186
8.48k
        return Version(1 << 28, 1 << 29);
187
8.48k
    }
188
189
    friend std::ostream& operator<<(std::ostream& os, const Version& version);
190
191
2.20k
    bool operator!=(const Version& rhs) const { return first != rhs.first || second != rhs.second; }
192
193
7.93M
    bool operator==(const Version& rhs) const { return first == rhs.first && second == rhs.second; }
194
195
184k
    bool contains(const Version& other) const {
196
184k
        return first <= other.first && second >= other.second;
197
184k
    }
198
199
1.37M
    std::string to_string() const { return fmt::format("[{}-{}]", first, second); }
200
};
201
202
struct TsoRange : public Version {
203
6.97M
    TsoRange() : Version(-1, -1) {}
204
7.50M
    TsoRange(int64_t start_tso, int64_t end_tso) : Version(start_tso, end_tso) {}
205
206
1.63M
    int64_t start_tso() const { return first; }
207
1.63M
    int64_t end_tso() const { return second; }
208
209
0
    bool contains(const TsoRange& other) const { return Version::contains(other); }
210
};
211
212
using Versions = std::vector<Version>;
213
214
15.5k
inline std::ostream& operator<<(std::ostream& os, const Version& version) {
215
15.5k
    return os << version.to_string();
216
15.5k
}
217
218
0
inline std::ostream& operator<<(std::ostream& os, const Versions& versions) {
219
0
    for (auto& version : versions) {
220
0
        os << version;
221
0
    }
222
0
    return os;
223
0
}
224
225
// used for hash-struct of hash_map<Version, Rowset*>.
226
struct HashOfVersion {
227
9.28M
    size_t operator()(const Version& version) const {
228
9.28M
        size_t seed = 0;
229
9.28M
        seed = HashUtil::hash64(&version.first, sizeof(version.first), seed);
230
9.28M
        seed = HashUtil::hash64(&version.second, sizeof(version.second), seed);
231
9.28M
        return seed;
232
9.28M
    }
233
};
234
235
// It is used to represent Graph vertex.
236
struct Vertex {
237
    int64_t value = 0;
238
    std::list<int64_t> edges;
239
240
1.30M
    Vertex(int64_t v) : value(v) {}
241
};
242
243
// ReaderStatistics used to collect statistics when scan data from storage
244
struct OlapReaderStatistics {
245
    int64_t io_ns = 0;
246
    int64_t compressed_bytes_read = 0;
247
248
    int64_t decompress_ns = 0;
249
    int64_t uncompressed_bytes_read = 0;
250
251
    // total read bytes in memory
252
    int64_t bytes_read = 0;
253
254
    int64_t block_fetch_ns = 0; // time of rowset reader's `next_batch()` call
255
    int64_t block_load_ns = 0;
256
    int64_t blocks_load = 0;
257
    // Not used any more, will be removed after non-vectorized code is removed
258
    int64_t block_seek_num = 0;
259
    // Not used any more, will be removed after non-vectorized code is removed
260
    int64_t block_seek_ns = 0;
261
262
    // block_load_ns
263
    //      block_init_ns
264
    //          block_init_seek_ns
265
    //          generate_row_ranges_ns
266
    //      predicate_column_read_ns
267
    //          predicate_column_read_seek_ns
268
    //      lazy_read_ns
269
    //          block_lazy_read_seek_ns
270
    int64_t block_init_ns = 0;
271
    int64_t block_init_seek_num = 0;
272
    int64_t block_init_seek_ns = 0;
273
    int64_t predicate_column_read_ns = 0;
274
    int64_t non_predicate_read_ns = 0;
275
    int64_t predicate_column_read_seek_num = 0;
276
    int64_t predicate_column_read_seek_ns = 0;
277
    int64_t lazy_read_ns = 0;
278
    int64_t block_lazy_read_seek_num = 0;
279
    int64_t block_lazy_read_seek_ns = 0;
280
    int64_t lazy_read_pruned_ns = 0;
281
282
    int64_t raw_rows_read = 0;
283
284
    int64_t rows_vec_cond_filtered = 0;
285
    int64_t rows_short_circuit_cond_filtered = 0;
286
    int64_t rows_expr_cond_filtered = 0;
287
    int64_t vec_cond_input_rows = 0;
288
    int64_t short_circuit_cond_input_rows = 0;
289
    int64_t expr_cond_input_rows = 0;
290
    int64_t rows_vec_del_cond_filtered = 0;
291
    int64_t vec_cond_ns = 0;
292
    int64_t short_cond_ns = 0;
293
    int64_t expr_filter_ns = 0;
294
    int64_t output_col_ns = 0;
295
    int64_t rows_key_range_filtered = 0;
296
    int64_t rows_stats_filtered = 0;
297
    int64_t rows_stats_rp_filtered = 0;
298
    int64_t expr_zonemap_filtered_segments = 0;
299
    int64_t expr_zonemap_filtered_pages = 0;
300
    int64_t expr_zonemap_unusable_evals = 0;
301
    int64_t in_zonemap_point_check_count = 0;
302
    int64_t in_zonemap_range_only_count = 0;
303
    int64_t rows_bf_filtered = 0;
304
    int64_t segment_dict_filtered = 0;
305
    // Including the number of rows filtered out according to the Delete information in the Tablet,
306
    // and the number of rows filtered for marked deleted rows under the unique key model.
307
    // This metric is mainly used to record the number of rows filtered by the delete condition in Segment V1,
308
    // and it is also used to record the replaced rows in the Unique key model in the "Reader" class.
309
    // In segmentv2, if you want to get all filtered rows, you need the sum of "rows_del_filtered" and "rows_conditions_filtered".
310
    int64_t rows_del_filtered = 0;
311
    int64_t rows_del_by_bitmap = 0;
312
    // the number of rows filtered by various column indexes.
313
    int64_t rows_conditions_filtered = 0;
314
    int64_t generate_row_ranges_by_keys_ns = 0;
315
    int64_t generate_row_ranges_by_column_conditions_ns = 0;
316
    int64_t generate_row_ranges_by_bf_ns = 0;
317
    int64_t generate_row_ranges_by_zonemap_ns = 0;
318
    int64_t generate_row_ranges_by_dict_ns = 0;
319
320
    int64_t index_load_ns = 0;
321
322
    int64_t total_pages_num = 0;
323
    int64_t cached_pages_num = 0;
324
325
    int64_t rows_inverted_index_filtered = 0;
326
    int64_t inverted_index_filter_timer = 0;
327
    int64_t inverted_index_query_timer = 0;
328
    int64_t inverted_index_query_cache_hit = 0;
329
    int64_t inverted_index_query_cache_miss = 0;
330
    int64_t inverted_index_query_cache_lookup = 0;
331
    int64_t inverted_index_query_cache_insert = 0;
332
    int64_t inverted_index_query_null_bitmap_timer = 0;
333
    int64_t inverted_index_query_bitmap_copy_timer = 0;
334
    int64_t inverted_index_searcher_open_timer = 0;
335
    int64_t inverted_index_searcher_search_timer = 0;
336
    int64_t inverted_index_searcher_search_init_timer = 0;
337
    int64_t inverted_index_searcher_search_exec_timer = 0;
338
    int64_t inverted_index_searcher_cache_hit = 0;
339
    int64_t inverted_index_searcher_cache_miss = 0;
340
    int64_t inverted_index_downgrade_count = 0;
341
    // Pushed-down conjuncts skipped (never index-evaluated) because the row
342
    // bitmap was already empty when their turn came.
343
    int64_t inverted_index_conjuncts_short_circuited = 0;
344
    // Rows pruned by the approximate (gram) index: rows removed when the candidate bitmap is
345
    // intersected with _row_bitmap.
346
    int64_t rows_gram_index_filtered = 0;
347
    // Candidate rows produced by the approximate (gram) index: rows that still need expression
348
    // re-verification after the intersection.
349
    int64_t gram_index_candidate_rows = 0;
350
    // Query nodes the gram index's cost gate widened to the whole segment rather than read. A
351
    // non-zero count is why the two numbers above can show an index that eliminated nothing: it
352
    // was not consulted for those nodes, by a cost decision rather than because no gram matched.
353
    int64_t gram_index_gate_gave_up = 0;
354
    int64_t inverted_index_analyzer_timer = 0;
355
    int64_t inverted_index_lookup_timer = 0;
356
    // See snii_query_stats.h: one field here instead of one per SNII counter.
357
    snii::SniiQueryStats snii_stats;
358
    InvertedIndexStatistics inverted_index_stats;
359
360
    int64_t ann_index_load_ns = 0;
361
    int64_t ann_topn_search_ns = 0;
362
    int64_t ann_index_topn_search_cnt = 0;
363
    int64_t ann_ivf_on_disk_load_ns = 0;
364
    int64_t ann_ivf_on_disk_cache_hit_cnt = 0;
365
    int64_t ann_ivf_on_disk_cache_miss_cnt = 0;
366
    int64_t ann_index_cache_hits = 0;
367
368
    // Detailed timing for ANN operations
369
    int64_t ann_index_topn_engine_search_ns = 0;  // time spent in engine for range search
370
    int64_t ann_index_topn_result_process_ns = 0; // time spent processing TopN results
371
    int64_t ann_index_topn_engine_convert_ns = 0; // time spent on FAISS-side conversions (TopN)
372
    int64_t ann_index_topn_engine_prepare_ns =
373
            0; // time spent preparing before engine search (TopN)
374
    int64_t rows_ann_index_topn_filtered = 0;
375
376
    int64_t ann_index_range_search_ns = 0;
377
    int64_t ann_index_range_search_cnt = 0;
378
    // Detailed timing for ANN Range search
379
    int64_t ann_range_engine_search_ns = 0; // time spent in engine for range search
380
    int64_t ann_range_pre_process_ns = 0;   // time spent preparing before engine search
381
382
    int64_t ann_range_result_convert_ns = 0; // time spent processing range results
383
    int64_t ann_range_engine_convert_ns = 0; // time spent on FAISS-side conversions (Range)
384
    int64_t rows_ann_index_range_filtered = 0;
385
    int64_t ann_index_range_cache_hits = 0;
386
    int64_t ann_fall_back_brute_force_cnt = 0;
387
    int64_t ann_topn_fallback_by_small_candidate_cnt = 0;
388
    int64_t ann_topn_fallback_small_candidate_rows = 0;
389
    int64_t ann_range_fallback_by_small_candidate_cnt = 0;
390
    int64_t ann_range_fallback_small_candidate_rows = 0;
391
392
    int64_t output_index_result_column_timer = 0;
393
    // number of segment filtered by column stat when creating seg iterator
394
    int64_t filtered_segment_number = 0;
395
    // number of condition cache lookups, including misses
396
    int64_t condition_cache_lookup_count = 0;
397
    // number of segment with condition cache hit
398
    int64_t condition_cache_hit_seg_nums = 0;
399
    // number of rows filtered by condition cache hit
400
    int64_t condition_cache_filtered_rows = 0;
401
    // total number of segment
402
    int64_t total_segment_number = 0;
403
404
    io::FileCacheStatistics file_cache_stats;
405
    // Shared with range tasks so asynchronous completion never writes into this reader's lifetime.
406
    std::shared_ptr<io::ReadAheadStatistics> read_ahead_stats;
407
    int64_t load_segments_timer = 0;
408
409
    int64_t collect_iterator_merge_next_timer = 0;
410
    int64_t collect_iterator_normal_next_timer = 0;
411
    int64_t delete_bitmap_get_agg_ns = 0;
412
413
    int64_t tablet_reader_init_timer_ns = 0;
414
    int64_t tablet_reader_capture_rs_readers_timer_ns = 0;
415
    int64_t tablet_reader_init_keys_param_timer_ns = 0;
416
    int64_t tablet_reader_init_orderby_keys_param_timer_ns = 0;
417
    int64_t tablet_reader_init_conditions_param_timer_ns = 0;
418
    int64_t tablet_reader_init_delete_condition_param_timer_ns = 0;
419
    int64_t block_reader_vcollect_iter_init_timer_ns = 0;
420
    int64_t block_reader_rs_readers_init_timer_ns = 0;
421
    int64_t block_reader_build_heap_init_timer_ns = 0;
422
423
    int64_t rowset_reader_get_segment_iterators_timer_ns = 0;
424
    int64_t rowset_reader_create_iterators_timer_ns = 0;
425
    int64_t rowset_reader_init_iterators_timer_ns = 0;
426
    int64_t rowset_reader_load_segments_timer_ns = 0;
427
428
    int64_t segment_iterator_init_timer_ns = 0;
429
    int64_t segment_iterator_init_column_iterators_timer_ns = 0;
430
    int64_t segment_iterator_init_index_iterators_timer_ns = 0;
431
    int64_t segment_iterator_init_segment_prefetchers_timer_ns = 0;
432
433
    int64_t segment_create_column_readers_timer_ns = 0;
434
    int64_t segment_load_index_timer_ns = 0;
435
436
    int64_t adaptive_batch_size_predict_min_rows = INT64_MAX;
437
    int64_t adaptive_batch_size_predict_max_rows = 0;
438
439
    int64_t variant_scan_sparse_column_timer_ns = 0;
440
    int64_t variant_scan_sparse_column_bytes = 0;
441
    int64_t variant_fill_path_from_sparse_column_timer_ns = 0;
442
    int64_t variant_subtree_default_iter_count = 0;
443
    int64_t variant_subtree_leaf_iter_count = 0;
444
    int64_t variant_subtree_hierarchical_iter_count = 0;
445
    int64_t variant_subtree_sparse_iter_count = 0;
446
    int64_t variant_doc_value_column_iter_count = 0;
447
};
448
449
using ColumnId = uint32_t;
450
// Column unique id set
451
using UniqueIdSet = std::set<uint32_t>;
452
// Column unique Id -> column id map
453
using UniqueIdToColumnIdMap = std::map<ColumnId, ColumnId>;
454
455
// RowsetId moved to storage/rowset_id.h (included above): core/column/column.h
456
// needs the complete type, and this way it gets it without the rest of
457
// olap_common.h.
458
459
using RowsetIdUnorderedSet = std::unordered_set<RowsetId>;
460
461
// Extract rowset id from filename, return uninitialized rowset id if filename is invalid
462
82.4k
inline RowsetId extract_rowset_id(std::string_view filename) {
463
82.4k
    RowsetId rowset_id;
464
82.4k
    if (filename.ends_with(".dat")) {
465
        // filename format: {rowset_id}_{segment_num}.dat
466
76.4k
        auto end = filename.find('_');
467
76.4k
        if (end == std::string::npos) {
468
0
            return rowset_id;
469
0
        }
470
76.4k
        rowset_id.init(filename.substr(0, end));
471
76.4k
        return rowset_id;
472
76.4k
    }
473
6.00k
    if (filename.ends_with(".idx")) {
474
        // filename format: {rowset_id}_{segment_num}_{index_id}.idx
475
5.81k
        auto end = filename.find('_');
476
5.81k
        if (end == std::string::npos) {
477
0
            return rowset_id;
478
0
        }
479
5.81k
        rowset_id.init(filename.substr(0, end));
480
5.81k
        return rowset_id;
481
5.81k
    }
482
184
    return rowset_id;
483
6.00k
}
484
485
class DeleteBitmap;
486
// merge on write context
487
struct MowContext {
488
    MowContext(int64_t version, int64_t txnid, std::shared_ptr<RowsetIdUnorderedSet> ids,
489
               std::vector<RowsetSharedPtr> rowset_ptrs, std::shared_ptr<DeleteBitmap> db)
490
61.7k
            : max_version(version),
491
61.7k
              txn_id(txnid),
492
61.7k
              rowset_ids(std::move(ids)),
493
61.7k
              rowset_ptrs(std::move(rowset_ptrs)),
494
61.7k
              delete_bitmap(std::move(db)) {}
495
    int64_t max_version;
496
    int64_t txn_id;
497
    std::shared_ptr<RowsetIdUnorderedSet> rowset_ids;
498
    std::vector<RowsetSharedPtr> rowset_ptrs;
499
    std::shared_ptr<DeleteBitmap> delete_bitmap;
500
};
501
502
// used for controll compaction
503
struct VersionWithTime {
504
    std::atomic<int64_t> version;
505
    int64_t update_ts;
506
507
40.6k
    VersionWithTime() : version(0), update_ts(MonotonicMillis()) {}
508
509
38.0k
    void update_version_monoto(int64_t new_version) {
510
38.0k
        int64_t cur_version = version.load(std::memory_order_relaxed);
511
38.0k
        while (cur_version < new_version) {
512
38.0k
            if (version.compare_exchange_strong(cur_version, new_version, std::memory_order_relaxed,
513
38.0k
                                                std::memory_order_relaxed)) {
514
38.0k
                update_ts = MonotonicMillis();
515
38.0k
                break;
516
38.0k
            }
517
38.0k
        }
518
38.0k
    }
519
};
520
} // namespace doris