mirror of https://gitee.com/bigwinds/arangodb
constituent does elections more efficiently
This commit is contained in:
parent
72d8579a6a
commit
034961142a
|
@ -41,6 +41,7 @@
|
||||||
#include "Utils/OperationResult.h"
|
#include "Utils/OperationResult.h"
|
||||||
#include "Utils/SingleCollectionTransaction.h"
|
#include "Utils/SingleCollectionTransaction.h"
|
||||||
#include "Utils/StandaloneTransactionContext.h"
|
#include "Utils/StandaloneTransactionContext.h"
|
||||||
|
#include "VocBase/ticks.h"
|
||||||
#include "VocBase/vocbase.h"
|
#include "VocBase/vocbase.h"
|
||||||
|
|
||||||
using namespace arangodb::consensus;
|
using namespace arangodb::consensus;
|
||||||
|
@ -374,9 +375,14 @@ bool Constituent::vote(term_t termOfPeer, std::string id, index_t prevLogIndex,
|
||||||
|
|
||||||
/// @brief Call to election
|
/// @brief Call to election
|
||||||
void Constituent::callElection() {
|
void Constituent::callElection() {
|
||||||
|
|
||||||
|
using namespace std::chrono;
|
||||||
|
auto timeout = steady_clock::now() +
|
||||||
|
duration<double>(_agent->config().minPing());
|
||||||
|
|
||||||
std::map<std::string, bool> votes;
|
std::map<std::string, bool> votes;
|
||||||
std::vector<std::string> active =
|
std::vector<std::string> active = _agent->config().active();
|
||||||
_agent->config().active(); // Get copy of active
|
CoordTransactionID coordinatorTransactionID = TRI_NewTickServer();
|
||||||
|
|
||||||
votes[_id] = true; // vote for myself
|
votes[_id] = true; // vote for myself
|
||||||
|
|
||||||
|
@ -384,7 +390,7 @@ void Constituent::callElection() {
|
||||||
{
|
{
|
||||||
MUTEX_LOCKER(locker, _castLock);
|
MUTEX_LOCKER(locker, _castLock);
|
||||||
this->termNoLock(_term + 1); // raise my term
|
this->termNoLock(_term + 1); // raise my term
|
||||||
_cast = true;
|
_cast = true;
|
||||||
_votedFor = _id;
|
_votedFor = _id;
|
||||||
savedTerm = _term;
|
savedTerm = _term;
|
||||||
LOG_TOPIC(DEBUG, Logger::AGENCY) << "Set _leaderID to NO_LEADER"
|
LOG_TOPIC(DEBUG, Logger::AGENCY) << "Set _leaderID to NO_LEADER"
|
||||||
|
@ -400,78 +406,58 @@ void Constituent::callElection() {
|
||||||
<< "&candidateId=" << _id << "&prevLogIndex=" << _agent->lastLog().index
|
<< "&candidateId=" << _id << "&prevLogIndex=" << _agent->lastLog().index
|
||||||
<< "&prevLogTerm=" << _agent->lastLog().term;
|
<< "&prevLogTerm=" << _agent->lastLog().term;
|
||||||
|
|
||||||
double minPing = _agent->config().minPing();
|
|
||||||
|
|
||||||
double respTimeout = 0.9 * minPing;
|
|
||||||
double initTimeout = 0.5 * minPing;
|
|
||||||
|
|
||||||
// Ask everyone for their vote
|
// Ask everyone for their vote
|
||||||
for (auto const& i : active) {
|
for (auto const& i : active) {
|
||||||
if (i != _id) {
|
if (i != _id) {
|
||||||
auto headerFields =
|
auto headerFields =
|
||||||
std::make_unique<std::unordered_map<std::string, std::string>>();
|
std::make_unique<std::unordered_map<std::string, std::string>>();
|
||||||
operationIDs[i] = ClusterComm::instance()->asyncRequest(
|
operationIDs[i] = ClusterComm::instance()->asyncRequest(
|
||||||
"1", 1, _agent->config().poolAt(i),
|
"", coordinatorTransactionID, _agent->config().poolAt(i),
|
||||||
rest::RequestType::GET, path.str(),
|
rest::RequestType::GET, path.str(),
|
||||||
std::make_shared<std::string>(body), headerFields,
|
std::make_shared<std::string>(body), headerFields,
|
||||||
nullptr, respTimeout, true, initTimeout);
|
nullptr, 0.9 * _agent->config().minPing(), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait randomized timeout
|
// Collect ballots. I vote for myself.
|
||||||
std::this_thread::sleep_for(sleepFor(initTimeout, respTimeout));
|
size_t yea = 1, nea = 0, majority = size() / 2 + 1;
|
||||||
|
while (true) {
|
||||||
|
|
||||||
// Collect votes
|
auto res = ClusterComm::instance()->wait(
|
||||||
for (const auto& i : active) {
|
"", coordinatorTransactionID, 0, "",
|
||||||
if (i != _id) {
|
duration<double>(steady_clock::now()-timeout).count());
|
||||||
ClusterCommResult res =
|
|
||||||
arangodb::ClusterComm::instance()->enquire(operationIDs[i]);
|
if (res.status == CL_COMM_SENT) {
|
||||||
if (res.status == CL_COMM_SENT) { // Request successfully sent
|
auto body = res.result->getBodyVelocyPack();
|
||||||
res = ClusterComm::instance()->wait("1", 1, operationIDs[i], "1");
|
VPackSlice slc = body->slice();
|
||||||
std::shared_ptr<Builder> body = res.result->getBodyVelocyPack();
|
|
||||||
if (body->isEmpty()) { // body empty
|
// Got ballot
|
||||||
continue;
|
if (slc.isObject() && slc.hasKey("term") && slc.hasKey("voteGranted")) {
|
||||||
|
|
||||||
|
// Follow right away?
|
||||||
|
term_t t = slc.get("term").getUInt();
|
||||||
|
if (t > _term) {
|
||||||
|
follow(t);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check result and counts
|
||||||
|
if(slc.get("voteGranted").getBool()) { // majority in favour
|
||||||
|
if (++yea >= majority) {
|
||||||
|
lead(savedTerm, votes);
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (body->slice().isObject()) { // body
|
if (++nea >= majority) { // majority against
|
||||||
VPackSlice slc = body->slice();
|
follow(_term);
|
||||||
if (slc.hasKey("term") && slc.hasKey("voteGranted")) { // OK
|
break;
|
||||||
term_t t = slc.get("term").getUInt();
|
|
||||||
if (t > _term) { // follow?
|
|
||||||
follow(t);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
votes[i] = slc.get("voteGranted").getBool(); // Get vote
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { // Request failed
|
|
||||||
votes[i] = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count votes
|
|
||||||
size_t yea = 0;
|
|
||||||
for (auto const& i : votes) {
|
|
||||||
if (i.second) {
|
|
||||||
++yea;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
MUTEX_LOCKER(locker, _castLock);
|
|
||||||
if (savedTerm != _term) {
|
|
||||||
followNoLock(_term);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate election results
|
|
||||||
if (yea > size() / 2) {
|
|
||||||
lead(savedTerm, votes);
|
|
||||||
} else {
|
|
||||||
follow(_term);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Constituent::update(std::string const& leaderID, term_t t) {
|
void Constituent::update(std::string const& leaderID, term_t t) {
|
||||||
|
|
|
@ -447,7 +447,7 @@ bool Inception::estimateRAFTInterval() {
|
||||||
|
|
||||||
double precision = 1.0e-2;
|
double precision = 1.0e-2;
|
||||||
mn = precision *
|
mn = precision *
|
||||||
std::ceil((1. / precision)*(.35 + precision * (maxmean + 3.*maxstdev)));
|
std::ceil((1. / precision)*(.5 + precision * (maxmean + 3.*maxstdev)));
|
||||||
if (config.waitForSync()) {
|
if (config.waitForSync()) {
|
||||||
mn *= 4.;
|
mn *= 4.;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue