paxos/src/legislator/legislator.cc

199 lines
6.5 KiB
C++
Raw Normal View History

#include <string>
2020-05-05 12:47:12 +00:00
#include "legislator.hh"
2020-05-05 17:29:14 +00:00
#include "misc/logger.hh"
#include "message/message.hh"
#include "events/register.hh"
#include "events/send.hh"
#include "vote.hh"
2020-05-05 12:47:12 +00:00
namespace paxos
{
Legislator::Legislator(const LegislatorConfig& config)
2020-05-05 17:29:14 +00:00
: config_(config), ledger(config.name)
2020-05-05 12:47:12 +00:00
{
2020-05-05 17:29:14 +00:00
log("created legislator " + config.name, blue);
}
void Legislator::initiate_ballot()
{
quorum_previous_votes.clear();
2020-05-05 17:29:14 +00:00
int new_ballot_number = ledger.last_tried() + 1;
ledger.set_last_tried(new_ballot_number);
log(config_.name + " is initiating ballot " + std::to_string(new_ballot_number), cyan);
send_next_ballot(new_ballot_number);
}
void Legislator::send_next_ballot(int ballot)
{
std::string ballot_string = std::to_string(ballot);
Message message;
message.set_method("NextBallot");
message.add_header("ballot", ballot_string);
message.add_header("sender", self->config_.name);
for (auto legislator : legislators)
SendEW::send_message(message, legislator.second);
2020-05-05 17:29:14 +00:00
}
2020-05-05 19:04:03 +00:00
void Legislator::receive_next_ballot(Message message)
{
std::string ballot_str = *message.get_header("ballot");
int ballot = std::stoi(ballot_str);
receive_next_ballot(ballot, *message.get_header("sender"));
2020-05-05 19:04:03 +00:00
}
2020-05-05 17:29:14 +00:00
void Legislator::receive_next_ballot(int ballot, std::string sender)
{
log(config_.name + " has received a NextBallot("
+ std::to_string(ballot)
+ ") from " + sender, cyan);
int next_ballot = ledger.next_bal();
if (ballot <= next_ballot)
{
log("but it was discarded because ballot " + std::to_string(ballot)
+ " is inferior or equal to nextBallot "
+ std::to_string(next_ballot), red);
return;
}
ledger.set_next_bal(ballot);
Vote previous_vote = ledger.prev_vote();
2020-05-05 17:29:14 +00:00
previous_vote = previous_vote;
2020-05-05 19:37:14 +00:00
send_last_vote(ballot, previous_vote, sender);
}
void Legislator::send_last_vote(int ballot, Vote previous_vote,
2020-05-05 19:37:14 +00:00
std::string sender)
{
std::string ballot_string = std::to_string(ballot);
std::string vote_ballot_id_string
= std::to_string(previous_vote.ballot_id);
std::string decree_string = std::to_string(previous_vote.decree.decree);
2020-05-05 19:37:14 +00:00
Message message;
message.set_method("LastVote");
message.add_header("ballot", ballot_string);
message.add_header("vote_ballot_id", vote_ballot_id_string);
message.add_header("decree", decree_string);
2020-05-05 19:37:14 +00:00
message.add_header("sender", self->config_.name);
SendEW::send_message(message, legislators[sender]);
2020-05-05 17:29:14 +00:00
}
2020-05-05 19:04:03 +00:00
void Legislator::receive_last_vote(Message message)
{
std::string ballot_str = *message.get_header("ballot");
std::string vote_ballot_id_str = *message.get_header("vote");
std::string sender = *message.get_header("sender");
log(config_.name + " has received a LastVote("
+ ballot_str + ", " + vote_ballot_id_str
+ ") from " + sender, cyan);
int ballot = std::stoi(ballot_str);
int vote_ballot_id = std::stoi(vote_ballot_id_str);
int vote_decree = std::stoi(*message.get_header("decree"));
if (ballot != ledger.last_tried())
return;
Decree decree;
decree.decree = vote_decree;
Vote vote;
vote.decree = decree;
vote.legislator = sender;
vote.ballot_id = vote_ballot_id;
quorum_previous_votes.insert(std::pair<std::string, Vote>
(sender, vote));
int nb_legislators = legislators.size();
int quorum_size = quorum_previous_votes.size();
if (quorum_size > nb_legislators / 2)
receive_enough_last_vote();
2020-05-05 19:04:03 +00:00
}
void Legislator::receive_enough_last_vote()
2020-05-05 17:29:14 +00:00
{
2020-05-05 21:53:01 +00:00
int ballot = ledger.last_tried();
std::string ballot_str = std::to_string(ballot);
log(config_.name + " has received enough LastVote("
+ ballot_str + ", v"
+ ")", green);
Vote max_vote;
max_vote.ballot_id = -1;
for (auto legislator_vote_pair : quorum_previous_votes)
{
Vote current_vote = legislator_vote_pair.second;
if (current_vote.ballot_id > max_vote.ballot_id)
max_vote = current_vote;
}
2020-05-05 21:53:01 +00:00
Decree decree;
if (max_vote.ballot_id != -1)
decree = max_vote.decree;
else
decree.decree = ballot;
send_begin_ballot(ballot, decree);
}
void Legislator::send_begin_ballot(int ballot, Decree decree)
{
std::string ballot_string = std::to_string(ballot);
std::string decree_string = std::to_string(decree.decree);
Message message;
message.set_method("BeginBallot");
message.add_header("sender", self->config_.name);
message.add_header("ballot", ballot_string);
message.add_header("decree", decree_string);
for (auto legislator_vote_pair : quorum_previous_votes)
{
std::string legislator = legislator_vote_pair.first;
SendEW::send_message(message, legislators[legislator]);
}
}
void Legislator::receive_begin_ballot(Message message)
{
std::string ballot_string = *message.get_header("ballot");
std::string decree_string = *message.get_header("decree");
std::string sender = *message.get_header("sender");
log(config_.name + " has received BeginBallot("
+ ballot_string + ", " + decree_string
+ ") from " + sender, green);
int ballot = std::stoi(ballot_string);
int decree = std::stoi(decree_string);
receive_begin_ballot(ballot, decree, sender);
2020-05-05 17:29:14 +00:00
}
2020-05-05 21:53:01 +00:00
void Legislator::receive_begin_ballot(int ballot, int decree_id,
std::string sender)
2020-05-05 17:29:14 +00:00
{
if (ballot != ledger.next_bal())
return;
Vote vote;
vote.ballot_id = ballot;
Decree decree;
decree.decree = decree_id;
vote.decree = decree;
ledger.set_prev_vote(vote);
2020-05-05 17:29:14 +00:00
2020-05-05 21:53:01 +00:00
sender = sender;
2020-05-05 12:47:12 +00:00
}
2020-05-05 19:04:03 +00:00
void Legislator::handle_message(Message message)
{
std::string method = message.get_method();
if (method == "NextBallot")
receive_next_ballot(message);
else if (method == "LastVote")
receive_last_vote(message);
2020-05-05 21:53:01 +00:00
else if (method == "BeginBallot")
receive_begin_ballot(message);
2020-05-05 19:04:03 +00:00
}
2020-05-05 12:47:12 +00:00
}