version_t version;
__s16 session_mon;
uint64_t session_mon_tid;
+
+ // track which epoch the leader received a forwarded request in, so we can
+ // discard forwarded requests appropriately on election boundaries.
+ epoch_t rx_election_epoch;
PaxosServiceMessage()
: Message(MSG_PAXOS),
- version(0), session_mon(-1), session_mon_tid(0) { }
+ version(0), session_mon(-1), session_mon_tid(0),
+ rx_election_epoch(0) { }
PaxosServiceMessage(int type, version_t v, int enc_version=1, int compat_enc_version=0)
: Message(type, enc_version, compat_enc_version),
- version(v), session_mon(-1), session_mon_tid(0) { }
+ version(v), session_mon(-1), session_mon_tid(0),
+ rx_election_epoch(0) { }
protected:
~PaxosServiceMessage() {}
PaxosServiceMessage *req = m->msg;
m->msg = NULL; // so ~MForward doesn't delete it
req->set_connection(c);
+
+ /*
+ * note which election epoch this is; we will drop the message if
+ * there is a future election since our peers will resend routed
+ * requests in that case.
+ */
+ req->rx_election_epoch = get_epoch();
+
/* Because this is a special fake connection, we need to break
the ref loop between Connection and MonSession differently
than we normally do. Here, the Message refers to the Connection
bool PaxosService::dispatch(PaxosServiceMessage *m)
{
dout(10) << "dispatch " << *m << " from " << m->get_orig_source_inst() << dendl;
+
+ // make sure this message isn't forwarded from a previous election epoch
+ if (m->rx_election_epoch &&
+ m->rx_election_epoch < mon->get_epoch()) {
+ dout(10) << " discarding forwarded message from previous election epoch "
+ << m->rx_election_epoch << " < " << mon->get_epoch() << dendl;
+ m->put();
+ return true;
+ }
+
// make sure our map is readable and up to date
if (!is_readable(m->version)) {
dout(10) << " waiting for paxos -> readable (v" << m->version << ")" << dendl;