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

204 lines
6.7 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 "Aql/QueryList.h"
#include "Cluster/AgencyComm.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 "RestServer/DatabaseServerFeature.h"
#include "V8Server/V8DealerFeature.h"
#include "VocBase/server.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("Dispatcher");
startsAfter("Endpoint");
startsAfter("Scheduler");
startsAfter("Server");
startsAfter("LogfileManager");
startsAfter("Database");
startsAfter("Upgrade");
startsAfter("CheckVersion");
startsAfter("FoxxQueues");
startsAfter("RestServer");
}
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>({agency.prefix(), "Bootstrap"}));
if (value.isString()) {
// key was found and is a string
if (value.isEqualString("done")) {
// 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->vocbase();
V8DealerFeature::DEALER->loadJavascriptFiles(
vocbase, "server/bootstrap/cluster-bootstrap.js", 0);
LOG_TOPIC(DEBUG, Logger::STARTUP)
<< "raceForClusterBootstrap: bootstrap done";
b.clear();
b.add(VPackValue("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->vocbase();
auto ss = ServerState::instance();
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");
} else {
LOG_TOPIC(DEBUG, Logger::STARTUP) << "Running server/server.js";
V8DealerFeature::DEALER->loadJavascript(vocbase, "server/server.js");
}
// Start service properly:
rest::RestHandlerFactory::setMaintenance(false);
LOG(INFO) << "ArangoDB (version " << ARANGODB_VERSION_FULL
<< ") is ready for business. Have fun!";
if (_bark) {
LOG(INFO) << "der Hund so: wau wau!";
}
_isReady = true;
}
void BootstrapFeature::unprepare() {
auto server =
ApplicationServer::getFeature<DatabaseServerFeature>("DatabaseServer");
TRI_server_t* s = server->SERVER;
// notify all currently running queries about the shutdown
if (ServerState::instance()->isCoordinator()) {
std::vector<TRI_voc_tick_t> ids =
TRI_GetIdsCoordinatorDatabaseServer(s, true);
for (auto& id : ids) {
TRI_vocbase_t* vocbase = TRI_UseByIdCoordinatorDatabaseServer(s, id);
if (vocbase != nullptr) {
vocbase->_queries->killAll(true);
TRI_ReleaseVocBase(vocbase);
}
}
} else {
std::vector<std::string> names;
int res = TRI_GetDatabaseNamesServer(s, names);
if (res == TRI_ERROR_NO_ERROR) {
for (auto& name : names) {
TRI_vocbase_t* vocbase = TRI_UseDatabaseServer(s, name.c_str());
if (vocbase != nullptr) {
vocbase->_queries->killAll(true);
TRI_ReleaseVocBase(vocbase);
}
}
}
}
}