#include "messages/MMonElection.h"
#include "common/config.h"
-#include "include/assert.h"
+#include "include/ceph_assert.h"
#define dout_subsys ceph_subsys_mon
#undef dout_prefix
void Elector::bump_epoch(epoch_t e)
{
dout(10) << "bump_epoch " << epoch << " to " << e << dendl;
- assert(epoch <= e);
+ ceph_assert(epoch <= e);
epoch = e;
auto t(std::make_shared<MonitorDBStore::Transaction>());
t->put(Monitor::MONITOR_NAME, "election_epoch", epoch);
auto t(std::make_shared<MonitorDBStore::Transaction>());
t->put(Monitor::MONITOR_NAME, "election_writeable_test", rand());
int r = mon->store->apply_transaction(t);
- assert(r >= 0);
+ ceph_assert(r >= 0);
}
- start_stamp = ceph_clock_now();
electing_me = true;
acked_me[mon->rank].cluster_features = CEPH_FEATURES_ALL;
+ acked_me[mon->rank].mon_release = ceph_release();
acked_me[mon->rank].mon_features = ceph::features::mon::get_supported();
mon->collect_metadata(&acked_me[mon->rank].metadata);
leader_acked = -1;
MMonElection *m =
new MMonElection(MMonElection::OP_PROPOSE, epoch, mon->monmap);
m->mon_features = ceph::features::mon::get_supported();
- mon->messenger->send_message(m, mon->monmap->get_inst(i));
+ m->mon_release = ceph_release();
+ mon->send_mon_message(m, i);
}
reset_timer();
// ack them
leader_acked = who;
- ack_stamp = ceph_clock_now();
MMonElection *m = new MMonElection(MMonElection::OP_ACK, epoch, mon->monmap);
m->mon_features = ceph::features::mon::get_supported();
+ m->mon_release = ceph_release();
mon->collect_metadata(&m->metadata);
- // This field is unused completely in luminous, but jewel uses it to
- // determine whether we are a dumpling mon due to some crufty old
- // code. It only needs to see this buffer non-empty, so put
- // something useless there.
- m->sharing_bl = mon->get_local_commands_bl(mon->get_required_mon_features());
-
- mon->messenger->send_message(m, mon->monmap->get_inst(who));
+ mon->send_mon_message(m, who);
// set a timer
reset_timer(1.0); // give the leader some extra time to declare victory
* Leader.
*/
expire_event = mon->timer.add_event_after(
- g_conf->mon_election_timeout + plus,
+ g_conf()->mon_election_timeout + plus,
new C_MonContext(mon, [this](int) {
expire();
}));
mon_feature_t mon_features = ceph::features::mon::get_supported();
set<int> quorum;
map<int,Metadata> metadata;
+ int min_mon_release = -1;
for (map<int, elector_info_t>::iterator p = acked_me.begin();
p != acked_me.end();
++p) {
cluster_features &= p->second.cluster_features;
mon_features &= p->second.mon_features;
metadata[p->first] = p->second.metadata;
+ if (min_mon_release < 0 || p->second.mon_release < min_mon_release) {
+ min_mon_release = p->second.mon_release;
+ }
}
cancel_timer();
- assert(epoch % 2 == 1); // election
+ ceph_assert(epoch % 2 == 1); // election
bump_epoch(epoch+1); // is over!
// tell everyone!
m->quorum_features = cluster_features;
m->mon_features = mon_features;
m->sharing_bl = mon->get_local_commands_bl(mon_features);
- mon->messenger->send_message(m, mon->monmap->get_inst(*p));
+ m->mon_release = min_mon_release;
+ mon->send_mon_message(m, *p);
}
// tell monitor
mon->win_election(epoch, quorum,
- cluster_features, mon_features, metadata);
+ cluster_features, mon_features, min_mon_release,
+ metadata);
}
dout(5) << "handle_propose from " << m->get_source() << dendl;
int from = m->get_source().num();
- assert(m->epoch % 2 == 1); // election
+ ceph_assert(m->epoch % 2 == 1); // election
uint64_t required_features = mon->get_required_features();
mon_feature_t required_mon_features = mon->get_required_mon_features();
<< " without required features" << dendl;
nak_old_peer(op);
return;
+ } else if (mon->monmap->min_mon_release > m->mon_release) {
+ dout(5) << " ignoring propose from mon" << from
+ << " release " << m->mon_release
+ << " < min_mon_release " << mon->monmap->min_mon_release << dendl;
+ nak_old_peer(op);
+ return;
} else if (!m->mon_features.contains_all(required_mon_features)) {
// all the features in 'required_mon_features' not in 'm->mon_features'
mon_feature_t missing = required_mon_features.diff(m->mon_features);
if (mon->rank < from) {
// i would win over them.
if (leader_acked >= 0) { // we already acked someone
- assert(leader_acked < from); // and they still win, of course
+ ceph_assert(leader_acked < from); // and they still win, of course
dout(5) << "no, we already acked " << leader_acked << dendl;
} else {
// wait, i should win!
dout(5) << "handle_ack from " << m->get_source() << dendl;
int from = m->get_source().num();
- assert(m->epoch % 2 == 1); // election
+ ceph_assert(m->epoch % 2 == 1); // election
if (m->epoch > epoch) {
dout(5) << "woah, that's a newer epoch, i must have rebooted. bumping and re-starting!" << dendl;
bump_epoch(m->epoch);
start();
return;
}
- assert(m->epoch == epoch);
+ ceph_assert(m->epoch == epoch);
uint64_t required_features = mon->get_required_features();
if ((required_features ^ m->get_connection()->get_features()) &
required_features) {
// thanks
acked_me[from].cluster_features = m->get_connection()->get_features();
acked_me[from].mon_features = m->mon_features;
+ acked_me[from].mon_release = m->mon_release;
acked_me[from].metadata = m->metadata;
dout(5) << " so far i have {";
for (map<int, elector_info_t>::const_iterator p = acked_me.begin();
}
} else {
// ignore, i'm deferring already.
- assert(leader_acked >= 0);
+ ceph_assert(leader_acked >= 0);
}
}
<< dendl;
int from = m->get_source().num();
- assert(from < mon->rank);
- assert(m->epoch % 2 == 0);
+ ceph_assert(from < mon->rank);
+ ceph_assert(m->epoch % 2 == 0);
leader_acked = -1;
// they win
mon->lose_election(epoch, m->quorum, from,
- m->quorum_features, m->mon_features);
+ m->quorum_features, m->mon_features, m->mon_release);
// cancel my timer
cancel_timer();
// stash leader's commands
- assert(m->sharing_bl.length());
+ ceph_assert(m->sharing_bl.length());
vector<MonCommand> new_cmds;
- bufferlist::iterator bi = m->sharing_bl.begin();
+ auto bi = m->sharing_bl.cbegin();
MonCommand::decode_vector(new_cmds, bi);
mon->set_leader_commands(new_cmds);
}
uint64_t required_features = mon->get_required_features();
mon_feature_t required_mon_features = mon->get_required_mon_features();
dout(10) << "sending nak to peer " << m->get_source()
- << " that only supports " << supported_features
- << " " << m->mon_features
- << " of the required " << required_features
- << " " << required_mon_features
- << dendl;
-
+ << " supports " << supported_features << " " << m->mon_features
+ << ", required " << required_features << " " << required_mon_features
+ << ", release " << m->mon_release
+ << " vs required " << mon->monmap->min_mon_release
+ << dendl;
MMonElection *reply = new MMonElection(MMonElection::OP_NAK, m->epoch,
mon->monmap);
reply->quorum_features = required_features;
reply->mon_features = required_mon_features;
+ reply->mon_release = mon->monmap->min_mon_release;
mon->features.encode(reply->sharing_bl);
m->get_connection()->send_message(reply);
}
dout(1) << "handle_nak from " << m->get_source()
<< " quorum_features " << m->quorum_features
<< " " << m->mon_features
+ << " min_mon_release " << m->mon_release
<< dendl;
- CompatSet other;
- bufferlist::iterator bi = m->sharing_bl.begin();
- other.decode(bi);
- CompatSet diff = Monitor::get_supported_features().unsupported(other);
-
- mon_feature_t mon_supported = ceph::features::mon::get_supported();
- // all features in 'm->mon_features' not in 'mon_supported'
- mon_feature_t mon_diff = m->mon_features.diff(mon_supported);
+ if (m->mon_release > ceph_release()) {
+ derr << "Shutting down because I am release " << ceph_release()
+ << " < min_mon_release " << m->mon_release << dendl;
+ } else {
+ CompatSet other;
+ auto bi = m->sharing_bl.cbegin();
+ other.decode(bi);
+ CompatSet diff = Monitor::get_supported_features().unsupported(other);
- derr << "Shutting down because I do not support required monitor features: { "
- << diff << " } " << mon_diff << dendl;
+ mon_feature_t mon_supported = ceph::features::mon::get_supported();
+ // all features in 'm->mon_features' not in 'mon_supported'
+ mon_feature_t mon_diff = m->mon_features.diff(mon_supported);
+ derr << "Shutting down because I lack required monitor features: { "
+ << diff << " } " << mon_diff << dendl;
+ }
exit(0);
// the end!
}
void Elector::dispatch(MonOpRequestRef op)
{
op->mark_event("elector:dispatch");
- assert(op->is_type_election());
+ ceph_assert(op->is_type_election());
switch (op->get_req()->get_type()) {