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

151 lines
5.2 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 "Logger/Logger.h"
#include "Cluster/AgencyComm.h"
#include "Cluster/ClusterInfo.h"
#include "Cluster/ServerState.h"
#include "HttpServer/HttpHandlerFactory.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") {
startsAfter("Dispatcher");
startsAfter("Endpoint");
startsAfter("Scheduler");
startsAfter("Server");
startsAfter("Agency");
startsAfter("LogfileManager");
startsAfter("Database");
startsAfter("Upgrade");
startsAfter("CheckVersion");
startsAfter("FoxxQueues");
startsAfter("RestServer");
}
static void raceForClusterBootstrap() {
AgencyComm agency;
auto ci = ClusterInfo::instance();
while (true) {
AgencyCommResult result = agency.getValues("Bootstrap", false);
if (!result.successful() &&
result.httpCode() != (int) arangodb::GeneralResponse::ResponseCode::NOT_FOUND) {
// Error in communication, we could live with NOT_FOUND or OK
LOG_TOPIC(TRACE, Logger::STARTUP)
<< "raceForClusterBootstrap: no agency communication";
sleep(1);
continue;
}
result.parse("", false);
auto it = result._values.begin();
if (it != result._values.end()) {
VPackSlice value = it->second._vpack->slice();
if (value.isString() && value.isEqualString("done")) {
// all done, let's get out of here:
LOG_TOPIC(TRACE, Logger::STARTUP)
<< "raceForClusterBootstrap: bootstrap already done";
return;
}
LOG_TOPIC(INFO, 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(INFO, 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(INFO, 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(INFO, 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(INFO, Logger::STARTUP) << "Racing for cluster bootstrap...";
raceForClusterBootstrap();
LOG_TOPIC(INFO, Logger::STARTUP) << "Running server/bootstrap/coordinator.js";
V8DealerFeature::DEALER->loadJavascript(vocbase, "server/bootstrap/coordinator.js");
} else if (ss->isDBServer()) {
LOG_TOPIC(INFO, Logger::STARTUP) << "Running server/bootstrap/db-server.js";
V8DealerFeature::DEALER->loadJavascript(vocbase, "server/bootstrap/db-server.js");
} else {
LOG_TOPIC(INFO, Logger::STARTUP) << "Running server/server.js";
V8DealerFeature::DEALER->loadJavascript(vocbase, "server/server.js");
}
// Start service properly:
arangodb::rest::HttpHandlerFactory::setMaintenance(false);
LOG(INFO) << "ArangoDB (version " << ARANGODB_VERSION_FULL
<< ") is ready for business. Have fun!";
}