1
0
Fork 0
This commit is contained in:
Frank Celler 2016-04-07 15:40:11 +02:00
parent 31d477477e
commit 58b9cf7e91
34 changed files with 820 additions and 1394 deletions

View File

@ -0,0 +1,49 @@
////////////////////////////////////////////////////////////////////////////////
/// 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 Dr. Frank Celler
////////////////////////////////////////////////////////////////////////////////
#include "ActionFeature.h"
using namespace arangodb;
ActionFeature* ActionFeature::ACTION = nullptr;
#warning TODO
#if 0
if (_useActions) {
TRI_InitV8Actions(isolate, localContext, _vocbase, this);
}
bool ALLOW_USE_DATABASE_IN_REST_ACTIONS;
(
"server.allow-use-database", &ALLOW_USE_DATABASE_IN_REST_ACTIONS,
"allow change of database in REST actions, only needed for "
"unittests")
#endif

View File

@ -0,0 +1,44 @@
////////////////////////////////////////////////////////////////////////////////
/// 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 Dr. Frank Celler
////////////////////////////////////////////////////////////////////////////////
#ifndef APPLICATION_FEATURES_ACTION_FEATURE_H
#define APPLICATION_FEATURES_ACTION_FEATURE_H 1
#include "ApplicationFeatures/ApplicationFeature.h"
namespace arangodb {
class ActionFeature final : public application_features::ApplicationFeature {
public:
static ActionFeature* ACTION;
public:
explicit ActionFeature(application_features::ApplicationServer* server);
public:
bool allowUseDatabase() { return _allowUseAction; }
private:
bool _allowUseAction;
};
}
#endif

View File

