blob: fff120674e0b6cd6217cfab7d4973e2192f268d3 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#include "delete_bitmap_action.h"
#include <rapidjson/document.h>
#include <rapidjson/encodings.h>
#include <rapidjson/prettywriter.h>
#include <rapidjson/rapidjson.h>
#include <rapidjson/stringbuffer.h>
#include <chrono> // IWYU pragma: keep
#include <exception>
#include <future>
#include <memory>
#include <mutex>
#include <sstream>
#include <string>
#include <thread>
#include <utility>
#include "cloud/cloud_meta_mgr.h"
#include "cloud/cloud_storage_engine.h"
#include "cloud/cloud_tablet.h"
#include "cloud/cloud_tablet_mgr.h"
#include "cloud/config.h"
#include "common/logging.h"
#include "common/status.h"
#include "http/http_channel.h"
#include "http/http_headers.h"
#include "http/http_request.h"
#include "http/http_status.h"
#include "olap/olap_define.h"
#include "olap/tablet_manager.h"
#include "util/doris_metrics.h"
#include "util/stopwatch.hpp"
namespace doris {
#include "common/compile_check_begin.h"
using namespace ErrorCode;
namespace {
constexpr std::string_view HEADER_JSON = "application/json";
} // namespace
DeleteBitmapAction::DeleteBitmapAction(DeleteBitmapActionType ctype, ExecEnv* exec_env,
BaseStorageEngine& engine, TPrivilegeHier::type hier,
TPrivilegeType::type ptype)
: HttpHandlerWithAuth(exec_env, hier, ptype),
_engine(engine),
_delete_bitmap_action_type(ctype) {}
static Status _check_param(HttpRequest* req, uint64_t* tablet_id, bool* verbose) {
const auto& req_tablet_id = req->param(TABLET_ID_KEY);
if (req_tablet_id.empty()) {
return Status::InternalError<false>("tablet id is empty!");
}
try {
*tablet_id = std::stoull(req_tablet_id);
} catch (const std::exception& e) {
return Status::InternalError<false>("convert tablet_id failed, {}", e.what());
}
if (*tablet_id == 0) {
return Status::InternalError<false>("check param failed: invalid tablet_id");
}
*verbose = iequal(req->param("verbose"), "true");
return Status::OK();
}
static void _show_delete_bitmap(DeleteBitmap& dm, bool verbose, std::string* json_result) {
auto count = dm.get_delete_bitmap_count();
auto cardinality = dm.cardinality();
auto size = dm.get_size();
rapidjson::Document root;
root.SetObject();
root.AddMember("delete_bitmap_count", count, root.GetAllocator());
root.AddMember("cardinality", cardinality, root.GetAllocator());
root.AddMember("size", size, root.GetAllocator());
if (verbose) {
std::string pre_rowset_id;
int64_t pre_segment_id = -1;
std::vector<std::string> version_vector;
rapidjson::Document dm_arr;
dm_arr.SetObject();
auto add_rowset_delete_bitmap_info = [&]() {
std::string key =
"rowset: " + pre_rowset_id + ", segment: " + std::to_string(pre_segment_id);
rapidjson::Value key_value;
key_value.SetString(key.data(), cast_set<uint32_t>(key.length()), root.GetAllocator());
rapidjson::Document version_arr;
version_arr.SetArray();
for (const auto& str : version_vector) {
rapidjson::Value value;
value.SetString(str.c_str(), cast_set<uint32_t>(str.length()), root.GetAllocator());
version_arr.PushBack(value, root.GetAllocator());
}
dm_arr.AddMember(key_value, version_arr, root.GetAllocator());
version_vector.clear();
};
for (auto& [id, bitmap] : dm.delete_bitmap) {
auto& [rowset_id, segment_id, version] = id;
if (rowset_id.to_string() != pre_rowset_id || segment_id != pre_segment_id) {
// add previous result
if (!pre_rowset_id.empty()) {
add_rowset_delete_bitmap_info();
}
pre_rowset_id = rowset_id.to_string();
pre_segment_id = segment_id;
}
std::string str = fmt::format("v: {}, c: {}, s: {}", version, bitmap.cardinality(),
bitmap.getSizeInBytes());
version_vector.push_back(str);
}
// add last result
if (!version_vector.empty()) {
add_rowset_delete_bitmap_info();
}
root.AddMember("delete_bitmap", dm_arr, root.GetAllocator());
}
// to json string
rapidjson::StringBuffer strbuf;
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(strbuf);
root.Accept(writer);
*json_result = std::string(strbuf.GetString());
}
Status DeleteBitmapAction::_handle_show_local_delete_bitmap_count(HttpRequest* req,
std::string* json_result) {
uint64_t tablet_id = 0;
bool verbose = false;
RETURN_NOT_OK_STATUS_WITH_WARN(_check_param(req, &tablet_id, &verbose), "check param failed");
BaseTabletSPtr tablet = nullptr;
if (config::is_cloud_mode()) {
tablet = DORIS_TRY(_engine.to_cloud().tablet_mgr().get_tablet(tablet_id));
DBUG_EXECUTE_IF(
"DeleteBitmapAction._handle_show_local_delete_bitmap_count.vacuum_stale_rowsets",
{ _engine.to_cloud().tablet_mgr().vacuum_stale_rowsets(CountDownLatch(1)); });
} else {
tablet = _engine.to_local().tablet_manager()->get_tablet(tablet_id);
DBUG_EXECUTE_IF(
"DeleteBitmapAction._handle_show_local_delete_bitmap_count.start_delete_unused_"
"rowset",
{ _engine.to_local().start_delete_unused_rowset(); });
}
if (tablet == nullptr) {
return Status::NotFound("Tablet not found. tablet_id={}", tablet_id);
}
auto dm = tablet->tablet_meta()->delete_bitmap().snapshot();
_show_delete_bitmap(dm, verbose, json_result);
return Status::OK();
}
Status DeleteBitmapAction::_handle_show_ms_delete_bitmap_count(HttpRequest* req,
std::string* json_result) {
uint64_t tablet_id = 0;
bool verbose = false;
RETURN_NOT_OK_STATUS_WITH_WARN(_check_param(req, &tablet_id, &verbose), "check param failed");
TabletMetaSharedPtr tablet_meta;
auto st = _engine.to_cloud().meta_mgr().get_tablet_meta(tablet_id, &tablet_meta);
if (!st.ok()) {
LOG(WARNING) << "failed to get_tablet_meta for tablet=" << tablet_id
<< ", st=" << st.to_string();
return st;
}
auto tablet = std::make_shared<CloudTablet>(_engine.to_cloud(), std::move(tablet_meta));
SyncOptions options;
options.warmup_delta_data = false;
options.sync_delete_bitmap = true;
options.full_sync = true;
st = _engine.to_cloud().meta_mgr().sync_tablet_rowsets(tablet.get(), options);
if (!st.ok()) {
LOG(WARNING) << "failed to sync tablet=" << tablet_id << ", st=" << st;
return st;
}
auto dm = tablet->tablet_meta()->delete_bitmap().snapshot();
_show_delete_bitmap(dm, verbose, json_result);
return Status::OK();
}
void DeleteBitmapAction::handle(HttpRequest* req) {
req->add_output_header(HttpHeaders::CONTENT_TYPE, HEADER_JSON.data());
if (_delete_bitmap_action_type == DeleteBitmapActionType::COUNT_LOCAL) {
std::string json_result;
Status st = _handle_show_local_delete_bitmap_count(req, &json_result);
if (!st.ok()) {
HttpChannel::send_reply(req, HttpStatus::OK, st.to_json());
} else {
HttpChannel::send_reply(req, HttpStatus::OK, json_result);
}
} else if (_delete_bitmap_action_type == DeleteBitmapActionType::COUNT_MS) {
std::string json_result;
Status st = _handle_show_ms_delete_bitmap_count(req, &json_result);
if (!st.ok()) {
HttpChannel::send_reply(req, HttpStatus::OK, st.to_json());
} else {
HttpChannel::send_reply(req, HttpStatus::OK, json_result);
}
}
}
#include "common/compile_check_end.h"
} // namespace doris