1
0
Fork 0

Feature/schmutz plus plus (#5972)

- Schmutz now called "Maintenance" and completely implemented in C++
 - Fix index locking bug in mmfiles
 - Fix a bug in mmfiles with silent option and repsert
 - Slightly increase supervision okperiod and graceperiod
This commit is contained in:
Kaveh Vahedipour 2018-08-24 12:15:35 +02:00 committed by Max Neunhöffer
parent 50be715aeb
commit 28754cbf15
147 changed files with 18184 additions and 3373 deletions

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2018-2018 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
///////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2018 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2018 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -239,9 +239,12 @@ bool Inception::restartingActiveAgent() {
auto comres = cc->syncRequest(
clientId, 1, p, rest::RequestType::POST, path, greetstr,
std::unordered_map<std::string, std::string>(), 2.0);
if (comres->status == CL_COMM_SENT) {
// FIXMEMAINTENANCE: handle case of result not 200
if (comres->status == CL_COMM_SENT) { // WARN: What if result not 200?
auto const theirConfigVP = comres->result->getBodyVelocyPack();
auto const& theirConfig = theirConfigVP->slice();
// FIXMEMAINTENANCE: handle the case that tcc is not an object such
// that the next command would throw.
auto const& tcc = theirConfig.get("configuration");
auto const& theirId = tcc.get("id").copyString();

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
///////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
@ -276,13 +276,15 @@ class Node {
// These two operator() functions could be "protected" once
// unit tests updated.
//
public:
/// @brief Get node specified by path string
Node& operator()(std::string const& path);
/// @brief Get node specified by path string
Node const& operator()(std::string const& path) const;
/// @brief Get string value (throws if type NODE or if conversion fails)
std::string getString() const;
//
// The protected accessors are the "old" interface. They throw.
// Please use the hasAsXXX replacements.
@ -303,9 +305,6 @@ protected:
/// @brief Get double value (throws if type NODE or if conversion fails)
double getDouble() const;
/// @brief Get string value (throws if type NODE or if conversion fails)
std::string getString() const;
/// @brief Get array value
Slice getArray() const;

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2018-2018 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
@ -73,7 +73,7 @@ void RemoveFollower::run() {
}
bool RemoveFollower::create(std::shared_ptr<VPackBuilder> envelope) {
LOG_TOPIC(INFO, Logger::SUPERVISION) << "Todo: RemoveFollower(s) "
LOG_TOPIC(DEBUG, Logger::SUPERVISION) << "Todo: RemoveFollower(s) "
<< " to shard " << _shard << " in collection " << _collection;
bool selfCreate = (envelope == nullptr); // Do we create ourselves?
@ -373,7 +373,7 @@ bool RemoveFollower::start() {
if (res.accepted && res.indices.size() == 1 && res.indices[0]) {
_status = FINISHED;
LOG_TOPIC(INFO, Logger::SUPERVISION)
LOG_TOPIC(DEBUG, Logger::SUPERVISION)
<< "Pending: RemoveFollower(s) to shard " << _shard << " in collection "
<< _collection;
return true;

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
@ -39,7 +39,9 @@ class RestAgencyHandler : public RestBaseHandler {
public:
char const* name() const override final { return "RestAgencyHandler"; }
RequestLane lane() const override final { return RequestLane::AGENCY_CLUSTER; }
RestStatus execute() override;
private:

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
@ -66,7 +66,9 @@ class RestAgencyPrivHandler : public arangodb::RestBaseHandler {
public:
char const* name() const override final { return "RestAgencyPrivHandler"; }
RequestLane lane() const override final { return RequestLane::AGENCY_INTERNAL; }
RestStatus execute() override;
private:

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -2,7 +2,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
@ -154,8 +154,8 @@ Supervision::Supervision()
_snapshot("Supervision"),
_transient("Transient"),
_frequency(1.),
_gracePeriod(5.),
_okThreshold(1.5),
_gracePeriod(10.),
_okThreshold(5.),
_jobId(0),
_jobIdMax(0),
_selfShutdown(false),
@ -556,6 +556,54 @@ std::vector<check_t> Supervision::check(std::string const& type) {
return ret;
}
bool Supervision::earlyBird() const {
std::vector<std::string> tpath {"Sync","ServerStates"};
std::vector<std::string> pdbpath {"Plan","DBServers"};
std::vector<std::string> pcpath {"Plan","Coordinators"};
if (!_snapshot.has(pdbpath)) {
LOG_TOPIC(DEBUG, Logger::SUPERVISION)
<< "No Plan/DBServers key in persistent store";
return false;
}
VPackBuilder dbserversB = _snapshot(pdbpath).toBuilder();
VPackSlice dbservers = dbserversB.slice();
if (!_snapshot.has(pcpath)) {
LOG_TOPIC(DEBUG, Logger::SUPERVISION)
<< "No Plan/Coordinators key in persistent store";
return false;
}
VPackBuilder coordinatorsB = _snapshot(pcpath).toBuilder();
VPackSlice coordinators = coordinatorsB.slice();
if (!_transient.has(tpath)) {
LOG_TOPIC(DEBUG, Logger::SUPERVISION)
<< "No Sync/ServerStates key in transient store";
return false;
}
VPackBuilder serverStatesB = _transient(tpath).toBuilder();
VPackSlice serverStates = serverStatesB.slice();
// every db server in plan accounted for in transient store?
for (auto const& server : VPackObjectIterator(dbservers)) {
auto serverId = server.key.copyString();
if (!serverStates.hasKey(serverId)) {
return false;
}
}
// every db server in plan accounted for in transient store?
for (auto const& server : VPackObjectIterator(coordinators)) {
auto serverId = server.key.copyString();
if (!serverStates.hasKey(serverId)) {
return false;
}
}
return true;
}
// Update local agency snapshot, guarded by callers
bool Supervision::updateSnapshot() {
@ -698,7 +746,9 @@ void Supervision::run() {
upgradeAgency();
}
if (_agent->leaderFor() > 10) {
if (_agent->leaderFor() > 55 || earlyBird()) {
// 55 seconds is less than a minute, which fits to the
// 60 seconds timeout in /_admin/cluster/health
try {
doChecks();
} catch (std::exception const& e) {
@ -708,6 +758,10 @@ void Supervision::run() {
LOG_TOPIC(ERR, Logger::SUPERVISION) <<
"Supervision::doChecks() generated an uncaught exception.";
}
} else {
LOG_TOPIC(INFO, Logger::SUPERVISION)
<< "Postponing supervision for now, waiting for incoming "
"heartbeats: " << _agent->leaderFor();
}
handleJobs();

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
@ -24,14 +24,13 @@
#ifndef ARANGOD_CONSENSUS_SUPERVISION_H
#define ARANGOD_CONSENSUS_SUPERVISION_H 1
#include "Agency/AgencyCommon.h"
#include "Agency/Node.h"
#include "AgencyCommon.h"
#include "Agency/TimeString.h"
#include "Basics/ConditionVariable.h"
#include "Basics/Mutex.h"
#include "Cluster/CriticalThread.h"
#include <chrono>
namespace arangodb {
namespace consensus {
@ -124,6 +123,9 @@ class Supervision : public arangodb::CriticalThread {
private:
/// @brief decide, if we can start supervision ahead of armageddon delay
bool earlyBird() const;
/// @brief Upgrade agency with FailedServers an object from array
void upgradeZero(VPackBuilder&);
@ -219,34 +221,6 @@ class Supervision : public arangodb::CriticalThread {
*/
query_t removeTransactionBuilder(std::vector<std::string> const&);
inline std::string timepointToString(Supervision::TimePoint const& t) {
time_t tt = std::chrono::system_clock::to_time_t(t);
struct tm tb;
size_t const len(21);
char buffer[len];
TRI_gmtime(tt, &tb);
::strftime(buffer, sizeof(buffer), "%Y-%m-%dT%H:%M:%SZ", &tb);
return std::string(buffer, len - 1);
}
inline Supervision::TimePoint stringToTimepoint(std::string const& s) {
if (!s.empty()) {
try {
std::tm tt;
tt.tm_year = std::stoi(s.substr(0, 4)) - 1900;
tt.tm_mon = std::stoi(s.substr(5, 2)) - 1;
tt.tm_mday = std::stoi(s.substr(8, 2));
tt.tm_hour = std::stoi(s.substr(11, 2));
tt.tm_min = std::stoi(s.substr(14, 2));
tt.tm_sec = std::stoi(s.substr(17, 2));
tt.tm_isdst = 0;
auto time_c = TRI_timegm(&tt);
return std::chrono::system_clock::from_time_t(time_c);
} catch (...) {}
}
return std::chrono::time_point<std::chrono::system_clock>();
}
}} // Name spaces
#endif

View File

@ -0,0 +1,61 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2018 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGOD_CONSENSUS_TIMESTRING_H
#define ARANGOD_CONSENSUS_TIMESTRING_H 1
#include <chrono>
inline std::string timepointToString(std::chrono::system_clock::time_point const& t) {
time_t tt = std::chrono::system_clock::to_time_t(t);
struct tm tb;
size_t const len(21);
char buffer[len];
TRI_gmtime(tt, &tb);
::strftime(buffer, sizeof(buffer), "%Y-%m-%dT%H:%M:%SZ", &tb);
return std::string(buffer, len - 1);
}
inline std::string timepointToString(std::chrono::system_clock::duration const& d) {
return timepointToString(std::chrono::system_clock::time_point() + d);
}
inline std::chrono::system_clock::time_point stringToTimepoint(std::string const& s) {
if (!s.empty()) {
try {
std::tm tt;
tt.tm_year = std::stoi(s.substr(0, 4)) - 1900;
tt.tm_mon = std::stoi(s.substr(5, 2)) - 1;
tt.tm_mday = std::stoi(s.substr(8, 2));
tt.tm_hour = std::stoi(s.substr(11, 2));
tt.tm_min = std::stoi(s.substr(14, 2));
tt.tm_sec = std::stoi(s.substr(17, 2));
tt.tm_isdst = 0;
auto time_c = TRI_timegm(&tt);
return std::chrono::system_clock::from_time_t(time_c);
} catch (...) {}
}
return std::chrono::time_point<std::chrono::system_clock>();
}
#endif

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -283,6 +283,9 @@ SET(ARANGOD_SOURCES
Cache/TransactionalBucket.cpp
Cache/TransactionalCache.cpp
Cache/TransactionManager.cpp
Cluster/ActionBase.cpp
Cluster/Action.cpp
Cluster/ActionDescription.cpp
Cluster/AgencyCallback.cpp
Cluster/AgencyCallbackRegistry.cpp
Cluster/ClusterComm.cpp
@ -294,17 +297,32 @@ SET(ARANGOD_SOURCES
Cluster/ClusterRepairDistributeShardsLike.cpp
Cluster/ClusterRepairOperations.cpp
Cluster/ClusterTraverser.cpp
Cluster/CreateCollection.cpp
Cluster/CreateDatabase.cpp
Cluster/CriticalThread.cpp
Cluster/EngineEqualityCheckFeature.cpp
Cluster/FollowerInfo.cpp
Cluster/DBServerAgencySync.cpp
Cluster/DropCollection.cpp
Cluster/DropDatabase.cpp
Cluster/DropIndex.cpp
Cluster/EnsureIndex.cpp
Cluster/FollowerInfo.cpp
Cluster/HeartbeatThread.cpp
Cluster/Maintenance.cpp
Cluster/MaintenanceFeature.cpp
Cluster/MaintenanceRestHandler.cpp
Cluster/MaintenanceWorker.cpp
Cluster/NonAction.cpp
Cluster/ReplicationTimeoutFeature.cpp
Cluster/ResignShardLeadership.cpp
Cluster/RestAgencyCallbacksHandler.cpp
Cluster/RestClusterHandler.cpp
Cluster/ServerState.cpp
Cluster/SynchronizeShard.cpp
Cluster/TraverserEngine.cpp
Cluster/TraverserEngineRegistry.cpp
Cluster/UpdateCollection.cpp
Cluster/v8-cluster.cpp
GeneralServer/AsyncJobManager.cpp
GeneralServer/AuthenticationFeature.cpp

161
arangod/Cluster/Action.cpp Normal file
View File

@ -0,0 +1,161 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#include "Action.h"
#include "Cluster/CreateCollection.h"
#include "Cluster/CreateDatabase.h"
#include "Cluster/DropCollection.h"
#include "Cluster/DropDatabase.h"
#include "Cluster/DropIndex.h"
#include "Cluster/EnsureIndex.h"
#include "Cluster/NonAction.h"
#include "Cluster/ResignShardLeadership.h"
#include "Cluster/SynchronizeShard.h"
#include "Cluster/UpdateCollection.h"
#include "Logger/Logger.h"
using namespace arangodb;
using namespace arangodb::maintenance;
Action::Action(
MaintenanceFeature& feature,
ActionDescription const& description) : _action(nullptr) {
TRI_ASSERT(description.has("name"));
create(feature, description);
}
Action::Action(
MaintenanceFeature& feature,
ActionDescription&& description) : _action(nullptr) {
TRI_ASSERT(description.has("name"));
create(feature, std::move(description));
}
Action::Action(
MaintenanceFeature& feature,
std::shared_ptr<ActionDescription> const description)
: _action(nullptr) {
TRI_ASSERT(description->has("name"));
create(feature, *description);
}
Action::Action(std::unique_ptr<ActionBase> action)
: _action(std::move(action)) {}
Action::~Action() {}
void Action::create(
MaintenanceFeature& feature, ActionDescription const& description) {
std::string name = description.name();
if (name == "CreateCollection") {
_action.reset(new CreateCollection(feature, description));
} else if (name == "CreateDatabase") {
_action.reset(new CreateDatabase(feature, description));
} else if (name == "DropCollection") {
_action.reset(new DropCollection(feature, description));
} else if (name == "DropDatabase") {
_action.reset(new DropDatabase(feature, description));
} else if (name == "DropIndex") {
_action.reset(new DropIndex(feature, description));
} else if (name == "EnsureIndex") {
_action.reset(new EnsureIndex(feature, description));
} else if (name == "ResignShardLeadership") {
_action.reset(new ResignShardLeadership(feature, description));
} else if (name == "SynchronizeShard") {
_action.reset(new SynchronizeShard(feature, description));
} else if (name == "UpdateCollection") {
_action.reset(new UpdateCollection(feature, description));
} else {
_action.reset(new NonAction(feature, description));
}
}
ActionDescription const& Action::describe() const {
TRI_ASSERT(_action != nullptr);
return _action->describe();
}
arangodb::MaintenanceFeature& Action::feature() const {
TRI_ASSERT(_action != nullptr);
return _action->feature();
}
std::shared_ptr<VPackBuilder> const Action::properties() const {
return describe().properties();
}
bool Action::first() {
TRI_ASSERT(_action != nullptr);
return _action->first();
}
bool Action::next() {
TRI_ASSERT(_action != nullptr);
return _action->next();
}
arangodb::Result Action::result() {
TRI_ASSERT(_action != nullptr);
return _action->result();
}
arangodb::Result Action::kill(Signal const& signal) {
TRI_ASSERT(_action != nullptr);
return _action->kill(signal);
}
arangodb::Result Action::progress(double& p) {
TRI_ASSERT(_action != nullptr);
return _action->progress(p);
}
ActionState Action::getState() const {
return _action->getState();
}
void Action::startStats() {
_action->startStats();
}
void Action::incStats() {
_action->incStats();
}
void Action::endStats() {
_action->endStats();
}
void Action::toVelocyPack(arangodb::velocypack::Builder& builder) const {
TRI_ASSERT(_action != nullptr);
_action->toVelocyPack(builder);
}
namespace std {
ostream& operator<< (
ostream& out, arangodb::maintenance::Action const& d) {
out << d.toVelocyPack().toJson();
return out;
}}

193
arangod/Cluster/Action.h Normal file
View File

@ -0,0 +1,193 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGODB_CLUSTER_MAINTENANCE_ACTION_H
#define ARANGODB_CLUSTER_MAINTENANCE_ACTION_H
#include "ActionBase.h"
#include "ActionDescription.h"
#include "lib/Basics/Result.h"
#include <chrono>
namespace arangodb {
class MaintenanceFeature;
namespace maintenance {
class Action {
public:
/// @brief construct with description
Action(MaintenanceFeature&, ActionDescription const&);
/// @brief construct with description
Action(MaintenanceFeature&, ActionDescription&&);
/// @brief construct with description
Action(MaintenanceFeature&, std::shared_ptr<ActionDescription> const);
/**
* @brief construct with concrete action base
* @param feature Maintenance feature
* @param action Concrete action
*/
Action(std::unique_ptr<ActionBase> action);
/// @brief clean up
virtual ~Action();
/// @brief run for some time and tell, if need more time or done
bool next();
/// @brief run for some time and tell, if need more time or done
arangodb::Result result();
/// @brief run for some time and tell, if need more time or done
bool first ();
/// @brief run for some time and tell, if need more time or done
ActionState state() const;
/// @brief is object in a usable condition
bool ok() const { return (nullptr != _action.get() && _action->ok()); };
/// @brief kill action with signal
arangodb::Result kill(Signal const& signal);
/// @brief check progress
arangodb::Result progress(double& progress);
/// @brief describe action
ActionDescription const& describe() const;
/// @brief describe action
MaintenanceFeature& feature() const;
// @brief get properties
std::shared_ptr<VPackBuilder> const properties() const;
ActionState getState() const;
void setState(ActionState state) {
_action->setState(state);
}
/// @brief update incremental statistics
void startStats();
/// @brief update incremental statistics
void incStats();
/// @brief finalize statistics
void endStats();
/// @brief return progress statistic
uint64_t getProgress() const { return _action->getProgress(); }
/// @brief Once PreAction completes, remove its pointer
void clearPreAction() { _action->clearPreAction(); }
/// @brief Retrieve pointer to action that should run before this one
std::shared_ptr<Action> getPreAction() { return _action->getPreAction(); }
/// @brief Initiate a pre action
void createPreAction(ActionDescription const& description);
/// @brief Initiate a post action
void createPostAction(ActionDescription const& description);
/// @brief Retrieve pointer to action that should run directly after this one
std::shared_ptr<Action> getPostAction() { return _action->getPostAction(); }
/// @brief Save pointer to successor action
void setPostAction(std::shared_ptr<ActionDescription> post) {
_action->setPostAction(post);
}
/// @brief hash value of ActionDescription
/// @return uint64_t hash
uint64_t hash() const { return _action->hash(); }
/// @brief hash value of ActionDescription
/// @return uint64_t hash
uint64_t id() const { return _action->id(); }
/// @brief add VPackObject to supplied builder with info about this action
void toVelocyPack(VPackBuilder & builder) const;
/// @brief add VPackObject to supplied builder with info about this action
VPackBuilder toVelocyPack() const { return _action->toVelocyPack(); }
/// @brief Returns json array of object contents for status reports
/// Thread safety of this function is questionable for some member objects
// virtual Result toJson(/* builder */) {return Result;};
/// @brief Return Result object contain action specific status
Result result() const { return _action->result(); }
/// @brief execution finished successfully or failed ... and race timer expired
bool done() const { return _action->done(); }
/// @brief waiting for a worker to grab it and go!
bool runable() const {return _action->runable();}
/// @brief When object was constructed
std::chrono::system_clock::time_point getCreateTime() const
{return _action->getCreateTime();}
/// @brief When object was first started
std::chrono::system_clock::time_point getStartTime() const
{return _action->getStartTime();}
/// @brief When object most recently iterated
std::chrono::system_clock::time_point getLastStatTime() const
{return _action->getLastStatTime();}
/// @brief When object finished executing
std::chrono::system_clock::time_point getDoneTime() const
{return _action->getDoneTime();}
private:
/// @brief actually create the concrete action
void create(MaintenanceFeature&, ActionDescription const&);
/// @brief concrete action
std::unique_ptr<ActionBase> _action;
};
}}
namespace std {
ostream& operator<< (
ostream& o, arangodb::maintenance::Action const& d);
}
#endif

View File

@ -0,0 +1,259 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#include "Cluster/ActionBase.h"
#include "Agency/TimeString.h"
#include "ApplicationFeatures/ApplicationServer.h"
#include "Cluster/ClusterFeature.h"
#include "Cluster/MaintenanceFeature.h"
using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::maintenance;
// FIXMAINTENANCE: These strings appear again in ActionDescription.h,
// we should remove this duplication.
const char ActionBase::KEY[]="key";
const char ActionBase::FIELDS[]="fields";
const char ActionBase::TYPE[]="type";
const char ActionBase::INDEXES[]="indexes";
const char ActionBase::INDEX[]="index";
const char ActionBase::SHARDS[]="shards";
const char ActionBase::DATABASE[]="database";
const char ActionBase::COLLECTION[]="collection";
const char ActionBase::EDGE[]="edge";
const char ActionBase::NAME[]="name";
const char ActionBase::ID[]="id";
const char ActionBase::LEADER[]="theLeader";
const char ActionBase::LOCAL_LEADER[]="localLeader";
const char ActionBase::GLOB_UID[]="globallyUniqueId";
const char ActionBase::OBJECT_ID[]="objectId";
inline static std::chrono::system_clock::duration secs_since_epoch() {
return std::chrono::system_clock::now().time_since_epoch();
}
ActionBase::ActionBase(MaintenanceFeature& feature, ActionDescription const& desc)
: _feature(feature), _description(desc), _state(READY),
_progress(0) {
init();
}
ActionBase::ActionBase(MaintenanceFeature& feature, ActionDescription&& desc)
: _feature(feature), _description(std::move(desc)), _state(READY),
_progress(0) {
init();
}
void ActionBase::init() {
_hash = _description.hash();
_clientId = std::to_string(_hash);
_id = _feature.nextActionId();
// initialization of duration struct is not guaranteed in atomic form
_actionCreated = secs_since_epoch();
_actionStarted = std::chrono::system_clock::duration::zero();
_actionLastStat = std::chrono::system_clock::duration::zero();
_actionDone = std::chrono::system_clock::duration::zero();
}
ActionBase::~ActionBase() {
}
void ActionBase::notify() {
LOG_TOPIC(DEBUG, Logger::MAINTENANCE)
<< "Job " << _description << " calling syncDBServerStatusQuo";
auto cf = ApplicationServer::getFeature<ClusterFeature>("Cluster");
if (cf != nullptr) {
cf->syncDBServerStatusQuo();
}
}
/// @brief execution finished successfully or failed ... and race timer expired
bool ActionBase::done() const {
return (COMPLETE==_state || FAILED==_state) &&
_actionDone.load() + std::chrono::seconds(_feature.getSecondsActionsBlock()) <= secs_since_epoch();
} // ActionBase::done
ActionDescription const& ActionBase::describe() const {
return _description;
}
MaintenanceFeature& ActionBase::feature() const {
return _feature;
}
VPackSlice const ActionBase::properties() const {
return _description.properties()->slice();
}
/// @brief Initiate a new action that will start immediately, pausing this action
void ActionBase::createPreAction(std::shared_ptr<ActionDescription> const & description) {
_preAction = description;
std::shared_ptr<Action> new_action = _feature.preAction(description);
// shift from EXECUTING to WAITINGPRE ... EXECUTING is set to block other
// workers from picking it up
if (_preAction && new_action->ok()) {
setState(WAITINGPRE);
} else {
_result.reset(TRI_ERROR_BAD_PARAMETER, "preAction rejected parameters.");
} // else
} // ActionBase::createPreAction
/// @brief Retrieve pointer to action that should run before this one
std::shared_ptr<Action> ActionBase::getPreAction() {
return (_preAction != nullptr) ? _feature.findAction(_preAction) : nullptr;
}
/// @brief Retrieve pointer to action that should run after this one
std::shared_ptr<Action> ActionBase::getPostAction() {
return (_postAction != nullptr) ? _feature.findAction(_postAction) : nullptr;
}
// FIXMEMAINTENANCE: Code path could corrupt registry object because
// this does not hold lock. Also, current implementation is a race condition
// where another thread could pick this up.
/// @brief Create a new action that will start after this action successfully completes
void ActionBase::createPostAction(std::shared_ptr<ActionDescription> const& description) {
// preAction() sets up what we need
_postAction = description;
std::shared_ptr<Action> new_action = _feature.postAction(description);
// shift from EXECUTING to WAITINGPOST ... EXECUTING is set to block other
// workers from picking it up
if (_postAction && new_action->ok()) {
new_action->setState(WAITINGPOST);
} else {
_result.reset(TRI_ERROR_BAD_PARAMETER, "preAction rejected parameters for _postAction.");
} // else
} // ActionBase::createPostAction
void ActionBase::startStats() {
_actionStarted = secs_since_epoch();
} // ActionBase::startStats
/// @brief show progress on Action, and when that progress occurred
void ActionBase::incStats() {
++_progress;
_actionLastStat = secs_since_epoch();
} // ActionBase::incStats
void ActionBase::endStats() {
_actionDone = secs_since_epoch();
} // ActionBase::endStats
Result arangodb::actionError(int errorCode, std::string const& errorMessage) {
LOG_TOPIC(ERR, Logger::MAINTENANCE) << errorMessage;
return Result(errorCode, errorMessage);
}
Result arangodb::actionWarn(int errorCode, std::string const& errorMessage) {
LOG_TOPIC(WARN, Logger::MAINTENANCE) << errorMessage;
return Result(errorCode, errorMessage);
}
void ActionBase::toVelocyPack(VPackBuilder & builder) const {
VPackObjectBuilder ob(&builder);
builder.add("id", VPackValue(_id));
builder.add("state", VPackValue(_state));
builder.add("progress", VPackValue(_progress));
builder.add("created", VPackValue(timepointToString(_actionCreated.load())));
builder.add("started", VPackValue(timepointToString(_actionStarted.load())));
builder.add("lastStat", VPackValue(timepointToString(_actionLastStat.load())));
builder.add("done", VPackValue(timepointToString(_actionDone.load())));
builder.add("result", VPackValue(_result.errorNumber()));
builder.add(VPackValue("description"));
{ VPackObjectBuilder desc(&builder);
_description.toVelocyPack(builder); }
} // MaintanceAction::toVelocityPack
VPackBuilder ActionBase::toVelocyPack() const {
VPackBuilder builder;
toVelocyPack(builder);
return builder;
}
/**
* kill() operation is an expected future feature. Not supported in the
* original ActionBase derivatives
*/
arangodb::Result ActionBase::kill(Signal const& signal) {
return actionError(
TRI_ERROR_ACTION_OPERATION_UNABORTABLE, "Kill operation not supported on this action.");
}
/**
* progress() operation is an expected future feature. Not supported in the
* original ActionBase derivatives
*/
arangodb::Result ActionBase::progress(double& progress) {
progress = 0.5;
return arangodb::Result(TRI_ERROR_NO_ERROR);
}
namespace std {
ostream& operator<< (
ostream& out, arangodb::maintenance::ActionBase const& d) {
out << d.toVelocyPack().toJson();
return out;
}}

View File

@ -0,0 +1,251 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGODB_MAINTENANCE_ACTION_BASE_H
#define ARANGODB_MAINTENANCE_ACTION_BASE_H
#include "ActionDescription.h"
#include "Basics/Common.h"
#include "Basics/Result.h"
#include <chrono>
namespace arangodb {
class MaintenanceFeature;
namespace maintenance {
class Action;
class ActionBase {
public:
ActionBase (MaintenanceFeature&, ActionDescription const&);
ActionBase (MaintenanceFeature&, ActionDescription&&);
ActionBase() = delete;
virtual ~ActionBase();
//
// MaintenanceWork entry points
//
/// @brief initial call to object to perform a unit of work.
/// really short tasks could do all work here and return false
/// @return true to continue processing, false done (result() set)
virtual bool first() = 0;
/// @brief iterative call to perform a unit of work
/// @return true to continue processing, false done (result() set)
virtual bool next() { return false; }
//
// common property or decription names
//
static const char KEY[];
static const char FIELDS[];
static const char TYPE[];
static const char INDEXES[];
static const char INDEX[];
static const char SHARDS[];
static const char DATABASE[];
static const char COLLECTION[];
static const char EDGE[];
static const char NAME[];
static const char ID[];
static const char LEADER[];
static const char LOCAL_LEADER[];
static const char GLOB_UID[];
static const char OBJECT_ID[];
/// @brief execution finished successfully or failed ... and race timer expired
virtual bool done() const;
/// @brief waiting for a worker to grab it and go!
bool runable() const {return READY==_state;}
/// @brief did initialization have issues?
bool ok() const {return FAILED!=_state;}
/// @brief adjust state of object, assumes WRITE lock on _actionRegistryLock
ActionState state() const {
return _state;
}
void notify();
virtual arangodb::Result kill(Signal const& signal);
virtual arangodb::Result progress(double& progress);
ActionDescription const& describe() const;
MaintenanceFeature& feature() const;
std::string const& get(std::string const&) const;
VPackSlice const properties() const;
/// @brief adjust state of object, assumes WRITE lock on _actionRegistryLock
ActionState getState() const {
return _state;
}
/// @brief adjust state of object, assumes WRITE lock on _actionRegistryLock
void setState(ActionState state) {
_state = state;
}
/// @brief update incremental statistics
void startStats();
/// @brief update incremental statistics
void incStats();
/// @brief finalize statistics
void endStats();
/// @brief return progress statistic
uint64_t getProgress() const {return _progress.load();}
/// @brief Once PreAction completes, remove its pointer
void clearPreAction() {_preAction.reset();}
/// @brief Retrieve pointer to action that should run before this one
std::shared_ptr<Action> getPreAction();
/// @brief Initiate a pre action
void createPreAction(std::shared_ptr<ActionDescription> const& description);
/// @brief Initiate a post action
void createPostAction(std::shared_ptr<ActionDescription> const& description);
/// @brief Retrieve pointer to action that should run directly after this one
std::shared_ptr<Action> getPostAction();
/// @brief Save pointer to successor action
void setPostAction(std::shared_ptr<ActionDescription> post) {
_postAction=post;
}
/// @brief hash value of ActionDescription
/// @return uint64_t hash
std::string clientId() const { return _clientId; }
/// @brief hash value of ActionDescription
/// @return uint64_t hash
uint64_t hash() const {return _hash;}
/// @brief hash value of ActionDescription
/// @return uint64_t hash
uint64_t id() const {return _id;}
/// @brief add VPackObject to supplied builder with info about this action
virtual void toVelocyPack(VPackBuilder & builder) const;
/// @brief add VPackObject to supplied builder with info about this action
VPackBuilder toVelocyPack() const;
/// @brief Returns json array of object contents for status reports
/// Thread safety of this function is questionable for some member objects
// virtual Result toJson(/* builder */) {return Result;}
/// @brief Return Result object contain action specific status
Result result() const {return _result;}
/// @brief When object was constructed
std::chrono::system_clock::time_point getCreateTime() const
{return std::chrono::system_clock::time_point() + _actionCreated.load(); }
/// @brief When object was first started
std::chrono::system_clock::time_point getStartTime() const
{return std::chrono::system_clock::time_point() + _actionStarted.load(); }
/// @brief When object most recently iterated
std::chrono::system_clock::time_point getLastStatTime() const
{return std::chrono::system_clock::time_point() + _actionLastStat.load(); }
/// @brief When object finished executing
std::chrono::system_clock::time_point getDoneTime() const
{return std::chrono::system_clock::time_point() + _actionDone.load(); }
protected:
/// @brief common initialization for all constructors
void init();
arangodb::MaintenanceFeature& _feature;
ActionDescription _description;
ActionModel _model;
uint64_t _hash;
std::string _clientId;
uint64_t _id;
std::atomic<ActionState> _state;
// NOTE: preAction should only be set within first() or post(), not construction
std::shared_ptr<ActionDescription> _preAction;
std::shared_ptr<ActionDescription> _postAction;
// times for user reporting (and _actionDone used by done() to prevent
// race conditions of same task executing twice
std::atomic<std::chrono::system_clock::duration> _actionCreated;
std::atomic<std::chrono::system_clock::duration> _actionStarted;
std::atomic<std::chrono::system_clock::duration> _actionLastStat;
std::atomic<std::chrono::system_clock::duration> _actionDone;
std::atomic<uint64_t> _progress;
Result _result;
}; // class ActionBase
} // namespace maintenance
Result actionError(int errorCode, std::string const& errorMessage);
Result actionWarn(int errorCode, std::string const& errorMessage);
} // namespace arangodb
namespace std {
ostream& operator<< (
ostream& o, arangodb::maintenance::ActionBase const& d);
}
#endif

View File

@ -0,0 +1,147 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#include "ActionDescription.h"
#include <functional>
using namespace arangodb;
using namespace arangodb::maintenance;
/// @brief ctor
ActionDescription::ActionDescription(
std::map<std::string, std::string> const& d,
std::shared_ptr<VPackBuilder> const p) :
_description(d), _properties(p) {
TRI_ASSERT(d.find(NAME) != d.end());
TRI_ASSERT(p == nullptr || p->isEmpty() || p->slice().isObject());
}
/// @brief Default dtor
ActionDescription::~ActionDescription() {}
/// @brief Does this description have a "p" parameter?
bool ActionDescription::has(std::string const& p) const {
return _description.find(p) != _description.end();
}
/// @brief Does this description have a "p" parameter?
std::string ActionDescription::operator()(std::string const& p) const {
return _description.at(p);
}
/// @brief Does this description have a "p" parameter?
std::string ActionDescription::get(std::string const& p) const {
return _description.at(p);
}
/// @brief Get parameter
Result ActionDescription::get(std::string const& p, std::string& r) const {
Result result;
auto const& it = _description.find(p);
if (it == _description.end()) {
result.reset(TRI_ERROR_FAILED);
} else {
r = it->second;
}
return result;
}
/// @brief Hash function
std::size_t ActionDescription::hash() const {
std::string propstr;
for (auto const& i : _description) {
propstr += i.first + i.second;
}
return std::hash<std::string>{}(propstr);
}
std::size_t ActionDescription::hash(std::map<std::string, std::string> desc) {
std::string propstr;
for (auto const& i : desc) {
propstr += i.first + i.second;
}
return std::hash<std::string>{}(propstr);
}
/// @brief Equality operator
bool ActionDescription::operator==(
ActionDescription const& other) const {
return _description== other._description;
}
/// @brief Get action name. Cannot throw. See constructor
std::string const& ActionDescription::name() const {
static const std::string EMPTY_STRING;
auto const& it = _description.find(NAME);
return (it != _description.end()) ? it->second : EMPTY_STRING;
}
/// @brief summary to velocypack
VPackBuilder ActionDescription::toVelocyPack() const {
VPackBuilder b;
{ VPackObjectBuilder bb(&b);
toVelocyPack(b); }
return b;
}
/// @brief summary to velocypack
void ActionDescription::toVelocyPack(VPackBuilder& b) const {
TRI_ASSERT(b.isOpenObject());
for (auto const& i : _description) {
b.add(i.first, VPackValue(i.second));
}
if (_properties != nullptr && !_properties->isEmpty()) {
b.add("properties", _properties->slice());
}
}
/// @brief summary to JSON string
std::string ActionDescription::toJson() const {
return toVelocyPack().toJson();
}
/// @brief non discrimantory properties.
std::shared_ptr<VPackBuilder> const ActionDescription::properties() const {
return _properties;
}
/// @brief hash implementation for ActionRegistry
namespace std {
std::size_t hash<ActionDescription>::operator()(
ActionDescription const& a) const noexcept {
return a.hash();
}
ostream& operator<< (
ostream& out, arangodb::maintenance::ActionDescription const& d) {
out << d.toJson();
return out;
}
}

View File

@ -0,0 +1,205 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGODB_CLUSTER_MAINTENANCE_ACTION_DESCRIPTION_H
#define ARANGODB_CLUSTER_MAINTENANCE_ACTION_DESCRIPTION_H
#include "Basics/VelocyPackHelper.h"
#include <map>
#include <string>
namespace arangodb {
namespace maintenance {
enum Signal { GRACEFUL, IMMEDIATE };
enum ActionModel { BACKGROUND, FOREGROUND };
//
// state accessor and set functions
// (some require time checks and/or combination tests)
//
enum ActionState {
READY = 1, // waiting for a worker on the deque
EXECUTING = 2, // user or worker thread currently executing
WAITING = 3, // initiated a pre-task, waiting for its completion
WAITINGPRE = 4,// parent task created, about to execute on parent's thread
WAITINGPOST = 5,// parent task created, will execute after parent's success
PAUSED = 6, // (not implemented) user paused task
COMPLETE = 7, // task completed successfully
FAILED = 8, // task failed, no longer executing
};
static std::string const KEY("key");
static std::string const FIELDS("fields");
static std::string const TYPE("type");
static std::string const INDEXES("indexes");
static std::string const SHARDS("shards");
static std::string const DATABASE("database");
static std::string const EDGE("edge");
static std::string const COLLECTION("collection");
static std::string const SHARD("shard");
static std::string const NAME("name");
static std::string const ID("id");
static std::string const LEADER("theLeader");
static std::string const LOCAL_LEADER("localLeader");
static std::string const GLOB_UID("globallyUniqueId");
static std::string const OBJECT_ID("objectId");
static std::string const SERVER_ID("serverId");
/**
* @brief Action description for mainenance actions
*
* This structure holds once initialized constant parameters of a maintenance
* action. Members are declared const, thus thread safety guards are ommited.
*/
struct ActionDescription {
public:
/**
* @brief Construct with properties
* @param desc Descriminatory properties, which are considered for hash
* @param supp Non discriminatory properties
*/
ActionDescription(
std::map<std::string, std::string> const& desc,
std::shared_ptr<VPackBuilder> const suppl = std::make_shared<VPackBuilder>());
/**
* @brief Clean up
*/
virtual ~ActionDescription();
/**
* @brief Check equality (only _description considered)
* @param other Other descriptor
*/
bool operator== (ActionDescription const& other) const;
/**
* @brief Calculate hash of _description as concatenation
* @param other Other descriptor
*/
std::size_t hash() const;
static std::size_t hash(std::map<std::string, std::string> desc);
/// @brief Name of action
std::string const& name() const;
/**
* @brief Check if key exists in discrimantory container
* @param key Key to lookup
* @return true if key is found
*/
bool has(std::string const& keu) const;
/**
* @brief Get a string value from description
* @param key Key to get
* @exception std::out_of_range if the we do not have this key in discrimatory container
* @return Value to specified key
*/
std::string get(std::string const& key) const;
/**
* @brief Get a string value from description
* @param key Key to get
* @exception std::out_of_range if the we do not have this key in discrimatory container
* @return Value to specified key
*/
std::string operator()(std::string const& key) const;
/**
* @brief Get a string value from description
*
* @param key Key to get
* @param value If key is found the value is assigned to this variable
* @return Success (key found?)
*/
Result get(std::string const& key, std::string& value) const;
/**
* @brief Dump to JSON(vpack)
* @return JSON Velocypack of all paramters
*/
VPackBuilder toVelocyPack() const;
/**
* @brief Dump to JSON(vpack)
* @return JSON Velocypack of all paramters
*/
void toVelocyPack(VPackBuilder&) const;
/**
* @brief Dump to JSON(string)
* @return JSON string of all paramters
*/
std::string toJson() const;
/**
* @brief Dump to JSON(output stream)
* @param os Output stream reference
* @return Output stream reference
*/
std::ostream& print(std::ostream& os) const;
/**
* @brief Get non discrimantory properties
* Get non discrimantory properties.
* This function does not throw as builder is always when here.
* @return Non discriminatory properties
*/
std::shared_ptr<VPackBuilder> const properties() const;
private:
/// Note: members are const. No thread safety guards needed.
/** @brief discriminatory properties */
std::map<std::string, std::string> const _description;
/** @brief non-discriminatory properties */
std::shared_ptr<VPackBuilder> const _properties;
};
}}
namespace std {
ostream& operator<< (
ostream& o, arangodb::maintenance::ActionDescription const& d);
/// @brief Hash function used by std::unordered_map<ActionDescription,...>
template<> struct hash<arangodb::maintenance::ActionDescription> {
typedef arangodb::maintenance::ActionDescription argument_t;
typedef std::size_t result_t;
result_t operator()(argument_t const& a) const noexcept;
};
}
#endif

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
@ -36,6 +36,7 @@
#include "Logger/Logger.h"
using namespace arangodb;
using namespace arangodb::application_features;
AgencyCallback::AgencyCallback(AgencyComm& agency, std::string const& key,
std::function<bool(VPackSlice const&)> const& cb,

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -41,21 +41,20 @@
#include "SimpleHttpClient/ConnectionManager.h"
#include "StorageEngine/EngineSelectorFeature.h"
using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::basics;
using namespace arangodb::options;
namespace arangodb {
ClusterFeature::ClusterFeature(application_features::ApplicationServer& server)
: ApplicationFeature(server, "Cluster"),
_unregisterOnShutdown(false),
_enableCluster(false),
_requirePersistedId(false),
_heartbeatThread(nullptr),
_heartbeatInterval(0),
_agencyCallbackRegistry(nullptr),
_requestedRole(ServerState::RoleEnum::ROLE_UNDEFINED) {
: ApplicationFeature(server, "Cluster"),
_unregisterOnShutdown(false),
_enableCluster(false),
_requirePersistedId(false),
_heartbeatThread(nullptr),
_heartbeatInterval(0),
_agencyCallbackRegistry(nullptr),
_requestedRole(ServerState::RoleEnum::ROLE_UNDEFINED) {
setOptional(true);
startsAfter("DatabasePhase");
}
@ -110,7 +109,7 @@ void ClusterFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
new VectorParameter<StringParameter>(&_agencyEndpoints));
options->addHiddenOption("--cluster.agency-prefix", "agency prefix",
new StringParameter(&_agencyPrefix));
new StringParameter(&_agencyPrefix));
options->addObsoleteOption("--cluster.my-local-info", "this server's local info", false);
options->addObsoleteOption("--cluster.my-id", "this server's id", false);
@ -126,12 +125,12 @@ void ClusterFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
new UInt32Parameter(&_systemReplicationFactor));
options->addHiddenOption("--cluster.create-waits-for-sync-replication",
"active coordinator will wait for all replicas to create collection",
new BooleanParameter(&_createWaitsForSyncReplication));
"active coordinator will wait for all replicas to create collection",
new BooleanParameter(&_createWaitsForSyncReplication));
options->addHiddenOption("--cluster.index-create-timeout",
"amount of time (in seconds) the coordinator will wait for an index to be created before giving up",
new DoubleParameter(&_indexCreationTimeout));
"amount of time (in seconds) the coordinator will wait for an index to be created before giving up",
new DoubleParameter(&_indexCreationTimeout));
}
void ClusterFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
@ -156,7 +155,7 @@ void ClusterFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
// validate --cluster.agency-endpoint (currently a noop)
if (_agencyEndpoints.empty()) {
LOG_TOPIC(FATAL, Logger::CLUSTER)
<< "must at least specify one endpoint in --cluster.agency-endpoint";
<< "must at least specify one endpoint in --cluster.agency-endpoint";
FATAL_ERROR_EXIT();
}
@ -167,7 +166,7 @@ void ClusterFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
// validate --cluster.agency-prefix
size_t found = _agencyPrefix.find_first_not_of(
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/");
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/");
if (found != std::string::npos || _agencyPrefix.empty()) {
LOG_TOPIC(FATAL, arangodb::Logger::CLUSTER) << "invalid value specified for --cluster.agency-prefix";
@ -226,7 +225,7 @@ void ClusterFeature::prepare() {
// create callback registery
_agencyCallbackRegistry.reset(
new AgencyCallbackRegistry(agencyCallbacksPath()));
new AgencyCallbackRegistry(agencyCallbacksPath()));
// Initialize ClusterInfo library:
ClusterInfo::createInstance(_agencyCallbackRegistry.get());
@ -249,7 +248,7 @@ void ClusterFeature::prepare() {
// nullptr happens only during shutdown
if (af->isActive() && !af->hasUserdefinedJwt()) {
LOG_TOPIC(FATAL, arangodb::Logger::CLUSTER) << "Cluster authentication enabled but JWT not set via command line. Please"
<< " provide --server.jwt-secret which is used throughout the cluster.";
<< " provide --server.jwt-secret which is used throughout the cluster.";
FATAL_ERROR_EXIT();
}
}
@ -276,7 +275,7 @@ void ClusterFeature::prepare() {
if (unified.empty()) {
LOG_TOPIC(FATAL, arangodb::Logger::CLUSTER) << "invalid endpoint '" << _agencyEndpoints[i]
<< "' specified for --cluster.agency-endpoint";
<< "' specified for --cluster.agency-endpoint";
FATAL_ERROR_EXIT();
}
@ -293,7 +292,7 @@ void ClusterFeature::prepare() {
// perform an initial connect to the agency
if (!AgencyCommManager::MANAGER->start()) {
LOG_TOPIC(FATAL, arangodb::Logger::CLUSTER) << "Could not connect to any agency endpoints ("
<< AgencyCommManager::MANAGER->endpointsString() << ")";
<< AgencyCommManager::MANAGER->endpointsString() << ")";
FATAL_ERROR_EXIT();
}
@ -309,8 +308,8 @@ void ClusterFeature::prepare() {
if (role == ServerState::ROLE_UNDEFINED) {
// no role found
LOG_TOPIC(FATAL, arangodb::Logger::CLUSTER) << "unable to determine unambiguous role for server '"
<< ServerState::instance()->getId()
<< "'. No role configured in agency (" << endpoints << ")";
<< ServerState::instance()->getId()
<< "'. No role configured in agency (" << endpoints << ")";
FATAL_ERROR_EXIT();
}
@ -346,16 +345,16 @@ void ClusterFeature::prepare() {
if (_myAddress.empty()) {
LOG_TOPIC(FATAL, arangodb::Logger::CLUSTER) << "unable to determine internal address for server '"
<< ServerState::instance()->getId()
<< "'. Please specify --cluster.my-address or configure the "
"address for this server in the agency.";
<< ServerState::instance()->getId()
<< "'. Please specify --cluster.my-address or configure the "
"address for this server in the agency.";
FATAL_ERROR_EXIT();
}
// now we can validate --cluster.my-address
if (Endpoint::unifiedForm(_myAddress).empty()) {
LOG_TOPIC(FATAL, arangodb::Logger::CLUSTER) << "invalid endpoint '" << _myAddress
<< "' specified for --cluster.my-address";
<< "' specified for --cluster.my-address";
FATAL_ERROR_EXIT();
}
@ -384,22 +383,22 @@ void ClusterFeature::start() {
std::string myId = ServerState::instance()->getId();
LOG_TOPIC(INFO, arangodb::Logger::CLUSTER) << "Cluster feature is turned on. Agency version: " << version
<< ", Agency endpoints: " << endpoints << ", server id: '" << myId
<< "', internal address: " << _myAddress
<< ", role: " << role;
<< ", Agency endpoints: " << endpoints << ", server id: '" << myId
<< "', internal address: " << _myAddress
<< ", role: " << role;
AgencyCommResult result = comm.getValues("Sync/HeartbeatIntervalMs");
if (result.successful()) {
velocypack::Slice HeartbeatIntervalMs =
result.slice()[0].get(std::vector<std::string>(
{AgencyCommManager::path(), "Sync", "HeartbeatIntervalMs"}));
result.slice()[0].get(std::vector<std::string>(
{AgencyCommManager::path(), "Sync", "HeartbeatIntervalMs"}));
if (HeartbeatIntervalMs.isInteger()) {
try {
_heartbeatInterval = HeartbeatIntervalMs.getUInt();
LOG_TOPIC(INFO, arangodb::Logger::CLUSTER) << "using heartbeat interval value '" << _heartbeatInterval
<< " ms' from agency";
<< " ms' from agency";
} catch (...) {
// Ignore if it is not a small int or uint
}
@ -410,7 +409,7 @@ void ClusterFeature::start() {
if (_heartbeatInterval == 0) {
_heartbeatInterval = 5000; // 1/s
LOG_TOPIC(WARN, arangodb::Logger::CLUSTER) << "unable to read heartbeat interval from agency. Using "
<< "default value '" << _heartbeatInterval << " ms'";
<< "default value '" << _heartbeatInterval << " ms'";
}
startHeartbeatThread(_agencyCallbackRegistry.get(), _heartbeatInterval, 5, endpoints);
@ -440,6 +439,7 @@ void ClusterFeature::start() {
}
std::this_thread::sleep_for(std::chrono::seconds(1));
}
comm.increment("Current/Version");
@ -523,10 +523,10 @@ void ClusterFeature::unprepare() {
AgencySimpleOperationType::DELETE_OP));
// Unregister
unreg.operations.push_back(
AgencyOperation("Current/ServersRegistered/" + me,
AgencySimpleOperationType::DELETE_OP));
AgencyOperation("Current/ServersRegistered/" + me,
AgencySimpleOperationType::DELETE_OP));
unreg.operations.push_back(
AgencyOperation("Current/Version", AgencySimpleOperationType::INCREMENT_OP));
AgencyOperation("Current/Version", AgencySimpleOperationType::INCREMENT_OP));
comm.sendTransactionWithFailover(unreg, 120.0);
while (_heartbeatThread->isRunning()) {
@ -565,4 +565,10 @@ void ClusterFeature::startHeartbeatThread(AgencyCallbackRegistry* agencyCallback
}
}
} // arangodb
void ClusterFeature::syncDBServerStatusQuo() {
if (_heartbeatThread != nullptr) {
_heartbeatThread->syncDBServerStatusQuo(true);
}
}

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
@ -54,6 +54,8 @@ class ClusterFeature : public application_features::ApplicationFeature {
return _agencyPrefix;
}
void syncDBServerStatusQuo();
protected:
void startHeartbeatThread(AgencyCallbackRegistry* agencyCallbackRegistry,
uint64_t interval_ms,

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
@ -3612,3 +3612,26 @@ std::unordered_map<ServerID, std::string> ClusterInfo::getServerAliases() {
}
return ret;
}
arangodb::Result ClusterInfo::getShardServers(
ShardID const& shardId, std::vector<ServerID>& servers) {
READ_LOCKER(readLocker, _planProt.lock);
auto it = _shardServers.find(shardId);
if (it != _shardServers.end()) {
servers = (*it).second;
return arangodb::Result();
}
LOG_TOPIC(DEBUG, Logger::CLUSTER)
<< "Strange, did not find shard in _shardServers: " << shardId;
return arangodb::Result(TRI_ERROR_FAILED);
}
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
@ -605,6 +605,14 @@ class ClusterInfo {
return _currentVersion;
}
/**
* @brief Get sorted list of DB server, which serve a shard
*
* @param shardId The id of said shard
* @return List of DB servers serving the shard
*/
arangodb::Result getShardServers(ShardID const& shardId, std::vector<ServerID>&);
private:
void loadClusterId();

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -0,0 +1,204 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#include "CreateCollection.h"
#include "MaintenanceFeature.h"
#include "ApplicationFeatures/ApplicationServer.h"
#include "Basics/VelocyPackHelper.h"
#include "Cluster/ClusterFeature.h"
#include "Cluster/FollowerInfo.h"
#include "Utils/DatabaseGuard.h"
#include "VocBase/LogicalCollection.h"
#include "VocBase/Methods/Collections.h"
#include "VocBase/Methods/Databases.h"
#include <velocypack/Compare.h>
#include <velocypack/Iterator.h>
#include <velocypack/Slice.h>
#include <velocypack/velocypack-aliases.h>
using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::maintenance;
using namespace arangodb::methods;
constexpr auto WAIT_FOR_SYNC_REPL = "waitForSyncReplication";
constexpr auto ENF_REPL_FACT = "enforceReplicationFactor";
CreateCollection::CreateCollection(
MaintenanceFeature& feature, ActionDescription const& desc)
: ActionBase(feature, desc) {
std::stringstream error;
if (!desc.has(DATABASE)) {
error << "database must be specified. ";
}
TRI_ASSERT(desc.has(DATABASE));
if (!desc.has(COLLECTION)) {
error << "cluster-wide collection must be specified. ";
}
TRI_ASSERT(desc.has(COLLECTION));
if (!desc.has(SHARD)) {
error << "shard must be specified. ";
}
TRI_ASSERT(desc.has(SHARD));
if (!desc.has(LEADER)) {
error << "shard leader must be specified. ";
}
TRI_ASSERT(desc.has(LEADER));
if (!desc.has(SERVER_ID)) {
error << "own server id must be specified. ";
}
TRI_ASSERT(desc.has(SERVER_ID));
if (!properties().hasKey(TYPE) || !properties().get(TYPE).isNumber()) {
error << "properties slice must specify collection type. ";
}
TRI_ASSERT(properties().hasKey(TYPE) && properties().get(TYPE).isNumber());
uint32_t const type = properties().get(TYPE).getNumber<uint32_t>();
if (type != TRI_COL_TYPE_DOCUMENT && type != TRI_COL_TYPE_EDGE) {
error << "invalid collection type number. " << type;
}
TRI_ASSERT(type == TRI_COL_TYPE_DOCUMENT || type == TRI_COL_TYPE_EDGE);
if (!error.str().empty()) {
LOG_TOPIC(ERR, Logger::MAINTENANCE) << "CreateCollection: " << error.str();
_result.reset(TRI_ERROR_INTERNAL, error.str());
setState(FAILED);
}
}
CreateCollection::~CreateCollection() {};
bool CreateCollection::first() {
auto const& database = _description.get(DATABASE);
auto const& collection = _description.get(COLLECTION);
auto const& shard = _description.get(SHARD);
auto const& leader = _description.get(LEADER);
auto const& props = properties();
LOG_TOPIC(DEBUG, Logger::MAINTENANCE)
<< "CreateCollection: creating local shard '" << database << "/" << shard
<< "' for central '" << database << "/" << collection << "'";
try { // now try to guard the vocbase
DatabaseGuard guard(database);
auto vocbase = &guard.database();
auto cluster =
ApplicationServer::getFeature<ClusterFeature>("Cluster");
bool waitForRepl =
(props.hasKey(WAIT_FOR_SYNC_REPL) &&
props.get(WAIT_FOR_SYNC_REPL).isBool()) ?
props.get(WAIT_FOR_SYNC_REPL).getBool() :
cluster->createWaitsForSyncReplication();
bool enforceReplFact =
(props.hasKey(ENF_REPL_FACT) &&
props.get(ENF_REPL_FACT).isBool()) ?
props.get(ENF_REPL_FACT).getBool() : true;
TRI_col_type_e type = static_cast<TRI_col_type_e>(props.get(TYPE).getNumber<uint32_t>());
VPackBuilder docket;
{ VPackObjectBuilder d(&docket);
for (auto const& i : VPackObjectIterator(props)) {
auto const& key = i.key.copyString();
if (key == ID || key == NAME || key == GLOB_UID || key == OBJECT_ID) {
if (key == GLOB_UID || key == OBJECT_ID) {
LOG_TOPIC(WARN, Logger::MAINTENANCE)
<< "unexpected " << key << " in " << props.toJson();
}
continue;
}
docket.add(key, i.value);
}
docket.add("planId", VPackValue(collection));
}
_result = Collections::create(
vocbase, shard, type, docket.slice(), waitForRepl, enforceReplFact,
[=](LogicalCollection& col) {
LOG_TOPIC(DEBUG, Logger::MAINTENANCE) << "local collection " << database
<< "/" << shard << " successfully created";
col.followers()->setTheLeader(leader);
if (leader.empty()) {
col.followers()->clear();
}
});
if (_result.fail()) {
std::stringstream error;
error << "creating local shard '" << database << "/" << shard
<< "' for central '" << database << "/" << collection << "' failed: "
<< _result;
LOG_TOPIC(ERR, Logger::MAINTENANCE) << error.str();
// Error report for phaseTwo
VPackBuilder eb;
{ VPackObjectBuilder o(&eb);
eb.add("error", VPackValue(true));
eb.add("errorMessage", VPackValue(_result.errorMessage()));
eb.add("errorNum", VPackValue(_result.errorNumber()));
eb.add(VPackValue("indexes"));
{ VPackArrayBuilder a(&eb); } // []
eb.add(VPackValue("servers"));
{VPackArrayBuilder a(&eb); // [serverId]
eb.add(VPackValue(_description.get(SERVER_ID))); }}
// Steal buffer for maintenance feature
_feature.storeShardError(database, collection, shard, eb.steal());
_result.reset(TRI_ERROR_FAILED, error.str());
// FIXMEMAINTENANCE: notify here?
return false;
}
} catch (std::exception const& e) { // Guard failed?
std::stringstream error;
error << "action " << _description << " failed with exception " << e.what();
LOG_TOPIC(WARN, Logger::MAINTENANCE) << error.str();
_result.reset(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND, error.str());
// FIXMEMAINTENANCE: notify here?
return false;
}
notify();
return false;
}

View File

@ -0,0 +1,50 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGODB_MAINTENANCE_CREATE_COLLECTION_H
#define ARANGODB_MAINTENANCE_CREATE_COLLECTION_H
#include "ActionBase.h"
#include "ActionDescription.h"
#include <chrono>
namespace arangodb {
namespace maintenance {
class CreateCollection : public ActionBase {
public:
CreateCollection(MaintenanceFeature&, ActionDescription const& d);
virtual ~CreateCollection();
virtual bool first() override final;
};
}}
#endif

View File

@ -0,0 +1,106 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#include "ActionBase.h"
#include "CreateDatabase.h"
#include "MaintenanceFeature.h"
#include "ApplicationFeatures/ApplicationServer.h"
#include "Basics/VelocyPackHelper.h"
#include "RestServer/DatabaseFeature.h"
#include "Utils/DatabaseGuard.h"
#include "VocBase/Methods/Databases.h"
using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::maintenance;
using namespace arangodb::methods;
CreateDatabase::CreateDatabase(
MaintenanceFeature& feature, ActionDescription const& desc)
: ActionBase(feature, desc) {
std::stringstream error;
if (!desc.has(DATABASE)) {
error << "database must be specified";
}
TRI_ASSERT(desc.has(DATABASE));
if (!error.str().empty()) {
LOG_TOPIC(ERR, Logger::MAINTENANCE) << "CreateDatabase: " << error.str();
_result.reset(TRI_ERROR_INTERNAL, error.str());
setState(FAILED);
}
}
CreateDatabase::~CreateDatabase() {};
bool CreateDatabase::first() {
VPackSlice users;
auto database = _description.get(DATABASE);
LOG_TOPIC(INFO, Logger::MAINTENANCE)
<< "CreateDatabase: creating database " << database;
try {
DatabaseGuard guard("_system");
// Assertion in constructor makes sure that we have DATABASE.
_result = Databases::create(_description.get(DATABASE), users, properties());
if (!_result.ok()) {
LOG_TOPIC(ERR, Logger::MAINTENANCE)
<< "CreateDatabase: failed to create database " << database << ": " << _result;
VPackBuilder eb;
{ VPackObjectBuilder b(&eb);
eb.add(NAME, VPackValue(database));
eb.add("error", VPackValue(true));
eb.add("errorNum", VPackValue(_result.errorNumber()));
eb.add("errorMessage", VPackValue(_result.errorMessage())); }
_feature.storeDBError(database, eb.steal());
// FIXMEMAINTENANCE: notify here?
return false;
}
LOG_TOPIC(INFO, Logger::MAINTENANCE)
<< "CreateDatabase: database " << database << " created";
} catch (std::exception const& e) {
std::stringstream error;
error << "action " << _description << " failed with exception " << e.what();
LOG_TOPIC(ERR, Logger::MAINTENANCE) << "CreateDatabase: " << error.str();
_result.reset(TRI_ERROR_INTERNAL, error.str());
// FIXMEMAINTENANCE: notify here?
return false;
}
notify();
return false;
}

View File

@ -0,0 +1,49 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGODB_MAINTENANCE_CREATE_DATABASE_H
#define ARANGODB_MAINTENANCE_CREATE_DATABASE_H
#include "ActionBase.h"
namespace arangodb {
namespace maintenance {
class CreateDatabase : public ActionBase {
public:
CreateDatabase(MaintenanceFeature& feature,
ActionDescription const& description);
virtual ~CreateDatabase();
virtual bool first() override;
};
}}
#endif

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
@ -24,8 +24,13 @@
#include "DBServerAgencySync.h"
#include "Basics/MutexLocker.h"
#include "Cluster/ClusterFeature.h"
#include "Cluster/ClusterInfo.h"
#include "Cluster/FollowerInfo.h"
#include "Cluster/HeartbeatThread.h"
#include "Cluster/Maintenance.h"
#include "Cluster/MaintenanceFeature.h"
#include "Cluster/ServerState.h"
#include "Logger/Logger.h"
#include "RestServer/DatabaseFeature.h"
#include "Utils/DatabaseGuard.h"
@ -35,9 +40,12 @@
#include "V8Server/V8Context.h"
#include "V8Server/V8DealerFeature.h"
#include "VocBase/vocbase.h"
#include "VocBase/LogicalCollection.h"
#include "VocBase/Methods/Databases.h"
using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::methods;
using namespace arangodb::rest;
DBServerAgencySync::DBServerAgencySync(HeartbeatThread* heartbeat)
@ -52,125 +60,188 @@ void DBServerAgencySync::work() {
_heartbeat->dispatchedJobResult(result);
}
Result getLocalCollections(VPackBuilder& collections) {
using namespace arangodb::basics;
Result result;
DatabaseFeature* dbfeature = nullptr;
try {
dbfeature = ApplicationServer::getFeature<DatabaseFeature>("Database");
} catch (...) {}
if (dbfeature == nullptr) {
LOG_TOPIC(ERR, Logger::HEARTBEAT) << "Failed to get feature database";
return Result(TRI_ERROR_INTERNAL, "Failed to get feature database");
}
collections.clear();
VPackObjectBuilder c(&collections);
for (auto const& database : Databases::list()) {
try {
DatabaseGuard guard(database);
auto vocbase = &guard.database();
collections.add(VPackValue(database));
VPackObjectBuilder db(&collections);
auto cols = vocbase->collections(false);
for (auto const& collection : cols) {
collections.add(VPackValue(collection->name()));
VPackObjectBuilder col(&collections);
collection->toVelocyPack(collections,true,false);
collections.add(
"theLeader", VPackValue(collection->followers()->getLeader()));
}
} catch (std::exception const& e) {
return Result(
TRI_ERROR_INTERNAL,
std::string("Failed to guard database ") + database + ": " + e.what());
}
}
return Result();
}
DBServerAgencySyncResult DBServerAgencySync::execute() {
// default to system database
LOG_TOPIC(DEBUG, Logger::HEARTBEAT) << "DBServerAgencySync::execute starting";
DatabaseFeature* database =
TRI_ASSERT(AgencyCommManager::isEnabled());
AgencyComm comm;
using namespace std::chrono;
using clock = std::chrono::steady_clock;
LOG_TOPIC(DEBUG, Logger::MAINTENANCE) << "DBServerAgencySync::execute starting";
DatabaseFeature* dbfeature =
ApplicationServer::getFeature<DatabaseFeature>("Database");
TRI_vocbase_t* const vocbase = database->systemDatabase();
MaintenanceFeature* mfeature =
ApplicationServer::getFeature<MaintenanceFeature>("Maintenance");
TRI_vocbase_t* const vocbase = dbfeature->systemDatabase();
DBServerAgencySyncResult result;
if (vocbase == nullptr) {
LOG_TOPIC(DEBUG, Logger::HEARTBEAT)
LOG_TOPIC(DEBUG, Logger::MAINTENANCE)
<< "DBServerAgencySync::execute no vocbase";
return result;
}
Result tmp;
VPackBuilder rb;
auto clusterInfo = ClusterInfo::instance();
auto plan = clusterInfo->getPlan();
auto current = clusterInfo->getCurrent();
DatabaseGuard guard(*vocbase);
double startTime = TRI_microtime();
V8Context* context = V8DealerFeature::DEALER->enterContext(vocbase, true, V8DealerFeature::ANY_CONTEXT_OR_PRIORITY);
auto serverId = arangodb::ServerState::instance()->getId();
if (context == nullptr) {
LOG_TOPIC(WARN, arangodb::Logger::HEARTBEAT) << "DBServerAgencySync::execute: no V8 context";
VPackBuilder local;
Result glc = getLocalCollections(local);
if (!glc.ok()) {
// FIXMEMAINTENANCE: if this fails here, then result is empty, is this
// intended? I also notice that there is another Result object "tmp"
// that is going to eat bad results in few lines later. Again, is
// that the correct action? If so, how about supporting comments in
// the code for both.
return result;
}
TRI_DEFER(V8DealerFeature::DEALER->exitContext(context));
auto start = clock::now();
try {
// in previous life handlePlanChange
VPackObjectBuilder o(&rb);
double now = TRI_microtime();
LOG_TOPIC(DEBUG, Logger::MAINTENANCE) << "DBServerAgencySync::phaseOne";
tmp = arangodb::maintenance::phaseOne(
plan->slice(), local.slice(), serverId, *mfeature, rb);
LOG_TOPIC(DEBUG, Logger::MAINTENANCE) << "DBServerAgencySync::phaseOne done";
if (now - startTime > 5.0) {
LOG_TOPIC(WARN, arangodb::Logger::HEARTBEAT) << "DBServerAgencySync::execute took " << Logger::FIXED(now - startTime) << " to get free V8 context, starting handlePlanChange now";
LOG_TOPIC(DEBUG, Logger::MAINTENANCE) << "DBServerAgencySync::phaseTwo";
glc = getLocalCollections(local);
// We intentionally refetch local collections here, such that phase 2
// can already see potential changes introduced by phase 1. The two
// phases are sufficiently independent that this is OK.
LOG_TOPIC(TRACE, Logger::MAINTENANCE) << "DBServerAgencySync::phaseTwo - local state: " << local.toJson();
if (!glc.ok()) {
return result;
}
auto current = clusterInfo->getCurrent();
LOG_TOPIC(TRACE, Logger::MAINTENANCE) << "DBServerAgencySync::phaseTwo - current state: " << current->toJson();
tmp = arangodb::maintenance::phaseTwo(
plan->slice(), current->slice(), local.slice(), serverId, *mfeature, rb);
LOG_TOPIC(DEBUG, Logger::MAINTENANCE) << "DBServerAgencySync::phaseTwo done";
} catch (std::exception const& e) {
LOG_TOPIC(ERR, Logger::MAINTENANCE)
<< "Failed to handle plan change: " << e.what();
}
auto isolate = context->_isolate;
if (rb.isClosed()) {
// FIXMEMAINTENANCE: when would rb not be closed? and if "catch"
// just happened, would you want to be doing this anyway?
try {
v8::HandleScope scope(isolate);
auto report = rb.slice();
if (report.isObject()) {
// execute script inside the context
auto file = TRI_V8_ASCII_STRING(isolate, "handlePlanChange");
auto content =
TRI_V8_ASCII_STRING(isolate, "require('@arangodb/cluster').handlePlanChange");
v8::TryCatch tryCatch;
v8::Handle<v8::Value> handlePlanChange = TRI_ExecuteJavaScriptString(
isolate, isolate->GetCurrentContext(), content, file, false);
if (tryCatch.HasCaught()) {
TRI_LogV8Exception(isolate, &tryCatch);
return result;
}
if (!handlePlanChange->IsFunction()) {
LOG_TOPIC(ERR, Logger::HEARTBEAT) << "handlePlanChange is not a function";
return result;
}
v8::Handle<v8::Function> func =
v8::Handle<v8::Function>::Cast(handlePlanChange);
v8::Handle<v8::Value> args[2];
// Keep the shared_ptr to the builder while we run TRI_VPackToV8 on the
// slice(), just to be on the safe side:
auto builder = clusterInfo->getPlan();
args[0] = TRI_VPackToV8(isolate, builder->slice());
builder = clusterInfo->getCurrent();
args[1] = TRI_VPackToV8(isolate, builder->slice());
v8::Handle<v8::Value> res =
func->Call(isolate->GetCurrentContext()->Global(), 2, args);
if (tryCatch.HasCaught()) {
TRI_LogV8Exception(isolate, &tryCatch);
return result;
}
result.success = true; // unless overwritten by actual result
if (res->IsObject()) {
v8::Handle<v8::Object> o = res->ToObject();
v8::Handle<v8::Array> names = o->GetOwnPropertyNames();
uint32_t const n = names->Length();
std::vector<std::string> agency = {"phaseTwo", "agency"};
if (report.hasKey(agency) && report.get(agency).isObject()) {
for (uint32_t i = 0; i < n; ++i) {
v8::Handle<v8::Value> key = names->Get(i);
v8::String::Utf8Value str(key);
v8::Handle<v8::Value> value = o->Get(key);
auto phaseTwo = report.get(agency);
LOG_TOPIC(DEBUG, Logger::MAINTENANCE)
<< "DBServerAgencySync reporting to Current: " << phaseTwo.toJson();
// Report to current
if (!phaseTwo.isEmptyObject()) {
if (value->IsNumber()) {
if (strcmp(*str, "plan") == 0) {
result.planVersion =
static_cast<uint64_t>(value->ToInteger()->Value());
} else if (strcmp(*str, "current") == 0) {
result.currentVersion =
static_cast<uint64_t>(value->ToInteger()->Value());
std::vector<AgencyOperation> operations;
for (auto const& ao : VPackObjectIterator(phaseTwo)) {
auto const key = ao.key.copyString();
auto const op = ao.value.get("op").copyString();
if (op == "set") {
auto const value = ao.value.get("payload");
operations.push_back(
AgencyOperation(key, AgencyValueOperationType::SET, value));
} else if (op == "delete") {
operations.push_back(
AgencyOperation(key, AgencySimpleOperationType::DELETE_OP));
}
}
operations.push_back(
AgencyOperation(
"Current/Version", AgencySimpleOperationType::INCREMENT_OP));
AgencyWriteTransaction currentTransaction(operations);
AgencyCommResult r = comm.sendTransactionWithFailover(currentTransaction);
if (!r.successful()) {
LOG_TOPIC(ERR, Logger::MAINTENANCE) << "Error reporting to agency";
} else {
LOG_TOPIC(DEBUG, Logger::MAINTENANCE) << "Invalidating current in ClusterInfo";
clusterInfo->invalidateCurrent();
}
} else if (value->IsBoolean() && strcmp(*str, "success")) {
result.success = TRI_ObjectToBoolean(value);
}
}
} else {
LOG_TOPIC(ERR, Logger::HEARTBEAT)
<< "handlePlanChange returned a non-object";
return result;
// FIXMEMAINTENANCE: If comm.sendTransactionWithFailover()
// fails, the result is ok() based upon phaseTwo()'s execution?
result = DBServerAgencySyncResult(
tmp.ok(),
report.hasKey("Plan") ?
report.get("Plan").get("Version").getNumber<uint64_t>() : 0,
report.hasKey("Current") ?
report.get("Current").get("Version").getNumber<uint64_t>() : 0);
}
LOG_TOPIC(DEBUG, Logger::HEARTBEAT)
<< "DBServerAgencySync::execute back from JS";
// invalidate our local cache, even if an error occurred
clusterInfo->flush();
} catch (...) {
}
auto took = duration<double>(clock::now()-start).count();
if (took > 30.0) {
LOG_TOPIC(WARN, Logger::MAINTENANCE) << "DBServerAgencySync::execute "
"took " << took << " s to execute handlePlanChange";
}
now = TRI_microtime();
if (now - startTime > 30.0) {
LOG_TOPIC(WARN, Logger::HEARTBEAT) << "DBServerAgencySync::execute "
"took " << Logger::FIXED(now - startTime) << " s to execute handlePlanChange";
}
return result;
}

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
@ -37,6 +37,9 @@ struct DBServerAgencySyncResult {
DBServerAgencySyncResult()
: success(false), planVersion(0), currentVersion(0) {}
DBServerAgencySyncResult(bool s, uint64_t p, uint64_t c)
: success(s), planVersion(p), currentVersion(c) {}
DBServerAgencySyncResult(const DBServerAgencySyncResult& other)
: success(other.success),
planVersion(other.planVersion),

View File

@ -0,0 +1,104 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#include "DropCollection.h"
#include "ApplicationFeatures/ApplicationServer.h"
#include "Basics/VelocyPackHelper.h"
#include "Cluster/ClusterFeature.h"
#include "Utils/DatabaseGuard.h"
#include "VocBase/Methods/Collections.h"
#include "VocBase/Methods/Databases.h"
using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::maintenance;
using namespace arangodb::methods;
DropCollection::DropCollection(
MaintenanceFeature& feature, ActionDescription const& d) :
ActionBase(feature, d) {
std::stringstream error;
if (!d.has(COLLECTION)) {
error << "collection must be specified. ";
}
TRI_ASSERT(d.has(COLLECTION));
if (!d.has(DATABASE)) {
error << "database must be specified. ";
}
TRI_ASSERT(d.has(DATABASE));
if (!error.str().empty()) {
LOG_TOPIC(ERR, Logger::MAINTENANCE) << "DropCollectio: " << error.str();
_result.reset(TRI_ERROR_INTERNAL, error.str());
setState(FAILED);
}
}
DropCollection::~DropCollection() {};
bool DropCollection::first() {
auto const& database = _description.get(DATABASE);
auto const& collection = _description.get(COLLECTION);
LOG_TOPIC(DEBUG, Logger::MAINTENANCE)
<< "DropCollection: dropping local shard '" << database << "/" << collection;
try {
DatabaseGuard guard(database);
auto vocbase = &guard.database();
Result found = methods::Collections::lookup(
vocbase, collection, [&](LogicalCollection& coll) {
LOG_TOPIC(DEBUG, Logger::MAINTENANCE)
<< "Dropping local collection " + collection;
_result = Collections::drop(vocbase, &coll, false, 120);
});
if (found.fail()) {
std::stringstream error;
error << "failed to lookup local collection " << database << "/" << collection;
LOG_TOPIC(ERR, Logger::MAINTENANCE) << "DropCollection: " << error.str();
_result.reset(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND, error.str());
return false;
}
} catch (std::exception const& e) {
std::stringstream error;
error << " action " << _description << " failed with exception " << e.what();
LOG_TOPIC(ERR, Logger::MAINTENANCE) << error.str();
_result.reset(TRI_ERROR_INTERNAL, error.str());
return false;
}
notify();
return false;
}

View File

@ -0,0 +1,50 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGODB_MAINTENANCE_DROP_COLLECTION_H
#define ARANGODB_MAINTENANCE_DROP_COLLECTION_H
#include "ActionBase.h"
#include "ActionDescription.h"
#include <chrono>
namespace arangodb {
namespace maintenance {
class DropCollection : public ActionBase {
public:
DropCollection(MaintenanceFeature&, ActionDescription const&);
virtual ~DropCollection();
virtual bool first() override final;
};
}}
#endif

View File

@ -0,0 +1,85 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#include "DropDatabase.h"
#include "ApplicationFeatures/ApplicationServer.h"
#include "Basics/VelocyPackHelper.h"
#include "RestServer/DatabaseFeature.h"
#include "Utils/DatabaseGuard.h"
#include "VocBase/Methods/Databases.h"
using namespace arangodb::application_features;
using namespace arangodb::methods;
using namespace arangodb::maintenance;
using namespace arangodb;
DropDatabase::DropDatabase(
MaintenanceFeature& feature, ActionDescription const& desc)
: ActionBase(feature, desc) {
std::stringstream error;
if (!desc.has(DATABASE)) {
error << "database must be specified";
}
TRI_ASSERT(desc.has(DATABASE));
if (!error.str().empty()) {
LOG_TOPIC(ERR, Logger::MAINTENANCE) << "DropDatabase: " << error.str();
_result.reset(TRI_ERROR_INTERNAL, error.str());
setState(FAILED);
}
}
DropDatabase::~DropDatabase() {};
bool DropDatabase::first() {
std::string const database = _description.get(DATABASE);
LOG_TOPIC(DEBUG, Logger::MAINTENANCE) << "DropDatabase: dropping " << database;
try {
DatabaseGuard guard("_system");
auto vocbase = &guard.database();
_result = Databases::drop(vocbase, database);
if (!_result.ok()) {
LOG_TOPIC(ERR, Logger::AGENCY)
<< "DropDatabase: dropping database " << database << " failed: "
<< _result.errorMessage();
return false;
}
} catch (std::exception const& e) {
std::stringstream error;
error << "action " << _description << " failed with exception " << e.what();
_result.reset(TRI_ERROR_INTERNAL, error.str());
return false;
}
notify();
return false;
}

View File

@ -0,0 +1,51 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGODB_MAINTENANCE_DROP_DATABASE_H
#define ARANGODB_MAINTENANCE_DROP_DATABASE_H
#include "ActionBase.h"
#include "ActionDescription.h"
#include <chrono>
namespace arangodb {
namespace maintenance {
class DropDatabase : public ActionBase {
public:
DropDatabase(MaintenanceFeature&, ActionDescription const&);
virtual ~DropDatabase();
virtual bool first() override final;
};
}}
#endif

View File

@ -0,0 +1,123 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#include "DropIndex.h"
#include "ApplicationFeatures/ApplicationServer.h"
#include "Basics/VelocyPackHelper.h"
#include "Cluster/ClusterFeature.h"
#include "Utils/DatabaseGuard.h"
#include "VocBase/Methods/Collections.h"
#include "VocBase/Methods/Indexes.h"
#include "VocBase/Methods/Databases.h"
using namespace arangodb::application_features;
using namespace arangodb::maintenance;
using namespace arangodb::methods;
using namespace arangodb;
DropIndex::DropIndex(
MaintenanceFeature& feature, ActionDescription const& d) :
ActionBase(feature, d) {
std::stringstream error;
if (!d.has(COLLECTION)) {
error << "collection must be specified. ";
}
TRI_ASSERT(d.has(COLLECTION));
if (!d.has(DATABASE)) {
error << "database must be specified. ";
}
TRI_ASSERT(d.has(DATABASE));
if (!d.has(INDEX)) {
error << "index id must be stecified. ";
}
TRI_ASSERT(d.has(INDEX));
if (!error.str().empty()) {
LOG_TOPIC(ERR, Logger::MAINTENANCE) << "DropIndex: " << error.str();
_result.reset(TRI_ERROR_INTERNAL, error.str());
setState(FAILED);
}
}
DropIndex::~DropIndex() {};
bool DropIndex::first() {
auto const& database = _description.get(DATABASE);
auto const& collection = _description.get(COLLECTION);
auto const& id = _description.get(INDEX);
VPackBuilder index;
index.add(VPackValue(_description.get(INDEX)));
try {
DatabaseGuard guard(database);
auto vocbase = &guard.database();
auto col = vocbase->lookupCollection(collection);
if (col == nullptr) {
std::stringstream error;
error << "failed to lookup local collection " << collection
<< " in database " << database;
LOG_TOPIC(ERR, Logger::MAINTENANCE) << "DropIndex: " << error.str();
_result.reset(TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND, error.str());
return false;
}
// FIXMEMAINTENANCE: Why doing the actual work in a callback?
Result found = methods::Collections::lookup(
vocbase, collection, [&](LogicalCollection& coll) {
LOG_TOPIC(DEBUG, Logger::MAINTENANCE)
<< "Dropping local index " + collection + "/" + id;
_result = Indexes::drop(&coll, index.slice());
});
if (found.fail()) {
std::stringstream error;
error << "failed to lookup local collection " << collection
<< "in database " + database;
LOG_TOPIC(ERR, Logger::MAINTENANCE) << "DropIndex: " << error.str();
_result.reset(TRI_ERROR_ARANGO_INDEX_NOT_FOUND, error.str());
return false;
}
} catch (std::exception const& e) {
std::stringstream error;
error << "action " << _description << " failed with exception " << e.what();
LOG_TOPIC(ERR, Logger::MAINTENANCE) << "DropIndex " << error.str();
_result.reset(TRI_ERROR_INTERNAL, error.str());
return false;
}
notify();
return false;
}

View File

@ -0,0 +1,50 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGODB_MAINTENANCE_DROP_INDEX_H
#define ARANGODB_MAINTENANCE_DROP_INDEX_H
#include "ActionBase.h"
#include "ActionDescription.h"
#include <chrono>
namespace arangodb {
namespace maintenance {
class DropIndex : public ActionBase {
public:
DropIndex(MaintenanceFeature&, ActionDescription const&);
virtual ~DropIndex();
virtual bool first() override final;
};
}}
#endif

View File

@ -0,0 +1,169 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#include <velocypack/Iterator.h>
#include "EnsureIndex.h"
#include "ApplicationFeatures/ApplicationServer.h"
#include "Basics/VelocyPackHelper.h"
#include "Cluster/ClusterFeature.h"
#include "Cluster/MaintenanceFeature.h"
#include "Utils/DatabaseGuard.h"
#include "VocBase/Methods/Collections.h"
#include "VocBase/Methods/Databases.h"
#include "VocBase/Methods/Indexes.h"
using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::maintenance;
using namespace arangodb::methods;
EnsureIndex::EnsureIndex(
MaintenanceFeature& feature, ActionDescription const& desc) :
ActionBase(feature, desc) {
std::stringstream error;
if (!desc.has(DATABASE)) {
error << "database must be specified. ";
}
TRI_ASSERT(desc.has(DATABASE));
if (!desc.has(COLLECTION)) {
error << "cluster-wide collection must be specified. ";
}
TRI_ASSERT(desc.has(COLLECTION));
if (!desc.has(SHARD)) {
error << "shard must be specified. ";
}
TRI_ASSERT(desc.has(SHARD));
if (!properties().hasKey(ID)) {
error << "index properties must include id. ";
}
TRI_ASSERT(properties().hasKey(ID));
if (!desc.has(TYPE)) {
error << "index type must be specified - discriminatory. ";
}
TRI_ASSERT(desc.has(TYPE));
if (!desc.has(FIELDS)) {
error << "index fields must be specified - discriminatory. ";
}
TRI_ASSERT(desc.has(FIELDS));
if (!error.str().empty()) {
LOG_TOPIC(ERR, Logger::MAINTENANCE) << "EnsureIndex: " << error.str();
_result.reset(TRI_ERROR_INTERNAL, error.str());
setState(FAILED);
}
}
EnsureIndex::~EnsureIndex() {};
bool EnsureIndex::first() {
arangodb::Result res;
auto const& database = _description.get(DATABASE);
auto const& collection = _description.get(COLLECTION);
auto const& shard = _description.get(SHARD);
auto const& id = properties().get(ID).copyString();
VPackBuilder body;
try { // now try to guard the database
DatabaseGuard guard(database);
auto vocbase = &guard.database();
auto col = vocbase->lookupCollection(shard);
if (col == nullptr) {
std::stringstream error;
error << "failed to lookup local collection " << shard
<< " in database " + database;
LOG_TOPIC(ERR, Logger::MAINTENANCE) << "EnsureIndex: " << error.str();
_result.reset(TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND, error.str());
return false;
}
auto const props = properties();
{ VPackObjectBuilder b(&body);
body.add(COLLECTION, VPackValue(shard));
for (auto const& i : VPackObjectIterator(props)) {
body.add(i.key.copyString(), i.value);
}}
VPackBuilder index;
_result = methods::Indexes::ensureIndex(col.get(), body.slice(), true, index);
if (_result.ok()) {
VPackSlice created = index.slice().get("isNewlyCreated");
std::string log = std::string("Index ") + id;
log += (created.isBool() && created.getBool() ? std::string(" created")
: std::string(" updated"));
LOG_TOPIC(DEBUG, Logger::MAINTENANCE) << log;
} else {
std::stringstream error;
error << "failed to ensure index " << body.slice().toJson() << " "
<< _result.errorMessage();
LOG_TOPIC(ERR, Logger::MAINTENANCE) << "EnsureIndex: " << error.str();
VPackBuilder eb;
{ VPackObjectBuilder o(&eb);
eb.add("error", VPackValue(true));
eb.add("errorMessage", VPackValue(_result.errorMessage()));
eb.add("errorNum", VPackValue(_result.errorNumber()));
eb.add(ID, VPackValue(id)); }
LOG_TOPIC(DEBUG, Logger::MAINTENANCE)
<< "Reporting error " << eb.toJson();
// FIXMEMAINTENANCE: If this action is refused due to missing
// components in description, no IndexError gets produced. But
// then, if you are missing components, such as database name, will
// you be able to produce an IndexError?
_feature.storeIndexError(database, collection, shard, id, eb.steal());
_result.reset(TRI_ERROR_INTERNAL, error.str());
notify();
return false;
}
} catch (std::exception const& e) { // Guard failed?
std::stringstream error;
error << "action " << _description << " failed with exception " << e.what();
LOG_TOPIC(WARN, Logger::MAINTENANCE) << "EnsureIndex: " << error.str();
_result.reset(TRI_ERROR_INTERNAL, error.str());
return false;
}
notify();
return false;
}

View File

@ -0,0 +1,50 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGODB_MAINTENANCE_ENSURE_INDEX_H
#define ARANGODB_MAINTENANCE_ENSURE_INDEX_H
#include "ActionBase.h"
#include "ActionDescription.h"
#include <chrono>
namespace arangodb {
namespace maintenance {
class EnsureIndex : public ActionBase {
public:
EnsureIndex(MaintenanceFeature&, ActionDescription const& d);
virtual ~EnsureIndex();
virtual bool first() override final;
};
}}
#endif

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
@ -190,6 +190,10 @@ bool FollowerInfo::remove(ServerID const& sid) {
// such an important decision like dropping a follower.
return false;
}
LOG_TOPIC(DEBUG, Logger::CLUSTER)
<< "Removing follower " << sid << " from " << _docColl->name();
MUTEX_LOCKER(locker, _mutex);
// First check if there is anything to do:
@ -280,6 +284,10 @@ bool FollowerInfo::remove(ServerID const& sid) {
LOG_TOPIC(ERR, Logger::CLUSTER)
<< "FollowerInfo::remove, timeout in agency operation for key " << path;
}
LOG_TOPIC(DEBUG, Logger::CLUSTER)
<< "Removing follower " << sid << " from " << _docColl->name() << "succeeded: " << success;
return success;
}

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -265,7 +265,7 @@ void HeartbeatThread::runDBServer() {
if (version > _desiredVersions->plan) {
_desiredVersions->plan = version;
LOG_TOPIC(DEBUG, Logger::HEARTBEAT)
<< "Desired Current Version is now " << _desiredVersions->plan;
<< "Desired Plan Version is now " << _desiredVersions->plan;
doSync = true;
}
}
@ -291,6 +291,49 @@ void HeartbeatThread::runDBServer() {
}
}
std::function<bool(VPackSlice const& result)> updateCurrent =
[=](VPackSlice const& result) {
if (!result.isNumber()) {
LOG_TOPIC(ERR, Logger::HEARTBEAT)
<< "Plan Version is not a number! " << result.toJson();
return false;
}
uint64_t version = result.getNumber<uint64_t>();
bool doSync = false;
{
MUTEX_LOCKER(mutexLocker, *_statusLock);
if (version > _desiredVersions->current) {
_desiredVersions->current = version;
LOG_TOPIC(DEBUG, Logger::HEARTBEAT)
<< "Desired Current Version is now " << _desiredVersions->plan;
doSync = true;
}
}
if (doSync) {
syncDBServerStatusQuo(true);
}
return true;
};
auto currentAgencyCallback = std::make_shared<AgencyCallback>(
_agency, "Current/Version", updateCurrent, true);
registered = false;
while (!registered) {
registered =
_agencyCallbackRegistry->registerCallback(currentAgencyCallback);
if (!registered) {
LOG_TOPIC(ERR, Logger::HEARTBEAT)
<< "Couldn't register current change in agency!";
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
// we check Current/Version every few heartbeats:
int const currentCountStart = 1; // set to 1 by Max to speed up discovery
int currentCount = currentCountStart;
@ -414,8 +457,9 @@ void HeartbeatThread::runDBServer() {
}
if (!wasNotified) {
LOG_TOPIC(DEBUG, Logger::HEARTBEAT) << "Lock reached timeout";
LOG_TOPIC(DEBUG, Logger::HEARTBEAT) << "Heart beating...";
planAgencyCallback->refetchAndUpdate(true, false);
currentAgencyCallback->refetchAndUpdate(true, false);
} else {
// mop: a plan change returned successfully...
// recheck and redispatch in case our desired versions increased
@ -434,6 +478,7 @@ void HeartbeatThread::runDBServer() {
}
}
_agencyCallbackRegistry->unregisterCallback(currentAgencyCallback);
_agencyCallbackRegistry->unregisterCallback(planAgencyCallback);
}
@ -991,29 +1036,15 @@ void HeartbeatThread::beginShutdown() {
void HeartbeatThread::dispatchedJobResult(DBServerAgencySyncResult result) {
LOG_TOPIC(DEBUG, Logger::HEARTBEAT) << "Dispatched job returned!";
bool doSleep = false;
{
MUTEX_LOCKER(mutexLocker, *_statusLock);
if (result.success) {
LOG_TOPIC(DEBUG, Logger::HEARTBEAT)
<< "Sync request successful. Now have Plan " << result.planVersion
<< ", Current " << result.currentVersion;
_currentVersions = AgencyVersions(result);
} else {
LOG_TOPIC(DEBUG, Logger::HEARTBEAT) << "Sync request failed!";
// mop: we will retry immediately so wait at least a LITTLE bit
doSleep = true;
}
MUTEX_LOCKER(mutexLocker, *_statusLock);
if (result.success) {
LOG_TOPIC(DEBUG, Logger::HEARTBEAT)
<< "Sync request successful. Now have Plan " << result.planVersion
<< ", Current " << result.currentVersion;
_currentVersions = AgencyVersions(result);
} else {
LOG_TOPIC(ERR, Logger::HEARTBEAT) << "Sync request failed!";
}
if (doSleep) {
// Sleep a little longer, since this might be due to some synchronization
// of shards going on in the background
std::this_thread::sleep_for(std::chrono::microseconds(500000));
std::this_thread::sleep_for(std::chrono::microseconds(500000));
}
CONDITION_LOCKER(guard, _condition);
_wasNotified = true;
_condition.signal();
}
////////////////////////////////////////////////////////////////////////////////
@ -1134,34 +1165,34 @@ bool HeartbeatThread::handlePlanChangeCoordinator(uint64_t currentPlanVersion) {
////////////////////////////////////////////////////////////////////////////////
void HeartbeatThread::syncDBServerStatusQuo(bool asyncPush) {
bool shouldUpdate = false;
MUTEX_LOCKER(mutexLocker, *_statusLock);
bool shouldUpdate = false;
if (_desiredVersions->plan > _currentVersions.plan) {
LOG_TOPIC(DEBUG, Logger::HEARTBEAT)
<< "Plan version " << _currentVersions.plan
<< " is lower than desired version " << _desiredVersions->plan;
<< "Plan version " << _currentVersions.plan
<< " is lower than desired version " << _desiredVersions->plan;
shouldUpdate = true;
}
if (_desiredVersions->current > _currentVersions.current) {
LOG_TOPIC(DEBUG, Logger::HEARTBEAT)
<< "Current version " << _currentVersions.current
<< " is lower than desired version " << _desiredVersions->current;
<< "Current version " << _currentVersions.current
<< " is lower than desired version " << _desiredVersions->current;
shouldUpdate = true;
}
// 7.4 seconds is just less than half the 15 seconds agency uses to declare dead server,
// perform a safety execution of job in case other plan changes somehow incomplete or undetected
double now = TRI_microtime();
if (now > _lastSyncTime + 7.4 || asyncPush) {
shouldUpdate = true;
}
if (!shouldUpdate) {
return;
}
// First invalidate the caches in ClusterInfo:
auto ci = ClusterInfo::instance();
if (_desiredVersions->plan > ci->getPlanVersion()) {
@ -1170,21 +1201,22 @@ void HeartbeatThread::syncDBServerStatusQuo(bool asyncPush) {
if (_desiredVersions->current > ci->getCurrentVersion()) {
ci->invalidateCurrent();
}
if (_backgroundJobScheduledOrRunning) {
_launchAnotherBackgroundJob = true;
return;
}
// schedule a job for the change:
uint64_t jobNr = ++_backgroundJobsPosted;
LOG_TOPIC(DEBUG, Logger::HEARTBEAT) << "dispatching sync " << jobNr;
_backgroundJobScheduledOrRunning = true;
// the JobGuard is in the operator() of HeartbeatBackgroundJob
_lastSyncTime = TRI_microtime();
SchedulerFeature::SCHEDULER->post(
HeartbeatBackgroundJob(shared_from_this(), _lastSyncTime), false);
HeartbeatBackgroundJob(shared_from_this(), _lastSyncTime), false);
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -162,12 +162,14 @@ class HeartbeatThread : public CriticalThread,
/// @brief bring the db server in sync with the desired state
//////////////////////////////////////////////////////////////////////////////
public:
void syncDBServerStatusQuo(bool asyncPush = false);
//////////////////////////////////////////////////////////////////////////////
/// @brief update the local agent pool from the slice
//////////////////////////////////////////////////////////////////////////////
private:
void updateAgentPool(arangodb::velocypack::Slice const& agentPool);
//////////////////////////////////////////////////////////////////////////////
@ -176,7 +178,6 @@ class HeartbeatThread : public CriticalThread,
void updateServerMode(arangodb::velocypack::Slice const& readOnlySlice);
private:
//////////////////////////////////////////////////////////////////////////////
/// @brief AgencyCallbackRegistry
//////////////////////////////////////////////////////////////////////////////

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,161 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGODB_MAINTENANCE_MAINTENANCE_H
#define ARANGODB_MAINTENANCE_MAINTENANCE_H
#include "Basics/Result.h"
#include "Basics/VelocyPackHelper.h"
#include "Agency/Node.h"
#include "Cluster/MaintenanceFeature.h"
namespace arangodb {
class LogicalCollection;
namespace maintenance {
using Transactions = std::vector<std::pair<VPackBuilder,VPackBuilder>>;
arangodb::Result diffPlanLocalForDatabases(
VPackSlice const&, std::vector<std::string> const&,
std::vector<std::string>&, std::vector<std::string>&);
/**
* @brief Difference Plan and local for phase 1 of Maintenance run
*
* @param plan Snapshot of agency's planned state
* @param local Snapshot of local state
* @param serverId This server's UUID
* @param errors Copy of last maintenance feature errors
* @param actions Resulting actions from difference are packed in here
*
* @return Result
*/
arangodb::Result diffPlanLocal(
VPackSlice const& plan, VPackSlice const& local, std::string const& serverId,
MaintenanceFeature::errors_t& errors, std::vector<ActionDescription>& actions);
/**
* @brief Difference Plan and local for phase 1 of Maintenance run
*
* @param plan Snapshot of agency's planned state
* @param current Snapshot of agency's current state
* @param local Snapshot of local state
* @param serverId This server's UUID
* @param feature Maintenance feature
* @param report Report
*
* @return Result
*/
arangodb::Result executePlan (
VPackSlice const& plan, VPackSlice const& local, std::string const& serverId,
arangodb::MaintenanceFeature& feature, VPackBuilder& report);
/**
* @brief Difference local and current states for phase 2 of Maintenance
*
* @param local Snapshot of local state
* @param current Snapshot of agency's current state
* @param serverId This server's UUID
* @param report Resulting agency transaction, which is to be sent
*
* @return Result
*/
arangodb::Result diffLocalCurrent (
VPackSlice const& local, VPackSlice const& current,
std::string const& serverId, Transactions& report);
/**
* @brief Phase one: Execute plan, shard replication startups
*
* @param plan Snapshot of agency's planned state
* @param current Snapshot of agency's current state
* @param local Snapshot of local state
* @param serverId This server's UUID
* @param feature Maintenance feature
* @param report Resulting agency transaction, which is to be sent
*
* @return Result
*/
arangodb::Result phaseOne (
VPackSlice const& plan, VPackSlice const& local, std::string const& serverId,
MaintenanceFeature& feature, VPackBuilder& report);
/**
* @brief Phase two: Report in agency
*
* @param plan Snapshot of agency's planned state
* @param current Snapshot of agency's current state
* @param local Snapshot of local state
* @param serverId This server's UUID
* @param feature Maintenance feature
* @param report Report on what we did
*
* @return Result
*/
arangodb::Result phaseTwo (
VPackSlice const& plan, VPackSlice const& cur, VPackSlice const& local,
std::string const& serverId, MaintenanceFeature& feature, VPackBuilder& report);
/**
* @brief Report local changes to current
*
* @param plan Snapshot of agency's planned state
* @param current Snapshot of agency's current state
* @param local Snapshot of local state
* @param serverId This server's UUID
* @param report Report on what we did
*
* @return Result
*/
arangodb::Result reportInCurrent(
VPackSlice const& plan, VPackSlice const& cur, VPackSlice const& local,
MaintenanceFeature::errors_t const& allErrors,
std::string const& serverId, VPackBuilder& report);
/**
* @brief Schedule synchroneous replications
*
* @param plan Plan's snapshot
* @param current Current's scnapshot
* @param local Local snapshot
* @param serverId My server's uuid
* @param actions Resulting actions
* @param rescheduleForSync Report to DBServerAgencySync, that we need to rerun
*
* @return Success story
*/
arangodb::Result syncReplicatedShardsWithLeaders(
VPackSlice const& plan, VPackSlice const& current, VPackSlice const& local,
std::string const& serverId, std::vector<ActionDescription>& actions);
}}
#endif

View File

@ -0,0 +1,681 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#include "MaintenanceFeature.h"
#include "ApplicationFeatures/ApplicationServer.h"
#include "Basics/ConditionLocker.h"
#include "Basics/ReadLocker.h"
#include "Basics/WriteLocker.h"
#include "Basics/MutexLocker.h"
#include "Cluster/ActionDescription.h"
#include "Cluster/CreateDatabase.h"
#include "Cluster/Action.h"
#include "Cluster/MaintenanceWorker.h"
using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::options;
using namespace arangodb::maintenance;
MaintenanceFeature::MaintenanceFeature(application_features::ApplicationServer& server)
: ApplicationFeature(server, "Maintenance") {
// startsAfter("EngineSelector"); // ??? what should this be
// startsBefore("StorageEngine");
init();
} // MaintenanceFeature::MaintenanceFeature
void MaintenanceFeature::init() {
_isShuttingDown=false;
_nextActionId=1;
setOptional(true);
requiresElevatedPrivileges(false); // ??? this mean admin priv?
// these parameters might be updated by config and/or command line options
_maintenanceThreadsMax = static_cast<int32_t>(TRI_numberProcessors()/4 +1);
_secondsActionsBlock = 2;
_secondsActionsLinger = 3600;
return;
} // MaintenanceFeature::init
void MaintenanceFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
options->addSection("server", "Server features");
options->addHiddenOption(
"--server.maintenance-threads",
"maximum number of threads available for maintenance actions",
new Int32Parameter(&_maintenanceThreadsMax));
options->addHiddenOption(
"--server.maintenance-actions-block",
"minimum number of seconds finished Actions block duplicates",
new Int32Parameter(&_secondsActionsBlock));
options->addHiddenOption(
"--server.maintenance-actions-linger",
"minimum number of seconds finished Actions remain in deque",
new Int32Parameter(&_secondsActionsLinger));
} // MaintenanceFeature::collectOptions
/// do not start threads in prepare
void MaintenanceFeature::prepare() {
} // MaintenanceFeature::prepare
void MaintenanceFeature::start() {
int loop;
bool flag;
// start threads
for (loop=0; loop<_maintenanceThreadsMax; ++loop) {
maintenance::MaintenanceWorker * newWorker = new maintenance::MaintenanceWorker(*this);
_activeWorkers.push_back(newWorker);
flag = newWorker->start(&_workerCompletion);
if (!flag) {
LOG_TOPIC(ERR, Logger::MAINTENANCE)
<< "MaintenanceFeature::start: newWorker start failed";
} // if
} // for
} // MaintenanceFeature::start
void MaintenanceFeature::beginShutdown() {
_isShuttingDown=true;
CONDITION_LOCKER(cLock, _actionRegistryCond);
_actionRegistryCond.broadcast();
return;
} // MaintenanceFeature
void MaintenanceFeature::stop() {
for (auto itWorker : _activeWorkers ) {
CONDITION_LOCKER(cLock, _workerCompletion);
// loop on each worker, retesting at 10ms just in case
if (itWorker->isRunning()) {
_workerCompletion.wait(10000);
} // if
} // for
return;
} // MaintenanceFeature::stop
/// @brief Move an incomplete action to failed state
Result MaintenanceFeature::deleteAction(uint64_t action_id) {
Result result;
// pointer to action, or nullptr
auto action = findActionId(action_id);
if (action) {
if (maintenance::COMPLETE != action->getState()) {
action->setState(maintenance::FAILED);
} else {
result.reset(TRI_ERROR_BAD_PARAMETER,"deleteAction called after action complete.");
} // else
} else {
result.reset(TRI_ERROR_BAD_PARAMETER,"deleteAction could not find action to delete.");
} // else
return result;
} // MaintenanceFeature::deleteAction
// FIXMEMAINTENANCE: None of the addAction() and createAction() routines
// explicitly check to see if construction of action set FAILED.
// Therefore it is possible for an "executeNow" action to start running
// with known invalid parameters.
/// @brief This is the API for creating an Action and executing it.
/// Execution can be immediate by calling thread, or asynchronous via thread pool.
/// not yet: ActionDescription parameter will be MOVED to new object.
Result MaintenanceFeature::addAction(
std::shared_ptr<maintenance::Action> newAction, bool executeNow) {
Result result;
// the underlying routines are believed to be safe and throw free,
// but just in case
try {
size_t action_hash = newAction->hash();
WRITE_LOCKER(wLock, _actionRegistryLock);
std::shared_ptr<Action> curAction = findActionHashNoLock(action_hash);
// similar action not in the queue (or at least no longer viable)
if (curAction == nullptr || curAction->done()) {
createAction(newAction, executeNow);
if (!newAction || !newAction->ok()) {
/// something failed in action creation ... go check logs
result.reset(TRI_ERROR_BAD_PARAMETER, "createAction rejected parameters.");
} // if
} else {
// action already exist, need write lock to prevent race
result.reset(TRI_ERROR_BAD_PARAMETER, "addAction called while similar action already processing.");
} //else
// executeNow process on this thread, right now!
if (result.ok() && executeNow) {
maintenance::MaintenanceWorker worker(*this, newAction);
worker.run();
result = worker.result();
} // if
} catch (...) {
result.reset(TRI_ERROR_INTERNAL, "addAction experience an unexpected throw.");
} // catch
return result;
} // MaintenanceFeature::addAction
/// @brief This is the API for creating an Action and executing it.
/// Execution can be immediate by calling thread, or asynchronous via thread pool.
/// not yet: ActionDescription parameter will be MOVED to new object.
Result MaintenanceFeature::addAction(
std::shared_ptr<maintenance::ActionDescription> const & description,
bool executeNow) {
Result result;
// the underlying routines are believed to be safe and throw free,
// but just in case
try {
std::shared_ptr<Action> newAction;
// is there a known name field
auto find_it = description->get("name");
size_t action_hash = description->hash();
WRITE_LOCKER(wLock, _actionRegistryLock);
std::shared_ptr<Action> curAction = findActionHashNoLock(action_hash);
// similar action not in the queue (or at least no longer viable)
if (!curAction || curAction->done()) {
newAction = createAction(description, executeNow);
if (!newAction || !newAction->ok()) {
/// something failed in action creation ... go check logs
result.reset(TRI_ERROR_BAD_PARAMETER, "createAction rejected parameters.");
} // if
} else {
// action already exist, need write lock to prevent race
result.reset(TRI_ERROR_BAD_PARAMETER, "addAction called while similar action already processing.");
} //else
// executeNow process on this thread, right now!
if (result.ok() && executeNow) {
maintenance::MaintenanceWorker worker(*this, newAction);
worker.run();
result = worker.result();
} // if
} catch (...) {
result.reset(TRI_ERROR_INTERNAL, "addAction experience an unexpected throw.");
} // catch
return result;
} // MaintenanceFeature::addAction
std::shared_ptr<Action> MaintenanceFeature::preAction(
std::shared_ptr<ActionDescription> const & description) {
return createAction(description, true);
} // MaintenanceFeature::preAction
std::shared_ptr<Action> MaintenanceFeature::postAction(
std::shared_ptr<ActionDescription> const & description) {
return createAction(description, false);
} // MaintenanceFeature::postAction
void MaintenanceFeature::createAction(
std::shared_ptr<Action> action, bool executeNow) {
// mark as executing so no other workers accidentally grab it
if (executeNow) {
action->setState(maintenance::EXECUTING);
} // if
// WARNING: holding write lock to _actionRegistry and about to
// lock condition variable
{
_actionRegistry.push_back(action);
if (!executeNow) {
CONDITION_LOCKER(cLock, _actionRegistryCond);
_actionRegistryCond.signal();
} // if
} // lock
}
std::shared_ptr<Action> MaintenanceFeature::createAction(
std::shared_ptr<ActionDescription> const & description,
bool executeNow) {
// write lock via _actionRegistryLock is assumed held
std::shared_ptr<Action> newAction;
// name should already be verified as existing ... but trust no one
std::string name = description->get(NAME);
// call factory
newAction = std::make_shared<Action>(*this, *description);
// if a new action constructed successfully
if (newAction->ok()) {
createAction(newAction, executeNow);
} else {
LOG_TOPIC(ERR, Logger::MAINTENANCE)
<< "createAction: unknown action name given, \"" << name.c_str() << "\", or other construction failure.";
} // else
return newAction;
} // if
std::shared_ptr<Action> MaintenanceFeature::findAction(
std::shared_ptr<ActionDescription> const description) {
return findActionHash(description->hash());
}
std::shared_ptr<Action> MaintenanceFeature::findActionHash(size_t hash) {
READ_LOCKER(rLock, _actionRegistryLock);
return(findActionHashNoLock(hash));
} // MaintenanceFeature::findActionHash
std::shared_ptr<Action> MaintenanceFeature::findActionHashNoLock(size_t hash) {
// assert to test lock held?
std::shared_ptr<Action> ret_ptr;
for (auto action_it=_actionRegistry.begin();
_actionRegistry.end() != action_it && !ret_ptr; ++action_it) {
if ((*action_it)->hash() == hash) {
ret_ptr=*action_it;
} // if
} // for
return ret_ptr;
} // MaintenanceFeature::findActionHashNoLock
std::shared_ptr<Action> MaintenanceFeature::findActionId(uint64_t id) {
READ_LOCKER(rLock, _actionRegistryLock);
return(findActionIdNoLock(id));
} // MaintenanceFeature::findActionId
std::shared_ptr<Action> MaintenanceFeature::findActionIdNoLock(uint64_t id) {
// assert to test lock held?
std::shared_ptr<Action> ret_ptr;
for (auto action_it=_actionRegistry.begin();
_actionRegistry.end() != action_it && !ret_ptr; ++action_it) {
if ((*action_it)->id() == id) {
ret_ptr=*action_it;
} // if
} // for
return ret_ptr;
} // MaintenanceFeature::findActionIdNoLock
std::shared_ptr<Action> MaintenanceFeature::findReadyAction() {
std::shared_ptr<Action> ret_ptr;
while(!_isShuttingDown && !ret_ptr) {
// scan for ready action (and purge any that are done waiting)
{
WRITE_LOCKER(wLock, _actionRegistryLock);
for (auto loop=_actionRegistry.begin(); _actionRegistry.end()!=loop && !ret_ptr; ) {
auto state = (*loop)->getState();
if (state == maintenance::READY) {
ret_ptr=*loop;
ret_ptr->setState(maintenance::EXECUTING);
} else if ((*loop)->done()) {
loop = _actionRegistry.erase(loop);
} else {
++loop;
} // else
} // for
} // WRITE
// no pointer ... wait 5 second
if (!_isShuttingDown && !ret_ptr) {
CONDITION_LOCKER(cLock, _actionRegistryCond);
_actionRegistryCond.wait(100000);
} // if
} // while
return ret_ptr;
} // MaintenanceFeature::findReadyAction
VPackBuilder MaintenanceFeature::toVelocyPack() const {
VPackBuilder vb;
READ_LOCKER(rLock, _actionRegistryLock);
{ VPackArrayBuilder ab(&vb);
for (auto const& action : _actionRegistry ) {
action->toVelocyPack(vb);
} // for
}
return vb;
} // MaintenanceFeature::toVelocyPack
#if 0
std::string MaintenanceFeature::toJson(VPackBuilder & builder) {
} // MaintenanceFeature::toJson
#endif
std::string const SLASH("/");
arangodb::Result MaintenanceFeature::storeDBError (
std::string const& database, std::shared_ptr<VPackBuffer<uint8_t>> error) {
MUTEX_LOCKER(guard, _dbeLock);
auto const it = _dbErrors.find(database);
if (it != _dbErrors.end()) {
std::stringstream error;
error << "database " << database << " already has pending error";
LOG_TOPIC(DEBUG, Logger::MAINTENANCE) << error.str();
return Result(TRI_ERROR_FAILED, error.str());
}
try {
_dbErrors.emplace(database,error);
} catch (std::exception const& e) {
return Result(TRI_ERROR_FAILED, e.what());
}
return Result();
}
arangodb::Result MaintenanceFeature::dbError (
std::string const& database, std::shared_ptr<VPackBuffer<uint8_t>>& error) const {
MUTEX_LOCKER(guard, _dbeLock);
auto const it = _dbErrors.find(database);
error = (it != _dbErrors.end()) ? it->second : nullptr;
return Result();
}
arangodb::Result MaintenanceFeature::removeDBError (
std::string const& database) {
try {
MUTEX_LOCKER(guard, _seLock);
_shardErrors.erase(database);
} catch (std::exception const& e) {
std::stringstream error;
error << "erasing dataabse error for " << database << " failed";
LOG_TOPIC(DEBUG, Logger::MAINTENANCE) << error.str();
return Result(TRI_ERROR_FAILED, error.str());
}
return Result();
}
arangodb::Result MaintenanceFeature::storeShardError (
std::string const& database, std::string const& collection,
std::string const& shard, std::shared_ptr<VPackBuffer<uint8_t>> error) {
std::string key = database + SLASH + collection + SLASH + shard;
MUTEX_LOCKER(guard, _seLock);
auto const it = _shardErrors.find(key);
if (it != _shardErrors.end()) {
std::stringstream error;
error << "shard " << key << " already has pending error";
LOG_TOPIC(DEBUG, Logger::MAINTENANCE) << error.str();
return Result(TRI_ERROR_FAILED, error.str());
}
try {
_shardErrors.emplace(key,error);
} catch (std::exception const& e) {
return Result(TRI_ERROR_FAILED, e.what());
}
return Result();
}
arangodb::Result MaintenanceFeature::shardError (
std::string const& database, std::string const& collection,
std::string const& shard, std::shared_ptr<VPackBuffer<uint8_t>>& error) const {
std::string key = database + SLASH + collection + SLASH + shard;
MUTEX_LOCKER(guard, _seLock);
auto const it = _shardErrors.find(key);
error = (it != _shardErrors.end()) ? it->second : nullptr;
return Result();
}
arangodb::Result MaintenanceFeature::removeShardError (std::string const& key) {
try {
MUTEX_LOCKER(guard, _seLock);
_shardErrors.erase(key);
} catch (std::exception const& e) {
std::stringstream error;
error << "erasing shard error for " << key << " failed";
LOG_TOPIC(DEBUG, Logger::MAINTENANCE) << error.str();
return Result(TRI_ERROR_FAILED, error.str());
}
return Result();
}
arangodb::Result MaintenanceFeature::removeShardError (
std::string const& database, std::string const& collection,
std::string const& shard) {
return removeShardError(database + SLASH + collection + SLASH + shard);
}
arangodb::Result MaintenanceFeature::storeIndexError (
std::string const& database, std::string const& collection,
std::string const& shard, std::string const& indexId,
std::shared_ptr<VPackBuffer<uint8_t>> error) {
using buffer_t = std::shared_ptr<VPackBuffer<uint8_t>>;
std::string key = database + SLASH + collection + SLASH + shard;
MUTEX_LOCKER(guard, _ieLock);
auto errorsIt = _indexErrors.find(key);
if (errorsIt == _indexErrors.end()) {
try {
_indexErrors.emplace(key,std::map<std::string,buffer_t>());
} catch (std::exception const& e) {
return Result(TRI_ERROR_FAILED, e.what());
}
}
auto& errors = _indexErrors.find(key)->second;
auto const it = errors.find(indexId);
if (it != errors.end()) {
std::stringstream error;
error << "index " << indexId << " for shard "
<< key << " already has pending error";
LOG_TOPIC(DEBUG, Logger::MAINTENANCE) << error.str();
return Result(TRI_ERROR_FAILED, error.str());
}
try {
errors.emplace(indexId,error);
} catch (std::exception const& e) {
return Result(TRI_ERROR_FAILED, e.what());
}
return Result();
}
arangodb::Result MaintenanceFeature::indexErrors (
std::string const& database, std::string const& collection,
std::string const& shard,
std::map<std::string,std::shared_ptr<VPackBuffer<uint8_t>>>& error) const {
std::string key = database + SLASH + collection + SLASH + shard;
MUTEX_LOCKER(guard, _ieLock);
auto const& it = _indexErrors.find(key);
if (it != _indexErrors.end()) {
error = it->second;
}
return Result();
}
template<typename T>
std::ostream& operator<<(std::ostream& os, std::set<T>const& st) {
size_t j = 0;
os << "[";
for (auto const& i : st) {
os << i;
if (++j < st.size()) {
os << ", ";
}
}
os << "]";
return os;
}
arangodb::Result MaintenanceFeature::removeIndexErrors (
std::string const& key, std::unordered_set<std::string> indexIds) {
MUTEX_LOCKER(guard, _ieLock);
// If no entry for this shard exists bail out
auto kit = _indexErrors.find(key);
if (kit == _indexErrors.end()) {
std::stringstream error;
error << "erasing index " << indexIds << " error for shard " << key
<< " failed as no such key is found in index error bucket";
LOG_TOPIC(DEBUG, Logger::MAINTENANCE) << error.str();
return Result(TRI_ERROR_FAILED, error.str());
}
auto& errors = kit->second;
try {
for (auto const& indexId : indexIds) {
errors.erase(indexId);
}
} catch (std::exception const& e) {
std::stringstream error;
error << "erasing index errors " << indexIds << " for " << key << " failed";
LOG_TOPIC(DEBUG, Logger::MAINTENANCE) << error.str();
return Result(TRI_ERROR_FAILED, error.str());
}
return Result();
}
arangodb::Result MaintenanceFeature::removeIndexErrors (
std::string const& database, std::string const& collection,
std::string const& shard, std::unordered_set<std::string> indexIds) {
return removeIndexErrors(
database + SLASH + collection + SLASH + shard, indexIds);
}
arangodb::Result MaintenanceFeature::copyAllErrors(errors_t& errors) const {
{
MUTEX_LOCKER(guard, _seLock);
errors.shards = _shardErrors;
}
{
MUTEX_LOCKER(guard, _ieLock);
errors.indexes = _indexErrors;
}
{
MUTEX_LOCKER(guard, _dbeLock);
errors.databases = _dbErrors;
}
return Result();
}

View File

@ -0,0 +1,369 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2017 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGOD_CLUSTER_MAINTENANCE_FEATURE
#define ARANGOD_CLUSTER_MAINTENANCE_FEATURE 1
#include "ApplicationFeatures/ApplicationFeature.h"
#include "Basics/Common.h"
#include "Basics/ReadWriteLock.h"
#include "Basics/Result.h"
#include "Cluster/Action.h"
#include "Cluster/MaintenanceWorker.h"
#include "ProgramOptions/ProgramOptions.h"
namespace arangodb {
class MaintenanceFeature : public application_features::ApplicationFeature {
public:
explicit MaintenanceFeature(application_features::ApplicationServer&);
MaintenanceFeature();
virtual ~MaintenanceFeature() {};
struct errors_t {
std::map<std::string,
std::map<std::string,
std::shared_ptr<VPackBuffer<uint8_t>>>> indexes;
// dbname/collection/shardid -> error
std::unordered_map<std::string,
std::shared_ptr<VPackBuffer<uint8_t>>> shards;
// dbname -> error
std::unordered_map<std::string,
std::shared_ptr<VPackBuffer<uint8_t>>> databases;
};
public:
void collectOptions(std::shared_ptr<options::ProgramOptions>) override;
// preparation phase for feature in the preparation phase, the features must
// not start any threads. furthermore, they must not write any files under
// elevated privileges if they want other features to access them, or if they
// want to access these files with dropped privileges
virtual void prepare() override;
// start the feature
virtual void start() override;
// notify the feature about a shutdown request
virtual void beginShutdown() override;
// stop the feature
virtual void stop() override;
// shut down the feature
virtual void unprepare() override {};
//
// api features
//
/// @brief This is the API for creating an Action and executing it.
/// Execution can be immediate by calling thread, or asynchronous via thread pool.
/// not yet: ActionDescription parameter will be MOVED to new object.
virtual Result addAction(
std::shared_ptr<maintenance::ActionDescription> const & description,
bool executeNow=false);
/// @brief This is the API for creating an Action and executing it.
/// Execution can be immediate by calling thread, or asynchronous via thread pool.
/// not yet: ActionDescription parameter will be MOVED to new object.
virtual Result addAction(
std::shared_ptr<maintenance::Action> action, bool executeNow=false);
/// @brief Internal API that allows existing actions to create pre actions
/// FIXDOC: Please explain how this works in a lot more detail, for example,
/// say if this can be called in the code of an Action and if the already
/// running action is postponed in this case. Explain semantics such that
/// somebody not knowing the code can use it.
std::shared_ptr<maintenance::Action> preAction(
std::shared_ptr<maintenance::ActionDescription> const & description);
/// @brief Internal API that allows existing actions to create post actions
/// FIXDOC: Please explain how this works in a lot more detail, such that
/// somebody not knowing the code can use it.
std::shared_ptr<maintenance::Action> postAction(
std::shared_ptr<maintenance::ActionDescription> const & description);
protected:
std::shared_ptr<maintenance::Action> createAction(
std::shared_ptr<maintenance::ActionDescription> const & description,
bool executeNow);
void createAction(
std::shared_ptr<maintenance::Action> action, bool executeNow);
public:
/// @brief This API will attempt to fail an existing Action that is waiting
/// or executing. Will not fail Actions that have already succeeded or failed.
Result deleteAction(uint64_t id);
/// @brief Create a VPackBuilder object with snapshot of current action registry
VPackBuilder toVelocyPack() const;
/// @brief Returns json array of all MaintenanceActions within the deque
Result toJson(VPackBuilder & builder);
/// @brief Return pointer to next ready action, or nullptr
std::shared_ptr<maintenance::Action> findReadyAction();
/// @brief Process specific ID for a new action
/// @returns uint64_t
uint64_t nextActionId() {return _nextActionId++;};
bool isShuttingDown() const {return(_isShuttingDown);};
/// @brief Return number of seconds to say "not done" to block retries too soon
uint32_t getSecondsActionsBlock() const {return _secondsActionsBlock;};
/**
* @brief Find and return found action or nullptr
* @param desc Description of sought action
*/
std::shared_ptr<maintenance::Action> findAction(
std::shared_ptr<maintenance::ActionDescription> const desc);
/**
* @brief add index error to bucket
* Errors are added by EnsureIndex
*
* @param database database
* @param collection collection
* @param shard shard
* @param indexId index' id
*
* @return success
*/
arangodb::Result storeIndexError (
std::string const& database, std::string const& collection,
std::string const& shard, std::string const& indexId,
std::shared_ptr<VPackBuffer<uint8_t>> error);
/**
* @brief get all pending index errors for a specific shard
*
* @param database database
* @param collection collection
* @param shard shard
* @param errors errrors map returned to caller
*
* @return success
*/
arangodb::Result indexErrors(
std::string const& database, std::string const& collection,
std::string const& shard,
std::map<std::string, std::shared_ptr<VPackBuffer<uint8_t>>>& errors) const ;
/**
* @brief remove 1+ errors from index error bucket
* Errors are removed by phaseOne, as soon as indexes no longer in plan
*
* @param database database
* @param collection collection
* @param shard shard
* @param indexId index' id
*
* @return success
*/
arangodb::Result removeIndexErrors (
std::string const& database, std::string const& collection,
std::string const& shard, std::unordered_set<std::string> indexIds);
arangodb::Result removeIndexErrors (
std::string const& path, std::unordered_set<std::string> indexIds);
/**
* @brief add shard error to bucket
* Errors are added by CreateCollection, UpdateCollection
*
* @param database database
* @param collection collection
* @param shard shard
*
* @return success
*/
arangodb::Result storeShardError (
std::string const& database, std::string const& collection,
std::string const& shard, std::shared_ptr<VPackBuffer<uint8_t>> error);
/**
* @brief get all pending shard errors
*
* @param database database
* @param collection collection
* @param shard shard
*
* @return success
*/
arangodb::Result shardError(
std::string const& database, std::string const& collection,
std::string const& shard, std::shared_ptr<VPackBuffer<uint8_t>>& error) const;
/**
* @brief remove error from shard bucket
* Errors are removed by phaseOne, as soon as indexes no longer in plan
*
* @param database database
* @param collection collection
* @param shard shard
*
* @return success
*/
arangodb::Result removeShardError (
std::string const& database, std::string const& collection,
std::string const& shard);
arangodb::Result removeShardError (std::string const& key);
/**
* @brief add shard error to bucket
* Errors are added by CreateCollection, UpdateCollection
*
* @param database database
*
* @return success
*/
arangodb::Result storeDBError (
std::string const& database, std::shared_ptr<VPackBuffer<uint8_t>> error);
/**
* @brief get all pending shard errors
*
* @param database database
*
* @return success
*/
arangodb::Result dbError(
std::string const& database, std::shared_ptr<VPackBuffer<uint8_t>>& error) const;
/**
* @brief remove an error from db error bucket
* Errors are removed by phaseOne, as soon as indexes no longer in plan
*
* @param database database
*
* @return success
*/
arangodb::Result removeDBError (std::string const& database);
/**
* @brief copy all error maps (shards, indexes and databases) for Maintenance
*
* @param errors errors struct into which all maintenace feature error are copied
* @return success
*/
arangodb::Result copyAllErrors(errors_t& errors) const;
protected:
/// @brief common code used by multiple constructors
void init();
/// @brief Search for action by hash
/// @return shared pointer to action object if exists, _actionRegistry.end() if not
std::shared_ptr<maintenance::Action> findActionHash(size_t hash);
/// @brief Search for action by hash (but lock already held by caller)
/// @return shared pointer to action object if exists, nullptr if not
std::shared_ptr<maintenance::Action> findActionHashNoLock(size_t hash);
/// @brief Search for action by Id
/// @return shared pointer to action object if exists, nullptr if not
std::shared_ptr<maintenance::Action> findActionId(uint64_t id);
/// @brief Search for action by Id (but lock already held by caller)
/// @return shared pointer to action object if exists, nullptr if not
std::shared_ptr<maintenance::Action> findActionIdNoLock(uint64_t hash);
protected:
/// @brief tunable option for thread pool size
int32_t _maintenanceThreadsMax;
/// @brief tunable option for number of seconds COMPLETE or FAILED actions block
/// duplicates from adding to _actionRegistry
int32_t _secondsActionsBlock;
/// @brief tunable option for number of seconds COMPLETE and FAILE actions remain
/// within _actionRegistry
int32_t _secondsActionsLinger;
/// @brief flag to indicate when it is time to stop thread pool
std::atomic<bool> _isShuttingDown;
/// @brief simple counter for creating MaintenanceAction id. Ok for it to roll over.
std::atomic<uint64_t> _nextActionId;
//
// Lock notes:
// Reading _actionRegistry requires Read or Write lock via _actionRegistryLock
// Writing _actionRegistry requires BOTH:
// - CONDITION_LOCKER on _actionRegistryCond
// - then write lock via _actionRegistryLock
//
/// @brief all actions executing, waiting, and done
std::deque<std::shared_ptr<maintenance::Action>> _actionRegistry;
/// @brief lock to protect _actionRegistry and state changes to MaintenanceActions within
mutable arangodb::basics::ReadWriteLock _actionRegistryLock;
/// @brief condition variable to motivate workers to find new action
arangodb::basics::ConditionVariable _actionRegistryCond;
/// @brief list of background workers
std::vector<maintenance::MaintenanceWorker *> _activeWorkers;
/// @brief condition variable to indicate thread completion
arangodb::basics::ConditionVariable _workerCompletion;
/// Errors are managed through raiseIndexError / removeIndexError and
/// raiseShardError / renoveShardError. According locks must be held in said
/// methods.
/// @brief lock for index error bucket
mutable arangodb::Mutex _ieLock;
/// @brief pending errors raised by EnsureIndex
std::map<std::string,
std::map<std::string,
std::shared_ptr<VPackBuffer<uint8_t>>>> _indexErrors;
/// @brief lock for shard error bucket
mutable arangodb::Mutex _seLock;
/// @brief pending errors raised by CreateCollection/UpdateCollection
std::unordered_map<std::string,
std::shared_ptr<VPackBuffer<uint8_t>>> _shardErrors;
/// @brief lock for database error bucket
mutable arangodb::Mutex _dbeLock;
/// @brief pending errors raised by CreateDatabase
std::unordered_map<std::string,
std::shared_ptr<VPackBuffer<uint8_t>>> _dbErrors;
};
}
#endif

View File

@ -0,0 +1,193 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#include "MaintenanceRestHandler.h"
#include "ApplicationFeatures/ApplicationServer.h"
#include "Basics/StringUtils.h"
#include "Basics/conversions.h"
#include "Cluster/MaintenanceFeature.h"
#include "Rest/HttpRequest.h"
#include "Rest/HttpResponse.h"
using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::basics;
using namespace arangodb::rest;
MaintenanceRestHandler::MaintenanceRestHandler(GeneralRequest* request,
GeneralResponse* response)
: RestBaseHandler(request, response) {
}
RestStatus MaintenanceRestHandler::execute() {
// extract the sub-request type
auto const type = _request->requestType();
switch(type) {
// retrieve list of all actions
case rest::RequestType::GET:
getAction();
break;
// add an action to the list (or execute it directly)
case rest::RequestType::PUT:
putAction();
break;
// remove an action, stopping it if executing
case rest::RequestType::DELETE_REQ:
deleteAction();
break;
default:
generateError(rest::ResponseCode::METHOD_NOT_ALLOWED,
(int)rest::ResponseCode::METHOD_NOT_ALLOWED);
break;
} // switch
return RestStatus::DONE;
}
void MaintenanceRestHandler::putAction() {
bool good(true);
VPackSlice parameters;
std::map<std::string, std::string> param_map;
try {
parameters = _request->payload();
} catch (VPackException const& ex) {
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
std::string("expecting a valid JSON object in the request. got: ") + ex.what());
good=false;
} // catch
if (good && _request->payload().isEmptyObject()) {
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_CORRUPTED_JSON);
good=false;
}
// convert vpack into key/value map
if (good) {
good = parsePutBody(parameters);
// bad json
if (!good) {
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
std::string("unable to parse JSON object into key/value pairs."));
} // if
} // if
if (good) {
Result result;
// build the action
auto maintenance = ApplicationServer::getFeature<MaintenanceFeature>("Maintenance");
result = maintenance->addAction(_actionDesc);
if (!result.ok()) {
// possible errors? TRI_ERROR_BAD_PARAMETER TRI_ERROR_TASK_DUPLICATE_ID TRI_ERROR_SHUTTING_DOWN
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
result.errorMessage());
} // if
} // if
} // MaintenanceRestHandler::putAction
bool MaintenanceRestHandler::parsePutBody(VPackSlice const & parameters) {
bool good(true);
std::map<std::string, std::string> desc;
auto prop = std::make_shared<VPackBuilder>();
VPackObjectIterator it(parameters, true);
for ( ; it.valid() && good; ++it) {
VPackSlice key, value;
key = it.key();
value = it.value();
// attempt insert into map ... but needs to be unique
if (key.isString() && value.isString()) {
good = desc.insert(
{key.copyString(), value.copyString()}).second;
} else if (key.isString() && (key.copyString() == "properties")
&& value.isObject()) {
// code here
prop.reset(new VPackBuilder(value));
} else {
good = false;
} // else
} // for
_actionDesc = std::make_shared<maintenance::ActionDescription>(desc, prop);
return good;
} // MaintenanceRestHandler::parsePutBody
void MaintenanceRestHandler::getAction() {
// build the action
auto maintenance = ApplicationServer::getFeature<MaintenanceFeature>("Maintenance");
VPackBuilder registry = maintenance->toVelocyPack();
generateResult(rest::ResponseCode::OK, registry.slice());
} // MaintenanceRestHandler::getAction
void MaintenanceRestHandler::deleteAction() {
auto maintenance = ApplicationServer::getFeature<MaintenanceFeature>("Maintenance");
std::vector<std::string> const& suffixes = _request->suffixes();
// must be one parameter: "all" or number
if (1 == suffixes.size()) {
std::string param = suffixes[0];
Result result;
if (param == "all") {
// Jobs supports all. Should Action too? Going with "no" for now.
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
result.errorMessage());
} else {
uint64_t action_id = StringUtils::uint64(param);
result = maintenance->deleteAction(action_id);
// can fail on bad id or if action already succeeded.
if (!result.ok()) {
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER,
result.errorMessage());
} // if
} // else
} else {
generateError(rest::ResponseCode::BAD, TRI_ERROR_HTTP_BAD_PARAMETER);
}
} // MaintenanceRestHandler::deleteAction

View File

@ -0,0 +1,83 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGOD_CLUSTER_MAINTENANCE_REST_HANDLER
#define ARANGOD_CLUSTER_MAINTENANCE_REST_HANDLER 1
#include <velocypack/vpack.h>
#include <velocypack/velocypack-aliases.h>
#include "Cluster/Action.h"
#include "RestHandler/RestBaseHandler.h"
namespace arangodb {
////////////////////////////////////////////////////////////////////////////////
/// @brief Object that directs processing of one user maintenance requests
////////////////////////////////////////////////////////////////////////////////
class MaintenanceRestHandler : public RestBaseHandler {
public:
MaintenanceRestHandler(GeneralRequest*, GeneralResponse*);
public:
char const* name() const override { return "MaintenanceRestHandler"; }
RequestLane lane() const override final { return RequestLane::CLUSTER_INTERNAL; }
/// @brief Performs routing of request to appropriate subroutines
RestStatus execute() override;
//
// Accessors
//
/// @brief retrieve parsed action description
maintenance::ActionDescription const & getActionDesc() const {return *_actionDesc;};
/// @brief retrieve unparsed action properties
VPackBuilder const & getActionProp() const {return *(_actionDesc->properties());};
protected:
/// @brief PUT method adds an Action to the worklist (or executes action directly)
void putAction();
/// @brief GET method returns worklist
void getAction();
/// @brief DELETE method shifts non-finished action to Failed list.
/// (finished actions are untouched)
void deleteAction();
/// @brief internal routine to convert PUT body into _actionDesc and _actionProp
bool parsePutBody(VPackSlice const & parameters);
protected:
std::shared_ptr<maintenance::ActionDescription> _actionDesc;
};
}
#endif

View File

@ -0,0 +1,176 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2018 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#include "MaintenanceWorker.h"
#include "lib/Logger/Logger.h"
#include "Cluster/MaintenanceFeature.h"
namespace arangodb {
namespace maintenance {
MaintenanceWorker::MaintenanceWorker(arangodb::MaintenanceFeature & feature)
: Thread("MaintenanceWorker"),
_feature(feature), _curAction(nullptr), _loopState(eFIND_ACTION),
_directAction(false) {
return;
} // MaintenanceWorker::MaintenanceWorker
MaintenanceWorker::MaintenanceWorker(arangodb::MaintenanceFeature & feature,
std::shared_ptr<Action> & directAction)
: Thread("MaintenanceWorker"),
_feature(feature), _curAction(directAction), _loopState(eRUN_FIRST),
_directAction(true) {
return;
} // MaintenanceWorker::MaintenanceWorker
void MaintenanceWorker::run() {
bool more(false);
while(eSTOP != _loopState && !_feature.isShuttingDown()){
switch(_loopState) {
case eFIND_ACTION:
_curAction = _feature.findReadyAction();
more = (bool)_curAction;
break;
case eRUN_FIRST:
_curAction->startStats();
more = _curAction->first();
break;
case eRUN_NEXT:
more = _curAction->next();
break;
default:
_loopState = eSTOP;
LOG_TOPIC(ERR, Logger::CLUSTER)
<< "MaintenanceWorkerRun: unexpected state (" << _loopState << ")";
} // switch
// determine next loop state
nextState(more);
} // while
} // MaintenanceWorker::run
void MaintenanceWorker::nextState(bool actionMore) {
// bad result code forces actionMore to false
if (_curAction && (!_curAction->result().ok()
|| FAILED == _curAction->getState()))
{
actionMore = false;
} // if
// actionMore means iterate again
if (actionMore) {
// There should be an valid _curAction
if (_curAction) {
if (eFIND_ACTION == _loopState) {
_loopState = eRUN_FIRST;
} else {
_curAction->incStats();
_loopState = eRUN_NEXT;
} // if
// move execution to PreAction if it exists
if (_curAction->getPreAction()) {
std::shared_ptr<Action> tempPtr;
_curAction->setState(WAITING);
tempPtr=_curAction;
_curAction=_curAction->getPreAction();
_curAction->setPostAction(
std::make_shared<ActionDescription>(tempPtr->describe()));
_loopState = eRUN_FIRST;
} // if
} else {
// this state should not exist, but deal with it
_loopState = (_directAction ? eSTOP : eFIND_ACTION);
} // else
} else {
// finish the current action
if (_curAction) {
_lastResult = _curAction->result();
// if action's state not set, assume it succeeded when result ok
if (_curAction->result().ok()
&& FAILED != _curAction->getState()) {
_curAction->endStats();
_curAction->setState(COMPLETE);
// continue execution with "next" action tied to this one
if (_curAction->getPostAction()) {
_curAction = _curAction->getPostAction();
_curAction->clearPreAction();
_loopState = (WAITING == _curAction->getState() ? eRUN_NEXT : eRUN_FIRST);
_curAction->setState(EXECUTING);
} else {
_curAction.reset();
_loopState = (_directAction ? eSTOP : eFIND_ACTION);
} // else
} else {
std::shared_ptr<Action> failAction(_curAction);
// fail all actions that would follow
do {
failAction->setState(FAILED);
failAction->endStats();
failAction=failAction->getPostAction();
} while(failAction);
_loopState = (_directAction ? eSTOP : eFIND_ACTION);
} // else
} else {
// no current action, go back to hunting for one
_loopState = (_directAction ? eSTOP : eFIND_ACTION);
} // else
} // else
} // MaintenanceWorker::nextState
#if 0
std::shared_ptr<Action> MaintenanceWorker::findReadyAction() {
std::shared_ptr<Action> ret_ptr;
return ret_ptr;
} // Maintenance::findReadyAction
#endif
} // namespace maintenance
} // namespace arangodb

View File

@ -0,0 +1,89 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2018 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGOD_CLUSTER_MAINTENANCE_WORKER
#define ARANGOD_CLUSTER_MAINTENANCE_WORKER 1
#include "Basics/Thread.h"
#include "Cluster/Action.h"
namespace arangodb {
class MaintenanceFeature;
namespace maintenance {
class MaintenanceWorker : public Thread {
public:
MaintenanceWorker(MaintenanceFeature& feature);
MaintenanceWorker(
MaintenanceFeature& feature, std::shared_ptr<Action>& directAction);
virtual ~MaintenanceWorker() {};
//
// MaintenanceWorker entry points
//
/// @brief Thread object entry point
virtual void run();
/// @brief Share internal result state, likely derived from most recent action
/// @returns Result object
Result result() const {return _lastResult;};
protected:
enum WorkerState {
eSTOP = 1,
eFIND_ACTION = 2,
eRUN_FIRST = 3,
eRUN_NEXT = 4,
};
/// @brief Determine next loop state
/// @param true if action wants to continue, false if action done
void nextState(bool);
/// @brief Find an action that is ready to process within feature's deque
/// @return action to process, or nullptr
arangodb::MaintenanceFeature & _feature;
std::shared_ptr<Action> _curAction;
WorkerState _loopState;
bool _directAction;
Result _lastResult;
private:
MaintenanceWorker(MaintenanceWorker const &) = delete;
};// class MaintenanceWorker
} // namespace maintenance
} // namespace arangodb
#endif

View File

@ -0,0 +1,49 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#include "NonAction.h"
#include "MaintenanceFeature.h"
using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::maintenance;
NonAction::NonAction(
MaintenanceFeature& feature, ActionDescription const& desc)
: ActionBase(feature, desc) {
std::string const error =
std::string("Unknown maintenance action '") + desc.name() + "'";
LOG_TOPIC(ERR, Logger::MAINTENANCE) << error;
_result = arangodb::Result(TRI_ERROR_INTERNAL, error);
}
bool NonAction::first() {
std::string const error =
std::string("Unknown maintenance action '") + _description.name() + "'";
LOG_TOPIC(ERR, Logger::MAINTENANCE) << error;
_result = arangodb::Result(TRI_ERROR_INTERNAL, error);
return false;
}
NonAction::~NonAction() {}

View File

@ -0,0 +1,53 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGODB_MAINTENANCE_NON_ACTION_H
#define ARANGODB_MAINTENANCE_NON_ACTION_H
#include "ActionBase.h"
#include "ActionDescription.h"
#include <chrono>
namespace arangodb {
namespace maintenance {
/**
* @brief Dummy action for failure to find action
*/
class NonAction : public ActionBase {
public:
NonAction(MaintenanceFeature&, ActionDescription const& d);
virtual ~NonAction();
virtual bool first() override final;
};
}}
#endif

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -0,0 +1,136 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2018 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Kaveh Vahedipour
/// @author Matthew Von-Maszewski
////////////////////////////////////////////////////////////////////////////////
#include "ResignShardLeadership.h"
#include "MaintenanceFeature.h"
#include "ApplicationFeatures/ApplicationServer.h"
#include "Basics/VelocyPackHelper.h"
#include "Cluster/ClusterFeature.h"
#include "Cluster/FollowerInfo.h"
#include "Transaction/StandaloneContext.h"
#include "Transaction/Methods.h"
#include "Utils/DatabaseGuard.h"
#include "VocBase/LogicalCollection.h"
#include "VocBase/Methods/Collections.h"
#include "VocBase/Methods/Databases.h"
#include <velocypack/Compare.h>
#include <velocypack/Iterator.h>
#include <velocypack/Slice.h>
#include <velocypack/velocypack-aliases.h>
using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::maintenance;
using namespace arangodb::methods;
ResignShardLeadership::ResignShardLeadership(
MaintenanceFeature& feature, ActionDescription const& desc)
: ActionBase(feature, desc) {
std::stringstream error;
if (!desc.has(DATABASE)) {
error << "database must be specified";
}
TRI_ASSERT(desc.has(DATABASE));
if (!desc.has(SHARD)) {
error << "shard must be specified";
}
TRI_ASSERT(desc.has(SHARD));
if (!error.str().empty()) {
LOG_TOPIC(ERR, Logger::MAINTENANCE) << "ResignLeadership: " << error.str();
_result.reset(TRI_ERROR_INTERNAL, error.str());
setState(FAILED);
}
}
ResignShardLeadership::~ResignShardLeadership() {};
bool ResignShardLeadership::first() {
auto const& database = _description.get(DATABASE);
auto const& collection = _description.get(SHARD);
LOG_TOPIC(DEBUG, Logger::MAINTENANCE)
<< "trying to withdraw as leader of shard '" << database << "/" << collection;
// This starts a write transaction, just to wait for any ongoing
// write transaction on this shard to terminate. We will then later
// report to Current about this resignation. If a new write operation
// starts in the meantime (which is unlikely, since no coordinator that
// has seen the _ will start a new one), it is doomed, and we ignore the
// problem, since similar problems can arise in failover scenarios anyway.
try {
// Guard database againts deletion for now
DatabaseGuard guard(database);
auto vocbase = &guard.database();
auto col = vocbase->lookupCollection(collection);
if (col == nullptr) {
std::stringstream error;
error << "Failed to lookup local collection " << collection
<< " in database " + database;
LOG_TOPIC(ERR, Logger::MAINTENANCE) << "EnsureIndex: " << error.str();
_result.reset(TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND, error.str());
return false;
}
col->followers()->setTheLeader("LEADER_NOT_YET_KNOWN"); // resign
// Note that it is likely that we will be a follower for this shard
// with another leader in due course. However, we do not know the
// name of the new leader yet. This setting will make us a follower
// for now but we will not accept any replication operation from any
// leader, until we have negotiated a deal with it. Then the actual
// name of the leader will be set.
// Get write transaction on collection
auto ctx = std::make_shared<transaction::StandaloneContext>(*vocbase);
transaction::Methods trx(ctx, {}, {collection}, {}, transaction::Options());
Result res = trx.begin();
if (!res.ok()) {
THROW_ARANGO_EXCEPTION(res);
}
} catch (std::exception const& e) {
std::stringstream error;
error << "exception thrown when resigning:" << e.what();
LOG_TOPIC(ERR, Logger::MAINTENANCE) << "ResignLeadership: " << error.str();
_result.reset(TRI_ERROR_INTERNAL, error.str());
return false;
}
notify();
return false;
}

Some files were not shown because too many files have changed in this diff Show More