1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
#pragma once
#include <string>
#include <utility>
#include "async_key_value_source.h"
namespace {
bool less_than(const std::string& lhs, const std::string& rhs, bool if_equal=false)
{
int cmp = lhs.compare(rhs);
if(cmp < 0)
{
return true;
}
else if(cmp > 0)
{
return false;
}
else
{
return if_equal;
}
}
}
namespace libsinsp {
namespace cgroup_limits {
/**
* \brief The key for cgroup value lookup
*
* It's effectively a (container_id, cpu_cgroup, mem_cgroup) tuple
* that can be used as a hash key.
*/
struct cgroup_limits_key {
cgroup_limits_key() {}
cgroup_limits_key(std::string container_id,
std::string cpu_cgroup_dir,
std::string mem_cgroup_dir,
std::string cpuset_cgroup_dir) :
m_container_id(std::move(container_id)),
m_cpu_cgroup(std::move(cpu_cgroup_dir)),
m_mem_cgroup(std::move(mem_cgroup_dir)),
m_cpuset_cgroup(std::move(cpuset_cgroup_dir)) { }
bool operator<(const cgroup_limits_key& rhs) const
{
return less_than(m_container_id, rhs.m_container_id,
less_than(m_cpu_cgroup, rhs.m_cpu_cgroup,
less_than(m_mem_cgroup, rhs.m_mem_cgroup,
less_than(m_cpuset_cgroup, rhs.m_cpuset_cgroup))));
}
bool operator==(const cgroup_limits_key& rhs) const
{
return m_container_id == rhs.m_container_id &&
m_cpu_cgroup == rhs.m_cpu_cgroup &&
m_mem_cgroup == rhs.m_mem_cgroup &&
m_cpuset_cgroup == rhs.m_cpuset_cgroup;
}
explicit operator const std::string&() const
{
return m_container_id;
}
std::string m_container_id;
std::string m_cpu_cgroup;
std::string m_mem_cgroup;
std::string m_cpuset_cgroup;
};
/**
* \brief The result of an asynchronous cgroup lookup
*
* This contains all the cgroup values we read during the asynchronous lookup
*/
struct cgroup_limits_value {
cgroup_limits_value() :
m_cpu_shares(0),
m_cpu_quota(0),
m_cpu_period(0),
m_memory_limit(0),
m_cpuset_cpu_count(0) {}
int64_t m_cpu_shares;
int64_t m_cpu_quota;
int64_t m_cpu_period;
int64_t m_memory_limit;
int32_t m_cpuset_cpu_count;
};
/**
* \brief Read resource limits from cgroups
* @param key the container to read limits for
* @param value output value. when the return value is false, specific fields
* may or may not have been modified
* @param name_check if true and the container doesn't use its own cgroups
* for mem/cpu, we log a message and we ignore the values.
* "Use its own cgroups" means the container id is present in the cgroup
* path, which may not be true for all container engines.
* @return true when all values have been successfully read, false otherwise
*
* Note: reading a zero/negative/very large value is considered a failure,
* because it might mean that resource limits haven't yet been set. Essentially,
* `false` means "there's real chance the limits could conceivably change
* in the future", while `true` means we really don't expect them to change
* any more.
*/
bool get_cgroup_resource_limits(const cgroup_limits_key& key, cgroup_limits_value& value, bool name_check = true);
}
}
namespace std {
/**
* \brief Specialization of std::hash for cgroup_limits_key
*
* It allows `cgroup_limits_key` instances to be used as `unordered_map` keys
*/
template<> struct hash<libsinsp::cgroup_limits::cgroup_limits_key> {
std::size_t operator()(const libsinsp::cgroup_limits::cgroup_limits_key& h) const {
size_t h1 = ::std::hash<std::string>{}(h.m_container_id);
size_t h2 = ::std::hash<std::string>{}(h.m_cpu_cgroup);
size_t h3 = ::std::hash<std::string>{}(h.m_mem_cgroup);
size_t h4 = ::std::hash<std::string>{}(h.m_cpuset_cgroup);
return h1 ^ (h2 << 1u) ^ (h3 << 2u) ^ (h4 << 3u);
}
};
}
|