@ -66,6 +66,7 @@ endif ()
add_executable(${BIN_ARANGOD}
${ARANGO_MSVC}
${ProductVersionFiles}
Actions/ActionFeature.cpp
Actions/RestActionHandler.cpp
Actions/actions.cpp
Agency/Agent.cpp
@ -211,8 +212,8 @@ add_executable(${BIN_ARANGOD}
RestHandler/RestVersionHandler.cpp
RestHandler/RestVocbaseBaseHandler.cpp
RestHandler/WorkMonitorHandler.cpp
RestServer/ArangoServer.cpp
RestServer/ConsoleThread.cpp
RestServer/CheckVersionFeature.cpp
RestServer/DatabaseFeature.cpp
RestServer/EndpointFeature.cpp
RestServer/ServerFeature.cpp

View File

@ -82,7 +82,8 @@ void DispatcherFeature::validateOptions(std::shared_ptr<ProgramOptions>) {
}
if (_queueSize <= 128) {
LOG(FATAL) << "invalid value for `--server.maximal-queue-size', need at least 128";
LOG(FATAL)
<< "invalid value for `--server.maximal-queue-size', need at least 128";
FATAL_ERROR_EXIT();
}
}
@ -96,6 +97,27 @@ void DispatcherFeature::start() {
if (_startAqlQueue) {
buildAqlQueue();
}
#warning TODO
#if 0
// initialize V8
if (!_applicationServer->programOptions().has("javascript.v8-contexts")) {
// the option was added recently so it's not always set
// the behavior in older ArangoDB was to create one V8 context per
// dispatcher thread
_v8Contexts = _dispatcherThreads;
}
#endif
#warning TODO
#if 0
if (_dispatcher->dispatcher() != nullptr) {
// don't initialize dispatcher if there is no scheduler (server started
// with --no-server option)
TRI_InitV8Dispatcher(isolate, localContext, _vocbase, _scheduler,
_dispatcher, this);
}
#endif
}
void DispatcherFeature::stop() {
@ -130,11 +152,6 @@ void DispatcherFeature::setProcessorAffinity(std::vector<size_t> const& cores) {
#endif
}
#warning TODO
#if 0

View File

@ -1,99 +1,3 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS 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 Dr. Frank Celler
////////////////////////////////////////////////////////////////////////////////
#include "ArangoServer.h"
#include <v8.h>
#include <iostream>
#include <fstream>
#include "Actions/RestActionHandler.h"
#include "Actions/actions.h"
#include "Agency/Agent.h"
#include "Agency/ApplicationAgency.h"
#include "ApplicationServer/ApplicationServer.h"
#include "Aql/Query.h"
#include "Aql/QueryCache.h"
#include "Aql/RestAqlHandler.h"
#include "Basics/FileUtils.h"
#include "Logger/Logger.h"
#include "Basics/Nonce.h"
// #include "Basics/ProgramOptions.h"
// #include "Basics/ProgramOptionsDescription.h"
#include "Basics/RandomGenerator.h"
#include "Basics/Utf8Helper.h"
#include "Basics/files.h"
#include "Basics/messages.h"
#include "Basics/process-utils.h"
#include "Basics/tri-strings.h"
#include "Cluster/ApplicationCluster.h"
#include "Cluster/ClusterComm.h"
#include "Cluster/HeartbeatThread.h"
#include "Cluster/RestShardHandler.h"
// #include "Dispatcher/ApplicationDispatcher.h"
#include "Dispatcher/Dispatcher.h"
#include "HttpServer/AsyncJobManager.h"
#include "HttpServer/HttpHandlerFactory.h"
#include "Rest/InitializeRest.h"
#include "Rest/OperationMode.h"
#include "Rest/Version.h"
#include "RestHandler/RestAdminLogHandler.h"
#include "RestHandler/RestAgencyHandler.h"
#include "RestHandler/RestAgencyPrivHandler.h"
#include "RestHandler/RestBatchHandler.h"
#include "RestHandler/RestCursorHandler.h"
#include "RestHandler/RestDebugHandler.h"
#include "RestHandler/RestDocumentHandler.h"
#include "RestHandler/RestEdgeHandler.h"
#include "RestHandler/RestEdgesHandler.h"
#include "RestHandler/RestExportHandler.h"
#include "RestHandler/RestHandlerCreator.h"
#include "RestHandler/RestImportHandler.h"
#include "RestHandler/RestJobHandler.h"
#include "RestHandler/RestPleaseUpgradeHandler.h"
#include "RestHandler/RestQueryCacheHandler.h"
#include "RestHandler/RestQueryHandler.h"
#include "RestHandler/RestReplicationHandler.h"
#include "RestHandler/RestShutdownHandler.h"
#include "RestHandler/RestSimpleHandler.h"
#include "RestHandler/RestSimpleQueryHandler.h"
#include "RestHandler/RestUploadHandler.h"
#include "RestHandler/RestVersionHandler.h"
#include "RestHandler/WorkMonitorHandler.h"
#include "RestServer/ConsoleThread.h"
#include "RestServer/VocbaseContext.h"
#include "Statistics/statistics.h"
#include "V8/V8LineEditor.h"
#include "V8/v8-conv.h"
#include "V8/v8-utils.h"
#include "VocBase/auth.h"
using namespace arangodb;
using namespace arangodb::basics;
using namespace arangodb::rest;
bool ALLOW_USE_DATABASE_IN_REST_ACTIONS;
bool IGNORE_DATAFILE_ERRORS;
ArangoServer::ArangoServer(int argc, char** argv)
@ -114,10 +18,8 @@ ArangoServer::ArangoServer(int argc, char** argv)
_v8Contexts(8),
_indexThreads(2),
_databasePath(),
_ignoreDatafileErrors(false),
_disableReplicationApplier(false),
_disableQueryTracking(false),
_throwCollectionNotLoadedError(false),
_foxxQueues(true),
_foxxQueuesPollInterval(1.0),
_server(nullptr),
@ -134,141 +36,13 @@ ArangoServer::ArangoServer(int argc, char** argv)
ArangoServer::~ArangoServer() {
delete _jobManager;
delete _server;
Nonce::destroy();
#warning TODO
// delete _applicationServer;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief starts the server
////////////////////////////////////////////////////////////////////////////////
int ArangoServer::start() {
#warning TODO
#if 0
if (_applicationServer == nullptr) {
buildApplicationServer();
}
if (_supervisorMode) {
return startupSupervisor();
} else if (_daemonMode) {
return startupDaemon();
} else {
_applicationServer->setupLogging(true, false, false);
if (!_pidFile.empty()) {
CheckPidFile(_pidFile);
WritePidFile(_pidFile, Thread::currentProcessId());
}
int res = startupServer();
if (!_pidFile.empty()) {
if (!FileUtils::remove(_pidFile)) {
LOG(DEBUG) << "cannot remove pid file '" << _pidFile << "'";
}
}
return res;
}
#endif
}
////////////////////////////////////////////////////////////////////////////////
/// @brief begins shutdown sequence
////////////////////////////////////////////////////////////////////////////////
void ArangoServer::beginShutdown() {
#warning TODO
#if 0
if (_applicationServer != nullptr) {
_applicationServer->beginShutdown();
}
#endif
}
////////////////////////////////////////////////////////////////////////////////
/// @brief converts list of size_t to string
////////////////////////////////////////////////////////////////////////////////
template <typename T>
static std::string ToString(std::vector<T> const& v) {
std::string result = "";
std::string sep = "[";
for (auto const& e : v) {
result += sep + std::to_string(e);
sep = ",";
}
return result + "]";
}
////////////////////////////////////////////////////////////////////////////////
/// @brief define "_api" and "_admin" handlers
////////////////////////////////////////////////////////////////////////////////
void ArangoServer::buildApplicationServer() {
#warning TODO
#if 0
// .............................................................................
// define server options
// .............................................................................
std::map<std::string, ProgramOptionsDescription> additional;
// command-line only options
additional["General Options:help-default"](
"console",
"do not start as server, start a JavaScript emergency console instead")(
// .............................................................................
// set language of default collator
// .............................................................................
// other options
"start-service", "used to start as windows service")(
"no-server", "do not start the server, if console is requested")(
"use-thread-affinity", &_threadAffinity,
"try to set thread affinity (0=disable, 1=disjunct, 2=overlap, "
"3=scheduler, 4=dispatcher)");
// javascript options
// .............................................................................
additional["Javascript Options:help-admin"](
"javascript.script", &_scriptFile,
"do not start as server, run script instead")(
"javascript.script-parameter", &_scriptParameters, "script parameter");
additional["Hidden Options"](
"javascript.unit-tests", &_unitTests,
"do not start as server, run unit tests instead");
// .............................................................................
// database options
// .............................................................................
(
"database.ignore-datafile-errors", &_ignoreDatafileErrors,
"load collections even if datafiles may contain errors")
(
(
"database.throw-collection-not-loaded-error",
&_throwCollectionNotLoadedError,
"throw an error when accessing a collection that is still loading");
// .............................................................................
// cluster options
// .............................................................................
_applicationCluster =
new ApplicationCluster(_server);
_applicationServer->addFeature(_applicationCluster);
@ -280,193 +54,12 @@ void ArangoServer::buildApplicationServer() {
_applicationAgency = new ApplicationAgency();
_applicationServer->addFeature(_applicationAgency);
// .............................................................................
// server options
// .............................................................................
// .............................................................................
// for this server we display our own options such as port to use
// .............................................................................
additional["Server Options:help-admin"](
"server.authenticate-system-only", &_authenticateSystemOnly,
"use HTTP authentication only for requests to /_api and /_admin")(
"server.disable-authentication", &_disableAuthentication,
"disable authentication for ALL client requests")
#ifdef ARANGODB_HAVE_DOMAIN_SOCKETS
("server.disable-authentication-unix-sockets",
&_disableAuthenticationUnixSockets,
"disable authentication for requests via UNIX domain sockets")
#endif
("server.disable-replication-applier", &_disableReplicationApplier,
"start with replication applier turned off")(
"server.allow-use-database", &ALLOW_USE_DATABASE_IN_REST_ACTIONS,
"allow change of database in REST actions, only needed for "
"unittests")(
"server.additional-threads", &_additionalThreads,
"number of threads in additional queues")(
"server.hide-product-header", &HttpResponse::HIDE_PRODUCT_HEADER,
"do not expose \"Server: ArangoDB\" header in HTTP responses")(
"server.foxx-queues", &_foxxQueues, "enable Foxx queues")(
"server.foxx-queues-poll-interval", &_foxxQueuesPollInterval,
"Foxx queue manager poll interval (in seconds)")(
"server.session-timeout", &VocbaseContext::ServerSessionTtl,
"timeout of web interface server sessions (in seconds)");
bool disableStatistics = false;
additional["Server Options:help-admin"]("server.disable-statistics",
&disableStatistics,
"turn off statistics gathering");
// .............................................................................
// endpoint server
// .............................................................................
_jobManager = new AsyncJobManager(ClusterCommRestCallback);
_applicationEndpointServer = new ApplicationEndpointServer(
_applicationServer,
_jobManager, "arangodb", &SetRequestContext, (void*)_server);
_applicationServer->addFeature(_applicationEndpointServer);
// .............................................................................
// parse the command line options - exit if there is a parse error
// .............................................................................
IGNORE_DATAFILE_ERRORS = _ignoreDatafileErrors;
// .............................................................................
// set language name
// .............................................................................
// ...........................................................................
// init nonces
// ...........................................................................
uint32_t optionNonceHashSize = 0;
if (optionNonceHashSize > 0) {
LOG(DEBUG) << "setting nonce hash size to " << optionNonceHashSize;
Nonce::create(optionNonceHashSize);
}
if (disableStatistics) {
TRI_ENABLE_STATISTICS = false;
}
// validate journal size
if (_defaultMaximalSize < TRI_JOURNAL_MINIMAL_SIZE) {
LOG(FATAL) << "invalid value for '--database.maximal-journal-size'. "
"expected at least "
<< TRI_JOURNAL_MINIMAL_SIZE;
FATAL_ERROR_EXIT();
}
// .............................................................................
// set directories and scripts
// .............................................................................
std::vector<std::string> arguments = _applicationServer->programArguments();
if (1 < arguments.size()) {
LOG(FATAL) << "expected at most one database directory, got "
<< arguments.size();
FATAL_ERROR_EXIT();
} else if (1 == arguments.size()) {
_databasePath = arguments[0];
}
// disable certain options in unittest or script mode
OperationMode::server_operation_mode_e mode =
OperationMode::determineMode(_applicationServer->programOptions());
if (mode == OperationMode::MODE_SCRIPT ||
mode == OperationMode::MODE_UNITTESTS) {
// testing disables authentication
_disableAuthentication = true;
}
TRI_SetThrowCollectionNotLoadedVocBase(nullptr,
_throwCollectionNotLoadedError);
// set global query tracking flag
arangodb::aql::Query::DisableQueryTracking(_disableQueryTracking);
// configure the query cache
{
std::pair<std::string, size_t> cacheProperties{_queryCacheMode,
_queryCacheMaxResults};
arangodb::aql::QueryCache::instance()->setProperties(cacheProperties);
}
// .............................................................................
// now run arangod
// .............................................................................
// dump version details
LOG(INFO) << "" << rest::Version::getVerboseVersionString();
// if we got here, then we are in server mode
// .............................................................................
// sanity checks
// .............................................................................
OperationMode::server_operation_mode_e mode =
OperationMode::determineMode(_applicationServer->programOptions());
if (mode != OperationMode::MODE_SERVER) {
LOG(FATAL) << "invalid mode. must not specify --console together with "
"--daemon or --supervisor";
FATAL_ERROR_EXIT();
}
#endif
}
int ArangoServer::startupServer() {
#warning TODO
#if 0
TRI_InitializeStatistics();
OperationMode::server_operation_mode_e mode =
OperationMode::determineMode(_applicationServer->programOptions());
bool startServer = true;
if (_applicationServer->programOptions().has("no-server")) {
startServer = false;
TRI_ENABLE_STATISTICS = false;
// --no-server disables all replication appliers
_disableReplicationApplier = true;
}
// initialize V8
if (!_applicationServer->programOptions().has("javascript.v8-contexts")) {
// the option was added recently so it's not always set
// the behavior in older ArangoDB was to create one V8 context per
// dispatcher thread
_v8Contexts = _dispatcherThreads;
}
if (_v8Contexts < 1) {
_v8Contexts = 1;
}
if (mode == OperationMode::MODE_CONSOLE) {
// one V8 instance is taken by the console
if (startServer) {
++_v8Contexts;
}
} else if (mode == OperationMode::MODE_UNITTESTS ||
mode == OperationMode::MODE_SCRIPT) {
if (_v8Contexts == 1) {
// at least two to allow both the test-runner and the scheduler to use a
// V8 instance
_v8Contexts = 2;
}
}
// .............................................................................
// prepare everything
@ -484,11 +77,6 @@ int ArangoServer::startupServer() {
// and finish prepare
_applicationServer->prepare2();
_pairForAqlHandler = new std::pair<ApplicationV8*, aql::QueryRegistry*>(
_applicationV8, _queryRegistry);
_pairForJobHandler = new std::pair<Dispatcher*, AsyncJobManager*>(
_applicationDispatcher->dispatcher(), _jobManager);
// ...........................................................................
// create endpoints and handlers
// ...........................................................................
@ -547,7 +135,6 @@ int ArangoServer::startupServer() {
std::cout << std::endl << TRI_BYE_MESSAGE << std::endl;
}
TRI_ShutdownStatistics();
return res;
#endif

View File

@ -0,0 +1,162 @@
////////////////////////////////////////////////////////////////////////////////
/// 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 Dr. Frank Celler
////////////////////////////////////////////////////////////////////////////////
#include "CheckVersionFeature.h"
#include "ApplicationFeatures/LoggerFeature.h"
#include "ProgramOptions/ProgramOptions.h"
#include "ProgramOptions/Section.h"
#include "RestServer/DatabaseFeature.h"
#include "V8Server/V8Context.h"
#include "V8Server/V8DealerFeature.h"
#include "V8Server/v8-query.h"
#include "V8Server/v8-vocbase.h"
#include "VocBase/server.h"
using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::basics;
using namespace arangodb::options;
CheckVersionFeature::CheckVersionFeature(ApplicationServer* server, int* result)
: ApplicationFeature(server, "checkVersion"),
_checkVersion(false),
_result(result) {
setOptional(false);
requiresElevatedPrivileges(false);
startsAfter("Database");
startsAfter("V8Dealer");
}
void CheckVersionFeature::collectOptions(
std::shared_ptr<ProgramOptions> options) {
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::collectOptions";
options->addSection(Section("database", "Configure the database",
"database options", false, false));
options->addHiddenOption("--database.check-version",
"checks the versions of the database and exit",
new BooleanParameter(&_checkVersion, false));
}
void CheckVersionFeature::validateOptions(
std::shared_ptr<ProgramOptions> options) {
if (!_checkVersion) {
return;
}
std::vector<std::string> disable{"Daemon", "Dispatcher", "Endpoint",
"Scheduler", "Shutdown", "Ssl",
"Supervisor"};
for (auto name : disable) {
auto feature = ApplicationServer::lookupFeature(name);
if (feature != nullptr) {
feature->disable();
}
}
LoggerFeature* logger =
dynamic_cast<LoggerFeature*>(ApplicationServer::lookupFeature("Logger"));
logger->setThreaded(false);
DatabaseFeature* database = dynamic_cast<DatabaseFeature*>(
ApplicationServer::lookupFeature("Database"));
database->disableReplicationApplier();
database->disableCompactor();
database->enableCheckVersion();
}
void CheckVersionFeature::start() {
if (!_checkVersion) {
return;
}
// check the version
checkVersion();
// and force shutdown
server()->beginShutdown();
}
void CheckVersionFeature::checkVersion() {
*_result = 1;
// run version check
LOG(TRACE) << "starting version check";
auto* vocbase = DatabaseFeature::DATABASE->vocbase();
// enter context and isolate
{
V8Context* context =
V8DealerFeature::DEALER->enterContext(vocbase, true, 0);
v8::HandleScope scope(context->_isolate);
auto localContext =
v8::Local<v8::Context>::New(context->_isolate, context->_context);
localContext->Enter();
{
v8::Context::Scope contextScope(localContext);
// run version-check script
LOG(DEBUG) << "running database version check";
// can do this without a lock as this is the startup
auto server = DatabaseFeature::DATABASE->server();
auto unuser = server->_databasesProtector.use();
auto theLists = server->_databasesLists.load();
for (auto& p : theLists->_databases) {
TRI_vocbase_t* vocbase = p.second;
// special check script to be run just once in first thread (not in all)
// but for all databases
int status = TRI_CheckDatabaseVersion(vocbase, localContext);
LOG(DEBUG) << "version check return status " << status;
if (status < 0) {
LOG(FATAL) << "Database version check failed for '" << vocbase->_name
<< "'. Please inspect the logs from any errors";
FATAL_ERROR_EXIT();
} else if (status == 3) {
*_result = 3;
} else if (status == 2 && *_result == 1) {
*_result = 2;
}
}
}
// issue #391: when invoked with --upgrade, the server will not always shut
// down
localContext->Exit();
V8DealerFeature::DEALER->exitContext(context);
}
if (*_result == 1) {
*_result = EXIT_SUCCESS;
}
}

View File

@ -0,0 +1,51 @@
////////////////////////////////////////////////////////////////////////////////
/// 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 Dr. Frank Celler
////////////////////////////////////////////////////////////////////////////////
#ifndef APPLICATION_FEATURES_CHECK_VERSION_FEATURE_H
#define APPLICATION_FEATURES_CHECK_VERSION_FEATURE_H 1
#include "ApplicationFeatures/ApplicationFeature.h"
namespace arangodb {
class CheckVersionFeature final
: public application_features::ApplicationFeature {
public:
explicit CheckVersionFeature(application_features::ApplicationServer* server,
int* result);
private:
bool _checkVersion;
public:
void collectOptions(std::shared_ptr<options::ProgramOptions>) override;
void validateOptions(std::shared_ptr<options::ProgramOptions>) override;
void start() override;
private:
void checkVersion();
private:
int* _result;
};
}
#endif

View File

@ -22,7 +22,6 @@
#include "DatabaseFeature.h"
#include "ApplicationFeatures/LoggerFeature.h"
#include "Aql/QueryRegistry.h"
#include "Basics/StringUtils.h"
#include "Basics/ThreadPool.h"
@ -30,7 +29,7 @@
#include "Logger/Logger.h"
#include "ProgramOptions/ProgramOptions.h"
#include "ProgramOptions/Section.h"
#include "V8Server/V8Context.h"
#include "Rest/Version.h"
#include "V8Server/V8DealerFeature.h"
#include "V8Server/v8-query.h"
#include "V8Server/v8-vocbase.h"
@ -44,6 +43,8 @@ using namespace arangodb::application_features;
using namespace arangodb::basics;
using namespace arangodb::options;
DatabaseFeature* DatabaseFeature::DATABASE = nullptr;
DatabaseFeature::DatabaseFeature(ApplicationServer* server)
: ApplicationFeature(server, "Database"),
_directory(""),
@ -51,22 +52,23 @@ DatabaseFeature::DatabaseFeature(ApplicationServer* server)
_queryTracking(true),
_queryCacheMode("off"),
_queryCacheEntries(128),
_checkVersion(false),
_upgrade(false),
_skipUpgrade(false),
_indexThreads(2),
_defaultWaitForSync(false),
_forceSyncProperties(true),
_ignoreDatafileErrors(false),
_vocbase(nullptr),
_server(nullptr),
_replicationApplier(true) {
_replicationApplier(true),
_disableCompactor(false),
_checkVersion(false) {
setOptional(false);
requiresElevatedPrivileges(false);
startsAfter("Language");
startsAfter("Logger");
startsAfter("Random");
startsAfter("Temp");
startsAfter("V8Dealer");
startsAfter("WorkMonitor");
}
@ -95,10 +97,6 @@ void DatabaseFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
"turned off",
new BooleanParameter(&_forceSyncProperties));
options->addHiddenOption("--database.check-version",
"checks the versions of the database and exit",
new BooleanParameter(&_checkVersion, false));
options->addOption("--database.upgrade", "perform a database upgrade",
new BooleanParameter(&_upgrade));
@ -110,12 +108,46 @@ void DatabaseFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
"threads to start for parallel background index creation",
new UInt64Parameter(&_indexThreads));
#warning TODO
#if 0
(
_ignoreDatafileErrors(false),
"database.ignore-datafile-errors", &_ignoreDatafileErrors,
"load collections even if datafiles may contain errors")
IGNORE_DATAFILE_ERRORS = _ignoreDatafileErrors;
_throwCollectionNotLoadedError(false),
(
"database.throw-collection-not-loaded-error",
&_throwCollectionNotLoadedError,
"throw an error when accessing a collection that is still loading");
("server.disable-replication-applier", &_disableReplicationApplier,
"start with replication applier turned off")
TRI_SetThrowCollectionNotLoadedVocBase(_throwCollectionNotLoadedError);
#endif
options->addSection(
Section("query", "Configure queries", "query options", false, false));
options->addOption("--query.tracking", "wether to track queries",
new BooleanParameter(&_queryTracking));
#warning TODO
#if 0
// set global query tracking flag
arangodb::aql::Query::DisableQueryTracking(_disableQueryTracking);
// configure the query cache
{
std::pair<std::string, size_t> cacheProperties{_queryCacheMode,
_queryCacheMaxResults};
arangodb::aql::QueryCache::instance()->setProperties(cacheProperties);
}
#endif
options->addOption("--query.cache-mode",
"mode for the AQL query cache (on, off, demand)",
new StringParameter(&_queryCacheMode));
@ -126,6 +158,8 @@ void DatabaseFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
}
void DatabaseFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::validateOptions";
if (_directory.empty()) {
LOG(ERR) << "no database path has been supplied, giving up, please use "
"the '--database.directory' option";
@ -147,15 +181,21 @@ void DatabaseFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
abortInvalidParameters();
}
#warning TODO
#if 0
if (_checkVersion && _upgrade) {
LOG(ERR) << "cannot specify both '--database.check-version' and "
"'--database.upgrade'";
abortInvalidParameters();
}
#endif
#warning TODO
#if 0
if (_checkVersion || _upgrade) {
_replicationApplier = false;
}
#endif
if (_upgrade && _skipUpgrade) {
LOG(ERR) << "cannot specify both '--database.upgrade' and "
@ -163,23 +203,57 @@ void DatabaseFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
abortInvalidParameters();
}
if (_checkVersion) {
ApplicationServer::lookupFeature("Daemon")->disable();
ApplicationServer::lookupFeature("Dispatcher")->disable();
ApplicationServer::lookupFeature("Endpoint")->disable();
ApplicationServer::lookupFeature("Scheduler")->disable();
ApplicationServer::lookupFeature("Ssl")->disable();
ApplicationServer::lookupFeature("Supervisor")->disable();
#warning TODO
#if 0
std::vector<std::string> arguments = _applicationServer->programArguments();
ApplicationServer::lookupFeature("Shutdown")->enable();
LoggerFeature* logger = dynamic_cast<LoggerFeature*>(
ApplicationServer::lookupFeature("Logger"));
logger->setThreaded(false);
if (1 < arguments.size()) {
LOG(FATAL) << "expected at most one database directory, got "
<< arguments.size();
FATAL_ERROR_EXIT();
} else if (1 == arguments.size()) {
_databasePath = arguments[0];
}
// disable certain options in unittest or script mode
OperationMode::server_operation_mode_e mode =
OperationMode::determineMode(_applicationServer->programOptions());
if (mode == OperationMode::MODE_SCRIPT ||
mode == OperationMode::MODE_UNITTESTS) {
// testing disables authentication
_disableAuthentication = true;
}
OperationMode::server_operation_mode_e mode =
OperationMode::determineMode(_applicationServer->programOptions());
if (mode != OperationMode::MODE_SERVER) {
LOG(FATAL) << "invalid mode. must not specify --console together with "
"--daemon or --supervisor";
FATAL_ERROR_EXIT();
}
OperationMode::server_operation_mode_e mode =
OperationMode::determineMode(_applicationServer->programOptions());
bool startServer = true;
if (_applicationServer->programOptions().has("no-server")) {
startServer = false;
TRI_ENABLE_STATISTICS = false;
// --no-server disables all replication appliers
_disableReplicationApplier = true;
}
#endif
}
void DatabaseFeature::start() {
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::start";
LOG(INFO) << "" << rest::Version::getVerboseVersionString();
// set singleton
DATABASE = this;
// create the server
TRI_InitServerGlobals();
_server.reset(new TRI_server_t());
@ -207,28 +281,11 @@ void DatabaseFeature::start() {
// fetch the system database and update the contexts
updateContexts();
// check the version and exit
if (_checkVersion) {
checkVersion();
FATAL_ERROR_EXIT();
}
// otherwise openthe log file for writing
if (!wal::LogfileManager::instance()->open()) {
LOG(FATAL) << "Unable to finish WAL recovery procedure";
FATAL_ERROR_EXIT();
}
// upgrade the database
upgradeDatabase();
}
void DatabaseFeature::stop() {
#warning TODO: we can get rid of this once V8DealerFeature is started AFTER the DatabaseFeature
// get rid of references in V8
V8DealerFeature::DEALER->shutdownContexts();
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::stop";
// clear the query registery
_server->_queryRegistry = nullptr;
@ -238,6 +295,9 @@ void DatabaseFeature::stop() {
// delete the server
TRI_StopServer(_server.get());
// clear singleton
DATABASE = nullptr;
LOG(INFO) << "ArangoDB has been shut down";
}
@ -254,17 +314,20 @@ void DatabaseFeature::updateContexts() {
auto server = _server.get();
auto vocbase = _vocbase;
V8DealerFeature::DEALER->updateContexts(
[&queryRegistry, &server, &vocbase](
v8::Isolate* isolate, v8::Handle<v8::Context> context, size_t i) {
TRI_InitV8VocBridge(isolate, context, queryRegistry, server, vocbase,
i);
TRI_InitV8Queries(isolate, context);
TRI_InitV8Cluster(isolate, context);
},
vocbase);
V8DealerFeature* dealer = dynamic_cast<V8DealerFeature*>(
ApplicationServer::lookupFeature("V8Dealer"));
V8DealerFeature::DEALER->loadJavascript(_vocbase);
if (dealer != nullptr) {
dealer->defineContextUpdate(
[queryRegistry, server, vocbase](
v8::Isolate* isolate, v8::Handle<v8::Context> context, size_t i) {
TRI_InitV8VocBridge(isolate, context, queryRegistry, server, vocbase,
i);
TRI_InitV8Queries(isolate, context);
TRI_InitV8Cluster(isolate, context);
},
vocbase);
}
}
void DatabaseFeature::shutdownCompactor() {
@ -289,69 +352,9 @@ void DatabaseFeature::shutdownCompactor() {
}
}
void DatabaseFeature::checkVersion() {
// run version check
int result = 1;
LOG(TRACE) << "starting version check";
// enter context and isolate
{
V8Context* context =
V8DealerFeature::DEALER->enterContext(_vocbase, true, 0);
v8::HandleScope scope(context->_isolate);
auto localContext =
v8::Local<v8::Context>::New(context->_isolate, context->_context);
localContext->Enter();
{
v8::Context::Scope contextScope(localContext);
// run version-check script
LOG(DEBUG) << "running database version check";
// can do this without a lock as this is the startup
auto unuser = _server->_databasesProtector.use();
auto theLists = _server->_databasesLists.load();
for (auto& p : theLists->_databases) {
TRI_vocbase_t* vocbase = p.second;
// special check script to be run just once in first thread (not in all)
// but for all databases
int status = TRI_CheckDatabaseVersion(vocbase, localContext);
LOG(DEBUG) << "version check return status " << status;
if (status < 0) {
LOG(FATAL) << "Database version check failed for '" << vocbase->_name
<< "'. Please inspect the logs from any errors";
FATAL_ERROR_EXIT();
} else if (status == 3) {
result = 3;
} else if (status == 2 && result == 1) {
result = 2;
}
}
}
// issue #391: when invoked with --upgrade, the server will not always shut
// down
localContext->Exit();
V8DealerFeature::DEALER->exitContext(context);
}
// regular shutdown... wait for all threads to finish
shutdownCompactor();
if (result == 1) {
TRI_EXIT_FUNCTION(EXIT_SUCCESS, nullptr);
} else {
TRI_EXIT_FUNCTION(result, nullptr);
}
}
void DatabaseFeature::upgradeDatabase() {
#warning TODO
#if 0
LOG(TRACE) << "starting database init/upgrade";
// enter context and isolate
@ -432,6 +435,7 @@ void DatabaseFeature::upgradeDatabase() {
// and return from the context
LOG(TRACE) << "finished database init/upgrade";
#endif
}
void DatabaseFeature::openDatabases() {
@ -461,9 +465,9 @@ void DatabaseFeature::openDatabases() {
bool const iterateMarkersOnOpen =
!wal::LogfileManager::instance()->hasFoundLastTick();
int res =
TRI_InitServer(_server.get(), _indexPool.get(), _databasePath.c_str(), nullptr,
&defaults, !_replicationApplier, iterateMarkersOnOpen);
int res = TRI_InitServer(
_server.get(), _indexPool.get(), _databasePath.c_str(), nullptr,
&defaults, !_replicationApplier, _disableCompactor, iterateMarkersOnOpen);
if (res != TRI_ERROR_NO_ERROR) {
LOG(FATAL) << "cannot create server instance: out of memory";

View File

@ -38,6 +38,9 @@ class QueryRegistry;
}
class DatabaseFeature final : public application_features::ApplicationFeature {
public:
static DatabaseFeature* DATABASE;
public:
explicit DatabaseFeature(application_features::ApplicationServer* server);
@ -49,6 +52,11 @@ class DatabaseFeature final : public application_features::ApplicationFeature {
public:
TRI_vocbase_t* vocbase() const { return _vocbase; }
TRI_server_t* server() const { return _server.get(); }
bool ignoreDatafileErrors() const { return _ignoreDatafileErrors; }
void disableReplicationApplier() { _replicationApplier = false; }
void disableCompactor() { _disableCompactor = true; }
void enableCheckVersion() { _checkVersion = true; }
private:
std::string _directory;
@ -56,15 +64,14 @@ class DatabaseFeature final : public application_features::ApplicationFeature {
bool _queryTracking;
std::string _queryCacheMode;
uint64_t _queryCacheEntries;
bool _checkVersion;
bool _upgrade;
bool _skipUpgrade;
uint64_t _indexThreads;
bool _defaultWaitForSync;
bool _forceSyncProperties;
bool _ignoreDatafileErrors;
private:
void checkVersion();
void openDatabases();
void closeDatabases();
void upgradeDatabase();
@ -78,6 +85,8 @@ class DatabaseFeature final : public application_features::ApplicationFeature {
std::string _databasePath;
std::unique_ptr<basics::ThreadPool> _indexPool;
bool _replicationApplier;
bool _disableCompactor;
bool _checkVersion;
};
}

View File

@ -0,0 +1,12 @@
options->addSection(Section("frontend", "Configure the frontend",
"frontend options", false, false));
options->addHiddenOption("--frontend.version-check",
"alert the user if new versions are available",
new BooleanParameter(&_frontendVersionCheck, false));
TRI_AddGlobalVariableVocbase(
isolate, localContext, TRI_V8_ASCII_STRING("FE_VERSION_CHECK"),
v8::Boolean::New(isolate, _frontendVersionCheck));

View File

@ -0,0 +1,17 @@
start:
// ...........................................................................
// init nonces
// ...........................................................................
uint32_t optionNonceHashSize = 0;
if (optionNonceHashSize > 0) {
LOG(DEBUG) << "setting nonce hash size to " << optionNonceHashSize;
Nonce::create(optionNonceHashSize);
}
stop:
Nonce::destroy();

View File

@ -87,6 +87,51 @@ void ServerFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
"default API compatibility version",
new Int32Parameter(&_defaultApiCompatibility));
#warning TODO
#if 0
additional["General Options:help-default"](
"console",
"do not start as server, start a JavaScript emergency console instead")(
// other options
"start-service", "used to start as windows service")(
"no-server", "do not start the server, if console is requested")(
"use-thread-affinity", &_threadAffinity,
"try to set thread affinity (0=disable, 1=disjunct, 2=overlap, "
"3=scheduler, 4=dispatcher)");
additional["Javascript Options:help-admin"](
"javascript.script", &_scriptFile,
"do not start as server, run script instead")(
"javascript.script-parameter", &_scriptParameters, "script parameter");
additional["Hidden Options"](
"javascript.unit-tests", &_unitTests,
"do not start as server, run unit tests instead");
(
"server.hide-product-header", &HttpResponse::HIDE_PRODUCT_HEADER,
"do not expose \"Server: ArangoDB\" header in HTTP responses")
"server.session-timeout", &VocbaseContext::ServerSessionTtl,
"timeout of web interface server sessions (in seconds)");
additional["Server Options:help-admin"](
"server.authenticate-system-only", &_authenticateSystemOnly,
"use HTTP authentication only for requests to /_api and /_admin")
(
"server.disable-authentication", &_disableAuthentication,
"disable authentication for ALL client requests")
#ifdef ARANGODB_HAVE_DOMAIN_SOCKETS
("server.disable-authentication-unix-sockets",
&_disableAuthenticationUnixSockets,
"disable authentication for requests via UNIX domain sockets")
#endif
#endif
options->addSection(
Section("http", "HttpServer features", "http options", false, false));
@ -117,6 +162,8 @@ void ServerFeature::prepare() {
}
void ServerFeature::start() {
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::start";
DatabaseFeature* database = dynamic_cast<DatabaseFeature*>(
application_features::ApplicationServer::lookupFeature("Database"));
@ -124,6 +171,28 @@ void ServerFeature::start() {
defineHandlers();
HttpHandlerFactory::setMaintenance(false);
#warning TODO
#if 0
_jobManager = new AsyncJobManager(ClusterCommRestCallback);
#endif
#warning TODO
#if 0
if (mode == OperationMode::MODE_CONSOLE) {
// one V8 instance is taken by the console
if (startServer) {
++_v8Contexts;
}
} else if (mode == OperationMode::MODE_UNITTESTS ||
mode == OperationMode::MODE_SCRIPT) {
if (_v8Contexts == 1) {
// at least two to allow both the test-runner and the scheduler to use a
// V8 instance
_v8Contexts = 2;
}
}
#endif
}
void ServerFeature::beginShutdown() {
@ -339,6 +408,19 @@ void ServerFeature::defineHandlers() {
#if 0
template <typename T>
static std::string ToString(std::vector<T> const& v) {
std::string result = "";
std::string sep = "[";
for (auto const& e : v) {
result += sep + std::to_string(e);
sep = ",";
}
return result + "]";
}
// .............................................................................
// try to figure out the thread affinity
// .............................................................................

View File

@ -0,0 +1,13 @@
bool disableStatistics = false;
additional["Server Options:help-admin"]("server.disable-statistics",
&disableStatistics,
"turn off statistics gathering");
if (disableStatistics) {
TRI_ENABLE_STATISTICS = false;
}
TRI_InitializeStatistics();
TRI_ShutdownStatistics();

View File

@ -0,0 +1,11 @@
start:
// otherwise openthe log file for writing
if (!wal::LogfileManager::instance()->open()) {
LOG(FATAL) << "Unable to finish WAL recovery procedure";
FATAL_ERROR_EXIT();
}
// upgrade the database
upgradeDatabase();

View File

@ -0,0 +1,7 @@
#warning TODO needs a database I assume
#if 0
for (size_t i = 0; i < _nrContexts; ++i) {
prepareV8Server(i, _startupFile);
}
#endif

View File

@ -37,6 +37,7 @@
#include "Basics/ArangoGlobalContext.h"
#include "Dispatcher/DispatcherFeature.h"
#include "ProgramOptions/ProgramOptions.h"
#include "RestServer/CheckVersionFeature.h"
#include "RestServer/DatabaseFeature.h"
#include "RestServer/EndpointFeature.h"
#include "RestServer/ServerFeature.h"
@ -60,7 +61,7 @@ ArangoServer* ArangoInstance = nullptr;
////////////////////////////////////////////////////////////////////////////////
#warning TODO
#if 0
#if 0
#ifdef _WIN32
extern bool TRI_ParseMoreArgs(int argc, char* argv[]);
extern void TRI_StartService(int argc, char* argv[]);
@ -89,6 +90,7 @@ int main(int argc, char* argv[]) {
int ret = EXIT_FAILURE;
server.addFeature(new CheckVersionFeature(&server, &ret));
server.addFeature(new ConfigFeature(&server, name));
server.addFeature(new DatabaseFeature(&server));
server.addFeature(new DispatcherFeature(&server));
@ -108,10 +110,13 @@ int main(int argc, char* argv[]) {
logger->setThreaded(true);
server.addFeature(logger.release());
#warning todo
#if 0
std::unique_ptr<ShutdownFeature> shutdown =
std::make_unique<ShutdownFeature>(&server, "Server");
shutdown->disable();
server.addFeature(shutdown.release());
#endif
#ifdef ARANGODB_HAVE_FORK
server.addFeature(new DaemonFeature(&server));
@ -129,7 +134,6 @@ int main(int argc, char* argv[]) {
return context.exit(ret);
}
#warning TODO
#if 0

View File

@ -89,675 +89,6 @@ ApplicationV8::ApplicationV8(TRI_server_t* server,
TRI_ASSERT(_server != nullptr);
}
ApplicationV8::~ApplicationV8() {}
////////////////////////////////////////////////////////////////////////////////
/// @brief sets the concurrency
////////////////////////////////////////////////////////////////////////////////
void ApplicationV8::setConcurrency(size_t n) {
_nrInstances = n;
_busyContexts.reserve(n);
_freeContexts.reserve(n);
_dirtyContexts.reserve(n);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief sets the database
////////////////////////////////////////////////////////////////////////////////
void ApplicationV8::setVocbase(TRI_vocbase_t* vocbase) { _vocbase = vocbase; }
////////////////////////////////////////////////////////////////////////////////
/// @brief runs the garbage collection
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief disables actions
////////////////////////////////////////////////////////////////////////////////
void ApplicationV8::disableActions() { _useActions = false; }
////////////////////////////////////////////////////////////////////////////////
/// @brief upgrades the database
////////////////////////////////////////////////////////////////////////////////
<<<<<<< HEAD
=======
void ApplicationV8::upgradeDatabase(bool skip, bool perform) {
LOG(TRACE) << "starting database init/upgrade";
// enter context and isolate
V8Context* context = _contexts[0];
TRI_ASSERT(context->_locker == nullptr);
context->_locker = new v8::Locker(context->isolate);
auto isolate = context->isolate;
isolate->Enter();
{
v8::HandleScope scope(isolate);
auto localContext = v8::Local<v8::Context>::New(isolate, context->_context);
localContext->Enter();
{
v8::Context::Scope contextScope(localContext);
// run upgrade script
if (!skip) {
LOG(DEBUG) << "running database init/upgrade";
auto unuser(_server->_databasesProtector.use());
auto theLists = _server->_databasesLists.load();
for (auto& p : theLists->_databases) {
TRI_vocbase_t* vocbase = p.second;
// special check script to be run just once in first thread (not in
// all)
// but for all databases
v8::HandleScope scope(isolate);
v8::Handle<v8::Object> args = v8::Object::New(isolate);
args->Set(TRI_V8_ASCII_STRING("upgrade"),
v8::Boolean::New(isolate, perform));
localContext->Global()->Set(TRI_V8_ASCII_STRING("UPGRADE_ARGS"),
args);
bool ok = TRI_UpgradeDatabase(vocbase, &_startupLoader, localContext);
if (!ok) {
if (localContext->Global()->Has(
TRI_V8_ASCII_STRING("UPGRADE_STARTED"))) {
localContext->Exit();
if (perform) {
LOG(FATAL) << "Database '" << vocbase->_name
<< "' upgrade failed. Please inspect the logs from "
"the upgrade procedure";
FATAL_ERROR_EXIT();
} else {
LOG(FATAL)
<< "Database '" << vocbase->_name
<< "' needs upgrade. Please start the server with the "
"--upgrade option";
FATAL_ERROR_EXIT();
}
} else {
LOG(FATAL) << "JavaScript error during server start";
FATAL_ERROR_EXIT();
}
LOG(DEBUG) << "database '" << vocbase->_name
<< "' init/upgrade done";
}
}
}
}
// finally leave the context. otherwise v8 will crash with assertion failure
// when we delete
// the context locker below
localContext->Exit();
}
isolate->Exit();
delete context->_locker;
context->_locker = nullptr;
if (perform) {
// issue #391: when invoked with --upgrade, the server will not always shut
// down
LOG(INFO) << "database upgrade passed";
// regular shutdown... wait for all threads to finish
auto unuser(_server->_databasesProtector.use());
auto theLists = _server->_databasesLists.load();
for (auto& p : theLists->_databases) {
TRI_vocbase_t* vocbase = p.second;
vocbase->_state = 2;
int res = TRI_ERROR_NO_ERROR;
res |= TRI_StopCompactorVocBase(vocbase);
vocbase->_state = 3;
res |= TRI_JoinThread(&vocbase->_cleanup);
if (res != TRI_ERROR_NO_ERROR) {
LOG(ERR) << "unable to join database threads for database '"
<< vocbase->_name << "'";
}
}
LOG(INFO) << "finished";
TRI_EXIT_FUNCTION(EXIT_SUCCESS, nullptr);
} else {
// and return from the context
LOG(TRACE) << "finished database init/upgrade";
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief runs the version check
////////////////////////////////////////////////////////////////////////////////
void ApplicationV8::versionCheck() {
int result = 1;
LOG(TRACE) << "starting version check";
// enter context and isolate
V8Context* context = _contexts[0];
TRI_ASSERT(context->_locker == nullptr);
context->_locker = new v8::Locker(context->isolate);
auto isolate = context->isolate;
isolate->Enter();
{
v8::HandleScope scope(isolate);
auto localContext = v8::Local<v8::Context>::New(isolate, context->_context);
localContext->Enter();
v8::Context::Scope contextScope(localContext);
// run upgrade script
LOG(DEBUG) << "running database version check";
// can do this without a lock as this is the startup
auto unuser(_server->_databasesProtector.use());
auto theLists = _server->_databasesLists.load();
for (auto& p : theLists->_databases) {
TRI_vocbase_t* vocbase = p.second;
// special check script to be run just once in first thread (not in all)
// but for all databases
int status =
TRI_CheckDatabaseVersion(vocbase, &_startupLoader, localContext);
if (status < 0) {
LOG(FATAL) << "Database version check failed for '" << vocbase->_name
<< "'. Please inspect the logs from any errors";
FATAL_ERROR_EXIT();
} else if (status == 3) {
result = 3;
} else if (status == 2 && result == 1) {
result = 2;
}
}
// issue #391: when invoked with --upgrade, the server will not always shut
// down
localContext->Exit();
}
isolate->Exit();
delete context->_locker;
context->_locker = nullptr;
// regular shutdown... wait for all threads to finish
auto unuser(_server->_databasesProtector.use());
auto theLists = _server->_databasesLists.load();
for (auto& p : theLists->_databases) {
TRI_vocbase_t* vocbase = p.second;
vocbase->_state = 2;
int res = TRI_ERROR_NO_ERROR;
res |= TRI_StopCompactorVocBase(vocbase);
vocbase->_state = 3;
res |= TRI_JoinThread(&vocbase->_cleanup);
if (res != TRI_ERROR_NO_ERROR) {
LOG(ERR) << "unable to join database threads for database '"
<< vocbase->_name << "'";
}
}
if (result == 1) {
TRI_EXIT_FUNCTION(EXIT_SUCCESS, nullptr);
} else {
TRI_EXIT_FUNCTION(result, nullptr);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief prepares the server
////////////////////////////////////////////////////////////////////////////////
void ApplicationV8::prepareServer() {
size_t nrInstances = _nrInstances;
for (size_t i = 0; i < nrInstances; ++i) {
prepareV8Server(i, _startupFile);
}
}
void ApplicationV8::setupOptions(
std::map<std::string, basics::ProgramOptionsDescription>& options) {
// clang-format off
options["Javascript Options:help-admin"]
("javascript.gc-interval", &_gcInterval,
"JavaScript request-based garbage collection interval (each x requests)")
("javascript.gc-frequency", &_gcFrequency,
"JavaScript time-based garbage collection frequency (each x seconds)")
("javascript.app-path", &_appPath, "directory for Foxx applications")
("javascript.startup-directory", &_startupPath,
"path to the directory containing JavaScript startup scripts")
("javascript.v8-options", &_v8Options, "options to pass to v8")
;
options["Hidden Options"]
("frontend-version-check", &_frontendVersionCheck,
"show new versions in the frontend")
;
// clang-format on
}
bool ApplicationV8::prepare() {
// check the startup path
if (_startupPath.empty()) {
LOG(FATAL)
<< "no 'javascript.startup-directory' has been supplied, giving up";
FATAL_ERROR_EXIT();
}
// remove trailing / from path
_startupPath = StringUtils::rTrim(_startupPath, TRI_DIR_SEPARATOR_STR);
// dump paths
{
std::vector<std::string> paths;
paths.push_back(std::string("startup '" + _startupPath + "'"));
if (!_appPath.empty()) {
paths.push_back(std::string("application '" + _appPath + "'"));
}
LOG(INFO) << "JavaScript using " << StringUtils::join(paths, ", ");
}
// check whether app-path was specified
if (_appPath.empty()) {
LOG(FATAL) << "no value has been specified for --javascript.app-path.";
FATAL_ERROR_EXIT();
}
_startupLoader.setDirectory(_startupPath);
ServerState::instance()->setJavaScriptPath(_startupPath);
// add v8 options
if (!_v8Options.empty()) {
LOG(INFO) << "using V8 options '" << _v8Options << "'";
v8::V8::SetFlagsFromString(_v8Options.c_str(), (int)_v8Options.size());
}
#ifdef TRI_FORCE_ARMV6
std::string const forceARMv6 = "--noenable-armv7";
v8::V8::SetFlagsFromString(forceARMv6.c_str(), (int)forceARMv6.size());
#endif
// use a minimum of 1 second for GC
if (_gcFrequency < 1) {
_gcFrequency = 1;
}
return true;
}
bool ApplicationV8::prepare2() {
size_t nrInstances = _nrInstances;
v8::V8::InitializeICU();
TRI_ASSERT(_platform == nullptr);
_platform = v8::platform::CreateDefaultPlatform();
v8::V8::InitializePlatform(_platform);
v8::V8::Initialize();
_allocator.reset(new ArrayBufferAllocator);
// setup instances
{
CONDITION_LOCKER(guard, _contextCondition);
_contexts = new V8Context*[nrInstances];
}
std::vector<std::thread> threads;
_ok = true;
for (size_t i = 0; i < nrInstances; ++i) {
threads.push_back(std::thread(&ApplicationV8::prepareV8InstanceInThread,
this, i, _useActions));
}
for (size_t i = 0; i < nrInstances; ++i) {
threads[i].join();
}
return _ok;
}
bool ApplicationV8::start() {
TRI_ASSERT(_gcThread == nullptr);
_gcThread = new V8GcThread(this);
_gcThread->start();
_gcFinished = false;
return true;
}
void ApplicationV8::close() {
_stopping = true;
_contextCondition.broadcast();
// unregister all tasks
if (_scheduler != nullptr && _scheduler->scheduler() != nullptr) {
_scheduler->scheduler()->unregisterUserTasks();
}
// wait for all contexts to finish
CONDITION_LOCKER(guard, _contextCondition);
for (size_t n = 0; n < 10 * 5; ++n) {
if (_busyContexts.empty()) {
LOG(DEBUG) << "no busy V8 contexts";
break;
}
LOG(DEBUG) << "waiting for " << _busyContexts.size()
<< " busy V8 contexts to finish";
guard.wait(100000);
}
}
void ApplicationV8::stop() {
// send all busy contexts a termate signal
{
CONDITION_LOCKER(guard, _contextCondition);
for (auto& it : _busyContexts) {
LOG(WARN) << "sending termination signal to V8 context";
v8::V8::TerminateExecution(it->isolate);
}
}
// wait for one minute
{
CONDITION_LOCKER(guard, _contextCondition);
for (size_t n = 0; n < 10 * 60; ++n) {
if (_busyContexts.empty()) {
break;
}
guard.wait(100000);
}
}
LOG(DEBUG) << "Waiting for GC Thread to finish action";
// wait until garbage collector thread is done
while (!_gcFinished) {
usleep(10000);
}
LOG(DEBUG) << "Commanding GC Thread to terminate";
// stop GC thread
_gcThread->beginShutdown();
// shutdown all instances
{
CONDITION_LOCKER(guard, _contextCondition);
size_t nrInstances = _nrInstances;
for (size_t i = 0; i < nrInstances; ++i) {
shutdownV8Instance(i);
}
delete[] _contexts;
}
LOG(DEBUG) << "Shutting down V8";
v8::V8::Dispose();
v8::V8::ShutdownPlatform();
TRI_ASSERT(_platform != nullptr);
delete _platform;
// delete GC thread after all action threads have been stopped
delete _gcThread;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief determine which of the free contexts should be picked for the GC
////////////////////////////////////////////////////////////////////////////////
ApplicationV8::V8Context* ApplicationV8::pickFreeContextForGc() {
int const n = (int)_freeContexts.size();
if (n == 0) {
// this is easy...
return nullptr;
}
V8GcThread* gc = dynamic_cast<V8GcThread*>(_gcThread);
TRI_ASSERT(gc != nullptr);
// we got more than 1 context to clean up, pick the one with the "oldest" GC
// stamp
int pickedContextNr =
-1; // index of context with lowest GC stamp, -1 means "none"
for (int i = n - 1; i > 0; --i) {
// check if there's actually anything to clean up in the context
if (_freeContexts[i]->_numExecutions < 50 &&
!_freeContexts[i]->_hasActiveExternals) {
continue;
}
// compare last GC stamp
if (pickedContextNr == -1 ||
_freeContexts[i]->_lastGcStamp <=
_freeContexts[pickedContextNr]->_lastGcStamp) {
pickedContextNr = i;
}
}
// we now have the context to clean up in pickedContextNr
if (pickedContextNr == -1) {
// no context found
return nullptr;
}
// this is the context to clean up
V8Context* context = _freeContexts[pickedContextNr];
TRI_ASSERT(context != nullptr);
// now compare its last GC timestamp with the last global GC stamp
if (context->_lastGcStamp + _gcFrequency >= gc->getLastGcStamp()) {
// no need yet to clean up the context
return nullptr;
}
// we'll pop the context from the vector. the context might be at
// any position in the vector so we need to move the other elements
// around
if (n > 1) {
for (int i = pickedContextNr; i < n - 1; ++i) {
_freeContexts[i] = _freeContexts[i + 1];
}
}
_freeContexts.pop_back();
return context;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief prepares a V8 instance
////////////////////////////////////////////////////////////////////////////////
bool ApplicationV8::prepareV8Instance(size_t i, bool useActions) {
CONDITION_LOCKER(guard, _contextCondition);
std::vector<std::string> files{ "server/initialize.js" };
v8::Isolate::CreateParams createParams;
createParams.array_buffer_allocator = _allocator.get();
v8::Isolate* isolate = v8::Isolate::New(createParams);
V8Context* context = _contexts[i] = new V8Context();
if (context == nullptr) {
LOG(FATAL) << "cannot initialize V8 context #" << i;
FATAL_ERROR_EXIT();
}
TRI_ASSERT(context->_locker == nullptr);
// enter a new isolate
bool hasActiveExternals = false;
context->_id = i;
context->isolate = isolate;
TRI_ASSERT(context->_locker == nullptr);
context->_locker = new v8::Locker(isolate);
context->isolate->Enter();
// create the context
{
v8::HandleScope handle_scope(isolate);
v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
v8::Persistent<v8::Context> persistentContext;
persistentContext.Reset(isolate, v8::Context::New(isolate, 0, global));
auto localContext = v8::Local<v8::Context>::New(isolate, persistentContext);
localContext->Enter();
{
v8::Context::Scope contextScope(localContext);
context->_context.Reset(context->isolate, localContext);
if (context->_context.IsEmpty()) {
LOG(FATAL) << "cannot initialize V8 engine";
FATAL_ERROR_EXIT();
}
v8::Handle<v8::Object> globalObj = localContext->Global();
globalObj->Set(TRI_V8_ASCII_STRING("GLOBAL"), globalObj);
globalObj->Set(TRI_V8_ASCII_STRING("global"), globalObj);
globalObj->Set(TRI_V8_ASCII_STRING("root"), globalObj);
TRI_InitV8VocBridge(isolate, this, localContext, _queryRegistry, _server,
_vocbase, &_startupLoader, i);
TRI_InitV8Queries(isolate, localContext);
TRI_InitV8UserStructures(isolate, localContext);
TRI_InitV8Cluster(isolate, localContext);
if (_dispatcher->dispatcher() != nullptr) {
// don't initialize dispatcher if there is no scheduler (server started
// with --no-server option)
TRI_InitV8Dispatcher(isolate, localContext, _vocbase, _scheduler,
_dispatcher, this);
}
if (useActions) {
TRI_InitV8Actions(isolate, localContext, _vocbase, this);
}
std::string modulesPath = _startupPath + TRI_DIR_SEPARATOR_STR +
"server" + TRI_DIR_SEPARATOR_STR + "modules;" +
_startupPath + TRI_DIR_SEPARATOR_STR +
"common" + TRI_DIR_SEPARATOR_STR + "modules;" +
_startupPath + TRI_DIR_SEPARATOR_STR + "node";
TRI_InitV8Buffer(isolate, localContext);
TRI_InitV8Conversions(localContext);
TRI_InitV8Utils(isolate, localContext, _startupPath, modulesPath);
TRI_InitV8DebugUtils(isolate, localContext, _startupPath, modulesPath);
TRI_InitV8Shell(isolate, localContext);
{
v8::HandleScope scope(isolate);
TRI_AddGlobalVariableVocbase(isolate, localContext,
TRI_V8_ASCII_STRING("APP_PATH"),
TRI_V8_STD_STRING(_appPath));
TRI_AddGlobalVariableVocbase(
isolate, localContext, TRI_V8_ASCII_STRING("FE_VERSION_CHECK"),
v8::Boolean::New(isolate, _frontendVersionCheck));
for (auto j : _definedBooleans) {
localContext->Global()->ForceSet(TRI_V8_STD_STRING(j.first),
v8::Boolean::New(isolate, j.second),
v8::ReadOnly);
}
for (auto j : _definedDoubles) {
localContext->Global()->ForceSet(TRI_V8_STD_STRING(j.first),
v8::Number::New(isolate, j.second),
v8::ReadOnly);
}
}
// load all init files
for (auto& file : files) {
switch (_startupLoader.loadScript(isolate, localContext, file)) {
case JSLoader::eSuccess:
LOG(TRACE) << "loaded JavaScript file '" << file << "'";
break;
case JSLoader::eFailLoad:
LOG(FATAL) << "cannot load JavaScript file '" << file << "'";
FATAL_ERROR_EXIT();
break;
case JSLoader::eFailExecute:
LOG(FATAL) << "error during execution of JavaScript file '" << file
<< "'";
FATAL_ERROR_EXIT();
break;
}
}
TRI_GET_GLOBALS();
hasActiveExternals = v8g->hasActiveExternals();
}
// and return from the context
localContext->Exit();
}
isolate->Exit();
delete context->_locker;
context->_locker = nullptr;
// some random delay value to add as an initial garbage collection offset
// this avoids collecting all contexts at the very same time
double const randomWait = fmod(static_cast<double>(TRI_UInt32Random()), 15.0);
// initialize garbage collection for context
context->_numExecutions = 0;
context->_hasActiveExternals = hasActiveExternals;
context->_lastGcStamp = TRI_microtime() + randomWait;
LOG(TRACE) << "initialized V8 context #" << i;
_freeContexts.emplace_back(context);
return true;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief prepares a V8 instance, multi-threaded version calling the above
////////////////////////////////////////////////////////////////////////////////
void ApplicationV8::prepareV8InstanceInThread(size_t i, bool useAction) {
if (!prepareV8Instance(i, useAction)) {
_ok = false;
}
}
>>>>>>> f0bb30c3f7865ea1d2c41bb8a110652e0c8a2c41
////////////////////////////////////////////////////////////////////////////////
/// @brief prepares the V8 server
////////////////////////////////////////////////////////////////////////////////

View File

@ -32,6 +32,7 @@
#include "Dispatcher/DispatcherThread.h"
#include "ProgramOptions/ProgramOptions.h"
#include "ProgramOptions/Section.h"
#include "RestServer/DatabaseFeature.h"
#include "Utils/V8TransactionContext.h"
#include "V8/v8-buffer.h"
#include "V8/v8-conv.h"
@ -47,6 +48,7 @@
#include "3rdParty/valgrind/valgrind.h"
using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::basics;
using namespace arangodb::options;
@ -90,15 +92,17 @@ V8DealerFeature::V8DealerFeature(
_ok(false),
_gcThread(nullptr),
_stopping(false),
_gcFinished(false),
_contexts(nullptr) {
_gcFinished(false) {
setOptional(false);
requiresElevatedPrivileges(false);
startsAfter("V8Platform");
startsAfter("WorkMonitor");
startsAfter("Database");
}
void V8DealerFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::collectOptions";
options->addSection(Section("javascript", "Configure the Javascript engine",
"javascript options", false, false));
@ -124,13 +128,6 @@ void V8DealerFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
"--javascript.v8-contexts",
"number of V8 contexts that are created for executing JavaScript actions",
new UInt64Parameter(&_nrContexts));
options->addSection(Section("frontend", "Configure the frontend",
"frontend options", false, false));
options->addHiddenOption("--frontend.version-check",
"alert the user if new versions are available",
new BooleanParameter(&_frontendVersionCheck, false));
}
void V8DealerFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
@ -143,9 +140,12 @@ void V8DealerFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
FATAL_ERROR_EXIT();
}
// remove trailing / from path
// remove trailing / from path and set path
_startupPath = StringUtils::rTrim(_startupPath, TRI_DIR_SEPARATOR_STR);
_startupLoader.setDirectory(_startupPath);
ServerState::instance()->setJavaScriptPath(_startupPath);
// dump paths
{
std::vector<std::string> paths;
@ -165,22 +165,26 @@ void V8DealerFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
FATAL_ERROR_EXIT();
}
_startupLoader.setDirectory(_startupPath);
ServerState::instance()->setJavaScriptPath(_startupPath);
// use a minimum of 1 second for GC
if (_gcFrequency < 1) {
_gcFrequency = 1;
}
// set a minimum of V8 contexts
if (_nrContexts < 1) {
_nrContexts = 1;
}
}
void V8DealerFeature::start() {
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::start";
DEALER = this;
// setup instances
{
CONDITION_LOCKER(guard, _contextCondition);
_contexts = new V8Context*[_nrContexts];
_contexts.resize(_nrContexts, nullptr);
_busyContexts.reserve(_nrContexts);
_freeContexts.reserve(_nrContexts);
@ -191,16 +195,24 @@ void V8DealerFeature::start() {
initializeContext(i);
}
#warning TODO needs a database I assume
#if 0
for (size_t i = 0; i < _nrContexts; ++i) {
prepareV8Server(i, _startupFile);
}
#endif
applyContextUpdates();
DatabaseFeature* database = dynamic_cast<DatabaseFeature*>(
ApplicationServer::lookupFeature("Database"));
loadJavascript(database->vocbase());
}
void V8DealerFeature::stop() {
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::stop";
shutdownContexts();
// delete GC thread after all action threads have been stopped
if (_gcThread != nullptr) {
delete _gcThread;
}
DEALER = nullptr;
}
@ -627,26 +639,32 @@ void V8DealerFeature::exitContext(V8Context* context) {
}
}
void V8DealerFeature::updateContexts(
void V8DealerFeature::defineContextUpdate(
std::function<void(v8::Isolate*, v8::Handle<v8::Context>, size_t)> func,
TRI_vocbase_t* vocbase) {
_contextUpdates.emplace_back(func, vocbase);
}
void V8DealerFeature::applyContextUpdates() {
for (size_t i = 0; i < _nrContexts; ++i) {
V8Context* context =
V8DealerFeature::DEALER->enterContext(vocbase, true, 0);
v8::HandleScope scope(context->_isolate);
auto localContext =
v8::Local<v8::Context>::New(context->_isolate, context->_context);
localContext->Enter();
for (auto& p : _contextUpdates) {
V8Context* context =
V8DealerFeature::DEALER->enterContext(p.second, true, 0);
v8::HandleScope scope(context->_isolate);
auto localContext =
v8::Local<v8::Context>::New(context->_isolate, context->_context);
localContext->Enter();
{
v8::Context::Scope contextScope(localContext);
func(context->_isolate, localContext, i);
{
v8::Context::Scope contextScope(localContext);
p.first(context->_isolate, localContext, i);
}
localContext->Exit();
V8DealerFeature::DEALER->exitContext(context);
LOG(TRACE) << "updated V8 context #" << i;
}
localContext->Exit();
V8DealerFeature::DEALER->exitContext(context);
LOG(TRACE) << "updated V8 context #" << i;
}
}
@ -694,6 +712,11 @@ void V8DealerFeature::shutdownContexts() {
}
}
if (!_busyContexts.empty()) {
LOG(FATAL) << "cannot shutdown V8 contexts";
FATAL_ERROR_EXIT();
}
// stop GC thread
if (_gcThread != nullptr) {
LOG(DEBUG) << "Waiting for GC Thread to finish action";
@ -711,19 +734,14 @@ void V8DealerFeature::shutdownContexts() {
{
CONDITION_LOCKER(guard, _contextCondition);
for (size_t i = 0; i < _nrContexts; ++i) {
shutdownV8Instance(i);
for (auto context : _contexts) {
shutdownV8Instance(context);
}
delete[] _contexts;
_contexts.clear();
}
LOG(DEBUG) << "Shutting down V8";
// delete GC thread after all action threads have been stopped
if (_gcThread != nullptr) {
delete _gcThread;
}
LOG(DEBUG) << "V( contexts are shut down";
}
V8Context* V8DealerFeature::pickFreeContextForGc() {
@ -842,31 +860,13 @@ void V8DealerFeature::initializeContext(size_t i) {
globalObj->Set(TRI_V8_ASCII_STRING("global"), globalObj);
globalObj->Set(TRI_V8_ASCII_STRING("root"), globalObj);
TRI_InitV8UserStructures(isolate, localContext);
#warning TODO
#if 0
if (_dispatcher->dispatcher() != nullptr) {
// don't initialize dispatcher if there is no scheduler (server started
// with --no-server option)
TRI_InitV8Dispatcher(isolate, localContext, _vocbase, _scheduler,
_dispatcher, this);
}
#endif
#warning TODO
#if 0
if (_useActions) {
TRI_InitV8Actions(isolate, localContext, _vocbase, this);
}
#endif
std::string modulesPath = _startupPath + TRI_DIR_SEPARATOR_STR +
"server" + TRI_DIR_SEPARATOR_STR + "modules;" +
_startupPath + TRI_DIR_SEPARATOR_STR +
"common" + TRI_DIR_SEPARATOR_STR + "modules;" +
_startupPath + TRI_DIR_SEPARATOR_STR + "node";
TRI_InitV8UserStructures(isolate, localContext);
TRI_InitV8Buffer(isolate, localContext);
TRI_InitV8Conversions(localContext);
TRI_InitV8Utils(isolate, localContext, _startupPath, modulesPath);
@ -879,9 +879,6 @@ void V8DealerFeature::initializeContext(size_t i) {
TRI_AddGlobalVariableVocbase(isolate, localContext,
TRI_V8_ASCII_STRING("APP_PATH"),
TRI_V8_STD_STRING(_appPath));
TRI_AddGlobalVariableVocbase(
isolate, localContext, TRI_V8_ASCII_STRING("FE_VERSION_CHECK"),
v8::Boolean::New(isolate, _frontendVersionCheck));
for (auto j : _definedBooleans) {
localContext->Global()->ForceSet(TRI_V8_STD_STRING(j.first),
@ -894,6 +891,12 @@ void V8DealerFeature::initializeContext(size_t i) {
v8::Number::New(isolate, j.second),
v8::ReadOnly);
}
for (auto j : _definedStrings) {
localContext->Global()->ForceSet(TRI_V8_STD_STRING(j.first),
TRI_V8_STD_STRING(j.second),
v8::ReadOnly);
}
}
}
@ -959,10 +962,8 @@ void V8DealerFeature::loadJavascriptFiles(TRI_vocbase_t* vocbase, size_t i) {
LOG(TRACE) << "loaded Javascript files for V8 context #" << i;
}
void V8DealerFeature::shutdownV8Instance(size_t i) {
LOG(TRACE) << "shutting down V8 context #" << i;
V8Context* context = _contexts[i];
void V8DealerFeature::shutdownV8Instance(V8Context* context) {
LOG(TRACE) << "shutting down V8 context #" << context->_id;
auto isolate = context->_isolate;
isolate->Enter();
@ -1016,5 +1017,5 @@ void V8DealerFeature::shutdownV8Instance(size_t i) {
delete context;
LOG(TRACE) << "closed V8 context #" << i;
LOG(TRACE) << "closed V8 context #" << context->_id;
}

View File

@ -67,9 +67,10 @@ class V8DealerFeature final : public application_features::ApplicationFeature {
ssize_t forceContext = -1);
void exitContext(V8Context*);
void updateContexts(
void defineContextUpdate(
std::function<void(v8::Isolate*, v8::Handle<v8::Context>, size_t)>,
TRI_vocbase_t*);
void applyContextUpdates();
void shutdownContexts();
@ -77,7 +78,7 @@ class V8DealerFeature final : public application_features::ApplicationFeature {
V8Context* pickFreeContextForGc();
void initializeContext(size_t);
void loadJavascriptFiles(TRI_vocbase_t*, size_t);
void shutdownV8Instance(size_t);
void shutdownV8Instance(V8Context*);
private:
bool _useActions;
@ -87,7 +88,7 @@ class V8DealerFeature final : public application_features::ApplicationFeature {
std::atomic<bool> _stopping;
std::atomic<bool> _gcFinished;
V8Context** _contexts;
std::vector<V8Context*> _contexts;
basics::ConditionVariable _contextCondition;
std::vector<V8Context*> _freeContexts;
std::vector<V8Context*> _dirtyContexts;
@ -97,6 +98,11 @@ class V8DealerFeature final : public application_features::ApplicationFeature {
std::map<std::string, bool> _definedBooleans;
std::map<std::string, double> _definedDoubles;
std::map<std::string, std::string> _definedStrings;
std::vector<std::pair<
std::function<void(v8::Isolate*, v8::Handle<v8::Context>, size_t)>,
TRI_vocbase_t*>> _contextUpdates;
};
}

View File

@ -22,6 +22,8 @@
////////////////////////////////////////////////////////////////////////////////
#include "v8-actions.h"
#include "Actions/ActionFeature.h"
#include "Actions/actions.h"
#include "Basics/MutexLocker.h"
#include "Basics/ReadLocker.h"
@ -30,11 +32,11 @@
#include "Basics/conversions.h"
#include "Basics/files.h"
#include "Basics/json.h"
#include "Logger/Logger.h"
#include "Basics/tri-strings.h"
#include "Cluster/ClusterComm.h"
#include "Cluster/ServerState.h"
#include "HttpServer/HttpServer.h"
#include "Logger/Logger.h"
#include "Rest/HttpRequest.h"
#include "Rest/HttpResponse.h"
#include "RestServer/VocbaseContext.h"
@ -87,8 +89,7 @@ class v8_action_t : public TRI_action_t {
TRI_action_result_t result;
// allow use datase execution in rest calls
extern bool ALLOW_USE_DATABASE_IN_REST_ACTIONS;
bool allowUseDatabaseInRestActions = ALLOW_USE_DATABASE_IN_REST_ACTIONS;
bool allowUseDatabaseInRestActions = ActionFeature::ACTION->allowUseDatabase();
if (_allowUseDatabase) {
allowUseDatabaseInRestActions = true;

View File

@ -1661,18 +1661,11 @@ static void JS_ThrowCollectionNotLoaded(
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
TRI_vocbase_t* vocbase = GetContextVocBase(isolate);
if (vocbase == nullptr) {
TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
}
if (args.Length() == 0) {
bool value = TRI_GetThrowCollectionNotLoadedVocBase(vocbase);
bool value = TRI_GetThrowCollectionNotLoadedVocBase();
TRI_V8_RETURN(v8::Boolean::New(isolate, value));
} else if (args.Length() == 1) {
TRI_SetThrowCollectionNotLoadedVocBase(vocbase,
TRI_ObjectToBoolean(args[0]));
TRI_SetThrowCollectionNotLoadedVocBase(TRI_ObjectToBoolean(args[0]));
} else {
TRI_V8_THROW_EXCEPTION_USAGE("THROW_COLLECTION_NOT_LOADED(<value>)");
}

View File

@ -1125,7 +1125,7 @@ int TRI_InitServer(TRI_server_t* server,
arangodb::basics::ThreadPool* indexPool,
char const* basePath, char const* appPath,
TRI_vocbase_defaults_t const* defaults, bool disableAppliers,
bool iterateMarkersOnOpen) {
bool disableCompactor, bool iterateMarkersOnOpen) {
TRI_ASSERT(server != nullptr);
TRI_ASSERT(basePath != nullptr);
@ -1196,6 +1196,7 @@ int TRI_InitServer(TRI_server_t* server,
// ...........................................................................
server->_disableReplicationAppliers = disableAppliers;
server->_disableCompactor = disableCompactor;
server->_initialized = true;
@ -2170,7 +2171,10 @@ TRI_server_t::~TRI_server_t() {
auto p = _databasesLists.load();
delete p;
TRI_Free(TRI_CORE_MEM_ZONE, _appPath);
if (_appPath != nullptr) {
TRI_Free(TRI_CORE_MEM_ZONE, _appPath);
}
TRI_Free(TRI_CORE_MEM_ZONE, _serverIdFilename);
TRI_Free(TRI_CORE_MEM_ZONE, _lockFilename);
TRI_Free(TRI_CORE_MEM_ZONE, _databasePath);

View File

@ -80,6 +80,7 @@ struct TRI_server_t {
char* _appPath;
bool _disableReplicationAppliers;
bool _disableCompactor;
bool _iterateMarkersOnOpen;
bool _hasCreatedSystemDatabase;
bool _initialized;
@ -96,7 +97,8 @@ extern size_t PageSize;
////////////////////////////////////////////////////////////////////////////////
int TRI_InitServer(TRI_server_t*, arangodb::basics::ThreadPool*, char const*,
char const*, TRI_vocbase_defaults_t const*, bool, bool);
char const*, TRI_vocbase_defaults_t const*, bool, bool,
bool);
////////////////////////////////////////////////////////////////////////////////
/// @brief initialize globals

View File

@ -29,29 +29,30 @@
#include "Aql/QueryCache.h"
#include "Aql/QueryList.h"
#include "Basics/Exceptions.h"
#include "Basics/FileUtils.h"
#include "Basics/conversions.h"
#include "Basics/files.h"
#include "Basics/hashes.h"
#include "Basics/locks.h"
#include "Logger/Logger.h"
#include "Basics/memory-map.h"
#include "Basics/tri-strings.h"
#include "Basics/threads.h"
#include "Basics/Exceptions.h"
#include "Basics/FileUtils.h"
#include "Basics/tri-strings.h"
#include "Logger/Logger.h"
#include "RestServer/DatabaseFeature.h"
#include "Utils/CollectionKeysRepository.h"
#include "Utils/CursorRepository.h"
#include "Utils/transactions.h"
#include "V8Server/v8-user-structures.h"
#include "VocBase/Ditch.h"
#include "VocBase/auth.h"
#include "VocBase/cleanup.h"
#include "VocBase/compactor.h"
#include "VocBase/Ditch.h"
#include "VocBase/document-collection.h"
#include "VocBase/replication-applier.h"
#include "VocBase/server.h"
#include "VocBase/transaction.h"
#include "VocBase/vocbase-defaults.h"
#include "V8Server/v8-user-structures.h"
#include "Wal/LogfileManager.h"
#include <velocypack/Builder.h>
@ -59,6 +60,7 @@
#include <velocypack/Parser.h>
#include <velocypack/velocypack-aliases.h>
using namespace arangodb;
using namespace arangodb::basics;
////////////////////////////////////////////////////////////////////////////////
@ -1022,7 +1024,7 @@ static int LoadCollectionVocBase(TRI_vocbase_t* vocbase,
TRI_WRITE_UNLOCK_STATUS_VOCBASE_COL(collection);
TRI_document_collection_t* document =
TRI_OpenDocumentCollection(vocbase, collection, IGNORE_DATAFILE_ERRORS);
TRI_OpenDocumentCollection(vocbase, collection, DatabaseFeature::DATABASE->ignoreDatafileErrors());
// lock again the adjust the status
TRI_EVENTUAL_WRITE_LOCK_STATUS_VOCBASE_COL(collection);
@ -1479,10 +1481,12 @@ void TRI_StartCompactorVocBase(TRI_vocbase_t* vocbase) {
LOG(TRACE) << "starting compactor for database '" << vocbase->_name << "'";
// start compactor thread
TRI_InitThread(&vocbase->_compactor);
TRI_StartThread(&vocbase->_compactor, nullptr, "Compactor",
TRI_CompactorVocBase, vocbase);
vocbase->_hasCompactor = true;
if (!vocbase->_server->_disableCompactor) {
TRI_InitThread(&vocbase->_compactor);
TRI_StartThread(&vocbase->_compactor, nullptr, "Compactor",
TRI_CompactorVocBase, vocbase);
vocbase->_hasCompactor = true;
}
}
////////////////////////////////////////////////////////////////////////////////
@ -2229,7 +2233,7 @@ TRI_voc_tick_t TRI_NextQueryIdVocBase(TRI_vocbase_t* vocbase) {
/// @brief gets the "throw collection not loaded error"
////////////////////////////////////////////////////////////////////////////////
bool TRI_GetThrowCollectionNotLoadedVocBase(TRI_vocbase_t* vocbase) {
bool TRI_GetThrowCollectionNotLoadedVocBase() {
return ThrowCollectionNotLoaded.load(std::memory_order_seq_cst);
}
@ -2237,8 +2241,7 @@ bool TRI_GetThrowCollectionNotLoadedVocBase(TRI_vocbase_t* vocbase) {
/// @brief sets the "throw collection not loaded error"
////////////////////////////////////////////////////////////////////////////////
void TRI_SetThrowCollectionNotLoadedVocBase(TRI_vocbase_t* vocbase,
bool value) {
void TRI_SetThrowCollectionNotLoadedVocBase(bool value) {
ThrowCollectionNotLoaded.store(value, std::memory_order_seq_cst);
}

View File

@ -626,12 +626,12 @@ TRI_voc_tick_t TRI_NextQueryIdVocBase(TRI_vocbase_t*);
/// @brief gets the "throw collection not loaded error"
////////////////////////////////////////////////////////////////////////////////
bool TRI_GetThrowCollectionNotLoadedVocBase(TRI_vocbase_t*);
bool TRI_GetThrowCollectionNotLoadedVocBase();
////////////////////////////////////////////////////////////////////////////////
/// @brief sets the "throw collection not loaded error"
////////////////////////////////////////////////////////////////////////////////
void TRI_SetThrowCollectionNotLoadedVocBase(TRI_vocbase_t*, bool);
void TRI_SetThrowCollectionNotLoadedVocBase(bool);
#endif

View File

@ -53,6 +53,7 @@ int main(int argc, char* argv[]) {
int ret;
server.addFeature(new CheckVersionFeature(&server));
server.addFeature(new ClientFeature(&server));
server.addFeature(new ConfigFeature(&server, name));
server.addFeature(new ConsoleFeature(&server));

View File

@ -1,7 +1,7 @@
/*jshint -W051:true */
/*global jqconsole, Symbol */
/*eslint-disable */
global.DEFINE_MODULE('console', (function () {
global.DEFINE_MODULE('console', (function() {
'use strict';
/*eslint-enable */
@ -32,8 +32,6 @@ global.DEFINE_MODULE('console', (function () {
/// @author Copyright 2010-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var exports = {};
var internal = require('internal');
var sprintf = internal.sprintf;
@ -52,12 +50,10 @@ var groupLevel = '';
var timers;
try {
timers = Object.create(null);
}
catch (e) {
} catch (e) {
timers = {};
}
////////////////////////////////////////////////////////////////////////////////
/// @brief internal logging
////////////////////////////////////////////////////////////////////////////////
@ -68,10 +64,9 @@ if (global.SYS_LOG) {
// this will work when we are in arangod but not in the browser / web interface
log = global.SYS_LOG;
delete global.SYS_LOG;
}
else {
} else {
// this will work in the web interface
log = function (level, message) {
log = function(level, message) {
if (typeof jqconsole !== 'undefined') {
jqconsole.Write(message + '\n', 'jssuccess');
}
@ -82,7 +77,7 @@ else {
/// @brief internal logging with group level
////////////////////////////////////////////////////////////////////////////////
function logGroup (level, msg) {
function logGroup(level, msg) {
log(level, groupLevel + msg);
}
@ -90,7 +85,7 @@ function logGroup (level, msg) {
/// @brief try to prettify
////////////////////////////////////////////////////////////////////////////////
function prepareArgs (args) {
function prepareArgs(args) {
var ShapedJson = require('internal').ShapedJson;
var result = [];
@ -103,16 +98,17 @@ function prepareArgs (args) {
if (typeof arg === 'object') {
if (ShapedJson !== undefined && arg instanceof ShapedJson) {
arg = inspect(arg, {prettyPrint: false});
}
else if (arg === null) {
arg = inspect(arg, {
prettyPrint: false
});
} else if (arg === null) {
arg = 'null';
}
else if (arg instanceof Date || arg instanceof RegExp) {
} else if (arg instanceof Date || arg instanceof RegExp) {
arg = String(arg);
}
else if (Object.prototype.isPrototypeOf(arg) || Array.isArray(arg)) {
arg = inspect(arg, {prettyPrint: false});
} else if (Object.prototype.isPrototypeOf(arg) || Array.isArray(arg)) {
arg = inspect(arg, {
prettyPrint: false
});
}
}
@ -122,12 +118,11 @@ function prepareArgs (args) {
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief assert
////////////////////////////////////////////////////////////////////////////////
exports.assert = function (condition) {
exports.assert = function(condition) {
if (condition) {
return;
}
@ -137,8 +132,7 @@ exports.assert = function (condition) {
try {
msg = sprintf.apply(sprintf, prepareArgs(args));
}
catch (e) {
} catch (e) {
msg = msg = `${e}: ${args}`;
}
@ -151,13 +145,12 @@ exports.assert = function (condition) {
/// @brief debug
////////////////////////////////////////////////////////////////////////////////
exports.debug = function () {
exports.debug = function() {
var msg;
try {
msg = sprintf.apply(sprintf, prepareArgs(arguments));
}
catch (e) {
} catch (e) {
msg = `${e}: ${arguments}`;
}
@ -168,13 +161,12 @@ exports.debug = function () {
/// @brief debugLines
////////////////////////////////////////////////////////////////////////////////
exports.debugLines = function () {
exports.debugLines = function() {
var msg;
try {
msg = sprintf.apply(sprintf, prepareArgs(arguments));
}
catch (e) {
} catch (e) {
msg = `${e}: ${arguments}`;
}
@ -189,7 +181,7 @@ exports.debugLines = function () {
/// @brief dir
////////////////////////////////////////////////////////////////////////////////
exports.dir = function (object) {
exports.dir = function(object) {
logGroup('info', inspect(object));
};
@ -197,13 +189,12 @@ exports.dir = function (object) {
/// @brief error
////////////////////////////////////////////////////////////////////////////////
exports.error = function () {
exports.error = function() {
var msg;
try {
msg = sprintf.apply(sprintf, prepareArgs(arguments));
}
catch (e) {
} catch (e) {
msg = `${e}: ${arguments}`;
}
@ -214,13 +205,12 @@ exports.error = function () {
/// @brief errorLines
////////////////////////////////////////////////////////////////////////////////
exports.errorLines = function () {
exports.errorLines = function() {
var msg;
try {
msg = sprintf.apply(sprintf, prepareArgs(arguments));
}
catch (e) {
} catch (e) {
msg = `${e}: ${arguments}`;
}
@ -243,13 +233,12 @@ if (global.SYS_GETLINE) {
/// @brief group
////////////////////////////////////////////////////////////////////////////////
exports.group = function () {
exports.group = function() {
var msg;
try {
msg = sprintf.apply(sprintf, prepareArgs(arguments));
}
catch (e) {
} catch (e) {
msg = `${e}: ${arguments}`;
}
@ -261,13 +250,12 @@ exports.group = function () {
/// @brief groupCollapsed
////////////////////////////////////////////////////////////////////////////////
exports.groupCollapsed = function () {
exports.groupCollapsed = function() {
var msg;
try {
msg = sprintf.apply(sprintf, prepareArgs(arguments));
}
catch (e) {
} catch (e) {
msg = `${e}: ${arguments}`;
}
@ -279,7 +267,7 @@ exports.groupCollapsed = function () {
/// @brief groupEnd
////////////////////////////////////////////////////////////////////////////////
exports.groupEnd = function () {
exports.groupEnd = function() {
groupLevel = groupLevel.substr(2);
};
@ -287,13 +275,12 @@ exports.groupEnd = function () {
/// @brief info
////////////////////////////////////////////////////////////////////////////////
exports.info = function () {
exports.info = function() {
var msg;
try {
msg = sprintf.apply(sprintf, prepareArgs(arguments));
}
catch (e) {
} catch (e) {
msg = `${e}: ${arguments}`;
}
logGroup('info', msg);
@ -303,13 +290,12 @@ exports.info = function () {
/// @brief infoLines
////////////////////////////////////////////////////////////////////////////////
exports.infoLines = function () {
exports.infoLines = function() {
var msg;
try {
msg = sprintf.apply(sprintf, prepareArgs(arguments));
}
catch (e) {
} catch (e) {
msg = `${e}: ${arguments}`;
}
@ -337,7 +323,7 @@ exports.logLines = exports.infoLines;
/// @brief time
////////////////////////////////////////////////////////////////////////////////
exports.time = function (label) {
exports.time = function(label) {
if (typeof label !== 'string') {
throw new Error('label must be a string');
}
@ -370,7 +356,7 @@ exports.timeEnd = function(label) {
/// @brief trace
////////////////////////////////////////////////////////////////////////////////
exports.trace = function () {
exports.trace = function() {
var err = new Error();
err.name = 'Trace';
err.message = sprintf.apply(sprintf, prepareArgs(arguments));
@ -388,13 +374,12 @@ exports.trace = function () {
/// @brief warn
////////////////////////////////////////////////////////////////////////////////
exports.warn = function () {
exports.warn = function() {
var msg;
try {
msg = sprintf.apply(sprintf, prepareArgs(arguments));
}
catch (e) {
} catch (e) {
msg = `${e}: ${arguments}`;
}
@ -405,13 +390,12 @@ exports.warn = function () {
/// @brief warnLines
////////////////////////////////////////////////////////////////////////////////
exports.warnLines = function () {
exports.warnLines = function() {
var msg;
try {
msg = sprintf.apply(sprintf, prepareArgs(arguments));
}
catch (e) {
} catch (e) {
msg = `${e}: ${arguments}`;
}
@ -425,5 +409,3 @@ exports.warnLines = function () {
return exports;
}()));

View File

@ -33,7 +33,12 @@
(function() {
return require("@arangodb/database-version").databaseVersion().result;
try {
console.debug("checking database version");
return require("@arangodb/database-version").databaseVersion().result;
} catch (err) {
console.error("database version check failed: " + err);
}
}());

View File

@ -34,26 +34,24 @@ var fs = require("fs");
var db = require("@arangodb").db;
var console = require("console");
////////////////////////////////////////////////////////////////////////////////
/// @brief logger
////////////////////////////////////////////////////////////////////////////////
var logger = {
info: function (msg) {
info: function(msg) {
console.log("In database '%s': %s", db._name(), msg);
},
error: function (msg) {
error: function(msg) {
console.error("In database '%s': %s", db._name(), msg);
},
log: function (msg) {
log: function(msg) {
this.info(msg);
}
};
////////////////////////////////////////////////////////////////////////////////
/// @brief CURRENT_VERSION
////////////////////////////////////////////////////////////////////////////////
@ -116,14 +114,17 @@ exports.NO_VERSION_FILE = -4;
exports.NO_SERVER_VERSION = -5;
////////////////////////////////////////////////////////////////////////////////
/// @brief checks the version
////////////////////////////////////////////////////////////////////////////////
exports.databaseVersion = function () {
exports.databaseVersion = function() {
if (cluster.isCoordinator()) {
return { result: exports.IS_CLUSTER };
console.debug("skip on corrdinator");
return {
result: exports.IS_CLUSTER
};
}
// path to the VERSION file
@ -133,25 +134,31 @@ exports.databaseVersion = function () {
// VERSION file exists, read its contents
if (fs.exists(versionFile)) {
var versionInfo = fs.read(versionFile);
console.debug("found version file: " + versionInfo);
if (versionInfo !== '') {
var versionValues = JSON.parse(versionInfo);
if (versionValues && versionValues.version && ! isNaN(versionValues.version)) {
if (versionValues && versionValues.version && !isNaN(versionValues.version)) {
lastVersion = parseFloat(versionValues.version);
}
else {
} else {
logger.error("Cannot parse VERSION file '" + versionFile + "': '" + versionInfo + "'");
return { result: exports.CANNOT_PARSE_VERSION_FILE };
return {
result: exports.CANNOT_PARSE_VERSION_FILE
};
}
}
else {
} else {
logger.error("Cannot read VERSION file: '" + versionFile + "'");
return { result: exports.CANNOT_READ_VERSION_FILE };
return {
result: exports.CANNOT_READ_VERSION_FILE
};
}
}
else {
return { result: exports.NO_VERSION_FILE };
} else {
console.debug("version file (" + versionFile + ") not found");
return {
result: exports.NO_VERSION_FILE
};
}
// extract server version
@ -159,6 +166,9 @@ exports.databaseVersion = function () {
// version match!
if (Math.floor(lastVersion / 100) === Math.floor(currentVersion / 100)) {
console.debug("version match: last version " + lastVersion +
", current version " + currentVersion);
return {
result: exports.VERSION_MATCH,
serverVersion: currentVersion,
@ -168,6 +178,9 @@ exports.databaseVersion = function () {
// downgrade??
if (lastVersion > currentVersion) {
console.debug("downgrade: last version " + lastVersion +
", current version " + currentVersion);
return {
result: exports.DOWNGRADE_NEEDED,
serverVersion: currentVersion,
@ -177,12 +190,20 @@ exports.databaseVersion = function () {
// upgrade
if (lastVersion < currentVersion) {
console.debug("upgrade: last version " + lastVersion +
", current version " + currentVersion);
return {
result: exports.UPGRADE_NEEDED,
serverVersion: currentVersion,
databaseVersion: lastVersion
};
}
console.error("should not happen: last version " + lastVersion +
", current version " + currentVersion);
return {
result: exports.NO_VERSION_FILE
};
};

View File

@ -43,6 +43,7 @@ DaemonFeature::DaemonFeature(application_features::ApplicationServer* server)
_workingDirectory(".") {
setOptional(true);
requiresElevatedPrivileges(false);
startsAfter("Logger");
startsAfter("WorkMonitor");
#ifndef _WIN32

View File

@ -38,6 +38,7 @@ RandomFeature::RandomFeature(application_features::ApplicationServer* server)
_randomGenerator((uint32_t) RandomGenerator::RandomType::MERSENNE) {
setOptional(false);
requiresElevatedPrivileges(false);
startsAfter("Logger");
}
void RandomFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {

View File

@ -35,7 +35,10 @@ ShutdownFeature::ShutdownFeature(
setOptional(true);
requiresElevatedPrivileges(false);
startsAfter("Logger");
startsAfter(feature);
if (feature != "Logger") {
startsAfter(feature);
}
}
void ShutdownFeature::start() {

View File

@ -39,6 +39,7 @@ SupervisorFeature::SupervisorFeature(
setOptional(true);
requiresElevatedPrivileges(false);
startsAfter("Daemon");
startsAfter("Logger");
startsAfter("WorkMonitor");
}