#include <boost/circular_buffer.hpp>
#include "common/RWLock.h"
+#include "include/str_map.h"
#include "msg/msg_types.h"
// For PerfCounterType
#include "messages/MMgrReport.h"
+namespace ceph {
+ class Formatter;
+}
// Unique reference to a daemon within a cluster
typedef std::pair<std::string, std::string> DaemonKey;
+static inline std::string to_string(const DaemonKey& dk) {
+ return dk.first + "." + dk.second;
+}
+
// An instance of a performance counter type, within
// a particular daemon.
class PerfCounterInstance
{
return buffer;
}
+ const DataPoint& get_latest_data() const
+ {
+ return buffer.back();
+ }
const boost::circular_buffer<AvgDataPoint> & get_data_avg() const
{
return avg_buffer;
}
+ const AvgDataPoint& get_latest_data_avg() const
+ {
+ return avg_buffer.back();
+ }
void push(utime_t t, uint64_t const &v);
void push_avg(utime_t t, uint64_t const &s, uint64_t const &c);
// The record of perf stat types, shared between daemons
PerfCounterTypes &types;
- DaemonPerfCounters(PerfCounterTypes &types_)
+ explicit DaemonPerfCounters(PerfCounterTypes &types_)
: types(types_)
{}
// The metadata (hostname, version, etc) sent from the daemon
std::map<std::string, std::string> metadata;
+ /// device ids -> devname, derived from metadata[device_ids]
+ std::map<std::string,std::string> devices;
+
// TODO: this can be generalized to other daemons
- std::vector<OSDHealthMetric> osd_health_metrics;
+ std::vector<DaemonHealthMetric> daemon_health_metrics;
// Ephemeral state
bool service_daemon = false;
std::map<std::string, std::string> service_status;
utime_t last_service_beacon;
+ // running config
+ std::map<std::string,std::map<int32_t,std::string>> config;
+
+ // mon config values we failed to set
+ std::map<std::string,std::string> ignored_mon_config;
+
+ // compiled-in config defaults (rarely used, so we leave them encoded!)
+ bufferlist config_defaults_bl;
+ std::map<std::string,std::string> config_defaults;
+
// The perf counters received in MMgrReport messages
DaemonPerfCounters perf_counters;
- DaemonState(PerfCounterTypes &types_)
+ explicit DaemonState(PerfCounterTypes &types_)
: perf_counters(types_)
{
}
+
+ void set_metadata(const std::map<std::string,std::string>& m) {
+ devices.clear();
+ metadata = m;
+ auto p = m.find("device_ids");
+ if (p != m.end()) {
+ map<std::string,std::string> devs;
+ get_str_map(p->second, &devs, ",; ");
+ for (auto& i : devs) {
+ if (i.second.size()) { // skip blank ids
+ devices[i.second] = i.first;
+ }
+ }
+ }
+ }
+
+ const std::map<std::string,std::string>& _get_config_defaults() {
+ if (config_defaults.empty() &&
+ config_defaults_bl.length()) {
+ auto p = config_defaults_bl.cbegin();
+ try {
+ decode(config_defaults, p);
+ } catch (buffer::error& e) {
+ }
+ }
+ return config_defaults;
+ }
};
typedef std::shared_ptr<DaemonState> DaemonStatePtr;
typedef std::map<DaemonKey, DaemonStatePtr> DaemonStateCollection;
+struct DeviceState : public RefCountedObject
+{
+ std::string devid;
+ std::set<pair<std::string,std::string>> devnames; ///< (server,devname)
+ std::set<DaemonKey> daemons;
+ std::map<string,string> metadata; ///< persistent metadata
+
+ pair<utime_t,utime_t> life_expectancy; ///< when device failure is expected
+ utime_t life_expectancy_stamp; ///< when life expectency was recorded
+
+ DeviceState(const std::string& n)
+ : RefCountedObject(nullptr, 0),
+ devid(n) {}
+
+ void set_metadata(map<string,string>&& m);
+
+ void set_life_expectancy(utime_t from, utime_t to, utime_t now);
+ void rm_life_expectancy();
+
+ string get_life_expectancy_str(utime_t now) const;
+
+ /// true of we can be safely forgotten/removed from memory
+ bool empty() const {
+ return daemons.empty() && metadata.empty();
+ }
+
+ void dump(Formatter *f) const;
+ void print(ostream& out) const;
+};
+
+typedef boost::intrusive_ptr<DeviceState> DeviceStateRef;
/**
* Fuse the collection of per-daemon metadata from Ceph into
*/
class DaemonStateIndex
{
- private:
+private:
mutable RWLock lock = {"DaemonStateIndex", true, true, true};
std::map<std::string, DaemonStateCollection> by_server;
DaemonStateCollection all;
std::set<DaemonKey> updating;
+ std::map<std::string,DeviceStateRef> devices;
+
void _erase(const DaemonKey& dmk);
- public:
+ DeviceStateRef _get_or_create_device(const std::string& dev) {
+ auto p = devices.find(dev);
+ if (p != devices.end()) {
+ return p->second;
+ }
+ devices[dev] = new DeviceState(dev);
+ return devices[dev];
+ }
+ void _erase_device(DeviceStateRef d) {
+ devices.erase(d->devid);
+ }
+
+public:
DaemonStateIndex() {}
// FIXME: shouldn't really be public, maybe construct DaemonState
PerfCounterTypes types;
void insert(DaemonStatePtr dm);
+ void _insert(DaemonStatePtr dm);
bool exists(const DaemonKey &key) const;
DaemonStatePtr get(const DaemonKey &key);
+ void rm(const DaemonKey &key);
+ void _rm(const DaemonKey &key);
// Note that these return by value rather than reference to avoid
// callers needing to stay in lock while using result. Callers must
return std::forward<Callback>(cb)(by_server, std::forward<Args>(args)...);
}
+ template<typename Callback, typename...Args>
+ bool with_device(const std::string& dev,
+ Callback&& cb, Args&&... args) const {
+ RWLock::RLocker l(lock);
+ auto p = devices.find(dev);
+ if (p == devices.end()) {
+ return false;
+ }
+ std::forward<Callback>(cb)(*p->second, std::forward<Args>(args)...);
+ return true;
+ }
+
+ template<typename Callback, typename...Args>
+ bool with_device_write(const std::string& dev,
+ Callback&& cb, Args&&... args) {
+ RWLock::WLocker l(lock);
+ auto p = devices.find(dev);
+ if (p == devices.end()) {
+ return false;
+ }
+ std::forward<Callback>(cb)(*p->second, std::forward<Args>(args)...);
+ if (p->second->empty()) {
+ _erase_device(p->second);
+ }
+ return true;
+ }
+
+ template<typename Callback, typename...Args>
+ void with_device_create(const std::string& dev,
+ Callback&& cb, Args&&... args) {
+ RWLock::WLocker l(lock);
+ auto d = _get_or_create_device(dev);
+ std::forward<Callback>(cb)(*d, std::forward<Args>(args)...);
+ }
+
+ template<typename Callback, typename...Args>
+ void with_devices(Callback&& cb, Args&&... args) const {
+ RWLock::RLocker l(lock);
+ for (auto& i : devices) {
+ std::forward<Callback>(cb)(*i.second, std::forward<Args>(args)...);
+ }
+ }
+
+ template<typename CallbackInitial, typename Callback, typename...Args>
+ void with_devices2(CallbackInitial&& cbi, // with lock taken
+ Callback&& cb, // for each device
+ Args&&... args) const {
+ RWLock::RLocker l(lock);
+ cbi();
+ for (auto& i : devices) {
+ std::forward<Callback>(cb)(*i.second, std::forward<Args>(args)...);
+ }
+ }
+
+ void list_devids_by_server(const std::string& server,
+ std::set<std::string> *ls) {
+ auto m = get_by_server(server);
+ for (auto& i : m) {
+ std::lock_guard l(i.second->lock);
+ for (auto& j : i.second->devices) {
+ ls->insert(j.first);
+ }
+ }
+ }
+
void notify_updating(const DaemonKey &k) {
RWLock::WLocker l(lock);
updating.insert(k);
return updating.count(k) > 0;
}
+ void update_metadata(DaemonStatePtr state,
+ const map<string,string>& meta) {
+ // remove and re-insert in case the device metadata changed
+ RWLock::WLocker l(lock);
+ _rm(state->key);
+ {
+ Mutex::Locker l2(state->lock);
+ state->set_metadata(meta);
+ }
+ _insert(state);
+ }
+
/**
* Remove state for all daemons of this type whose names are
* not present in `names_exist`. Use this function when you have