diff --git a/arangod/Agency/Constituent.cpp b/arangod/Agency/Constituent.cpp index 77ab43d5dc..c4b5c1afb4 100644 --- a/arangod/Agency/Constituent.cpp +++ b/arangod/Agency/Constituent.cpp @@ -41,6 +41,7 @@ #include "Utils/OperationResult.h" #include "Utils/SingleCollectionTransaction.h" #include "Utils/StandaloneTransactionContext.h" +#include "VocBase/ticks.h" #include "VocBase/vocbase.h" using namespace arangodb::consensus; @@ -374,9 +375,14 @@ bool Constituent::vote(term_t termOfPeer, std::string id, index_t prevLogIndex, /// @brief Call to election void Constituent::callElection() { + + using namespace std::chrono; + auto timeout = steady_clock::now() + + duration(_agent->config().minPing()); + std::map votes; - std::vector active = - _agent->config().active(); // Get copy of active + std::vector active = _agent->config().active(); + CoordTransactionID coordinatorTransactionID = TRI_NewTickServer(); votes[_id] = true; // vote for myself @@ -384,7 +390,7 @@ void Constituent::callElection() { { MUTEX_LOCKER(locker, _castLock); this->termNoLock(_term + 1); // raise my term - _cast = true; + _cast = true; _votedFor = _id; savedTerm = _term; LOG_TOPIC(DEBUG, Logger::AGENCY) << "Set _leaderID to NO_LEADER" @@ -400,78 +406,58 @@ void Constituent::callElection() { << "&candidateId=" << _id << "&prevLogIndex=" << _agent->lastLog().index << "&prevLogTerm=" << _agent->lastLog().term; - double minPing = _agent->config().minPing(); - - double respTimeout = 0.9 * minPing; - double initTimeout = 0.5 * minPing; - // Ask everyone for their vote for (auto const& i : active) { if (i != _id) { auto headerFields = std::make_unique>(); operationIDs[i] = ClusterComm::instance()->asyncRequest( - "1", 1, _agent->config().poolAt(i), + "", coordinatorTransactionID, _agent->config().poolAt(i), rest::RequestType::GET, path.str(), std::make_shared(body), headerFields, - nullptr, respTimeout, true, initTimeout); + nullptr, 0.9 * _agent->config().minPing(), true); } } - // Wait randomized timeout - std::this_thread::sleep_for(sleepFor(initTimeout, respTimeout)); + // Collect ballots. I vote for myself. + size_t yea = 1, nea = 0, majority = size() / 2 + 1; + while (true) { - // Collect votes - for (const auto& i : active) { - if (i != _id) { - ClusterCommResult res = - arangodb::ClusterComm::instance()->enquire(operationIDs[i]); - if (res.status == CL_COMM_SENT) { // Request successfully sent - res = ClusterComm::instance()->wait("1", 1, operationIDs[i], "1"); - std::shared_ptr body = res.result->getBodyVelocyPack(); - if (body->isEmpty()) { // body empty - continue; + auto res = ClusterComm::instance()->wait( + "", coordinatorTransactionID, 0, "", + duration(steady_clock::now()-timeout).count()); + + if (res.status == CL_COMM_SENT) { + auto body = res.result->getBodyVelocyPack(); + VPackSlice slc = body->slice(); + + // Got ballot + 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 { - if (body->slice().isObject()) { // body - VPackSlice slc = body->slice(); - if (slc.hasKey("term") && slc.hasKey("voteGranted")) { // OK - term_t t = slc.get("term").getUInt(); - if (t > _term) { // follow? - follow(t); - break; - } - votes[i] = slc.get("voteGranted").getBool(); // Get vote - } + if (++nea >= majority) { // majority against + follow(_term); + break; } } - } 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) { diff --git a/arangod/Agency/Inception.cpp b/arangod/Agency/Inception.cpp index 0241969b84..1969191f87 100644 --- a/arangod/Agency/Inception.cpp +++ b/arangod/Agency/Inception.cpp @@ -447,7 +447,7 @@ bool Inception::estimateRAFTInterval() { double precision = 1.0e-2; mn = precision * - std::ceil((1. / precision)*(.35 + precision * (maxmean + 3.*maxstdev))); + std::ceil((1. / precision)*(.5 + precision * (maxmean + 3.*maxstdev))); if (config.waitForSync()) { mn *= 4.; }