Coverage Report

Created: 2026-11-02 08:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/storage/tablet/base_tablet.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/olap_common.pb.h>
21
22
#include <memory>
23
#include <mutex>
24
#include <shared_mutex>
25
#include <string>
26
27
#include "common/metrics/metrics.h"
28
#include "common/status.h"
29
#include "io/io_common.h"
30
#include "storage/iterators.h"
31
#include "storage/olap_common.h"
32
#include "storage/partial_update_info.h"
33
#include "storage/segment/segment.h"
34
#include "storage/tablet/tablet_fwd.h"
35
#include "storage/tablet/tablet_meta.h"
36
#include "storage/tablet/tablet_schema.h"
37
#include "storage/version_graph.h"
38
#include "util/bthread_shared_mutex.h"
39
40
namespace doris {
41
namespace io {
42
class FileRangeReadContext;
43
}
44
45
struct RowSetSplits;
46
struct RowsetWriterContext;
47
class RowsetWriter;
48
class CalcDeleteBitmapToken;
49
class SegmentCacheHandle;
50
class RowIdConversion;
51
struct PartialUpdateInfo;
52
class PartialUpdateReadPlan;
53
struct CaptureRowsetOps;
54
struct CaptureRowsetResult;
55
struct TabletReadSource;
56
class FixedReadPlan;
57
58
struct TabletWithVersion {
59
    BaseTabletSPtr tablet;
60
    int64_t version;
61
};
62
63
enum class CompactionStage { NOT_SCHEDULED, PENDING, EXECUTING };
64
65
// Base class for all tablet classes
66
class BaseTablet : public std::enable_shared_from_this<BaseTablet> {
67
public:
68
    explicit BaseTablet(TabletMetaSharedPtr tablet_meta);
69
    virtual ~BaseTablet();
70
    BaseTablet(const BaseTablet&) = delete;
71
    BaseTablet& operator=(const BaseTablet&) = delete;
72
73
1.03G
    TabletState tablet_state() const { return _tablet_meta->tablet_state(); }
74
    Status set_tablet_state(TabletState state);
75
3.55M
    int64_t table_id() const { return _tablet_meta->table_id(); }
76
135k
    size_t row_size() const { return _tablet_meta->tablet_schema()->row_size(); }
77
3.62M
    int64_t index_id() const { return _tablet_meta->index_id(); }
78
8.51M
    int64_t partition_id() const { return _tablet_meta->partition_id(); }
79
4.01G
    int64_t tablet_id() const { return _tablet_meta->tablet_id(); }
80
304k
    int32_t schema_hash() const { return _tablet_meta->schema_hash(); }
81
135k
    CompressKind compress_kind() const { return _tablet_meta->tablet_schema()->compress_kind(); }
82
2.13M
    KeysType keys_type() const { return _tablet_meta->tablet_schema()->keys_type(); }
83
2.25k
    size_t num_key_columns() const { return _tablet_meta->tablet_schema()->num_key_columns(); }
84
0
    int64_t ttl_seconds() const { return _tablet_meta->ttl_seconds(); }
85
    // See TabletMeta::file_cache_ttl_expiration_time().
86
1.15M
    int64_t file_cache_ttl_expiration_time() const {
87
1.15M
        return _tablet_meta->file_cache_ttl_expiration_time();
88
1.15M
    }
89
    // currently used by schema change, inverted index building, and cooldown
90
10.9k
    std::timed_mutex& get_schema_change_lock() { return _schema_change_lock; }
91
5.19M
    bool enable_unique_key_merge_on_write() const {
92
#ifdef BE_TEST
93
        if (_tablet_meta == nullptr) {
94
            return false;
95
        }
96
#endif
97
5.19M
        return _tablet_meta->enable_unique_key_merge_on_write();
98
5.19M
    }
99
100
2.34M
    bool need_read_delete_bitmap() const {
101
2.34M
        return _tablet_meta->enable_unique_key_merge_on_write() ||
102
2.34M
               _tablet_meta->is_changelog_tablet();
103
2.34M
    }
104
105
4.99G
    bool is_changelog_tablet() const { return _tablet_meta->is_changelog_tablet(); }
106
107
    // Property encapsulated in TabletMeta
108
3.77G
    const TabletMetaSharedPtr& tablet_meta() const { return _tablet_meta; }
109
110
3.13k
    BinlogConfig binlog_config() const {
111
3.13k
        std::shared_lock rlock(_meta_lock);
112
3.13k
        return _tablet_meta->binlog_config();
113
3.13k
    }
114
115
    int32_t max_version_config();
116
117
    // FIXME(plat1ko): It is not appropriate to expose this lock
118
4.30M
    BthreadSharedMutex& get_header_lock() { return _meta_lock; }
119
120
    void update_max_version_schema(const TabletSchemaSPtr& tablet_schema);
121
122
1.41M
    TabletSchemaSPtr tablet_schema() const {
123
1.41M
        std::shared_lock rlock(_meta_lock);
124
1.41M
        return _max_version_schema;
125
1.41M
    }
126
127
10.9k
    void set_alter_failed(bool alter_failed) { _alter_failed = alter_failed; }
128
135k
    bool is_alter_failed() { return _alter_failed; }
129
130
    virtual std::string tablet_path() const = 0;
131
132
    virtual bool exceed_version_limit(int32_t limit) = 0;
133
134
    virtual Result<std::unique_ptr<RowsetWriter>> create_rowset_writer(RowsetWriterContext& context,
135
                                                                       bool vertical) = 0;
136
137
    virtual Status capture_rs_readers(const Version& spec_version,
138
                                      std::vector<RowSetSplits>* rs_splits,
139
                                      const CaptureRowsetOps& opts) = 0;
140
141
    virtual size_t tablet_footprint() = 0;
142
143
    // this method just return the compaction sum on each rowset
144
    // note(tsy): we should unify the compaction score calculation finally
145
    uint32_t get_real_compaction_score() const;
146
    // MUST hold shared `_meta_lock`. Use this variant when the caller already
147
    // holds the header lock to avoid recursively re-acquiring the (now
148
    // writer-preferring) `_meta_lock`, which would self-deadlock.
149
    uint32_t get_real_compaction_score_unlocked() const;
150
151
    // MUST hold shared meta lock
152
    Status capture_rs_readers_unlocked(const Versions& version_path,
153
                                       std::vector<RowSetSplits>* rs_splits) const;
154
155
    // _rs_version_map and _stale_rs_version_map should be protected by _meta_lock
156
    // The caller must call hold _meta_lock when call this three function.
157
    RowsetSharedPtr get_rowset_by_version(const Version& version, bool find_is_stale = false) const;
158
    RowsetSharedPtr get_stale_rowset_by_version(const Version& version) const;
159
    RowsetSharedPtr get_rowset_with_max_version() const;
160
161
    Status get_all_rs_id(int64_t max_version, RowsetIdUnorderedSet* rowset_ids) const;
162
    Status get_all_rs_id_unlocked(int64_t max_version, RowsetIdUnorderedSet* rowset_ids) const;
163
164
    // Get the missed versions until the spec_version.
165
    Versions get_missed_versions(int64_t spec_version) const;
166
    Versions get_missed_versions_unlocked(int64_t spec_version) const;
167
168
    void generate_tablet_meta_copy(TabletMeta& new_tablet_meta, bool cloud_get_rowset_meta) const;
169
    void generate_tablet_meta_copy_unlocked(TabletMeta& new_tablet_meta,
170
                                            bool cloud_get_rowset_meta) const;
171
172
    bool scan_expired_changelog_rowsets();
173
174
636
    virtual int64_t max_version_unlocked() const { return _tablet_meta->max_version().second; }
175
176
    static TabletSchemaSPtr tablet_schema_with_merged_max_schema_version(
177
            const std::vector<RowsetMetaSharedPtr>& rowset_metas);
178
179
    ////////////////////////////////////////////////////////////////////////////
180
    // begin MoW functions
181
    ////////////////////////////////////////////////////////////////////////////
182
    std::vector<RowsetSharedPtr> get_rowset_by_ids(
183
            const RowsetIdUnorderedSet* specified_rowset_ids);
184
185
    // Lookup a row with TupleDescriptor and fill Block
186
    Status lookup_row_data(const Slice& encoded_key, const RowLocation& row_location,
187
                           RowsetSharedPtr rowset, OlapReaderStatistics& stats, std::string& values,
188
                           bool write_to_cache = false, const io::IOContext* io_ctx = nullptr);
189
190
    // Reuse the segment returned by lookup_row_key. The caller must keep the segment and
191
    // its acquired rowset alive until this method returns.
192
    Status lookup_row_data(const Slice& encoded_key, const RowLocation& row_location,
193
                           const segment_v2::SegmentSharedPtr& segment, RowsetSharedPtr rowset,
194
                           OlapReaderStatistics& stats, std::string& values,
195
                           bool write_to_cache = false, const io::IOContext* io_ctx = nullptr);
196
197
    // Read from the resolved segment with query-scoped range read-ahead admission. The caller
198
    // keeps the segment and its acquired rowset alive as with lookup_row_data above.
199
    Status lookup_row_data_with_read_ahead(
200
            const Slice& encoded_key, const RowLocation& row_location,
201
            const segment_v2::SegmentSharedPtr& segment, RowsetSharedPtr rowset,
202
            OlapReaderStatistics& stats, std::string& values, bool write_to_cache,
203
            const io::IOContext* io_ctx,
204
            const std::shared_ptr<io::FileRangeReadContext>& read_ahead_context);
205
    // Lookup the row location of `encoded_key`, the function sets `row_location` on success.
206
    // NOTE: the method only works in unique key model with primary key index, you will got a
207
    //       not supported error in other data model.
208
    Status lookup_row_key(const Slice& encoded_key, TabletSchema* latest_schema, bool with_seq_col,
209
                          const std::vector<RowsetSharedPtr>& specified_rowsets,
210
                          RowLocation* row_location, int64_t version,
211
                          std::vector<std::unique_ptr<SegmentCacheHandle>>& segment_caches,
212
                          RowsetSharedPtr* rowset = nullptr, bool with_rowid = true,
213
                          std::string* encoded_seq_value = nullptr,
214
                          OlapReaderStatistics* stats = nullptr,
215
                          DeleteBitmapPtr tablet_delete_bitmap = nullptr,
216
                          const io::IOContext* io_ctx = nullptr,
217
                          segment_v2::SegmentSharedPtr* segment = nullptr);
218
219
    // calc delete bitmap when flush memtable, use a fake version to calc
220
    // For example, cur max version is 5, and we use version 6 to calc but
221
    // finally this rowset publish version with 8, we should make up data
222
    // for rowset 6-7. Also, if a compaction happens between commit_txn and
223
    // publish_txn, we should remove compaction input rowsets' delete_bitmap
224
    // and build newly generated rowset's delete_bitmap
225
    static Status calc_delete_bitmap(const BaseTabletSPtr& tablet, RowsetSharedPtr rowset,
226
                                     const std::vector<segment_v2::SegmentSharedPtr>& segments,
227
                                     const std::vector<RowsetSharedPtr>& specified_rowsets,
228
                                     DeleteBitmapPtr delete_bitmap, int64_t version,
229
                                     CalcDeleteBitmapToken* token,
230
                                     RowsetWriter* rowset_writer = nullptr,
231
                                     DeleteBitmapPtr tablet_delete_bitmap = nullptr);
232
233
    Status calc_segment_delete_bitmap(RowsetSharedPtr rowset,
234
                                      const segment_v2::SegmentSharedPtr& seg,
235
                                      const std::vector<RowsetSharedPtr>& specified_rowsets,
236
                                      DeleteBitmapPtr delete_bitmap, int64_t end_version,
237
                                      RowsetWriter* rowset_writer,
238
                                      DeleteBitmapPtr tablet_delete_bitmap = nullptr,
239
                                      int64_t queue_time_us = 0);
240
241
    Status calc_delete_bitmap_between_segments(
242
            TabletSchemaSPtr schema, RowsetId rowset_id,
243
            const std::vector<segment_v2::SegmentSharedPtr>& segments,
244
            DeleteBitmapPtr delete_bitmap, int64_t queue_time_us = 0);
245
246
    static Status commit_phase_update_delete_bitmap(
247
            const BaseTabletSPtr& tablet, const RowsetSharedPtr& rowset,
248
            RowsetIdUnorderedSet& pre_rowset_ids, DeleteBitmapPtr delete_bitmap,
249
            const std::vector<segment_v2::SegmentSharedPtr>& segments, int64_t txn_id,
250
            CalcDeleteBitmapToken* token, RowsetWriter* rowset_writer = nullptr);
251
252
    static void add_sentinel_mark_to_delete_bitmap(DeleteBitmap* delete_bitmap,
253
                                                   const RowsetIdUnorderedSet& rowsetids);
254
255
    Status check_delete_bitmap_correctness(DeleteBitmapPtr delete_bitmap, int64_t max_version,
256
                                           int64_t txn_id, const RowsetIdUnorderedSet& rowset_ids,
257
                                           std::vector<RowsetSharedPtr>* rowsets = nullptr);
258
259
    static const signed char* get_delete_sign_column_data(const Block& block,
260
                                                          size_t rows_at_least = 0);
261
262
    static Status generate_default_value_block(
263
            const TabletSchema& schema, const std::vector<uint32_t>& cids,
264
            const PartialUpdateInfo& partial_update_info, const Block& row_block,
265
            Block& default_value_block, const std::map<uint32_t, uint32_t>* row_indices = nullptr);
266
267
    static Status generate_new_block_for_partial_update(
268
            TabletSchemaSPtr rowset_schema, const PartialUpdateInfo* partial_update_info,
269
            const FixedReadPlan& read_plan_ori, const FixedReadPlan& read_plan_update,
270
            const std::map<RowsetId, RowsetSharedPtr>& rsid_to_rowset, Block* output_block);
271
272
    static Status generate_new_block_for_flexible_partial_update(
273
            TabletSchemaSPtr rowset_schema, const PartialUpdateInfo* partial_update_info,
274
            std::set<uint32_t>& rids_be_overwritten, const FixedReadPlan& read_plan_ori,
275
            const FixedReadPlan& read_plan_update,
276
            const std::map<RowsetId, RowsetSharedPtr>& rsid_to_rowset, Block* output_block);
277
278
    // We use the TabletSchema from the caller because the TabletSchema in the rowset'meta
279
    // may be outdated due to schema change. Also note that the the cids should indicate the indexes
280
    // of the columns in the TabletSchema passed in.
281
    static Status fetch_value_through_row_column(RowsetSharedPtr input_rowset,
282
                                                 const TabletSchema& tablet_schema, uint32_t segid,
283
                                                 const std::vector<uint32_t>& rowids,
284
                                                 const std::vector<uint32_t>& cids, Block& block);
285
286
    static Status fetch_values_by_rowids(RowsetSharedPtr input_rowset,
287
                                         const TabletSchema& tablet_schema, uint32_t segid,
288
                                         const std::vector<uint32_t>& rowids,
289
                                         const std::vector<uint32_t>& cids,
290
                                         MutableColumns& dst_columns);
291
292
    static Status fetch_value_by_rowids(RowsetSharedPtr input_rowset, uint32_t segid,
293
                                        const std::vector<uint32_t>& rowids,
294
                                        const TabletColumn& tablet_column, MutableColumnPtr& dst);
295
296
    virtual Result<std::unique_ptr<RowsetWriter>> create_transient_rowset_writer(
297
            const Rowset& rowset, std::shared_ptr<PartialUpdateInfo> partial_update_info,
298
            int64_t txn_expiration = 0) = 0;
299
300
    static Status update_delete_bitmap(const BaseTabletSPtr& self, TabletTxnInfo* txn_info,
301
                                       int64_t txn_id, int64_t txn_expiration = 0,
302
                                       DeleteBitmapPtr tablet_delete_bitmap = nullptr);
303
    virtual Status save_delete_bitmap(const TabletTxnInfo* txn_info, int64_t txn_id,
304
                                      DeleteBitmapPtr delete_bitmap, RowsetWriter* rowset_writer,
305
                                      const RowsetIdUnorderedSet& cur_rowset_ids,
306
                                      int64_t lock_id = -1, int64_t next_visible_version = -1) = 0;
307
    virtual CalcDeleteBitmapExecutor* calc_delete_bitmap_executor() = 0;
308
309
    void calc_compaction_output_rowset_delete_bitmap(
310
            const std::vector<RowsetSharedPtr>& input_rowsets, const RowsetSharedPtr& output_rowset,
311
            const RowIdConversion& rowid_conversion, uint64_t start_version, uint64_t end_version,
312
            std::set<RowLocation>* missed_rows,
313
            std::map<RowsetSharedPtr, std::list<std::pair<RowLocation, RowLocation>>>* location_map,
314
            const DeleteBitmap& input_delete_bitmap, DeleteBitmap* output_rowset_delete_bitmap);
315
316
    Status check_rowid_conversion(
317
            RowsetSharedPtr dst_rowset,
318
            const std::map<RowsetSharedPtr, std::list<std::pair<RowLocation, RowLocation>>>&
319
                    location_map);
320
321
    static Status update_delete_bitmap_without_lock(
322
            const BaseTabletSPtr& self, const RowsetSharedPtr& rowset,
323
            const std::vector<RowsetSharedPtr>* specified_base_rowsets = nullptr);
324
325
    using DeleteBitmapKeyRanges =
326
            std::vector<std::tuple<DeleteBitmap::BitmapKey, DeleteBitmap::BitmapKey>>;
327
    void agg_delete_bitmap_for_stale_rowsets(
328
            Version version, DeleteBitmapKeyRanges& remove_delete_bitmap_key_ranges);
329
    void check_agg_delete_bitmap_for_stale_rowsets(int64_t& useless_rowset_count,
330
                                                   int64_t& useless_rowset_version_count);
331
    ////////////////////////////////////////////////////////////////////////////
332
    // end MoW functions
333
    ////////////////////////////////////////////////////////////////////////////
334
335
    RowsetSharedPtr get_rowset(const RowsetId& rowset_id);
336
337
    std::vector<RowsetSharedPtr> get_snapshot_rowset(bool include_stale_rowset = false) const;
338
339
    virtual void clear_cache() = 0;
340
341
    // Find the first consecutive empty rowsets. output->size() >= limit
342
    void calc_consecutive_empty_rowsets(std::vector<RowsetSharedPtr>* empty_rowsets,
343
                                        const std::vector<RowsetSharedPtr>& candidate_rowsets,
344
                                        int64_t limit);
345
346
    void traverse_rowsets(std::function<void(const RowsetSharedPtr&)> visitor,
347
300k
                          bool include_stale = false) {
348
300k
        std::shared_lock rlock(_meta_lock);
349
300k
        traverse_rowsets_unlocked(visitor, include_stale);
350
300k
    }
351
352
    void traverse_rowsets_unlocked(std::function<void(const RowsetSharedPtr&)> visitor,
353
808k
                                   bool include_stale = false) const {
354
2.33M
        for (auto& [v, rs] : _rs_version_map) {
355
2.33M
            visitor(rs);
356
2.33M
        }
357
808k
        if (!include_stale) return;
358
527k
        for (auto& [v, rs] : _stale_rs_version_map) {
359
60.7k
            visitor(rs);
360
60.7k
        }
361
527k
    }
362
363
    Status calc_file_crc(uint32_t* crc_value, int64_t start_version, int64_t end_version,
364
                         uint32_t* rowset_count, int64_t* file_count);
365
366
    Status show_nested_index_file(std::string* json_meta);
367
368
2.09M
    TabletUid tablet_uid() const { return _tablet_meta->tablet_uid(); }
369
299k
    TabletInfo get_tablet_info() const { return TabletInfo(tablet_id(), tablet_uid()); }
370
371
    void get_base_rowset_delete_bitmap_count(
372
            uint64_t* max_base_rowset_delete_bitmap_score,
373
            int64_t* max_base_rowset_delete_bitmap_score_tablet_id);
374
375
167
    virtual Status check_delete_bitmap_cache(int64_t txn_id, DeleteBitmap* expected_delete_bitmap) {
376
167
        return Status::OK();
377
167
    }
378
379
    void prefill_dbm_agg_cache(const RowsetSharedPtr& rowset, int64_t version);
380
    void prefill_dbm_agg_cache_after_compaction(const RowsetSharedPtr& output_rowset);
381
382
    [[nodiscard]] Result<CaptureRowsetResult> capture_consistent_rowsets_unlocked(
383
            const Version& version_range, const CaptureRowsetOps& options) const;
384
385
    [[nodiscard]] virtual Result<std::vector<Version>> capture_consistent_versions_unlocked(
386
            const Version& version_range, const CaptureRowsetOps& options) const;
387
388
    [[nodiscard]] Result<std::vector<RowSetSplits>> capture_rs_readers_unlocked(
389
            const Version& version_range, const CaptureRowsetOps& options) const;
390
391
    [[nodiscard]] Result<TabletReadSource> capture_read_source(const Version& version_range,
392
                                                               const CaptureRowsetOps& options);
393
394
protected:
395
    Status _lookup_row_data(const Slice& encoded_key, const RowLocation& row_location,
396
                            const segment_v2::SegmentSharedPtr* segment, RowsetSharedPtr rowset,
397
                            OlapReaderStatistics& stats, std::string& values, bool write_to_cache,
398
                            const io::IOContext* io_ctx) const;
399
400
    // Protected by the tablet header lock; discovery resumes after this version.
401
    Version _changelog_ttl_scan_cursor {-1, -1};
402
403
    // Find the missed versions until the spec_version.
404
    //
405
    // for example:
406
    //     [0-4][5-5][8-8][9-9][14-14]
407
    // for cloud, if spec_version = 12, it will return [6-7],[10-12]
408
    // for local, if spec_version = 12, it will return [6, 6], [7, 7], [10, 10], [11, 11], [12, 12]
409
    virtual Versions calc_missed_versions(int64_t spec_version,
410
                                          Versions existing_versions) const = 0;
411
412
    void _print_missed_versions(const Versions& missed_versions) const;
413
    bool _reconstruct_version_tracker_if_necessary();
414
415
    static void _rowset_ids_difference(const RowsetIdUnorderedSet& cur,
416
                                       const RowsetIdUnorderedSet& pre,
417
                                       RowsetIdUnorderedSet* to_add, RowsetIdUnorderedSet* to_del);
418
419
    // We can only know if a key is excluded from the segment
420
    // based on strictly order compare result with segments key bounds
421
    static bool _key_is_not_in_segment(Slice key, const KeyBoundsPB& segment_key_bounds,
422
                                       bool is_segments_key_bounds_truncated);
423
424
    Status sort_block(Block& in_block, Block& output_block,
425
                      std::vector<uint32_t>* permutation = nullptr);
426
427
    Result<CaptureRowsetResult> _remote_capture_rowsets(const Version& version_range) const;
428
429
    mutable BthreadSharedMutex _meta_lock;
430
    TimestampedVersionTracker _timestamped_version_tracker;
431
432
    // After version 0.13, all newly created rowsets are saved in _rs_version_map.
433
    // And if rowset being compacted, the old rowsets will be saved in _stale_rs_version_map;
434
    std::unordered_map<Version, RowsetSharedPtr, HashOfVersion> _rs_version_map;
435
    // This variable _stale_rs_version_map is used to record these rowsets which are be compacted.
436
    // These _stale rowsets are been removed when rowsets' pathVersion is expired,
437
    // this policy is judged and computed by TimestampedVersionTracker.
438
    std::unordered_map<Version, RowsetSharedPtr, HashOfVersion> _stale_rs_version_map;
439
    const TabletMetaSharedPtr _tablet_meta;
440
    TabletSchemaSPtr _max_version_schema;
441
442
    // `_alter_failed` is used to indicate whether the tablet failed to perform a schema change
443
    std::atomic<bool> _alter_failed = false;
444
445
    // metrics of this tablet
446
    std::shared_ptr<MetricEntity> _metric_entity;
447
448
protected:
449
    std::timed_mutex _schema_change_lock;
450
451
public:
452
    IntCounter* query_scan_bytes = nullptr;
453
    IntCounter* query_scan_rows = nullptr;
454
    IntCounter* query_scan_count = nullptr;
455
    IntCounter* flush_bytes = nullptr;
456
    IntCounter* flush_finish_count = nullptr;
457
    // Last time this tablet was scanned by a query / flushed by a load (ms since epoch),
458
    // named after the counter each one accompanies (query_scan_count / flush_finish_count).
459
    // Set only on the query scan path and the memtable flush path respectively, so they are
460
    // NOT polluted by compaction / snapshot / agent tasks the way CloudTablet::
461
    // last_access_time_ms is. Do NOT shorten to last_load_time_ms: CloudTablet already has
462
    // a field by that name tracking load start for the compaction freeze check.
463
    std::atomic<int64_t> last_query_scan_time_ms {0};
464
    std::atomic<int64_t> last_load_flush_time_ms {0};
465
    // Snapshots taken at the last SUCCESSFULLY DELIVERED report. Committed only after
466
    // handle_report() returns true, never with exchange() during collection -- see
467
    // ActiveTabletCollector::commit(). Seeded in the constructor from the counters' current
468
    // values, which are shared with any other live BaseTablet for the same tablet id.
469
    std::atomic<int64_t> last_reported_scan_count {0};
470
    std::atomic<int64_t> last_reported_flush_count {0};
471
    // Monotonic clock of that commit -- NOT wall clock. Its only use is the
472
    // `now - last_reported_mono_ms` subtraction that yields the delta window; a backward
473
    // NTP step on the wall clock would clamp that window to 1 ms and inflate every rate
474
    // by orders of magnitude. The two last_*_time_ms fields above must stay wall clock:
475
    // they are shipped to FE, which compares them against its own clock.
476
    //
477
    // Shared by every tablet in a round, because commit() is all-or-nothing: a dropped
478
    // report (5 retries exhausted, or handle_report() returning false) advances no
479
    // baseline at all, so the next round's delta spans several intervals. Backends also
480
    // report on independent phases. FE compares entries across backends and across
481
    // rounds, so it must normalise delta by this window rather than compare raw counts.
482
    std::atomic<int64_t> last_reported_mono_ms {0};
483
    std::atomic<int64_t> published_count = 0;
484
    std::atomic<int64_t> read_block_count = 0;
485
    std::atomic<int64_t> write_count = 0;
486
    std::atomic<int64_t> compaction_count = 0;
487
488
    CompactionStage compaction_stage = CompactionStage::NOT_SCHEDULED;
489
    // Separate sample_infos for each compaction type to avoid race condition
490
    // when different types of compaction run concurrently on the same tablet
491
    std::mutex cumu_sample_info_lock;
492
    std::mutex base_sample_info_lock;
493
    std::mutex full_sample_info_lock;
494
    std::vector<CompactionSampleInfo> cumu_sample_infos;
495
    std::vector<CompactionSampleInfo> base_sample_infos;
496
    std::vector<CompactionSampleInfo> full_sample_infos;
497
    Status last_compaction_status = Status::OK();
498
499
42.5k
    std::mutex& get_sample_info_lock(ReaderType reader_type) {
500
42.5k
        switch (reader_type) {
501
39.0k
        case ReaderType::READER_CUMULATIVE_COMPACTION:
502
39.0k
            return cumu_sample_info_lock;
503
2.06k
        case ReaderType::READER_BASE_COMPACTION:
504
2.06k
            return base_sample_info_lock;
505
1.80k
        case ReaderType::READER_FULL_COMPACTION:
506
1.80k
            return full_sample_info_lock;
507
0
        default:
508
            // For other compaction types, use base_sample_info_lock as default
509
0
            return base_sample_info_lock;
510
42.5k
        }
511
42.5k
    }
512
513
42.5k
    std::vector<CompactionSampleInfo>& get_sample_infos(ReaderType reader_type) {
514
42.5k
        switch (reader_type) {
515
39.0k
        case ReaderType::READER_CUMULATIVE_COMPACTION:
516
39.0k
            return cumu_sample_infos;
517
2.06k
        case ReaderType::READER_BASE_COMPACTION:
518
2.06k
            return base_sample_infos;
519
1.80k
        case ReaderType::READER_FULL_COMPACTION:
520
1.80k
            return full_sample_infos;
521
3
        default:
522
            // For other compaction types, use base_sample_infos as default
523
3
            return base_sample_infos;
524
42.5k
        }
525
42.5k
    }
526
527
    // Density ratio for sparse optimization (non_null_cells / total_cells)
528
    // Value range: [0.0, 1.0], smaller value means more sparse
529
    // Default 1.0 means no history data, will not enable sparse optimization initially
530
    std::atomic<double> compaction_density {1.0};
531
};
532
533
struct CaptureRowsetOps {
534
    bool skip_missing_versions = false;
535
    bool quiet = false;
536
    bool include_stale_rowsets = true;
537
    bool enable_fetch_rowsets_from_peers = false;
538
539
    // ======== only take effect in cloud mode ========
540
541
    // Enable preference for cached/warmed-up rowsets when building version paths.
542
    // When enabled, the capture process will prioritize already cached rowsets
543
    // to avoid cold data reads and improve query performance.
544
    bool enable_prefer_cached_rowset {false};
545
546
    // Query freshness tolerance in milliseconds.
547
    // Defines the time window for considering data as "fresh enough".
548
    // Rowsets that became visible within this time range can be skipped if not warmed up,
549
    // but older rowsets (before current_time - query_freshness_tolerance_ms) that are
550
    // not warmed up will trigger fallback to normal capture.
551
    // Set to -1 to disable freshness tolerance checking.
552
    int64_t query_freshness_tolerance_ms {-1};
553
};
554
555
struct CaptureRowsetResult {
556
    std::vector<RowsetSharedPtr> rowsets;
557
    std::shared_ptr<DeleteBitmap> delete_bitmap;
558
};
559
560
struct TabletReadSource {
561
    std::vector<RowSetSplits> rs_splits;
562
    std::vector<RowsetMetaSharedPtr> delete_predicates;
563
    std::shared_ptr<DeleteBitmap> delete_bitmap;
564
    // Fill delete predicates with `rs_splits`
565
    void fill_delete_predicates();
566
};
567
568
} /* namespace doris */