bufferlist monmap_bl;
set<int> quorum;
uint64_t quorum_features;
+ bufferlist sharing_bl;
/* the following were both used in the next branch for a while
* on user cluster, so we've left them in for compatibility. */
version_t defunct_one;
version_t defunct_two;
- bufferlist commands;
MMonElection() : Message(MSG_MON_ELECTION, HEAD_VERSION, COMPAT_VERSION),
op(0), epoch(0), quorum_features(0), defunct_one(0),
::encode(quorum_features, payload);
::encode(defunct_one, payload);
::encode(defunct_two, payload);
- ::encode(commands, payload);
+ ::encode(sharing_bl, payload);
}
void decode_payload() {
bufferlist::iterator p = payload.begin();
::decode(defunct_two, p);
}
if (header.version >= 5)
- ::decode(commands, p);
+ ::decode(sharing_bl, p);
}
};
leader_acked = who;
ack_stamp = ceph_clock_now(g_ceph_context);
MMonElection *m = new MMonElection(MMonElection::OP_ACK, epoch, mon->monmap);
- m->commands = mon->get_supported_commands_bl();
+ m->sharing_bl = mon->get_supported_commands_bl();
mon->messenger->send_message(m, mon->monmap->get_inst(who));
// set a timer
MMonElection *m = new MMonElection(MMonElection::OP_VICTORY, epoch, mon->monmap);
m->quorum = quorum;
m->quorum_features = features;
- m->commands = *cmds_bl;
+ m->sharing_bl = *cmds_bl;
mon->messenger->send_message(m, mon->monmap->get_inst(*p));
}
assert(m->epoch % 2 == 1); // election
if ((required_features ^ m->get_connection()->get_features()) &
required_features) {
- dout(5) << " ignoring propose from mon without required features" << dendl;
- m->put();
+ dout(5) << " ignoring propose from mon" << from
+ << " without required features" << dendl;
+ nak_old_peer(m);
return;
} else if (m->epoch > epoch) {
bump_epoch(m->epoch);
if (electing_me) {
// thanks
acked_me[from] = m->get_connection()->get_features();
- if (!m->commands.length())
+ if (!m->sharing_bl.length())
classic_mons.insert(from);
dout(5) << " so far i have " << acked_me << dendl;
cancel_timer();
// stash leader's commands
- if (m->commands.length()) {
+ if (m->sharing_bl.length()) {
MonCommand *new_cmds;
int cmdsize;
- bufferlist::iterator bi = m->commands.begin();
+ bufferlist::iterator bi = m->sharing_bl.begin();
MonCommand::decode_array(&new_cmds, &cmdsize, bi);
mon->set_leader_supported_commands(new_cmds, cmdsize);
} else { // they are a legacy monitor; use known legacy command set
m->put();
}
+void Elector::nak_old_peer(MMonElection *m)
+{
+ uint64_t supported_features = m->get_connection()->get_features();
+
+ if (supported_features & CEPH_FEATURE_OSDMAP_ENC) {
+ uint64_t required_features = mon->apply_compatset_features_to_quorum_requirements();
+ dout(10) << "sending nak to peer " << m->get_source()
+ << " that only supports " << supported_features
+ << " of the required " << required_features << dendl;
+
+ MMonElection *reply = new MMonElection(MMonElection::OP_NAK, m->epoch,
+ mon->monmap);
+ reply->quorum_features = required_features;
+ mon->features.encode(reply->sharing_bl);
+ mon->messenger->send_message(reply, m->get_connection());
+ }
+ m->put();
+}
+void Elector::handle_nak(MMonElection *m)
+{
+ dout(1) << "handle_nak from " << m->get_source()
+ << " quorum_features " << m->quorum_features << dendl;
+ CompatSet other;
+ bufferlist::iterator bi = m->sharing_bl.begin();
+ other.decode(bi);
+ CompatSet diff = Monitor::get_supported_features().unsupported(other);
+
+ derr << "Shutting down because I do not support required monitor features: { "
+ << diff << " }" << dendl;
+
+ exit(0);
+ // the end!
+}
void Elector::dispatch(Message *m)
{
case MMonElection::OP_VICTORY:
handle_victory(em);
return;
+ case MMonElection::OP_NAK:
+ handle_nak(em);
+ return;
default:
assert(0);
}
* @post We sent a message of type OP_VICTORY to each quorum member.
*/
void victory();
-
+
/**
* Handle a message from some other node proposing himself to become him
* the Leader.
* @param m A message with an operation type of OP_VICTORY
*/
void handle_victory(class MMonElection *m);
+ /**
+ * Send a nak to a peer who's out of date, containing information about why.
+ *
+ * If we get a message from a peer who can't support the required quorum
+ * features, we have to ignore them. This function will at least send
+ * them a message about *why* they're being ignored -- if they're new
+ * enough to support such a message.
+ *
+ * @param m A message from a monitor not supporting required features. We
+ * take ownership of the reference.
+ */
+ void nak_old_peer(class MMonElection *m);
+ /**
+ * Handle a message from some other participant declaring
+ * we cannot join the quorum.
+ *
+ * Apparently the quorum requires some feature that we do not implement. Shut
+ * down gracefully.
+ *
+ * @pre Election is on-going.
+ * @post We've shut down.
+ *
+ * @param m A message with an operation type of OP_NAK
+ */
+ void handle_nak(class MMonElection *m);
public:
/**