mirror of https://gitee.com/bigwinds/arangodb
WIP
This commit is contained in:
parent
31d477477e
commit
58b9cf7e91
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
@ -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();
|
|
@ -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
|
||||
// .............................................................................
|
||||
|
|
|
@ -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();
|
|
@ -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();
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>)");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}()));
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}());
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ DaemonFeature::DaemonFeature(application_features::ApplicationServer* server)
|
|||
_workingDirectory(".") {
|
||||
setOptional(true);
|
||||
requiresElevatedPrivileges(false);
|
||||
startsAfter("Logger");
|
||||
startsAfter("WorkMonitor");
|
||||
|
||||
#ifndef _WIN32
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -35,7 +35,10 @@ ShutdownFeature::ShutdownFeature(
|
|||
setOptional(true);
|
||||
requiresElevatedPrivileges(false);
|
||||
startsAfter("Logger");
|
||||
startsAfter(feature);
|
||||
|
||||
if (feature != "Logger") {
|
||||
startsAfter(feature);
|
||||
}
|
||||
}
|
||||
|
||||
void ShutdownFeature::start() {
|
||||
|
|
|
@ -39,6 +39,7 @@ SupervisorFeature::SupervisorFeature(
|
|||
setOptional(true);
|
||||
requiresElevatedPrivileges(false);
|
||||
startsAfter("Daemon");
|
||||
startsAfter("Logger");
|
||||
startsAfter("WorkMonitor");
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue