1
0
Fork 0
arangodb/arangod/RestServer/BootstrapFeature.cpp

198 lines
6.6 KiB
C++

////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 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 Max Neunhoeffer
////////////////////////////////////////////////////////////////////////////////
#include "RestServer/BootstrapFeature.h"
#include "Agency/AgencyComm.h"
#include "Aql/QueryList.h"
#include "Cluster/ClusterInfo.h"
#include "Cluster/ServerState.h"
#include "GeneralServer/RestHandlerFactory.h"
#include "Logger/Logger.h"
#include "ProgramOptions/Parameters.h"
#include "ProgramOptions/ProgramOptions.h"
#include "Rest/GeneralResponse.h"
#include "Rest/Version.h"
#include "RestServer/DatabaseFeature.h"
#include "V8Server/V8DealerFeature.h"
using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::options;
BootstrapFeature::BootstrapFeature(
application_features::ApplicationServer* server)
: ApplicationFeature(server, "Bootstrap"), _isReady(false), _bark(false) {
startsAfter("Endpoint");
startsAfter("Scheduler");
startsAfter("Server");
startsAfter("MMFilesLogfileManager");
startsAfter("Database");
startsAfter("Upgrade");
startsAfter("CheckVersion");
startsAfter("FoxxQueues");
startsAfter("GeneralServer");
}
void BootstrapFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
options->addHiddenOption("hund", "make ArangoDB bark on startup",
new BooleanParameter(&_bark));
}
static void raceForClusterBootstrap() {
AgencyComm agency;
auto ci = ClusterInfo::instance();
while (true) {
AgencyCommResult result = agency.getValues("Bootstrap");
if (!result.successful()) {
// Error in communication, note that value not found is not an error
LOG_TOPIC(TRACE, Logger::STARTUP)
<< "raceForClusterBootstrap: no agency communication";
sleep(1);
continue;
}
VPackSlice value = result.slice()[0].get(
std::vector<std::string>({AgencyCommManager::path(), "Bootstrap"}));
if (value.isString()) {
// key was found and is a string
if (value.copyString().find("done") != std::string::npos) {
// all done, let's get out of here:
LOG_TOPIC(TRACE, Logger::STARTUP)
<< "raceForClusterBootstrap: bootstrap already done";
return;
}
LOG_TOPIC(DEBUG, Logger::STARTUP)
<< "raceForClusterBootstrap: somebody else does the bootstrap";
sleep(1);
continue;
}
// No value set, we try to do the bootstrap ourselves:
VPackBuilder b;
b.add(VPackValue(arangodb::ServerState::instance()->getId()));
result = agency.casValue("Bootstrap", b.slice(), false, 300, 15);
if (!result.successful()) {
LOG_TOPIC(DEBUG, Logger::STARTUP)
<< "raceForClusterBootstrap: lost race, somebody else will bootstrap";
// Cannot get foot into the door, try again later:
sleep(1);
continue;
}
// OK, we handle things now, let's see whether a DBserver is there:
auto dbservers = ci->getCurrentDBServers();
if (dbservers.size() == 0) {
LOG_TOPIC(TRACE, Logger::STARTUP)
<< "raceForClusterBootstrap: no DBservers, waiting";
agency.removeValues("Bootstrap", false);
sleep(1);
continue;
}
LOG_TOPIC(DEBUG, Logger::STARTUP)
<< "raceForClusterBootstrap: race won, we do the bootstrap";
auto vocbase = DatabaseFeature::DATABASE->systemDatabase();
V8DealerFeature::DEALER->loadJavascriptFiles(
vocbase, "server/bootstrap/cluster-bootstrap.js", 0);
LOG_TOPIC(DEBUG, Logger::STARTUP)
<< "raceForClusterBootstrap: bootstrap done";
b.clear();
b.add(VPackValue(arangodb::ServerState::instance()->getId() + ": done"));
result = agency.setValue("Bootstrap", b.slice(), 0);
if (result.successful()) {
return;
}
LOG_TOPIC(TRACE, Logger::STARTUP)
<< "raceForClusterBootstrap: could not indicate success";
sleep(1);
}
}
void BootstrapFeature::start() {
auto vocbase = DatabaseFeature::DATABASE->systemDatabase();
auto ss = ServerState::instance();
if (!ss->isRunningInCluster()) {
LOG_TOPIC(DEBUG, Logger::STARTUP) << "Running server/server.js";
V8DealerFeature::DEALER->loadJavascript(vocbase, "server/server.js");
} else if (ss->isCoordinator()) {
LOG_TOPIC(DEBUG, Logger::STARTUP) << "Racing for cluster bootstrap...";
raceForClusterBootstrap();
LOG_TOPIC(DEBUG, Logger::STARTUP)
<< "Running server/bootstrap/coordinator.js";
V8DealerFeature::DEALER->loadJavascript(vocbase,
"server/bootstrap/coordinator.js");
} else if (ss->isDBServer()) {
LOG_TOPIC(DEBUG, Logger::STARTUP)
<< "Running server/bootstrap/db-server.js";
V8DealerFeature::DEALER->loadJavascript(vocbase,
"server/bootstrap/db-server.js");
}
// Start service properly:
rest::RestHandlerFactory::setMaintenance(false);
LOG_TOPIC(INFO, arangodb::Logger::FIXME) << "ArangoDB (version " << ARANGODB_VERSION_FULL
<< ") is ready for business. Have fun!";
if (_bark) {
LOG_TOPIC(INFO, arangodb::Logger::FIXME) << "The dog says: wau wau!";
}
_isReady = true;
}
void BootstrapFeature::unprepare() {
// notify all currently running queries about the shutdown
auto databaseFeature =
application_features::ApplicationServer::getFeature<DatabaseFeature>(
"Database");
if (ServerState::instance()->isCoordinator()) {
for (auto& id : databaseFeature->getDatabaseIdsCoordinator(true)) {
TRI_vocbase_t* vocbase = databaseFeature->useDatabase(id);
if (vocbase != nullptr) {
vocbase->queryList()->killAll(true);
vocbase->release();
}
}
} else {
for (auto& name : databaseFeature->getDatabaseNames()) {
TRI_vocbase_t* vocbase = databaseFeature->useDatabase(name);
if (vocbase != nullptr) {
vocbase->queryList()->killAll(true);
vocbase->release();
}
}
}
}