void AuthMonitor::update_from_paxos(bool *need_bootstrap)
{
dout(10) << __func__ << dendl;
- load_health();
version_t version = get_last_committed();
version_t keys_ver = mon.key_server.get_ver();
put_last_committed(t, version);
// health
- health_check_map_t next;
+ auto& next = get_health_checks_pending_writeable();
map<string,list<string>> bad_detail; // entity -> details
for (auto i = mon.key_server.secrets_begin();
i != mon.key_server.secrets_end();
}
}
}
- encode_health(next, t);
}
void AuthMonitor::encode_full(MonitorDBStore::TransactionRef t)
{
version = get_last_committed();
dout(10) << __func__ << dendl;
- load_health();
bufferlist qbl;
mon.store->get(service_name, "quorum", qbl);
t->put(service_name, "mutes", bl);
}
- health_check_map_t pending_health;
+ auto& pending_health = get_health_checks_pending_writeable();
// combine per-mon details carefully...
map<string,set<string>> names; // code -> <mon names>
}
pending_health.merge(leader_checks);
- encode_health(pending_health, t);
}
version_t HealthMonitor::get_trim_to() const
ceph_assert(version > get_fsmap().get_epoch());
load_metadata(pending_metadata);
- load_health();
// read and decode
bufferlist fsmap_bl;
remove_from_metadata(pending, t);
// health
- health_check_map_t new_checks;
+ auto& new_checks = get_health_checks_pending_writeable();
const auto &info_map = pending.get_mds_info();
for (const auto &i : info_map) {
const auto &gid = i.first;
std::regex("%hasorhave%"),
p.second.detail.size() > 1 ? "have" : "has");
}
- encode_health(new_checks, t);
}
version_t MDSMonitor::get_trim_to() const
ever_had_active_mgr = get_value("ever_had_active_mgr");
- load_health();
if (map.available) {
first_seen_inactive = utime_t();
pending_metadata.clear();
pending_metadata_rm.clear();
- health_check_map_t next;
+ auto& next = get_health_checks_pending_writeable();
if (pending_map.active_gid == 0) {
auto level = should_warn_about_mgr_down();
if (level != HEALTH_OK) {
} else {
put_value(t, "ever_had_active_mgr", 1);
}
- encode_health(next, t);
if (pending_command_descs.size()) {
dout(4) << __func__ << " encoding " << pending_command_descs.size()
{
version = get_last_committed();
dout(10) << " " << version << dendl;
- load_health();
bufferlist bl;
get_version(version, bl);
if (version) {
{
dout(10) << " " << version << dendl;
pending_digest = digest;
- pending_health_checks = get_health_checks();
pending_service_map_bl.clear();
encode(service_map, pending_service_map_bl, mon.get_quorum_con_features());
}
encode(pending_pool_availability, bl);
put_version(t, version, bl);
put_last_committed(t, version);
-
- encode_health(pending_health_checks, t);
}
version_t MgrStatMonitor::get_trim_to() const
bufferlist bl = m->get_data();
auto p = bl.cbegin();
decode(pending_digest, p);
- pending_health_checks.swap(m->health_checks);
+ auto& pending_health_checks = get_health_checks_pending_writeable();
if (m->service_map_bl.length()) {
pending_service_map_bl.swap(m->service_map_bl);
}
}
//health
- health_check_map_t next;
+ auto& next = get_health_checks_pending_writeable();
pending_map.check_health(&next);
- encode_health(next, t);
}
class C_ApplyFeatures : public Context {
put_last_committed(t, pending_map.epoch);
//health
- health_check_map_t checks;
+ auto& checks = get_health_checks_pending_writeable();
pending_map.get_health_checks(&checks);
- encode_health(checks, t);
}
void NVMeofGwMon::update_from_paxos(bool *need_bootstrap)
bufferlist bl;
int err = get_version(version, bl);
ceph_assert(err == 0);
- load_health();
auto p = bl.cbegin();
map.decode(p);
mapping_job.reset();
}
- load_health();
/*
* We will possibly have a stashed latest that *we* wrote, and we will
}
// health
- health_check_map_t next;
+ auto& next = get_health_checks_pending_writeable();
tmp.check_health(cct, &next);
- encode_health(next, t);
}
int OSDMonitor::load_metadata(int osd, map<string, string>& m, ostream *err)
format_version = new_format;
- update_from_paxos(need_bootstrap);
+ _update_from_paxos(need_bootstrap);
}
void PaxosService::post_refresh()
if (should_stash_full())
encode_full(t);
- encode_pending(t);
+ _encode_pending(t);
have_pending = false;
if (format_version > 0) {
if (mon.is_leader()) {
dout(7) << __func__ << " creating new pending" << dendl;
if (!have_pending) {
- create_pending();
+ _create_pending();
have_pending = true;
}
}
}
-void PaxosService::load_health()
+void PaxosService::_create_pending() {
+ dout(10) << __func__ << dendl;
+ health_checks.create_pending();
+ dout(30) << __func__ << ": health_checks pending: " << health_checks << dendl;
+ create_pending();
+}
+
+void PaxosService::_encode_pending(MonitorDBStore::TransactionRef t) {
+ dout(10) << __func__ << dendl;
+ using ceph::encode;
+ encode_pending(t);
+ dout(30) << __func__ << ": health_checks encoding: " << health_checks << dendl;
+ auto const& pending = health_checks.get_pending_map();
+ ceph::buffer::list bl;
+ encode(pending, bl);
+ t->put("health", service_name, bl);
+ mon.log_health(pending, health_checks.get_map(), t);
+}
+
+void PaxosService::_update_from_paxos(bool* need_bootstrap)
{
+ dout(10) << __func__ << dendl;
bufferlist bl;
mon.store->get("health", service_name, bl);
if (bl.length()) {
auto p = bl.cbegin();
- using ceph::decode;
- decode(health_checks, p);
+ health_checks.decode(p);
+ dout(30) << __func__ << ": health_checks decoded: " << health_checks << dendl;
}
+ update_from_paxos(need_bootstrap);
}
#include "Paxos.h"
#include "Monitor.h"
#include "MonitorDBStore.h"
+#include "PaxosMap.h"
/**
* A Paxos Service is an abstraction that easily allows one to obtain an
* If we are or have queued anything for proposal, this variable will be true
* until our proposal has been finished.
*/
- bool proposing;
+ bool proposing = false;
bool need_immediate_propose = false;
* must keep its own version, if so they wish. This variable should be used
* for that purpose.
*/
- version_t service_version;
+ version_t service_version = 0;
- private:
+private:
/**
* Event callback responsible for proposing our pending value once a timer
* runs out and fires.
*/
- Context *proposal_timer;
+ Context *proposal_timer = nullptr;
/**
* If the implementation class has anything pending to be proposed to Paxos,
* then have_pending should be true; otherwise, false.
*/
- bool have_pending;
+ bool have_pending = false;
+
+protected:
+ /**
+ * format of our state in RocksDB, 0 for default
+ */
+ version_t format_version = 0;
/**
* health checks for this service
- *
- * Child must populate this during encode_pending() by calling encode_health().
*/
- health_check_map_t health_checks;
-protected:
+ PaxosMap<Monitor, PaxosService, health_check_map_t> health_checks;
+
/**
- * format of our state in RocksDB, 0 for default
+ * The pending health check map. Only callable by the service itself.
*/
- version_t format_version;
+ health_check_map_t& get_health_checks_pending_writeable() {
+ return health_checks.get_pending_map_writeable();
+ }
public:
- const health_check_map_t& get_health_checks() const {
- return health_checks;
+ /**
+ * The current (i.e. not pending) health check map.
+ */
+ health_check_map_t const& get_health_checks() const {
+ return health_checks.get_map();
}
/**
* @param name Our service's name.
*/
PaxosService(Monitor &mn, Paxos &p, std::string name)
- : mon(mn), paxos(p), service_name(name),
- proposing(false),
- service_version(0), proposal_timer(0), have_pending(false),
- format_version(0),
- last_committed_name("last_committed"),
- first_committed_name("first_committed"),
- full_prefix_name("full"), full_latest_name("latest"),
- cached_first_committed(0), cached_last_committed(0)
+ : mon(mn), paxos(p), service_name(std::move(name)), health_checks(mn, *this)
{
}
*/
void _active();
+ void _create_pending();
+
+ void _encode_pending(MonitorDBStore::TransactionRef t);
+
+ void _update_from_paxos(bool* need_bootstrap);
+
public:
/**
* Propose a new value through Paxos.
*/
virtual void tick() {}
- void encode_health(const health_check_map_t& next,
- MonitorDBStore::TransactionRef t) {
- using ceph::encode;
- ceph::buffer::list bl;
- encode(next, bl);
- t->put("health", service_name, bl);
- mon.log_health(next, health_checks, t);
- }
- void load_health();
-
/**
* @defgroup PaxosService_h_store_keys Set of keys that are usually used on
* all the services implementing this
* mistakes.
* @{
*/
- const std::string last_committed_name;
- const std::string first_committed_name;
- const std::string full_prefix_name;
- const std::string full_latest_name;
+ const std::string last_committed_name{"last_committed"};
+ const std::string first_committed_name{"first_committed"};
+ const std::string full_prefix_name{"full"};
+ const std::string full_latest_name{"latest"};
/**
* @}
*/
* and avoid the overhead.
* @{
*/
- version_t cached_first_committed;
- version_t cached_last_committed;
+ version_t cached_first_committed = 0;
+ version_t cached_last_committed = 0;
/**
* @}
*/
#pragma once
-#include <string>
+#include <iosfwd>
#include <map>
+#include <string>
#include "include/health.h"
#include "include/utime.h"
+#include "common/CanHasPrint.h"
#include "common/Formatter.h"
+#include "common/dout.h"
struct health_check_t {
health_status_t severity;
return !(l == r);
}
+ void print(std::ostream& os) const {
+ os << "hc"
+ << "(" << summary
+ << " count=" << count
+ << ")";
+ }
+
void dump(ceph::Formatter *f, bool want_detail=true) const {
f->dump_stream("severity") << severity;
DENC_FINISH(p);
}
+ static constexpr bool is_ephemeral() {
+ return true;
+ }
+
+ void print(std::ostream& os) const {
+ os << "health_check_map_t"
+ << "("
+ << checks
+ << ")";
+ }
+
void dump(ceph::Formatter *f) const {
for (auto& [code, check] : checks) {
f->dump_object(code, check);