public:
uint32_t stats_period = 0;
-
+
// Default 0 means if unspecified will include all stats
uint32_t stats_threshold = 0;
- std::list<OSDPerfMetricQuery> osd_perf_metric_queries;
+ std::map<OSDPerfMetricQuery, OSDPerfMetricLimits> osd_perf_metric_queries;
void decode_payload() override
{
}
OSDPerfMetricQueryID ActivePyModules::add_osd_perf_query(
- const OSDPerfMetricQuery &query)
+ const OSDPerfMetricQuery &query,
+ const std::optional<OSDPerfMetricLimit> &limit)
{
- return server.add_osd_perf_query(query);
+ return server.add_osd_perf_query(query, limit);
}
void ActivePyModules::remove_osd_perf_query(OSDPerfMetricQueryID query_id)
const std::string &svc_id,
const std::string &path) const;
- OSDPerfMetricQueryID add_osd_perf_query(const OSDPerfMetricQuery &query);
+ OSDPerfMetricQueryID add_osd_perf_query(
+ const OSDPerfMetricQuery &query,
+ const std::optional<OSDPerfMetricLimit> &limit);
void remove_osd_perf_query(OSDPerfMetricQueryID query_id);
PyObject *get_osd_perf_counters(OSDPerfMetricQueryID query_id);
#include "BaseMgrModule.h"
#include "Gil.h"
+#include <algorithm>
+
#define dout_context g_ceph_context
#define dout_subsys ceph_subsys_mgr
static const std::string NAME_KEY_DESCRIPTOR = "key_descriptor";
static const std::string NAME_COUNTERS_DESCRIPTORS =
"performance_counter_descriptors";
+ static const std::string NAME_LIMIT = "limit";
static const std::string NAME_SUB_KEY_TYPE = "type";
static const std::string NAME_SUB_KEY_REGEX = "regex";
+ static const std::string NAME_LIMIT_ORDER_BY = "order_by";
+ static const std::string NAME_LIMIT_MAX_COUNT = "max_count";
static const std::map<std::string, OSDPerfMetricSubKeyType> sub_key_types = {
{"client_id", OSDPerfMetricSubKeyType::CLIENT_ID},
{"pool_id", OSDPerfMetricSubKeyType::POOL_ID},
PyObject *query_params = PyDict_Items(py_query);
OSDPerfMetricQuery query;
+ std::optional<OSDPerfMetricLimit> limit;
// {
// 'key_descriptor': [
// 'performance_counter_descriptors': [
// list, of, descriptor, types
// ],
+ // 'limit': {'order_by': performance_counter_type, 'max_count': n},
// }
for (int i = 0; i < PyList_Size(query_params); ++i) {
}
query.performance_counter_descriptors.push_back(it->second);
}
+ } else if (query_param_name == NAME_LIMIT) {
+ if (!PyDict_Check(query_param_val)) {
+ derr << __func__ << " query " << query_param_name << " not a dict"
+ << dendl;
+ Py_RETURN_NONE;
+ }
+
+ limit = OSDPerfMetricLimit();
+ PyObject *limit_params = PyDict_Items(query_param_val);
+
+ for (int j = 0; j < PyList_Size(limit_params); ++j) {
+ PyObject *kv = PyList_GET_ITEM(limit_params, j);
+ char *limit_param_name = nullptr;
+ PyObject *limit_param_val = nullptr;
+ if (!PyArg_ParseTuple(kv, "sO:pair", &limit_param_name,
+ &limit_param_val)) {
+ derr << __func__ << " limit item " << j << " not a size 2 tuple"
+ << dendl;
+ Py_RETURN_NONE;
+ }
+
+ if (limit_param_name == NAME_LIMIT_ORDER_BY) {
+ if (!PyString_Check(limit_param_val)) {
+ derr << __func__ << " " << limit_param_name << " not a string"
+ << dendl;
+ Py_RETURN_NONE;
+ }
+ auto order_by = PyString_AsString(limit_param_val);
+ auto it = counter_types.find(order_by);
+ if (it == counter_types.end()) {
+ derr << __func__ << " limit " << limit_param_name
+ << " not a valid counter type" << dendl;
+ Py_RETURN_NONE;
+ }
+ limit->order_by = it->second;
+ } else if (limit_param_name == NAME_LIMIT_MAX_COUNT) {
+#if PY_MAJOR_VERSION <= 2
+ if (!PyInt_Check(limit_param_val) && !PyLong_Check(limit_param_val)) {
+#else
+ if (!PyLong_Check(limit_param_val)) {
+#endif
+ derr << __func__ << " " << limit_param_name << " not an int"
+ << dendl;
+ Py_RETURN_NONE;
+ }
+ limit->max_count = PyLong_AsLong(limit_param_val);
+ } else {
+ derr << __func__ << " unknown limit param: " << limit_param_name
+ << dendl;
+ Py_RETURN_NONE;
+ }
+ }
} else {
- derr << "unknown query param: " << query_param_name << dendl;
+ derr << __func__ << " unknown query param: " << query_param_name << dendl;
Py_RETURN_NONE;
}
}
if (query.key_descriptor.empty() ||
query.performance_counter_descriptors.empty()) {
- derr << "invalid query" << dendl;
+ derr << __func__ << " invalid query" << dendl;
Py_RETURN_NONE;
}
- auto query_id = self->py_modules->add_osd_perf_query(query);
+ if (limit) {
+ auto &ds = query.performance_counter_descriptors;
+ if (std::find(ds.begin(), ds.end(), limit->order_by) == ds.end()) {
+ derr << __func__ << " limit order_by " << limit->order_by
+ << " not in performance_counter_descriptors" << dendl;
+ Py_RETURN_NONE;
+ }
+ }
+
+ auto query_id = self->py_modules->add_osd_perf_query(query, limit);
return PyLong_FromLong(query_id);
}
}
OSDPerfMetricQueryID DaemonServer::add_osd_perf_query(
- const OSDPerfMetricQuery &query)
+ const OSDPerfMetricQuery &query,
+ const std::optional<OSDPerfMetricLimit> &limit)
{
- return osd_perf_metric_collector.add_query(query);
+ return osd_perf_metric_collector.add_query(query, limit);
}
int DaemonServer::remove_osd_perf_query(OSDPerfMetricQueryID query_id)
void _send_configure(ConnectionRef c);
- OSDPerfMetricQueryID add_osd_perf_query(const OSDPerfMetricQuery &query);
+ OSDPerfMetricQueryID add_osd_perf_query(
+ const OSDPerfMetricQuery &query,
+ const std::optional<OSDPerfMetricLimit> &limit);
int remove_osd_perf_query(OSDPerfMetricQueryID query_id);
int get_osd_perf_counters(OSDPerfMetricQueryID query_id,
std::map<OSDPerfMetricKey, PerformanceCounters> *c);
// If provided, use this to compose an MPGStats to send with
// our reports (hook for use by OSD)
std::function<MPGStats*()> pgstats_cb;
- std::function<void(const std::list<OSDPerfMetricQuery> &)> set_perf_queries_cb;
+ std::function<void(const std::map<OSDPerfMetricQuery,
+ OSDPerfMetricLimits> &)> set_perf_queries_cb;
std::function<void(std::map<OSDPerfMetricQuery,
OSDPerfMetricReport> *)> get_perf_report_cb;
bool handle_command_reply(MCommandReply *m);
void set_perf_metric_query_cb(
- std::function<void(const std::list<OSDPerfMetricQuery> &)> cb_set,
+ std::function<void(const std::map<OSDPerfMetricQuery,
+ OSDPerfMetricLimits> &)> cb_set,
std::function<void(std::map<OSDPerfMetricQuery,
OSDPerfMetricReport> *)> cb_get)
{
#undef dout_prefix
#define dout_prefix *_dout << "mgr.osd_perf_metric_collector " << __func__ << " "
+namespace {
+
+bool is_limited(const std::map<OSDPerfMetricQueryID,
+ std::optional<OSDPerfMetricLimit>> &limits) {
+ for (auto &it : limits) {
+ if (!it.second) {
+ return false;
+ }
+ }
+ return true;
+}
+
+} // anonymous namespace
+
OSDPerfMetricCollector::OSDPerfMetricCollector(Listener &listener)
: listener(listener), lock("OSDPerfMetricCollector::lock") {
}
-std::list<OSDPerfMetricQuery> OSDPerfMetricCollector::get_queries() {
+std::map<OSDPerfMetricQuery, OSDPerfMetricLimits>
+OSDPerfMetricCollector::get_queries() const {
std::lock_guard locker(lock);
- std::list<OSDPerfMetricQuery> query_list;
+ std::map<OSDPerfMetricQuery, OSDPerfMetricLimits> result;
for (auto &it : queries) {
- query_list.push_back(it.first);
+ auto &query = it.first;
+ auto &limits = it.second;
+ auto result_it = result.insert({query, {}}).first;
+ if (is_limited(limits)) {
+ for (auto &iter : limits) {
+ result_it->second.insert(*iter.second);
+ }
+ }
}
- return query_list;
+ return result;
}
-int OSDPerfMetricCollector::add_query(const OSDPerfMetricQuery& query) {
+OSDPerfMetricQueryID OSDPerfMetricCollector::add_query(
+ const OSDPerfMetricQuery& query,
+ const std::optional<OSDPerfMetricLimit> &limit) {
uint64_t query_id;
bool notify = false;
if (it == queries.end()) {
it = queries.insert({query, {}}).first;
notify = true;
+ } else if (is_limited(it->second)) {
+ notify = true;
}
- it->second.insert(query_id);
+ it->second.insert({query_id, limit});
counters[query_id];
}
- dout(10) << query << " query_id=" << query_id << dendl;
+ dout(10) << query << " " << (limit ? stringify(*limit) : "unlimited")
+ << " query_id=" << query_id << dendl;
if (notify) {
listener.handle_query_updated();
std::lock_guard locker(lock);
for (auto it = queries.begin() ; it != queries.end(); it++) {
- auto &ids = it->second;
+ auto iter = it->second.find(query_id);
+ if (iter == it->second.end()) {
+ continue;
+ }
- if (ids.erase(query_id) > 0) {
- if (ids.empty()) {
- queries.erase(it);
- notify = true;
- }
- found = true;
- break;
+ it->second.erase(iter);
+ if (it->second.empty()) {
+ queries.erase(it);
+ notify = true;
+ } else if (is_limited(it->second)) {
+ notify = true;
}
+ found = true;
+ break;
}
counters.erase(query_id);
}
auto &key = it.first;
auto bl_it = it.second.cbegin();
- for (auto query_id : queries[query]) {
+ for (auto &queries_it : queries[query]) {
+ auto query_id = queries_it.first;
auto &key_counters = counters[query_id][key];
if (key_counters.empty()) {
key_counters.resize(query.performance_counter_descriptors.size(),
if (desc_it == report.performance_counter_descriptors.end()) {
break;
}
- if (desc_it->type != query.performance_counter_descriptors[i].type) {
+ if (*desc_it != query.performance_counter_descriptors[i]) {
continue;
}
PerformanceCounter c;
desc_it->unpack_counter(bl_it, &c);
dout(20) << "counter " << key << " " << *desc_it << ": " << c << dendl;
- for (auto query_id : queries[query]) {
+ for (auto &queries_it : queries[query]) {
+ auto query_id = queries_it.first;
auto &key_counters = counters[query_id][key];
key_counters[i].first += c.first;
key_counters[i].second += c.second;
#include "mgr/OSDPerfMetricTypes.h"
-#include <list>
-#include <set>
+#include <map>
/**
* OSD performance query class.
OSDPerfMetricCollector(Listener &listener);
- std::list<OSDPerfMetricQuery> get_queries();
+ std::map<OSDPerfMetricQuery, OSDPerfMetricLimits> get_queries() const;
- OSDPerfMetricQueryID add_query(const OSDPerfMetricQuery& query);
+ OSDPerfMetricQueryID add_query(
+ const OSDPerfMetricQuery& query,
+ const std::optional<OSDPerfMetricLimit> &limit);
int remove_query(OSDPerfMetricQueryID query_id);
void remove_all_queries();
const std::map<OSDPerfMetricQuery, OSDPerfMetricReport> &reports);
private:
- typedef std::map<OSDPerfMetricQuery, std::set<OSDPerfMetricQueryID>> Queries;
+ typedef std::optional<OSDPerfMetricLimit> OptionalLimit;
+ typedef std::map<OSDPerfMetricQuery,
+ std::map<OSDPerfMetricQueryID, OptionalLimit>> Queries;
typedef std::map<OSDPerfMetricQueryID,
std::map<OSDPerfMetricKey, PerformanceCounters>> Counters;
}
}
+std::ostream& operator<<(std::ostream& os, const OSDPerfMetricLimit &limit) {
+ return os << "{order_by=" << limit.order_by << ", max_count="
+ << limit.max_count << "}";
+}
+
void OSDPerfMetricQuery::pack_counters(const PerformanceCounters &counters,
bufferlist *bl) const {
auto it = counters.begin();
return type < other.type;
}
+ bool operator==(const PerformanceCounterDescriptor &other) const {
+ return type == other.type;
+ }
+
+ bool operator!=(const PerformanceCounterDescriptor &other) const {
+ return type != other.type;
+ }
+
DENC(PerformanceCounterDescriptor, v, p) {
DENC_START(1, 1, p);
denc(v.type, p);
}
};
+struct OSDPerfMetricLimit {
+ PerformanceCounterDescriptor order_by;
+ uint64_t max_count = 0;
+
+ OSDPerfMetricLimit() {
+ }
+
+ OSDPerfMetricLimit(const PerformanceCounterDescriptor &order_by,
+ uint64_t max_count)
+ : order_by(order_by), max_count(max_count) {
+ }
+
+ bool operator<(const OSDPerfMetricLimit &other) const {
+ if (order_by != other.order_by) {
+ return order_by < other.order_by;
+ }
+ return max_count < other.max_count;
+ }
+
+ DENC(OSDPerfMetricLimit, v, p) {
+ DENC_START(1, 1, p);
+ denc(v.order_by, p);
+ denc(v.max_count, p);
+ DENC_FINISH(p);
+ }
+};
+WRITE_CLASS_DENC(OSDPerfMetricLimit)
+
+std::ostream& operator<<(std::ostream& os, const OSDPerfMetricLimit &limit);
+
+typedef std::set<OSDPerfMetricLimit> OSDPerfMetricLimits;
+
typedef int OSDPerfMetricQueryID;
struct OSDPerfMetricQuery {
mgrc.set_pgstats_cb([this](){ return collect_pg_stats(); });
mgrc.set_perf_metric_query_cb(
- [this](const std::list<OSDPerfMetricQuery> &queries) {
+ [this](const std::map<OSDPerfMetricQuery, OSDPerfMetricLimits> &queries) {
set_perf_queries(queries);
},
[this](std::map<OSDPerfMetricQuery, OSDPerfMetricReport> *reports) {
return 0;
}
-void OSD::set_perf_queries(const std::list<OSDPerfMetricQuery> &queries) {
+void OSD::set_perf_queries(
+ const std::map<OSDPerfMetricQuery, OSDPerfMetricLimits> &queries) {
dout(10) << "setting " << queries.size() << " queries" << dendl;
std::list<OSDPerfMetricQuery> supported_queries;
- std::copy_if(queries.begin(), queries.end(),
- std::back_inserter(supported_queries),
- [](const OSDPerfMetricQuery &query) {
- return !query.key_descriptor.empty();
- });
+ for (auto &it : queries) {
+ auto &query = it.first;
+ if (!query.key_descriptor.empty()) {
+ supported_queries.push_back(query);
+ }
+ }
if (supported_queries.size() < queries.size()) {
dout(1) << queries.size() - supported_queries.size()
<< " unsupported queries" << dendl;
friend class OSDService;
private:
- void set_perf_queries(const std::list<OSDPerfMetricQuery> &queries);
+ void set_perf_queries(
+ const std::map<OSDPerfMetricQuery, OSDPerfMetricLimits> &queries);
void get_perf_reports(
std::map<OSDPerfMetricQuery, OSDPerfMetricReport> *reports);
'performance_counter_descriptors': [
list, of, descriptor, types
],
+ 'limit': {'order_by': performance_counter_type, 'max_count': n},
}
Valid subkey types: 'client_id', 'pool_id', 'object_name'