Coverage Report

Created: 2026-03-14 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/service/http/action/show_hotspot_action.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 "service/http/action/show_hotspot_action.h"
19
20
#include <queue>
21
#include <string>
22
23
#include "cloud/cloud_tablet_mgr.h"
24
#include "service/http/http_channel.h"
25
#include "service/http/http_request.h"
26
27
namespace doris {
28
29
#include "common/compile_check_begin.h"
30
31
namespace {
32
33
enum class Metrics {
34
    READ_BLOCK = 0,
35
    WRITE = 1,
36
    COMPACTION = 2,
37
    NUM_ROWSETS = 3,
38
    NUM_BASE_ROWSETS = 4,
39
    NUM_CUMU_ROWSETS = 5,
40
    UNKNOWN = 100000,
41
};
42
43
0
Status check_param(HttpRequest* req, size_t& top_n, Metrics& metrics) {
44
0
    const std::string TOPN_PARAM = "topn";
45
46
0
    auto& topn_str = req->param(TOPN_PARAM);
47
0
    if (!topn_str.empty()) {
48
0
        try {
49
0
            top_n = std::stoul(topn_str);
50
0
        } catch (const std::exception& e) {
51
0
            return Status::InternalError("convert topn failed, {}", e.what());
52
0
        }
53
0
    }
54
55
0
    const std::string METRICS_PARAM = "metrics";
56
0
    auto& metrics_str = req->param(METRICS_PARAM);
57
0
    if (metrics_str.empty()) {
58
0
        return Status::InternalError("metrics must be specified");
59
0
    }
60
61
0
    if (metrics_str == "read_block") {
62
0
        metrics = Metrics::READ_BLOCK;
63
0
    } else if (metrics_str == "write") {
64
0
        metrics = Metrics::WRITE;
65
0
    } else if (metrics_str == "compaction") {
66
0
        metrics = Metrics::COMPACTION;
67
0
    } else if (metrics_str == "num_rowsets") {
68
0
        metrics = Metrics::NUM_ROWSETS;
69
0
    } else if (metrics_str == "num_cumu_rowsets") {
70
0
        metrics = Metrics::NUM_CUMU_ROWSETS;
71
0
    } else if (metrics_str == "num_base_rowsets") {
72
0
        metrics = Metrics::NUM_BASE_ROWSETS;
73
0
    } else {
74
0
        return Status::InternalError("unknown metrics: {}", metrics_str);
75
0
    }
76
77
0
    return Status::OK();
78
0
}
79
80
struct TabletCounter {
81
    int64_t tablet_id {0};
82
    int64_t count {0};
83
};
84
85
struct Comparator {
86
0
    constexpr bool operator()(const TabletCounter& lhs, const TabletCounter& rhs) const {
87
0
        return lhs.count > rhs.count;
88
0
    }
89
};
90
91
using MinHeap = std::priority_queue<TabletCounter, std::vector<TabletCounter>, Comparator>;
92
93
} // namespace
94
95
0
void ShowHotspotAction::handle(HttpRequest* req) {
96
0
    size_t topn = 0;
97
0
    Metrics metrics {Metrics::UNKNOWN};
98
0
    auto st = check_param(req, topn, metrics);
99
0
    if (!st.ok()) [[unlikely]] {
100
0
        HttpChannel::send_reply(req, HttpStatus::BAD_REQUEST, st.to_string());
101
0
        return;
102
0
    }
103
104
0
    std::function<int64_t(CloudTablet&)> count_fn;
105
0
    switch (metrics) {
106
0
    case Metrics::READ_BLOCK:
107
0
        count_fn = [](auto&& t) { return t.read_block_count.load(std::memory_order_relaxed); };
108
0
        break;
109
0
    case Metrics::WRITE:
110
0
        count_fn = [](auto&& t) { return t.write_count.load(std::memory_order_relaxed); };
111
0
        break;
112
0
    case Metrics::COMPACTION:
113
0
        count_fn = [](auto&& t) { return t.compaction_count.load(std::memory_order_relaxed); };
114
0
        break;
115
0
    case Metrics::NUM_ROWSETS:
116
0
        count_fn = [](auto&& t) { return t.fetch_add_approximate_num_rowsets(0); };
117
0
        break;
118
0
    case Metrics::NUM_BASE_ROWSETS:
119
0
        count_fn = [](auto&& t) {
120
0
            return t.fetch_add_approximate_num_rowsets(0) -
121
0
                   t.fetch_add_approximate_cumu_num_rowsets(0);
122
0
        };
123
0
        break;
124
0
    case Metrics::NUM_CUMU_ROWSETS:
125
0
        count_fn = [](auto&& t) { return t.fetch_add_approximate_cumu_num_rowsets(0); };
126
0
        break;
127
0
    default:
128
0
        break;
129
0
    }
130
131
0
    if (!count_fn) {
132
0
        HttpChannel::send_reply(req, HttpStatus::BAD_REQUEST, "metrics not specified");
133
0
        return;
134
0
    }
135
136
0
    auto tablets = _storage_engine.tablet_mgr().get_weak_tablets();
137
0
    std::vector<TabletCounter> buffer;
138
0
    buffer.reserve(tablets.size());
139
0
    for (auto&& t : tablets) {
140
0
        if (auto tablet = t.lock(); tablet) {
141
0
            buffer.push_back({tablet->tablet_id(), count_fn(*tablet)});
142
0
        }
143
0
    }
144
145
0
    if (topn <= 0) {
146
0
        topn = tablets.size();
147
0
    }
148
149
0
    MinHeap min_heap;
150
0
    for (auto&& counter : buffer) {
151
0
        min_heap.push(counter);
152
0
        if (min_heap.size() > topn) {
153
0
            min_heap.pop();
154
0
        }
155
0
    }
156
157
0
    buffer.resize(0);
158
0
    while (!min_heap.empty()) {
159
0
        buffer.push_back(min_heap.top());
160
0
        min_heap.pop();
161
0
    }
162
163
0
    std::string res;
164
0
    res.reserve(buffer.size() * 20);
165
    // Descending order
166
0
    std::for_each(buffer.rbegin(), buffer.rend(), [&res](auto&& counter) {
167
0
        res += fmt::format("{} {}\n", counter.tablet_id, counter.count);
168
0
    });
169
170
0
    HttpChannel::send_reply(req, HttpStatus::OK, res);
171
172
0
#include "common/compile_check_end.h"
173
0
}
174
175
} // namespace doris