/* * Copyright 2015-present ScyllaDB */ /* * SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.0 */ #pragma once #include #include #include #include #include #include #include "api/api_init.hh" #include "api/api-doc/utils.json.hh" #include "utils/histogram.hh" #include "utils/estimated_histogram.hh" #include #include "seastarx.hh" namespace api { template T map_sum(T&& dest, const S& src) { for (const auto& i : src) { dest[i.first] += i.second; } return std::move(dest); } /** * General sstring splitting function */ inline std::vector split(const sstring& text, const char* separator) { if (text == "") { return std::vector(); } std::vector tokens; return boost::split(tokens, text, boost::is_any_of(separator)); } /** * A helper function to sum values on an a distributed object that * has a get_stats method. * */ template future sum_stats(sharded& d, V F::*f) { return d.map_reduce0([f](const T& p) {return p.get_stats().*f;}, 0, std::plus()).then([](V val) { return make_ready_future(val); }); } inline httpd::utils_json::histogram to_json(const utils::ihistogram& val) { httpd::utils_json::histogram h; h = val; h.sum = val.estimated_sum(); return h; } inline httpd::utils_json::rate_moving_average meter_to_json(const utils::rate_moving_average& val) { httpd::utils_json::rate_moving_average m; m = val; return m; } inline httpd::utils_json::rate_moving_average_and_histogram timer_to_json(const utils::rate_moving_average_and_histogram& val) { httpd::utils_json::rate_moving_average_and_histogram h; h.hist = to_json(val.hist); h.meter = meter_to_json(val.rate); return h; } template future sum_histogram_stats(sharded& d, utils::timed_rate_moving_average_and_histogram F::*f) { return d.map_reduce0([f](const T& p) {return (p.get_stats().*f).hist;}, utils::ihistogram(), std::plus()).then([](const utils::ihistogram& val) { return make_ready_future(to_json(val)); }); } template future sum_timer_stats(sharded& d, utils::timed_rate_moving_average_and_histogram F::*f) { return d.map_reduce0([f](const T& p) {return (p.get_stats().*f).rate();}, utils::rate_moving_average_and_histogram(), std::plus()).then([](const utils::rate_moving_average_and_histogram& val) { return make_ready_future(timer_to_json(val)); }); } template future sum_timer_stats(sharded& d, utils::timed_rate_moving_average_summary_and_histogram F::*f) { return d.map_reduce0([f](const T& p) {return (p.get_stats().*f).rate();}, utils::rate_moving_average_and_histogram(), std::plus()).then([](const utils::rate_moving_average_and_histogram& val) { return make_ready_future(timer_to_json(val)); }); } inline int64_t min_int64(int64_t a, int64_t b) { return std::min(a,b); } inline int64_t max_int64(int64_t a, int64_t b) { return std::max(a,b); } /** * A helper struct for ratio calculation * It combine total and the sub set for the ratio and its * to_json method return the ration sub/total */ template struct basic_ratio_holder : public json::jsonable { T total = 0; T sub = 0; virtual std::string to_json() const { if (total == 0) { return "0"; } return std::to_string(sub/total); } basic_ratio_holder() = default; basic_ratio_holder& add(T _total, T _sub) { total += _total; sub += _sub; return *this; } basic_ratio_holder(T _total, T _sub) { total = _total; sub = _sub; } basic_ratio_holder& operator+=(const basic_ratio_holder& a) { return add(a.total, a.sub); } friend basic_ratio_holder operator+(basic_ratio_holder a, const basic_ratio_holder& b) { return a += b; } }; typedef basic_ratio_holder ratio_holder; typedef basic_ratio_holder integral_ratio_holder; class unimplemented_exception : public httpd::base_exception { public: unimplemented_exception() : base_exception("API call is not supported yet", reply::status_type::internal_server_error) { } }; inline void unimplemented() { throw unimplemented_exception(); } template std::vector concat(std::vector a, std::vector&& b) { a.reserve( a.size() + b.size()); a.insert(a.end(), b.begin(), b.end()); return a; } template class req_param { public: sstring name; T value; req_param(const request& req, sstring name, T default_val) : name(name) { sstring param = req.get_query_param(name); if (param.empty()) { value = default_val; return; } try { // boost::lexical_cast does not use boolalpha. Converting a // true/false throws exceptions. We don't want that. if constexpr (std::is_same_v) { // Cannot use boolalpha because we (probably) want to // accept 1 and 0 as well as true and false. And True. And fAlse. std::transform(param.begin(), param.end(), param.begin(), ::tolower); if (param == "true" || param == "1") { value = T(true); } else if (param == "false" || param == "0") { value = T(false); } else { throw boost::bad_lexical_cast{}; } } else { value = T{boost::lexical_cast(param)}; } } catch (boost::bad_lexical_cast&) { throw httpd::bad_param_exception(fmt::format("{} ({}): type error - should be {}", name, param, boost::units::detail::demangle(typeid(Base).name()))); } } operator T() const { return value; } }; httpd::utils_json::estimated_histogram time_to_json_histogram(const utils::time_estimated_histogram& val); }