mirror of https://gitee.com/bigwinds/arangodb
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:
parent
50be715aeb
commit
28754cbf15
|
@ -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.
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}}
|
|
@ -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
|
|
@ -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;
|
||||
}}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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,
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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() {}
|
|
@ -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
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue