1
0
Fork 0

Handle errors in loadScript for JS, use in cluster-bootstrap.

This recognizes errors that happen during the global cluster bootstrap.
If an error happens, the bootstrap is tried again later. The cluster
does not start until the cluster bootstrap has been finished
successfully.
This commit is contained in:
Max Neunhoeffer 2017-05-22 15:34:41 +02:00
parent cbdf9563cb
commit 4bddb0c1ad
7 changed files with 80 additions and 25 deletions

View File

@ -114,8 +114,24 @@ static void raceForClusterBootstrap() {
LOG_TOPIC(DEBUG, Logger::STARTUP)
<< "raceForClusterBootstrap: race won, we do the bootstrap";
auto vocbase = DatabaseFeature::DATABASE->systemDatabase();
VPackBuilder builder;
V8DealerFeature::DEALER->loadJavaScriptFileInDefaultContext(
vocbase, "server/bootstrap/cluster-bootstrap.js");
vocbase, "server/bootstrap/cluster-bootstrap.js", &builder);
VPackSlice jsresult = builder.slice();
if (!jsresult.isTrue()) {
LOG_TOPIC(ERR, Logger::STARTUP) << "Problems with cluster bootstrap, "
<< "marking as not successful.";
if (!jsresult.isNone()) {
LOG_TOPIC(ERR, Logger::STARTUP) << "Returned value: "
<< jsresult.toJson();
} else {
LOG_TOPIC(ERR, Logger::STARTUP) << "Empty returned value.";
}
agency.removeValues("Bootstrap", false);
sleep(1);
continue;
}
LOG_TOPIC(DEBUG, Logger::STARTUP)
<< "raceForClusterBootstrap: bootstrap done";
@ -141,19 +157,19 @@ void BootstrapFeature::start() {
if (!ss->isRunningInCluster()) {
LOG_TOPIC(DEBUG, Logger::STARTUP) << "Running server/server.js";
V8DealerFeature::DEALER->loadJavaScriptFileInAllContexts(vocbase, "server/server.js");
V8DealerFeature::DEALER->loadJavaScriptFileInAllContexts(vocbase, "server/server.js", nullptr);
} 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->loadJavaScriptFileInAllContexts(vocbase,
"server/bootstrap/coordinator.js");
"server/bootstrap/coordinator.js", nullptr);
} else if (ss->isDBServer()) {
LOG_TOPIC(DEBUG, Logger::STARTUP)
<< "Running server/bootstrap/db-server.js";
V8DealerFeature::DEALER->loadJavaScriptFileInAllContexts(vocbase,
"server/bootstrap/db-server.js");
"server/bootstrap/db-server.js", nullptr);
}
// Start service properly:

View File

@ -267,7 +267,7 @@ void V8DealerFeature::start() {
DatabaseFeature* database =
ApplicationServer::getFeature<DatabaseFeature>("Database");
loadJavaScriptFileInAllContexts(database->systemDatabase(), "server/initialize.js");
loadJavaScriptFileInAllContexts(database->systemDatabase(), "server/initialize.js", nullptr);
startGarbageCollection();
}
@ -280,7 +280,7 @@ V8Context* V8DealerFeature::addContext() {
DatabaseFeature* database =
ApplicationServer::getFeature<DatabaseFeature>("Database");
loadJavaScriptFileInContext(database->systemDatabase(), "server/initialize.js", context);
loadJavaScriptFileInContext(database->systemDatabase(), "server/initialize.js", context, nullptr);
return context;
}
@ -478,22 +478,29 @@ void V8DealerFeature::collectGarbage() {
}
void V8DealerFeature::loadJavaScriptFileInAllContexts(TRI_vocbase_t* vocbase,
std::string const& file) {
std::string const& file,
VPackBuilder* builder) {
CONDITION_LOCKER(guard, _contextCondition);
if (builder != nullptr) {
builder->openArray();
}
for (auto& context : _contexts) {
loadJavaScriptFileInContext(vocbase, file, context);
loadJavaScriptFileInContext(vocbase, file, context, builder);
}
if (builder != nullptr) {
builder->close();
}
}
void V8DealerFeature::loadJavaScriptFileInDefaultContext(TRI_vocbase_t* vocbase,
std::string const& file) {
std::string const& file, VPackBuilder* builder) {
// find context with id 0
CONDITION_LOCKER(guard, _contextCondition);
for (auto const& context : _contexts) {
if (context->_id == 0) {
loadJavaScriptFileInContext(vocbase, file, context);
loadJavaScriptFileInContext(vocbase, file, context, builder);
break;
}
}
@ -1177,7 +1184,8 @@ V8Context* V8DealerFeature::buildContext(size_t id) {
}
bool V8DealerFeature::loadJavaScriptFileInContext(TRI_vocbase_t* vocbase,
std::string const& file, V8Context* context) {
std::string const& file, V8Context* context,
VPackBuilder* builder) {
TRI_ASSERT(vocbase != nullptr);
@ -1191,13 +1199,13 @@ bool V8DealerFeature::loadJavaScriptFileInContext(TRI_vocbase_t* vocbase,
enterContextInternal(vocbase, context, true);
loadJavaScriptFileInternal(file, context);
loadJavaScriptFileInternal(file, context, builder);
exitContextInternal(context);
return true;
}
void V8DealerFeature::loadJavaScriptFileInternal(std::string const& file, V8Context* context) {
void V8DealerFeature::loadJavaScriptFileInternal(std::string const& file, V8Context* context, VPackBuilder* builder) {
v8::HandleScope scope(context->_isolate);
auto localContext =
v8::Local<v8::Context>::New(context->_isolate, context->_context);
@ -1207,7 +1215,7 @@ void V8DealerFeature::loadJavaScriptFileInternal(std::string const& file, V8Cont
v8::Context::Scope contextScope(localContext);
switch (
_startupLoader.loadScript(context->_isolate, localContext, file)) {
_startupLoader.loadScript(context->_isolate, localContext, file, builder)) {
case JSLoader::eSuccess:
LOG_TOPIC(TRACE, arangodb::Logger::V8) << "loaded JavaScript file '" << file << "'";
break;

View File

@ -28,6 +28,10 @@
#include "Basics/ConditionVariable.h"
#include "V8/JSLoader.h"
#include <velocypack/Slice.h>
#include <velocypack/Builder.h>
#include <velocypack/velocypack-aliases.h>
struct TRI_vocbase_t;
namespace arangodb {
@ -62,8 +66,13 @@ class V8DealerFeature final : public application_features::ApplicationFeature {
bool addGlobalContextMethod(std::string const&);
void collectGarbage();
void loadJavaScriptFileInAllContexts(TRI_vocbase_t*, std::string const& file);
void loadJavaScriptFileInDefaultContext(TRI_vocbase_t*, std::string const& file);
// In the following two, if the builder pointer is not nullptr, then
// the Javascript result(s) are returned as VPack in the builder,
// the builder is not cleared and thus should be empty before the call.
void loadJavaScriptFileInAllContexts(TRI_vocbase_t*, std::string const& file,
VPackBuilder* builder);
void loadJavaScriptFileInDefaultContext(TRI_vocbase_t*, std::string const& file,
VPackBuilder* builder);
void startGarbageCollection();
V8Context* enterContext(TRI_vocbase_t*, bool allowUseDatabase,
@ -93,8 +102,9 @@ class V8DealerFeature final : public application_features::ApplicationFeature {
V8Context* buildContext(size_t id);
V8Context* pickFreeContextForGc();
void shutdownContext(V8Context* context);
void loadJavaScriptFileInternal(std::string const& file, V8Context* context);
bool loadJavaScriptFileInContext(TRI_vocbase_t*, std::string const& file, V8Context* context);
void loadJavaScriptFileInternal(std::string const& file, V8Context* context,
VPackBuilder* builder);
bool loadJavaScriptFileInContext(TRI_vocbase_t*, std::string const& file, V8Context* context, VPackBuilder* builder);
void enterContextInternal(TRI_vocbase_t* vocbase, V8Context* context, bool allowUseDatabase);
void exitContextInternal(V8Context*);
void applyContextUpdate(V8Context* context);

View File

@ -990,7 +990,7 @@ void V8ShellFeature::loadModules(ShellFeature::RunMode runMode) {
files.push_back("client/client.js"); // needs internal
for (size_t i = 0; i < files.size(); ++i) {
switch (loader.loadScript(_isolate, context, files[i])) {
switch (loader.loadScript(_isolate, context, files[i], nullptr)) {
case JSLoader::eSuccess:
LOG_TOPIC(TRACE, arangodb::Logger::FIXME) << "loaded JavaScript file '" << files[i] << "'";
break;

View File

@ -55,5 +55,5 @@
global.ArangoAgency.set('Current/Foxxmaster', global.ArangoServerState.id());
return true;
return result;
}());

View File

@ -26,6 +26,7 @@
#include "Logger/Logger.h"
#include "Basics/StringUtils.h"
#include "V8/v8-utils.h"
#include "V8/v8-vpack.h"
using namespace arangodb;
using namespace arangodb::basics;
@ -82,7 +83,8 @@ v8::Handle<v8::Value> JSLoader::executeGlobalScript(
JSLoader::eState JSLoader::loadScript(v8::Isolate* isolate,
v8::Handle<v8::Context>& context,
std::string const& name) {
std::string const& name,
VPackBuilder* builder) {
v8::HandleScope scope(isolate);
v8::TryCatch tryCatch;
@ -99,8 +101,9 @@ JSLoader::eState JSLoader::loadScript(v8::Isolate* isolate,
// Enter the newly created execution environment.
v8::Context::Scope context_scope(context);
TRI_ExecuteJavaScriptString(isolate, context, TRI_V8_STD_STRING(i->second),
TRI_V8_STD_STRING(name), false);
v8::Handle<v8::Value> result =
TRI_ExecuteJavaScriptString(isolate, context, TRI_V8_STD_STRING(i->second),
TRI_V8_STD_STRING(name), false);
if (tryCatch.HasCaught()) {
if (tryCatch.CanContinue()) {
@ -114,6 +117,19 @@ JSLoader::eState JSLoader::loadScript(v8::Isolate* isolate,
}
}
// Report the result if there is one:
if (builder != nullptr) {
try {
if (!result.IsEmpty()) {
TRI_V8ToVPack(isolate, *builder, result, false);
} else {
builder->add(VPackValue(VPackValueType::Null));
}
}
catch (...) {
}
}
return eSuccess;
}

View File

@ -29,6 +29,10 @@
#include <v8.h>
#include <velocypack/Slice.h>
#include <velocypack/Builder.h>
#include <velocypack/velocypack-aliases.h>
namespace arangodb {
////////////////////////////////////////////////////////////////////////////////
@ -55,11 +59,12 @@ class JSLoader : public ScriptLoader {
std::string const& name);
//////////////////////////////////////////////////////////////////////////////
/// @brief loads a named script
/// @brief loads a named script, if the builder pointer is not nullptr the
/// returned result will be written there as vpack
//////////////////////////////////////////////////////////////////////////////
JSLoader::eState loadScript(v8::Isolate* isolate, v8::Handle<v8::Context>&,
std::string const& name);
std::string const& name, VPackBuilder* builder);
//////////////////////////////////////////////////////////////////////////////
/// @brief loads all scripts