Coverage Report

Created: 2026-03-16 16:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/service/http/action/delete_bitmap_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/delete_bitmap_action.h"
19
20
#include <rapidjson/document.h>
21
#include <rapidjson/encodings.h>
22
#include <rapidjson/prettywriter.h>
23
#include <rapidjson/rapidjson.h>
24
#include <rapidjson/stringbuffer.h>
25
26
#include <chrono> // IWYU pragma: keep
27
#include <exception>
28
#include <future>
29
#include <memory>
30
#include <mutex>
31
#include <sstream>
32
#include <string>
33
#include <thread>
34
#include <utility>
35
36
#include "cloud/cloud_meta_mgr.h"
37
#include "cloud/cloud_storage_engine.h"
38
#include "cloud/cloud_tablet.h"
39
#include "cloud/cloud_tablet_mgr.h"
40
#include "cloud/config.h"
41
#include "common/logging.h"
42
#include "common/metrics/doris_metrics.h"
43
#include "common/status.h"
44
#include "service/http/http_channel.h"
45
#include "service/http/http_headers.h"
46
#include "service/http/http_request.h"
47
#include "service/http/http_status.h"
48
#include "storage/olap_define.h"
49
#include "storage/tablet/tablet_manager.h"
50
#include "util/stopwatch.hpp"
51
52
namespace doris {
53
#include "common/compile_check_begin.h"
54
using namespace ErrorCode;
55
56
namespace {
57
58
constexpr std::string_view HEADER_JSON = "application/json";
59
60
} // namespace
61
62
DeleteBitmapAction::DeleteBitmapAction(DeleteBitmapActionType ctype, ExecEnv* exec_env,
63
                                       BaseStorageEngine& engine, TPrivilegeHier::type hier,
64
                                       TPrivilegeType::type ptype)
65
0
        : HttpHandlerWithAuth(exec_env, hier, ptype),
66
0
          _engine(engine),
67
0
          _delete_bitmap_action_type(ctype) {}
68
69
0
static Status _check_param(HttpRequest* req, uint64_t* tablet_id, bool* verbose) {
70
0
    const auto& req_tablet_id = req->param(TABLET_ID_KEY);
71
0
    if (req_tablet_id.empty()) {
72
0
        return Status::InternalError<false>("tablet id is empty!");
73
0
    }
74
0
    try {
75
0
        *tablet_id = std::stoull(req_tablet_id);
76
0
    } catch (const std::exception& e) {
77
0
        return Status::InternalError<false>("convert tablet_id failed, {}", e.what());
78
0
    }
79
0
    if (*tablet_id == 0) {
80
0
        return Status::InternalError<false>("check param failed: invalid tablet_id");
81
0
    }
82
0
    *verbose = iequal(req->param("verbose"), "true");
83
0
    return Status::OK();
84
0
}
85
86
0
static void _show_delete_bitmap(DeleteBitmap& dm, bool verbose, std::string* json_result) {
87
0
    auto count = dm.get_delete_bitmap_count();
88
0
    auto cardinality = dm.cardinality();
89
0
    auto size = dm.get_size();
90
0
    rapidjson::Document root;
91
0
    root.SetObject();
92
0
    root.AddMember("delete_bitmap_count", count, root.GetAllocator());
93
0
    root.AddMember("cardinality", cardinality, root.GetAllocator());
94
0
    root.AddMember("size", size, root.GetAllocator());
95
0
    if (verbose) {
96
0
        std::string pre_rowset_id;
97
0
        int64_t pre_segment_id = -1;
98
0
        std::vector<std::string> version_vector;
99
0
        rapidjson::Document dm_arr;
100
0
        dm_arr.SetObject();
101
102
0
        auto add_rowset_delete_bitmap_info = [&]() {
103
0
            std::string key =
104
0
                    "rowset: " + pre_rowset_id + ", segment: " + std::to_string(pre_segment_id);
105
0
            rapidjson::Value key_value;
106
0
            key_value.SetString(key.data(), cast_set<uint32_t>(key.length()), root.GetAllocator());
107
0
            rapidjson::Document version_arr;
108
0
            version_arr.SetArray();
109
0
            for (const auto& str : version_vector) {
110
0
                rapidjson::Value value;
111
0
                value.SetString(str.c_str(), cast_set<uint32_t>(str.length()), root.GetAllocator());
112
0
                version_arr.PushBack(value, root.GetAllocator());
113
0
            }
114
0
            dm_arr.AddMember(key_value, version_arr, root.GetAllocator());
115
0
            version_vector.clear();
116
0
        };
117
118
0
        for (auto& [id, bitmap] : dm.delete_bitmap) {
119
0
            auto& [rowset_id, segment_id, version] = id;
120
0
            if (rowset_id.to_string() != pre_rowset_id || segment_id != pre_segment_id) {
121
                // add previous result
122
0
                if (!pre_rowset_id.empty()) {
123
0
                    add_rowset_delete_bitmap_info();
124
0
                }
125
0
                pre_rowset_id = rowset_id.to_string();
126
0
                pre_segment_id = segment_id;
127
0
            }
128
0
            std::string str = fmt::format("v: {}, c: {}, s: {}", version, bitmap.cardinality(),
129
0
                                          bitmap.getSizeInBytes());
130
0
            version_vector.push_back(str);
131
0
        }
132
        // add last result
133
0
        if (!version_vector.empty()) {
134
0
            add_rowset_delete_bitmap_info();
135
0
        }
136
0
        root.AddMember("delete_bitmap", dm_arr, root.GetAllocator());
137
0
    }
138
139
    // to json string
140
0
    rapidjson::StringBuffer strbuf;
141
0
    rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(strbuf);
142
0
    root.Accept(writer);
143
0
    *json_result = std::string(strbuf.GetString());
144
0
}
145
146
Status DeleteBitmapAction::_handle_show_local_delete_bitmap_count(HttpRequest* req,
147
0
                                                                  std::string* json_result) {
148
0
    uint64_t tablet_id = 0;
149
0
    bool verbose = false;
150
0
    RETURN_NOT_OK_STATUS_WITH_WARN(_check_param(req, &tablet_id, &verbose), "check param failed");
151
152
0
    BaseTabletSPtr tablet = nullptr;
153
0
    if (config::is_cloud_mode()) {
154
0
        tablet = DORIS_TRY(_engine.to_cloud().tablet_mgr().get_tablet(tablet_id));
155
0
        DBUG_EXECUTE_IF(
156
0
                "DeleteBitmapAction._handle_show_local_delete_bitmap_count.vacuum_stale_rowsets",
157
0
                { _engine.to_cloud().tablet_mgr().vacuum_stale_rowsets(CountDownLatch(1)); });
158
0
    } else {
159
0
        tablet = _engine.to_local().tablet_manager()->get_tablet(tablet_id);
160
0
        DBUG_EXECUTE_IF(
161
0
                "DeleteBitmapAction._handle_show_local_delete_bitmap_count.start_delete_unused_"
162
0
                "rowset",
163
0
                { _engine.to_local().start_delete_unused_rowset(); });
164
0
    }
165
0
    if (tablet == nullptr) {
166
0
        return Status::NotFound("Tablet not found. tablet_id={}", tablet_id);
167
0
    }
168
0
    auto dm = tablet->tablet_meta()->delete_bitmap().snapshot();
169
0
    _show_delete_bitmap(dm, verbose, json_result);
170
0
    return Status::OK();
171
0
}
172
173
Status DeleteBitmapAction::_handle_show_ms_delete_bitmap_count(HttpRequest* req,
174
0
                                                               std::string* json_result) {
175
0
    uint64_t tablet_id = 0;
176
0
    bool verbose = false;
177
0
    RETURN_NOT_OK_STATUS_WITH_WARN(_check_param(req, &tablet_id, &verbose), "check param failed");
178
179
0
    TabletMetaSharedPtr tablet_meta;
180
0
    auto st = _engine.to_cloud().meta_mgr().get_tablet_meta(tablet_id, &tablet_meta);
181
0
    if (!st.ok()) {
182
0
        LOG(WARNING) << "failed to get_tablet_meta for tablet=" << tablet_id
183
0
                     << ", st=" << st.to_string();
184
0
        return st;
185
0
    }
186
0
    auto tablet = std::make_shared<CloudTablet>(_engine.to_cloud(), std::move(tablet_meta));
187
0
    SyncOptions options;
188
0
    options.warmup_delta_data = false;
189
0
    options.sync_delete_bitmap = true;
190
0
    options.full_sync = true;
191
0
    st = _engine.to_cloud().meta_mgr().sync_tablet_rowsets(tablet.get(), options);
192
0
    if (!st.ok()) {
193
0
        LOG(WARNING) << "failed to sync tablet=" << tablet_id << ", st=" << st;
194
0
        return st;
195
0
    }
196
0
    auto dm = tablet->tablet_meta()->delete_bitmap().snapshot();
197
0
    _show_delete_bitmap(dm, verbose, json_result);
198
0
    return Status::OK();
199
0
}
200
201
Status DeleteBitmapAction::_handle_show_agg_cache_delete_bitmap_count(HttpRequest* req,
202
0
                                                                      std::string* json_result) {
203
0
    uint64_t tablet_id = 0;
204
0
    bool verbose = false;
205
0
    RETURN_NOT_OK_STATUS_WITH_WARN(_check_param(req, &tablet_id, &verbose), "check param failed");
206
0
    BaseTabletSPtr tablet = nullptr;
207
0
    if (config::is_cloud_mode()) {
208
0
        tablet = DORIS_TRY(_engine.to_cloud().tablet_mgr().get_tablet(tablet_id));
209
0
        DBUG_EXECUTE_IF(
210
0
                "DeleteBitmapAction._handle_show_local_delete_bitmap_count.vacuum_stale_rowsets",
211
0
                { _engine.to_cloud().tablet_mgr().vacuum_stale_rowsets(CountDownLatch(1)); });
212
0
    } else {
213
0
        tablet = _engine.to_local().tablet_manager()->get_tablet(tablet_id);
214
0
        DBUG_EXECUTE_IF(
215
0
                "DeleteBitmapAction._handle_show_local_delete_bitmap_count.start_delete_unused_"
216
0
                "rowset",
217
0
                { _engine.to_local().start_delete_unused_rowset(); });
218
0
    }
219
0
    if (tablet == nullptr) {
220
0
        return Status::NotFound("Tablet not found. tablet_id={}", tablet_id);
221
0
    }
222
0
    auto dbm = tablet->tablet_meta()->delete_bitmap().agg_cache_snapshot();
223
0
    _show_delete_bitmap(dbm, verbose, json_result);
224
0
    return Status::OK();
225
0
}
226
227
0
void DeleteBitmapAction::handle(HttpRequest* req) {
228
0
    req->add_output_header(HttpHeaders::CONTENT_TYPE, HEADER_JSON.data());
229
0
    if (_delete_bitmap_action_type == DeleteBitmapActionType::COUNT_LOCAL) {
230
0
        std::string json_result;
231
0
        Status st = _handle_show_local_delete_bitmap_count(req, &json_result);
232
0
        if (!st.ok()) {
233
0
            HttpChannel::send_reply(req, HttpStatus::OK, st.to_json());
234
0
        } else {
235
0
            HttpChannel::send_reply(req, HttpStatus::OK, json_result);
236
0
        }
237
0
    } else if (_delete_bitmap_action_type == DeleteBitmapActionType::COUNT_MS) {
238
0
        std::string json_result;
239
0
        Status st = _handle_show_ms_delete_bitmap_count(req, &json_result);
240
0
        if (!st.ok()) {
241
0
            HttpChannel::send_reply(req, HttpStatus::OK, st.to_json());
242
0
        } else {
243
0
            HttpChannel::send_reply(req, HttpStatus::OK, json_result);
244
0
        }
245
0
    } else if (_delete_bitmap_action_type == DeleteBitmapActionType::COUNT_AGG_CACHE) {
246
0
        std::string json_result;
247
0
        Status st = _handle_show_agg_cache_delete_bitmap_count(req, &json_result);
248
0
        if (!st.ok()) {
249
0
            HttpChannel::send_reply(req, HttpStatus::OK, st.to_json());
250
0
        } else {
251
0
            HttpChannel::send_reply(req, HttpStatus::OK, json_result);
252
0
        }
253
0
    }
254
0
}
255
256
#include "common/compile_check_end.h"
257
} // namespace doris