Coverage Report

Created: 2026-08-14 18:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/cloud/cloud_tablet_mgr.cpp
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 "cloud/cloud_tablet_mgr.h"
19
20
#include <bthread/countdown_event.h>
21
22
#include <chrono>
23
24
#include "cloud/cloud_cluster_info.h"
25
#include "cloud/cloud_meta_mgr.h"
26
#include "cloud/cloud_storage_engine.h"
27
#include "cloud/cloud_tablet.h"
28
#include "cloud/config.h"
29
#include "common/status.h"
30
#include "cpp/sync_point.h"
31
#include "runtime/memory/cache_policy.h"
32
#include "storage/compaction/cumulative_compaction_time_series_policy.h"
33
#include "util/debug_points.h"
34
#include "util/lru_cache.h"
35
#include "util/stack_util.h"
36
37
namespace doris {
38
uint64_t g_tablet_report_inactive_duration_ms = 0;
39
bvar::Adder<uint64_t> g_base_compaction_not_frozen_tablet_num(
40
        "base_compaction_not_frozen_tablet_num");
41
bvar::Adder<uint64_t> g_cumu_compaction_not_frozen_tablet_num(
42
        "cumu_compaction_not_frozen_tablet_num");
43
namespace {
44
45
// port from
46
// https://github.com/golang/groupcache/blob/master/singleflight/singleflight.go
47
template <typename Key, typename Val>
48
class SingleFlight {
49
public:
50
8
    SingleFlight() = default;
51
52
    SingleFlight(const SingleFlight&) = delete;
53
    void operator=(const SingleFlight&) = delete;
54
55
    using Loader = std::function<Val(const Key&)>;
56
57
    // Do executes and returns the results of the given function, making
58
    // sure that only one execution is in-flight for a given key at a
59
    // time. If a duplicate comes in, the duplicate caller waits for the
60
    // original to complete and receives the same results.
61
119k
    Val load(const Key& key, Loader loader) {
62
119k
        std::unique_lock lock(_call_map_mtx);
63
64
119k
        auto it = _call_map.find(key);
65
119k
        if (it != _call_map.end()) {
66
81
            auto call = it->second;
67
81
            lock.unlock();
68
81
            if (int ec = call->event.wait(); ec != 0) {
69
0
                throw std::system_error(std::error_code(ec, std::system_category()),
70
0
                                        "CountdownEvent wait failed");
71
0
            }
72
81
            return call->val;
73
81
        }
74
118k
        auto call = std::make_shared<Call>();
75
118k
        _call_map.emplace(key, call);
76
118k
        lock.unlock();
77
78
118k
        call->val = loader(key);
79
118k
        call->event.signal();
80
81
118k
        lock.lock();
82
118k
        _call_map.erase(key);
83
118k
        lock.unlock();
84
85
118k
        return call->val;
86
119k
    }
87
88
private:
89
    // `Call` is an in-flight or completed `load` call
90
    struct Call {
91
        bthread::CountdownEvent event;
92
        Val val;
93
    };
94
95
    std::mutex _call_map_mtx;
96
    std::unordered_map<Key, std::shared_ptr<Call>> _call_map;
97
};
98
99
// tablet_id -> load tablet function
100
SingleFlight<int64_t, Result<std::shared_ptr<CloudTablet>>> s_singleflight_load_tablet;
101
102
} // namespace
103
104
// tablet_id -> cached tablet
105
// This map owns all cached tablets. The lifetime of tablet can be longer than the LRU handle.
106
// It's also used for scenarios where users want to access the tablet by `tablet_id` without changing the LRU order.
107
// TODO(plat1ko): multi shard to increase concurrency
108
class CloudTabletMgr::TabletMap {
109
public:
110
117k
    void put(std::shared_ptr<CloudTablet> tablet) {
111
117k
        std::lock_guard lock(_mtx);
112
117k
        _map[tablet->tablet_id()] = std::move(tablet);
113
117k
    }
114
115
18.9k
    void erase(CloudTablet* tablet) {
116
18.9k
        std::lock_guard lock(_mtx);
117
18.9k
        auto it = _map.find(tablet->tablet_id());
118
        // According to the implementation of `LRUCache`, `deleter` may be called after a tablet
119
        // with same tablet id insert into cache and `TabletMap`. So we MUST check if the tablet
120
        // instance to be erased is the same one in the map.
121
19.1k
        if (it != _map.end() && it->second.get() == tablet) {
122
19.1k
            _map.erase(it);
123
19.1k
        }
124
18.9k
    }
125
126
43
    std::shared_ptr<CloudTablet> get(int64_t tablet_id) {
127
43
        std::lock_guard lock(_mtx);
128
43
        if (auto it = _map.find(tablet_id); it != _map.end()) {
129
8
            return it->second;
130
8
        }
131
35
        return nullptr;
132
43
    }
133
134
15.8k
    size_t size() { return _map.size(); }
135
136
15.9k
    void traverse(std::function<void(const std::shared_ptr<CloudTablet>&)> visitor) {
137
15.9k
        std::lock_guard lock(_mtx);
138
476M
        for (auto& [_, tablet] : _map) {
139
476M
            visitor(tablet);
140
476M
        }
141
15.9k
    }
142
143
private:
144
    std::mutex _mtx;
145
    std::unordered_map<int64_t, std::shared_ptr<CloudTablet>> _map;
146
};
147
148
// TODO(plat1ko): Prune cache
149
CloudTabletMgr::CloudTabletMgr(CloudStorageEngine& engine)
150
257
        : _engine(engine),
151
257
          _tablet_map(std::make_unique<TabletMap>()),
152
257
          _cache(std::make_unique<LRUCachePolicy>(
153
257
                  CachePolicy::CacheType::CLOUD_TABLET_CACHE, config::tablet_cache_capacity,
154
257
                  LRUCacheType::NUMBER, /*sweep time*/ 0, config::tablet_cache_shards,
155
257
                  /*element_count_capacity*/ 0, /*enable_prune*/ false,
156
257
                  /*is_lru_k*/ false)) {}
157
158
256
CloudTabletMgr::~CloudTabletMgr() = default;
159
160
3.08M
void set_tablet_access_time_ms(CloudTablet* tablet) {
161
3.08M
    using namespace std::chrono;
162
3.08M
    int64_t now = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
163
3.08M
    tablet->last_access_time_ms = now;
164
3.08M
}
165
166
Result<std::shared_ptr<CloudTablet>> CloudTabletMgr::get_tablet(int64_t tablet_id, bool warmup_data,
167
                                                                bool sync_delete_bitmap,
168
                                                                SyncRowsetStats* sync_stats,
169
                                                                bool force_use_only_cached,
170
1.53M
                                                                bool cache_on_miss) {
171
1.53M
    DBUG_EXECUTE_IF("CloudTabletMgr::get_tablet.block", DBUG_BLOCK);
172
    // LRU value type. `Value`'s lifetime MUST NOT be longer than `CloudTabletMgr`
173
1.53M
    class Value : public LRUCacheValueBase {
174
1.53M
    public:
175
1.53M
        Value(const std::shared_ptr<CloudTablet>& tablet, TabletMap& tablet_map)
176
1.53M
                : tablet(tablet), tablet_map(tablet_map) {}
177
1.53M
        ~Value() override { tablet_map.erase(tablet.get()); }
178
179
        // FIXME(plat1ko): The ownership of tablet seems to belong to 'TabletMap', while `Value`
180
        // only requires a reference.
181
1.53M
        std::shared_ptr<CloudTablet> tablet;
182
1.53M
        TabletMap& tablet_map;
183
1.53M
    };
184
185
18.4E
    VLOG_DEBUG << "get_tablet tablet_id=" << tablet_id << " stack: " << get_stack_trace();
186
187
1.53M
    auto tablet_id_str = std::to_string(tablet_id);
188
1.53M
    CacheKey key(tablet_id_str);
189
1.53M
    auto* handle = _cache->lookup(key);
190
191
1.53M
    if (handle == nullptr) {
192
#ifdef BE_TEST
193
        if (auto tablet = _tablet_map->get(tablet_id); tablet != nullptr) {
194
            set_tablet_access_time_ms(tablet.get());
195
            return tablet;
196
        }
197
#endif
198
118k
        if (force_use_only_cached) {
199
0
            LOG(INFO) << "tablet=" << tablet_id
200
0
                      << "does not exists in local tablet cache, because param "
201
0
                         "force_use_only_cached=true, "
202
0
                         "treat it as an error";
203
0
            return ResultError(Status::InternalError(
204
0
                    "tablet={} does not exists in local tablet cache, because param "
205
0
                    "force_use_only_cached=true, "
206
0
                    "treat it as an error",
207
0
                    tablet_id));
208
0
        }
209
118k
        TEST_SYNC_POINT("CloudTabletMgr::get_tablet.not_found_in_cache");
210
118k
        if (sync_stats) {
211
13.2k
            ++sync_stats->tablet_meta_cache_miss;
212
13.2k
        }
213
        // Insert into cache and tablet_map inside SingleFlight lambda to ensure
214
        // only the leader caller does this. Moving these outside the lambda causes
215
        // a race condition: when multiple concurrent callers share the same CloudTablet*
216
        // from SingleFlight, each creates a competing LRU cache entry. Delayed Value
217
        // destructors then erase the tablet_map entry (the raw pointer safety check
218
        // passes since all callers share the same pointer), and the tablet permanently
219
        // disappears from tablet_map. Subsequent get_tablet() calls hit the LRU cache
220
        // directly (cache hit path) which never re-inserts into tablet_map, making the
221
        // tablet invisible to the compaction scheduler.
222
118k
        auto load_tablet = [this, &key, warmup_data, sync_delete_bitmap, sync_stats, cache_on_miss](
223
119k
                                   int64_t tablet_id) -> Result<std::shared_ptr<CloudTablet>> {
224
119k
            TabletMetaSharedPtr tablet_meta;
225
119k
            auto start = std::chrono::steady_clock::now();
226
119k
            auto st = _engine.meta_mgr().get_tablet_meta(tablet_id, &tablet_meta);
227
119k
            auto end = std::chrono::steady_clock::now();
228
119k
            if (sync_stats) {
229
13.2k
                sync_stats->get_remote_tablet_meta_rpc_ns +=
230
13.2k
                        std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count();
231
13.2k
            }
232
119k
            if (!st.ok()) {
233
110
                LOG(WARNING) << "failed to tablet " << tablet_id << ": " << st;
234
110
                return ResultError(st);
235
110
            }
236
237
119k
            auto tablet = std::make_shared<CloudTablet>(_engine, std::move(tablet_meta));
238
            // MUST sync stats to let compaction scheduler work correctly
239
119k
            SyncOptions options;
240
119k
            options.warmup_delta_data = warmup_data;
241
119k
            options.sync_delete_bitmap = sync_delete_bitmap;
242
119k
            st = _engine.meta_mgr().sync_tablet_rowsets(tablet.get(), options, sync_stats);
243
119k
            if (!st.ok()) {
244
0
                LOG(WARNING) << "failed to sync tablet " << tablet_id << ": " << st;
245
0
                return ResultError(st);
246
0
            }
247
248
119k
            if (!cache_on_miss) {
249
0
                set_tablet_access_time_ms(tablet.get());
250
0
                return tablet;
251
0
            }
252
253
119k
            auto value = std::make_unique<Value>(tablet, *_tablet_map);
254
119k
            auto* insert_handle = _cache->insert(key, value.release(), 1, sizeof(CloudTablet),
255
119k
                                                 CachePriority::NORMAL);
256
119k
            auto ret = std::shared_ptr<CloudTablet>(tablet.get(),
257
119k
                                                    [this, insert_handle](CloudTablet* tablet_ptr) {
258
118k
                                                        set_tablet_access_time_ms(tablet_ptr);
259
118k
                                                        _cache->release(insert_handle);
260
118k
                                                    });
261
119k
            _tablet_map->put(std::move(tablet));
262
119k
            return ret;
263
119k
        };
264
265
118k
        auto load_result = s_singleflight_load_tablet.load(tablet_id, std::move(load_tablet));
266
118k
        if (!load_result.has_value()) {
267
100
            return ResultError(Status::InternalError("failed to get tablet {}, msg={}", tablet_id,
268
100
                                                     load_result.error()));
269
100
        }
270
118k
        auto tablet = load_result.value();
271
118k
        set_tablet_access_time_ms(tablet.get());
272
118k
        return tablet;
273
118k
    }
274
1.41M
    if (sync_stats) {
275
1.01M
        ++sync_stats->tablet_meta_cache_hit;
276
1.01M
    }
277
1.41M
    CloudTablet* tablet_raw_ptr = reinterpret_cast<Value*>(_cache->value(handle))->tablet.get();
278
1.41M
    set_tablet_access_time_ms(tablet_raw_ptr);
279
1.43M
    auto tablet = std::shared_ptr<CloudTablet>(tablet_raw_ptr, [this, handle](CloudTablet* tablet) {
280
1.43M
        set_tablet_access_time_ms(tablet);
281
1.43M
        _cache->release(handle);
282
1.43M
    });
283
1.41M
    return tablet;
284
1.53M
}
285
286
0
bool CloudTabletMgr::peek_tablet_meta(int64_t tablet_id, TabletMetaSharedPtr* tablet_meta) {
287
0
    if (tablet_meta == nullptr) {
288
0
        return false;
289
0
    }
290
0
    auto tablet = _tablet_map->get(tablet_id);
291
0
    if (!tablet) {
292
0
        return false;
293
0
    }
294
0
    *tablet_meta = tablet->tablet_meta();
295
0
    return true;
296
0
}
297
298
16
std::shared_ptr<CloudTablet> CloudTabletMgr::get_tablet_if_cached(int64_t tablet_id) {
299
16
    return _tablet_map->get(tablet_id);
300
16
}
301
302
173
void CloudTabletMgr::erase_tablet(int64_t tablet_id) {
303
173
    auto tablet_id_str = std::to_string(tablet_id);
304
173
    CacheKey key(tablet_id_str.data(), tablet_id_str.size());
305
173
    _cache->erase(key);
306
173
}
307
308
10
void CloudTabletMgr::vacuum_stale_rowsets(const CountDownLatch& stop_latch) {
309
10
    LOG_INFO("begin to vacuum stale rowsets");
310
10
    std::vector<std::shared_ptr<CloudTablet>> tablets_to_vacuum;
311
10
    tablets_to_vacuum.reserve(_tablet_map->size());
312
510k
    _tablet_map->traverse([&tablets_to_vacuum](auto&& t) {
313
510k
        if (t->has_stale_rowsets()) {
314
9.55k
            tablets_to_vacuum.push_back(t);
315
9.55k
        }
316
510k
    });
317
10
    int num_vacuumed = 0;
318
9.55k
    for (auto& t : tablets_to_vacuum) {
319
9.55k
        if (stop_latch.count() <= 0) {
320
0
            break;
321
0
        }
322
323
9.55k
        num_vacuumed += t->delete_expired_stale_rowsets();
324
9.55k
    }
325
10
    LOG_INFO("finish vacuum stale rowsets")
326
10
            .tag("num_vacuumed", num_vacuumed)
327
10
            .tag("num_tablets", tablets_to_vacuum.size());
328
329
10
    {
330
10
        LOG_INFO("begin to remove unused rowsets");
331
10
        std::vector<std::shared_ptr<CloudTablet>> tablets_to_remove_unused_rowsets;
332
10
        tablets_to_remove_unused_rowsets.reserve(_tablet_map->size());
333
510k
        _tablet_map->traverse([&tablets_to_remove_unused_rowsets](auto&& t) {
334
510k
            if (t->need_remove_unused_rowsets()) {
335
4.94k
                tablets_to_remove_unused_rowsets.push_back(t);
336
4.94k
            }
337
510k
        });
338
4.94k
        for (auto& t : tablets_to_remove_unused_rowsets) {
339
4.94k
            t->remove_unused_rowsets();
340
4.94k
        }
341
10
        LOG_INFO("finish remove unused rowsets")
342
10
                .tag("num_tablets", tablets_to_remove_unused_rowsets.size());
343
10
        if (config::enable_check_agg_and_remove_pre_rowsets_delete_bitmap) {
344
0
            int64_t max_useless_rowset_count = 0;
345
0
            int64_t tablet_id_with_max_useless_rowset_count = 0;
346
0
            int64_t max_useless_rowset_version_count = 0;
347
0
            int64_t tablet_id_with_max_useless_rowset_version_count = 0;
348
0
            OlapStopWatch watch;
349
0
            _tablet_map->traverse([&](auto&& tablet) {
350
0
                int64_t useless_rowset_count = 0;
351
0
                int64_t useless_rowset_version_count = 0;
352
0
                tablet->check_agg_delete_bitmap_for_stale_rowsets(useless_rowset_count,
353
0
                                                                  useless_rowset_version_count);
354
0
                if (useless_rowset_count > max_useless_rowset_count) {
355
0
                    max_useless_rowset_count = useless_rowset_count;
356
0
                    tablet_id_with_max_useless_rowset_count = tablet->tablet_id();
357
0
                }
358
0
                if (useless_rowset_version_count > max_useless_rowset_version_count) {
359
0
                    max_useless_rowset_version_count = useless_rowset_version_count;
360
0
                    tablet_id_with_max_useless_rowset_version_count = tablet->tablet_id();
361
0
                }
362
0
            });
363
0
            g_max_rowsets_with_useless_delete_bitmap.set_value(max_useless_rowset_count);
364
0
            g_max_rowsets_with_useless_delete_bitmap_version.set_value(
365
0
                    max_useless_rowset_version_count);
366
0
            LOG(INFO) << "finish check_agg_delete_bitmap_for_stale_rowsets, cost(us)="
367
0
                      << watch.get_elapse_time_us()
368
0
                      << ". max useless rowset count=" << max_useless_rowset_count
369
0
                      << ", tablet_id=" << tablet_id_with_max_useless_rowset_count
370
0
                      << ", max useless rowset version count=" << max_useless_rowset_version_count
371
0
                      << ", tablet_id=" << tablet_id_with_max_useless_rowset_version_count;
372
0
        }
373
10
    }
374
10
    {
375
10
        _tablet_map->traverse(
376
510k
                [](auto&& tablet) { tablet->clear_unused_visible_pending_rowsets(); });
377
10
    }
378
10
}
379
380
15.8k
std::vector<std::weak_ptr<CloudTablet>> CloudTabletMgr::get_weak_tablets() {
381
15.8k
    std::vector<std::weak_ptr<CloudTablet>> weak_tablets;
382
15.8k
    weak_tablets.reserve(_tablet_map->size());
383
474M
    _tablet_map->traverse([&weak_tablets](auto& t) { weak_tablets.push_back(t); });
384
15.8k
    return weak_tablets;
385
15.8k
}
386
387
5
void CloudTabletMgr::sync_tablets(const CountDownLatch& stop_latch) {
388
5
    LOG_INFO("begin to sync tablets");
389
5
    int64_t last_sync_time_bound = ::time(nullptr) - config::tablet_sync_interval_s;
390
391
5
    auto weak_tablets = get_weak_tablets();
392
393
    // sort by last_sync_time
394
181k
    static auto cmp = [](const auto& a, const auto& b) { return a.first < b.first; };
395
5
    std::multiset<std::pair<int64_t, std::weak_ptr<CloudTablet>>, decltype(cmp)>
396
5
            sync_time_tablet_set(cmp);
397
398
279k
    for (auto& weak_tablet : weak_tablets) {
399
279k
        if (auto tablet = weak_tablet.lock()) {
400
279k
            int64_t last_sync_time = tablet->last_sync_time_s;
401
279k
            if (last_sync_time <= last_sync_time_bound) {
402
10.8k
                sync_time_tablet_set.emplace(last_sync_time, weak_tablet);
403
10.8k
            }
404
279k
        }
405
279k
    }
406
407
5
    int num_sync = 0;
408
10.8k
    for (auto&& [_, weak_tablet] : sync_time_tablet_set) {
409
10.8k
        if (stop_latch.count() <= 0) {
410
0
            break;
411
0
        }
412
413
10.8k
        if (auto tablet = weak_tablet.lock()) {
414
7.29k
            if (tablet->last_sync_time_s > last_sync_time_bound) {
415
0
                continue;
416
0
            }
417
418
7.29k
            ++num_sync;
419
7.29k
            auto st = tablet->sync_meta();
420
7.29k
            if (!st) {
421
0
                LOG_WARNING("failed to sync tablet meta {}", tablet->tablet_id()).error(st);
422
0
                if (st.is<ErrorCode::NOT_FOUND>()) {
423
0
                    continue;
424
0
                }
425
0
            }
426
7.29k
            SyncOptions options;
427
7.29k
            options.query_version = -1;
428
7.29k
            options.merge_schema = true;
429
7.29k
            st = tablet->sync_rowsets(options);
430
7.29k
            if (!st) {
431
0
                LOG_WARNING("failed to sync tablet rowsets {}", tablet->tablet_id()).error(st);
432
0
            }
433
7.29k
        }
434
10.8k
    }
435
5
    LOG_INFO("finish sync tablets").tag("num_sync", num_sync);
436
5
}
437
438
Status CloudTabletMgr::get_topn_tablets_to_compact(
439
        int n, CompactionType compaction_type, const std::function<bool(CloudTablet*)>& filter_out,
440
15.7k
        std::vector<std::shared_ptr<CloudTablet>>* tablets, CompactionScoreStats* score_stats) {
441
15.7k
    DCHECK(compaction_type == CompactionType::BASE_COMPACTION ||
442
15.7k
           compaction_type == CompactionType::CUMULATIVE_COMPACTION ||
443
15.7k
           compaction_type == CompactionType::CUMU_BINLOG_COMPACTION);
444
15.7k
    *score_stats = {};
445
15.7k
    score_stats->scanned = true;
446
15.7k
    int64_t max_score_tablet_id = 0;
447
    // clang-format off
448
470M
    auto score = [compaction_type](CloudTablet* t) {
449
470M
        if (compaction_type == CompactionType::CUMU_BINLOG_COMPACTION && !t->is_row_binlog_tablet()) {
450
2
            return int64_t {0};
451
2
        }
452
470M
        if (compaction_type != CompactionType::CUMU_BINLOG_COMPACTION && t->is_row_binlog_tablet()) {
453
0
            return int64_t {0};
454
0
        }
455
470M
        return compaction_type == CompactionType::BASE_COMPACTION ? t->get_cloud_base_compaction_score()
456
470M
               : (compaction_type == CompactionType::CUMULATIVE_COMPACTION ||
457
423M
                  compaction_type == CompactionType::CUMU_BINLOG_COMPACTION) ? t->get_cloud_cumu_compaction_score()
458
423M
               : 0;
459
470M
    };
460
461
15.7k
    using namespace std::chrono;
462
15.7k
    auto now = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
463
404M
    auto skip = [now, compaction_type](CloudTablet* t) {
464
404M
        auto* cloud_cluster_info = static_cast<CloudClusterInfo*>(ExecEnv::GetInstance()->cluster_info());
465
466
404M
        if (config::enable_standby_passive_compaction && cloud_cluster_info->is_in_standby()) {
467
0
            if (t->fetch_add_approximate_num_rowsets(0) < config::max_tablet_version_num * config::standby_compaction_version_ratio) {
468
0
                return true;
469
0
            }
470
0
        }
471
472
        // Compaction read-write separation: skip tablets that should be compacted by other clusters.
473
        // Placed after standby check so standby invariants (version count threshold) are preserved.
474
404M
        if (cloud_cluster_info->should_skip_compaction(t)) {
475
0
            return true;
476
0
        }
477
478
404M
        int32_t max_version_config = t->max_version_config();
479
404M
        if (compaction_type == CompactionType::BASE_COMPACTION) {
480
46.5M
            bool is_recent_failure = now - t->last_base_compaction_failure_time() < config::min_compaction_failure_interval_ms;
481
46.5M
            bool is_frozen = (now - t->last_load_time_ms > config::compaction_load_max_freeze_interval_s * 1000
482
46.5M
                   && now - t->last_base_compaction_success_time_ms < config::base_compaction_freeze_interval_s * 1000
483
46.5M
                   && t->fetch_add_approximate_num_rowsets(0) < max_version_config / 2);
484
46.5M
            g_base_compaction_not_frozen_tablet_num << !is_frozen;
485
46.5M
            return is_recent_failure || is_frozen;
486
46.5M
        }
487
488
        // If tablet has too many rowsets but not be compacted for a long time, compaction should be performed
489
        // regardless of whether there is a load job recently.
490
357M
        bool is_recent_failure = now - t->last_cumu_compaction_failure_time() < config::min_compaction_failure_interval_ms;
491
357M
        bool is_recent_no_suitable_version = now - t->last_cumu_no_suitable_version_ms < config::min_compaction_failure_interval_ms;
492
357M
        bool is_frozen = (now - t->last_load_time_ms > config::compaction_load_max_freeze_interval_s * 1000
493
357M
               && now - t->last_cumu_compaction_success_time_ms < config::cumu_compaction_interval_s * 1000
494
357M
               && t->fetch_add_approximate_num_rowsets(0) < max_version_config / 2);
495
357M
        g_cumu_compaction_not_frozen_tablet_num << !is_frozen;
496
357M
        return is_recent_failure || is_recent_no_suitable_version || is_frozen;
497
404M
    };
498
    // We don't schedule tablets that are disabled for compaction
499
411M
    auto disable = [](CloudTablet* t) { return t->tablet_meta()->tablet_schema()->disable_auto_compaction(); };
500
501
15.7k
    auto [num_filtered, num_disabled, num_skipped] = std::make_tuple(0, 0, 0);
502
503
15.7k
    auto weak_tablets = get_weak_tablets();
504
15.7k
    std::vector<std::pair<std::shared_ptr<CloudTablet>, int64_t>> buf;
505
15.7k
    buf.reserve(n + 1);
506
471M
    for (auto& weak_tablet : weak_tablets) {
507
471M
        auto t = weak_tablet.lock();
508
471M
        if (t == nullptr) { continue; }
509
510
470M
        int64_t s = score(t.get());
511
470M
        if (s <= 0) { continue; }
512
411M
        if (s > score_stats->max_score) {
513
86.2k
            max_score_tablet_id = t->tablet_id();
514
86.2k
            score_stats->max_score = s;
515
86.2k
        }
516
411M
        if (compaction_type == CompactionType::CUMULATIVE_COMPACTION) {
517
363M
            int64_t* policy_max_score =
518
363M
                    t->tablet_meta()->compaction_policy() == CUMULATIVE_TIME_SERIES_POLICY
519
363M
                            ? &score_stats->time_series_max_score
520
363M
                            : &score_stats->size_based_max_score;
521
363M
            if (s > *policy_max_score) {
522
94.3k
                *policy_max_score = s;
523
94.3k
            }
524
363M
        }
525
526
411M
        if (filter_out(t.get())) { ++num_filtered; continue; }
527
411M
        if (disable(t.get())) { ++num_disabled; continue; }
528
404M
        if (skip(t.get())) { ++num_skipped; continue; }
529
530
400M
        buf.emplace_back(std::move(t), s);
531
5.00G
        std::sort(buf.begin(), buf.end(), [](auto& a, auto& b) { return a.second > b.second; });
532
400M
        if (buf.size() > n) { buf.pop_back(); }
533
400M
    }
534
535
15.7k
    LOG_EVERY_N(INFO, 1000) << "get_topn_compaction_score, n=" << n << " type=" << compaction_type
536
17
               << " num_tablets=" << weak_tablets.size() << " num_skipped=" << num_skipped
537
17
               << " num_disabled=" << num_disabled << " num_filtered=" << num_filtered
538
17
               << " max_score=" << score_stats->max_score << " max_score_tablet=" << max_score_tablet_id
539
95
               << " tablets=[" << [&buf] { std::stringstream ss; for (auto& i : buf) ss << i.first->tablet_id() << ":" << i.second << ","; return ss.str(); }() << "]"
540
15.7k
               ;
541
    // clang-format on
542
543
15.7k
    tablets->clear();
544
15.7k
    tablets->reserve(n + 1);
545
93.8k
    for (auto& [t, _] : buf) {
546
93.8k
        tablets->emplace_back(std::move(t));
547
93.8k
    }
548
549
15.7k
    return Status::OK();
550
15.7k
}
551
552
void CloudTabletMgr::build_all_report_tablets_info(std::map<TTabletId, TTablet>* tablets_info,
553
56
                                                   uint64_t* tablet_num) {
554
56
    DCHECK(tablets_info != nullptr);
555
56
    VLOG_NOTICE << "begin to build all report cloud tablets info";
556
557
56
    HistogramStat tablet_version_num_hist;
558
559
2.83M
    auto handler = [&](const std::weak_ptr<CloudTablet>& tablet_wk) {
560
2.83M
        auto tablet = tablet_wk.lock();
561
2.83M
        if (!tablet) return;
562
2.83M
        (*tablet_num)++;
563
2.83M
        TTabletInfo tablet_info;
564
2.83M
        tablet->build_tablet_report_info(&tablet_info);
565
2.83M
        using namespace std::chrono;
566
2.83M
        int64_t now = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
567
2.83M
        if (now - g_tablet_report_inactive_duration_ms < tablet->last_access_time_ms) {
568
            // the tablet is still being accessed and used in recently, so not report it
569
2.83M
            return;
570
2.83M
        }
571
0
        auto& t_tablet = (*tablets_info)[tablet->tablet_id()];
572
        // On the cloud, a specific BE has only one tablet replica;
573
        // there are no multiple replicas for a specific BE.
574
        // This is only to reuse the non-cloud report protocol.
575
0
        tablet_version_num_hist.add(tablet_info.total_version_count);
576
0
        t_tablet.tablet_infos.emplace_back(std::move(tablet_info));
577
0
    };
578
579
56
    auto weak_tablets = get_weak_tablets();
580
56
    std::for_each(weak_tablets.begin(), weak_tablets.end(), handler);
581
582
56
    DorisMetrics::instance()->tablet_version_num_distribution->set_histogram(
583
56
            tablet_version_num_hist);
584
56
    LOG(INFO) << "success to build all cloud report tablets info. all_tablet_count=" << *tablet_num
585
56
              << " exceed drop time limit count=" << tablets_info->size();
586
56
}
587
588
0
void CloudTabletMgr::get_tablet_info(int64_t num_tablets, std::vector<TabletInfo>* tablets_info) {
589
0
    auto weak_tablets = get_weak_tablets();
590
0
    for (auto& weak_tablet : weak_tablets) {
591
0
        auto tablet = weak_tablet.lock();
592
0
        if (tablet == nullptr) {
593
0
            continue;
594
0
        }
595
0
        if (tablets_info->size() >= num_tablets) {
596
0
            return;
597
0
        }
598
0
        tablets_info->push_back(tablet->get_tablet_info());
599
0
    }
600
0
}
601
602
void CloudTabletMgr::get_topn_tablet_delete_bitmap_score(
603
10
        uint64_t* max_delete_bitmap_score, uint64_t* max_base_rowset_delete_bitmap_score) {
604
10
    int64_t max_delete_bitmap_score_tablet_id = 0;
605
10
    OlapStopWatch watch;
606
10
    uint64_t total_delete_map_count = 0;
607
10
    int64_t max_base_rowset_delete_bitmap_score_tablet_id = 0;
608
10
    int n = config::check_tablet_delete_bitmap_score_top_n;
609
10
    std::vector<std::pair<std::shared_ptr<CloudTablet>, int64_t>> buf;
610
10
    buf.reserve(n + 1);
611
509k
    auto handler = [&](const std::weak_ptr<CloudTablet>& tablet_wk) {
612
509k
        auto t = tablet_wk.lock();
613
509k
        if (!t || !t->enable_unique_key_merge_on_write()) return;
614
125k
        uint64_t delete_bitmap_count =
615
125k
                t.get()->tablet_meta()->delete_bitmap().get_delete_bitmap_count();
616
125k
        total_delete_map_count += delete_bitmap_count;
617
125k
        if (delete_bitmap_count > *max_delete_bitmap_score) {
618
64
            max_delete_bitmap_score_tablet_id = t->tablet_id();
619
64
            *max_delete_bitmap_score = delete_bitmap_count;
620
64
        }
621
125k
        buf.emplace_back(std::move(t), delete_bitmap_count);
622
2.50M
        std::sort(buf.begin(), buf.end(), [](auto& a, auto& b) { return a.second > b.second; });
623
125k
        if (buf.size() > n) {
624
124k
            buf.pop_back();
625
124k
        }
626
125k
    };
627
10
    auto weak_tablets = get_weak_tablets();
628
10
    std::for_each(weak_tablets.begin(), weak_tablets.end(), handler);
629
100
    for (auto& [t, _] : buf) {
630
100
        t->get_base_rowset_delete_bitmap_count(max_base_rowset_delete_bitmap_score,
631
100
                                               &max_base_rowset_delete_bitmap_score_tablet_id);
632
100
    }
633
10
    std::stringstream ss;
634
100
    for (auto& i : buf) {
635
100
        ss << i.first->tablet_id() << ": " << i.second << ", ";
636
100
    }
637
10
    LOG(INFO) << "get_topn_tablet_delete_bitmap_score, n=" << n
638
10
              << ", tablet size=" << weak_tablets.size()
639
10
              << ", total_delete_map_count=" << total_delete_map_count
640
10
              << ", cost(us)=" << watch.get_elapse_time_us()
641
10
              << ", max_delete_bitmap_score=" << *max_delete_bitmap_score
642
10
              << ", max_delete_bitmap_score_tablet_id=" << max_delete_bitmap_score_tablet_id
643
10
              << ", max_base_rowset_delete_bitmap_score=" << *max_base_rowset_delete_bitmap_score
644
10
              << ", max_base_rowset_delete_bitmap_score_tablet_id="
645
10
              << max_base_rowset_delete_bitmap_score_tablet_id << ", tablets=[" << ss.str() << "]";
646
10
}
647
648
6
std::vector<std::shared_ptr<CloudTablet>> CloudTabletMgr::get_all_tablet() {
649
6
    std::vector<std::shared_ptr<CloudTablet>> tablets;
650
6
    tablets.reserve(_tablet_map->size());
651
239k
    _tablet_map->traverse([&tablets](auto& t) { tablets.push_back(t); });
652
6
    return tablets;
653
6
}
654
655
14
void CloudTabletMgr::put_tablet_for_UT(std::shared_ptr<CloudTablet> tablet) {
656
14
    _tablet_map->put(tablet);
657
14
}
658
659
} // namespace doris