1
0
Fork 0
arangodb/arangod/Cluster/EngineEqualityCheckFeature.cpp

121 lines
4.0 KiB
C++

////////////////////////////////////////////////////////////////////////////////
/// 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 Jan Christoph Uhde
////////////////////////////////////////////////////////////////////////////////
#include "EngineEqualityCheckFeature.h"
#include "Logger/Logger.h"
#include "Cluster/ClusterComm.h"
#include "Cluster/ClusterInfo.h"
#include "Cluster/ServerState.h"
#include "StorageEngine/EngineSelectorFeature.h"
#include "StorageEngine/StorageEngine.h"
using namespace arangodb;
namespace {
bool equalStorageEngines() {
std::string engineName = EngineSelectorFeature::engineName();
auto allEqual = true;
auto ci = ClusterInfo::instance();
auto cc = ClusterComm::instance();
// get db servers
auto serverIdVector = ci->getCurrentDBServers();
// prepare requests
std::vector<ClusterCommRequest> requests;
auto bodyToSend = std::make_shared<std::string>();
std::string const url = "/_api/engine";
for(auto const& id : serverIdVector){
requests.emplace_back("server:" + id, rest::RequestType::GET, url,
bodyToSend);
}
// send requests
std::size_t requestsDone = 0;
// We are using a very long timeout here, since in our Jenkins we have
// observed that some dbservers need a long time to come up, since the
// I/O system is overloaded (lots of servers starting at the same time).
// Furthermore, this long timeout here does not really hurt. Besides,
// failure here is fatal for this coordinator, and thus for the whole
// test in a single coordinator scenario.
auto successful = cc->performRequests(requests, 600.0 /*20 fold timeout*/,
requestsDone ,Logger::CLUSTER ,false);
if (successful != requests.size()){
LOG_TOPIC(ERR, Logger::CLUSTER)
<< "could not reach all dbservers for engine check";
return false;
}
// check answers
for (auto const& request : requests){
auto const& result = request.result;
if (result.status == CL_COMM_RECEIVED) {
httpclient::SimpleHttpResult const& simpleResult = *request.result.result;
// extract engine from body
auto vpack = simpleResult.getBodyVelocyPack();
auto dbserverEngine = vpack->slice().get("name").copyString();
if (dbserverEngine != engineName) {
LOG_TOPIC(ERR, arangodb::Logger::ENGINES)
<< "this coordinator is using the '" << engineName
<< "' engine while the DB server at '" << request.destination
<< "' uses the '" << dbserverEngine << "' engine";
allEqual = false;
break;
}
} else {
allEqual = false;
break;
}
}
return allEqual;
}
} // namespace
EngineEqualityCheckFeature::EngineEqualityCheckFeature(
application_features::ApplicationServer& server
)
: ApplicationFeature(server, "EngineEqualityCheck") {
setOptional(false);
startsAfter("DatabasePhase");
// this feature is supposed to run after the cluster is somewhat ready
startsAfter("ClusterPhase");
startsAfter("Bootstrap");
}
void EngineEqualityCheckFeature::start() {
if (ServerState::instance()->isCoordinator()) {
LOG_TOPIC(TRACE, arangodb::Logger::ENGINES) << "running storage engine equality check";
if (!::equalStorageEngines()) {
LOG_TOPIC(FATAL, arangodb::Logger::ENGINES) << "the usage of different storage engines in the cluster is unsupported and may cause issues";
FATAL_ERROR_EXIT();
}
}
}