blob: a41f388e686a34a7f0f1ad6238f8a4ed27fc94a3 [file]
// 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 "service/http/action/warmup_stats_action.h"
#include <chrono>
#include <list>
#include <set>
#include <string>
#include <thread>
#include "cloud/cloud_warmup_metrics.h"
#include "service/http/http_channel.h"
#include "service/http/http_headers.h"
#include "service/http/http_request.h"
#include "service/http/http_status.h"
#include "util/debug_points.h"
#include "util/easy_json.h"
namespace doris {
// Fill windowed num/size metrics into a JSON object
static void fill_windowed(EasyJson& parent, const std::string& key, MBvarWindowedAdder& num_adder,
MBvarWindowedAdder& size_adder, const std::string& dim_key) {
EasyJson obj = parent.Set(key, EasyJson::kObject);
EasyJson num = obj.Set("num", EasyJson::kObject);
num["5m"] = num_adder.get_window_value(dim_key, 0);
num["30m"] = num_adder.get_window_value(dim_key, 1);
num["1h"] = num_adder.get_window_value(dim_key, 2);
EasyJson size = obj.Set("size", EasyJson::kObject);
size["5m"] = size_adder.get_window_value(dim_key, 0);
size["30m"] = size_adder.get_window_value(dim_key, 1);
size["1h"] = size_adder.get_window_value(dim_key, 2);
}
void WarmUpStatsAction::handle(HttpRequest* req) {
DBUG_EXECUTE_IF("WarmUpStatsAction.handle.return_error", {
HttpChannel::send_reply(req, HttpStatus::INTERNAL_SERVER_ERROR,
"injected warmup stats error");
return;
});
DBUG_EXECUTE_IF("WarmUpStatsAction.handle.sleep", {
auto sleep_ms = dp->param<int64_t>("sleep_ms", 6000);
std::this_thread::sleep_for(std::chrono::milliseconds(sleep_ms));
});
// Collect all job_id dimension keys from all metrics
std::set<std::string> all_keys;
for (auto& k : g_warmup_ed_requested_segment_num.list_dimensions()) all_keys.insert(k);
for (auto& k : g_warmup_ed_requested_index_num.list_dimensions()) all_keys.insert(k);
for (auto& k : g_warmup_ed_finish_segment_num.list_dimensions()) all_keys.insert(k);
for (auto& k : g_warmup_ed_finish_index_num.list_dimensions()) all_keys.insert(k);
for (auto& k : g_warmup_ed_fail_segment_num.list_dimensions()) all_keys.insert(k);
for (auto& k : g_warmup_ed_fail_index_num.list_dimensions()) all_keys.insert(k);
for (auto& k : g_warmup_ed_downstream_progress_tracker.list_job_ids()) all_keys.insert(k);
EasyJson result;
result["code"] = 0;
EasyJson jobs = result.Set("data", EasyJson::kArray);
for (auto& job_id_str : all_keys) {
EasyJson entry = jobs.PushBack(EasyJson::kObject);
try {
entry["job_id"] = static_cast<int64_t>(std::stoll(job_id_str));
} catch (...) {
entry["job_id"] = 0;
}
// requested
EasyJson req_obj = entry.Set("requested", EasyJson::kObject);
fill_windowed(req_obj, "seg", g_warmup_ed_requested_segment_num,
g_warmup_ed_requested_segment_size, job_id_str);
fill_windowed(req_obj, "idx", g_warmup_ed_requested_index_num,
g_warmup_ed_requested_index_size, job_id_str);
// finish
EasyJson fin_obj = entry.Set("finish", EasyJson::kObject);
fill_windowed(fin_obj, "seg", g_warmup_ed_finish_segment_num,
g_warmup_ed_finish_segment_size, job_id_str);
fill_windowed(fin_obj, "idx", g_warmup_ed_finish_index_num, g_warmup_ed_finish_index_size,
job_id_str);
// fail
EasyJson fail_obj = entry.Set("fail", EasyJson::kObject);
fill_windowed(fail_obj, "seg", g_warmup_ed_fail_segment_num, g_warmup_ed_fail_segment_size,
job_id_str);
fill_windowed(fail_obj, "idx", g_warmup_ed_fail_index_num, g_warmup_ed_fail_index_size,
job_id_str);
// Timestamps
auto* trigger_ts =
g_warmup_ed_last_trigger_ts.get_stats(std::list<std::string> {job_id_str});
entry["last_trigger_ts"] = trigger_ts ? trigger_ts->get_value() : 0;
auto* finish_ts = g_warmup_ed_last_finish_ts.get_stats(std::list<std::string> {job_id_str});
entry["last_finish_ts"] = finish_ts ? finish_ts->get_value() : 0;
// Target-side progress watermark for trigger-gap calculation. Pending work reports the
// earliest unfinished upstream trigger time; fully caught-up work reports the latest
// finished upstream trigger time.
entry["progress_trigger_ts"] =
g_warmup_ed_downstream_progress_tracker.get_progress_ts(job_id_str);
}
req->add_output_header(HttpHeaders::CONTENT_TYPE, "application/json");
HttpChannel::send_reply(req, HttpStatus::OK, result.ToString());
}
} // namespace doris