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}
|
add_executable(${BIN_ARANGOD}
|
||||||
${ARANGO_MSVC}
|
${ARANGO_MSVC}
|
||||||
${ProductVersionFiles}
|
${ProductVersionFiles}
|
||||||
|
Actions/ActionFeature.cpp
|
||||||
Actions/RestActionHandler.cpp
|
Actions/RestActionHandler.cpp
|
||||||
Actions/actions.cpp
|
Actions/actions.cpp
|
||||||
Agency/Agent.cpp
|
Agency/Agent.cpp
|
||||||
|
@ -211,8 +212,8 @@ add_executable(${BIN_ARANGOD}
|
||||||
RestHandler/RestVersionHandler.cpp
|
RestHandler/RestVersionHandler.cpp
|
||||||
RestHandler/RestVocbaseBaseHandler.cpp
|
RestHandler/RestVocbaseBaseHandler.cpp
|
||||||
RestHandler/WorkMonitorHandler.cpp
|
RestHandler/WorkMonitorHandler.cpp
|
||||||
RestServer/ArangoServer.cpp
|
|
||||||
RestServer/ConsoleThread.cpp
|
RestServer/ConsoleThread.cpp
|
||||||
|
RestServer/CheckVersionFeature.cpp
|
||||||
RestServer/DatabaseFeature.cpp
|
RestServer/DatabaseFeature.cpp
|
||||||
RestServer/EndpointFeature.cpp
|
RestServer/EndpointFeature.cpp
|
||||||
RestServer/ServerFeature.cpp
|
RestServer/ServerFeature.cpp
|
||||||
|
|
|
@ -82,7 +82,8 @@ void DispatcherFeature::validateOptions(std::shared_ptr<ProgramOptions>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_queueSize <= 128) {
|
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();
|
FATAL_ERROR_EXIT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,6 +97,27 @@ void DispatcherFeature::start() {
|
||||||
if (_startAqlQueue) {
|
if (_startAqlQueue) {
|
||||||
buildAqlQueue();
|
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() {
|
void DispatcherFeature::stop() {
|
||||||
|
@ -130,11 +152,6 @@ void DispatcherFeature::setProcessorAffinity(std::vector<size_t> const& cores) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#warning TODO
|
#warning TODO
|
||||||
#if 0
|
#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;
|
bool IGNORE_DATAFILE_ERRORS;
|
||||||
|
|
||||||
ArangoServer::ArangoServer(int argc, char** argv)
|
ArangoServer::ArangoServer(int argc, char** argv)
|
||||||
|
@ -114,10 +18,8 @@ ArangoServer::ArangoServer(int argc, char** argv)
|
||||||
_v8Contexts(8),
|
_v8Contexts(8),
|
||||||
_indexThreads(2),
|
_indexThreads(2),
|
||||||
_databasePath(),
|
_databasePath(),
|
||||||
_ignoreDatafileErrors(false),
|
|
||||||
_disableReplicationApplier(false),
|
_disableReplicationApplier(false),
|
||||||
_disableQueryTracking(false),
|
_disableQueryTracking(false),
|
||||||
_throwCollectionNotLoadedError(false),
|
|
||||||
_foxxQueues(true),
|
_foxxQueues(true),
|
||||||
_foxxQueuesPollInterval(1.0),
|
_foxxQueuesPollInterval(1.0),
|
||||||
_server(nullptr),
|
_server(nullptr),
|
||||||
|
@ -134,141 +36,13 @@ ArangoServer::ArangoServer(int argc, char** argv)
|
||||||
ArangoServer::~ArangoServer() {
|
ArangoServer::~ArangoServer() {
|
||||||
delete _jobManager;
|
delete _jobManager;
|
||||||
delete _server;
|
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() {
|
void ArangoServer::buildApplicationServer() {
|
||||||
#warning TODO
|
#warning TODO
|
||||||
#if 0
|
#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 =
|
_applicationCluster =
|
||||||
new ApplicationCluster(_server);
|
new ApplicationCluster(_server);
|
||||||
_applicationServer->addFeature(_applicationCluster);
|
_applicationServer->addFeature(_applicationCluster);
|
||||||
|
@ -280,193 +54,12 @@ void ArangoServer::buildApplicationServer() {
|
||||||
_applicationAgency = new ApplicationAgency();
|
_applicationAgency = new ApplicationAgency();
|
||||||
_applicationServer->addFeature(_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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int ArangoServer::startupServer() {
|
int ArangoServer::startupServer() {
|
||||||
#warning TODO
|
#warning TODO
|
||||||
#if 0
|
#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
|
// prepare everything
|
||||||
|
@ -484,11 +77,6 @@ int ArangoServer::startupServer() {
|
||||||
// and finish prepare
|
// and finish prepare
|
||||||
_applicationServer->prepare2();
|
_applicationServer->prepare2();
|
||||||
|
|
||||||
_pairForAqlHandler = new std::pair<ApplicationV8*, aql::QueryRegistry*>(
|
|
||||||
_applicationV8, _queryRegistry);
|
|
||||||
_pairForJobHandler = new std::pair<Dispatcher*, AsyncJobManager*>(
|
|
||||||
_applicationDispatcher->dispatcher(), _jobManager);
|
|
||||||
|
|
||||||
// ...........................................................................
|
// ...........................................................................
|
||||||
// create endpoints and handlers
|
// create endpoints and handlers
|
||||||
// ...........................................................................
|
// ...........................................................................
|
||||||
|
@ -547,7 +135,6 @@ int ArangoServer::startupServer() {
|
||||||
std::cout << std::endl << TRI_BYE_MESSAGE << std::endl;
|
std::cout << std::endl << TRI_BYE_MESSAGE << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRI_ShutdownStatistics();
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
#endif
|
#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 "DatabaseFeature.h"
|
||||||
|
|
||||||
#include "ApplicationFeatures/LoggerFeature.h"
|
|
||||||
#include "Aql/QueryRegistry.h"
|
#include "Aql/QueryRegistry.h"
|
||||||
#include "Basics/StringUtils.h"
|
#include "Basics/StringUtils.h"
|
||||||
#include "Basics/ThreadPool.h"
|
#include "Basics/ThreadPool.h"
|
||||||
|
@ -30,7 +29,7 @@
|
||||||
#include "Logger/Logger.h"
|
#include "Logger/Logger.h"
|
||||||
#include "ProgramOptions/ProgramOptions.h"
|
#include "ProgramOptions/ProgramOptions.h"
|
||||||
#include "ProgramOptions/Section.h"
|
#include "ProgramOptions/Section.h"
|
||||||
#include "V8Server/V8Context.h"
|
#include "Rest/Version.h"
|
||||||
#include "V8Server/V8DealerFeature.h"
|
#include "V8Server/V8DealerFeature.h"
|
||||||
#include "V8Server/v8-query.h"
|
#include "V8Server/v8-query.h"
|
||||||
#include "V8Server/v8-vocbase.h"
|
#include "V8Server/v8-vocbase.h"
|
||||||
|
@ -44,6 +43,8 @@ using namespace arangodb::application_features;
|
||||||
using namespace arangodb::basics;
|
using namespace arangodb::basics;
|
||||||
using namespace arangodb::options;
|
using namespace arangodb::options;
|
||||||
|
|
||||||
|
DatabaseFeature* DatabaseFeature::DATABASE = nullptr;
|
||||||
|
|
||||||
DatabaseFeature::DatabaseFeature(ApplicationServer* server)
|
DatabaseFeature::DatabaseFeature(ApplicationServer* server)
|
||||||
: ApplicationFeature(server, "Database"),
|
: ApplicationFeature(server, "Database"),
|
||||||
_directory(""),
|
_directory(""),
|
||||||
|
@ -51,22 +52,23 @@ DatabaseFeature::DatabaseFeature(ApplicationServer* server)
|
||||||
_queryTracking(true),
|
_queryTracking(true),
|
||||||
_queryCacheMode("off"),
|
_queryCacheMode("off"),
|
||||||
_queryCacheEntries(128),
|
_queryCacheEntries(128),
|
||||||
_checkVersion(false),
|
|
||||||
_upgrade(false),
|
_upgrade(false),
|
||||||
_skipUpgrade(false),
|
_skipUpgrade(false),
|
||||||
_indexThreads(2),
|
_indexThreads(2),
|
||||||
_defaultWaitForSync(false),
|
_defaultWaitForSync(false),
|
||||||
_forceSyncProperties(true),
|
_forceSyncProperties(true),
|
||||||
|
_ignoreDatafileErrors(false),
|
||||||
_vocbase(nullptr),
|
_vocbase(nullptr),
|
||||||
_server(nullptr),
|
_server(nullptr),
|
||||||
_replicationApplier(true) {
|
_replicationApplier(true),
|
||||||
|
_disableCompactor(false),
|
||||||
|
_checkVersion(false) {
|
||||||
setOptional(false);
|
setOptional(false);
|
||||||
requiresElevatedPrivileges(false);
|
requiresElevatedPrivileges(false);
|
||||||
startsAfter("Language");
|
startsAfter("Language");
|
||||||
startsAfter("Logger");
|
startsAfter("Logger");
|
||||||
startsAfter("Random");
|
startsAfter("Random");
|
||||||
startsAfter("Temp");
|
startsAfter("Temp");
|
||||||
startsAfter("V8Dealer");
|
|
||||||
startsAfter("WorkMonitor");
|
startsAfter("WorkMonitor");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,10 +97,6 @@ void DatabaseFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
|
||||||
"turned off",
|
"turned off",
|
||||||
new BooleanParameter(&_forceSyncProperties));
|
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",
|
options->addOption("--database.upgrade", "perform a database upgrade",
|
||||||
new BooleanParameter(&_upgrade));
|
new BooleanParameter(&_upgrade));
|
||||||
|
|
||||||
|
@ -110,12 +108,46 @@ void DatabaseFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
|
||||||
"threads to start for parallel background index creation",
|
"threads to start for parallel background index creation",
|
||||||
new UInt64Parameter(&_indexThreads));
|
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(
|
options->addSection(
|
||||||
Section("query", "Configure queries", "query options", false, false));
|
Section("query", "Configure queries", "query options", false, false));
|
||||||
|
|
||||||
options->addOption("--query.tracking", "wether to track queries",
|
options->addOption("--query.tracking", "wether to track queries",
|
||||||
new BooleanParameter(&_queryTracking));
|
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",
|
options->addOption("--query.cache-mode",
|
||||||
"mode for the AQL query cache (on, off, demand)",
|
"mode for the AQL query cache (on, off, demand)",
|
||||||
new StringParameter(&_queryCacheMode));
|
new StringParameter(&_queryCacheMode));
|
||||||
|
@ -126,6 +158,8 @@ void DatabaseFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
|
void DatabaseFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
|
||||||
|
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::validateOptions";
|
||||||
|
|
||||||
if (_directory.empty()) {
|
if (_directory.empty()) {
|
||||||
LOG(ERR) << "no database path has been supplied, giving up, please use "
|
LOG(ERR) << "no database path has been supplied, giving up, please use "
|
||||||
"the '--database.directory' option";
|
"the '--database.directory' option";
|
||||||
|
@ -147,15 +181,21 @@ void DatabaseFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
|
||||||
abortInvalidParameters();
|
abortInvalidParameters();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#warning TODO
|
||||||
|
#if 0
|
||||||
if (_checkVersion && _upgrade) {
|
if (_checkVersion && _upgrade) {
|
||||||
LOG(ERR) << "cannot specify both '--database.check-version' and "
|
LOG(ERR) << "cannot specify both '--database.check-version' and "
|
||||||
"'--database.upgrade'";
|
"'--database.upgrade'";
|
||||||
abortInvalidParameters();
|
abortInvalidParameters();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#warning TODO
|
||||||
|
#if 0
|
||||||
if (_checkVersion || _upgrade) {
|
if (_checkVersion || _upgrade) {
|
||||||
_replicationApplier = false;
|
_replicationApplier = false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (_upgrade && _skipUpgrade) {
|
if (_upgrade && _skipUpgrade) {
|
||||||
LOG(ERR) << "cannot specify both '--database.upgrade' and "
|
LOG(ERR) << "cannot specify both '--database.upgrade' and "
|
||||||
|
@ -163,23 +203,57 @@ void DatabaseFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
|
||||||
abortInvalidParameters();
|
abortInvalidParameters();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_checkVersion) {
|
#warning TODO
|
||||||
ApplicationServer::lookupFeature("Daemon")->disable();
|
#if 0
|
||||||
ApplicationServer::lookupFeature("Dispatcher")->disable();
|
std::vector<std::string> arguments = _applicationServer->programArguments();
|
||||||
ApplicationServer::lookupFeature("Endpoint")->disable();
|
|
||||||
ApplicationServer::lookupFeature("Scheduler")->disable();
|
|
||||||
ApplicationServer::lookupFeature("Ssl")->disable();
|
|
||||||
ApplicationServer::lookupFeature("Supervisor")->disable();
|
|
||||||
|
|
||||||
ApplicationServer::lookupFeature("Shutdown")->enable();
|
if (1 < arguments.size()) {
|
||||||
|
LOG(FATAL) << "expected at most one database directory, got "
|
||||||
LoggerFeature* logger = dynamic_cast<LoggerFeature*>(
|
<< arguments.size();
|
||||||
ApplicationServer::lookupFeature("Logger"));
|
FATAL_ERROR_EXIT();
|
||||||
logger->setThreaded(false);
|
} 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() {
|
void DatabaseFeature::start() {
|
||||||
|
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::start";
|
||||||
|
|
||||||
|
LOG(INFO) << "" << rest::Version::getVerboseVersionString();
|
||||||
|
|
||||||
|
// set singleton
|
||||||
|
DATABASE = this;
|
||||||
|
|
||||||
// create the server
|
// create the server
|
||||||
TRI_InitServerGlobals();
|
TRI_InitServerGlobals();
|
||||||
_server.reset(new TRI_server_t());
|
_server.reset(new TRI_server_t());
|
||||||
|
@ -207,28 +281,11 @@ void DatabaseFeature::start() {
|
||||||
|
|
||||||
// fetch the system database and update the contexts
|
// fetch the system database and update the contexts
|
||||||
updateContexts();
|
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() {
|
void DatabaseFeature::stop() {
|
||||||
#warning TODO: we can get rid of this once V8DealerFeature is started AFTER the DatabaseFeature
|
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::stop";
|
||||||
// get rid of references in V8
|
|
||||||
V8DealerFeature::DEALER->shutdownContexts();
|
|
||||||
|
|
||||||
// clear the query registery
|
// clear the query registery
|
||||||
_server->_queryRegistry = nullptr;
|
_server->_queryRegistry = nullptr;
|
||||||
|
|
||||||
|
@ -238,6 +295,9 @@ void DatabaseFeature::stop() {
|
||||||
// delete the server
|
// delete the server
|
||||||
TRI_StopServer(_server.get());
|
TRI_StopServer(_server.get());
|
||||||
|
|
||||||
|
// clear singleton
|
||||||
|
DATABASE = nullptr;
|
||||||
|
|
||||||
LOG(INFO) << "ArangoDB has been shut down";
|
LOG(INFO) << "ArangoDB has been shut down";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,17 +314,20 @@ void DatabaseFeature::updateContexts() {
|
||||||
auto server = _server.get();
|
auto server = _server.get();
|
||||||
auto vocbase = _vocbase;
|
auto vocbase = _vocbase;
|
||||||
|
|
||||||
V8DealerFeature::DEALER->updateContexts(
|
V8DealerFeature* dealer = dynamic_cast<V8DealerFeature*>(
|
||||||
[&queryRegistry, &server, &vocbase](
|
ApplicationServer::lookupFeature("V8Dealer"));
|
||||||
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->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() {
|
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() {
|
void DatabaseFeature::upgradeDatabase() {
|
||||||
|
#warning TODO
|
||||||
|
#if 0
|
||||||
LOG(TRACE) << "starting database init/upgrade";
|
LOG(TRACE) << "starting database init/upgrade";
|
||||||
|
|
||||||
// enter context and isolate
|
// enter context and isolate
|
||||||
|
@ -432,6 +435,7 @@ void DatabaseFeature::upgradeDatabase() {
|
||||||
|
|
||||||
// and return from the context
|
// and return from the context
|
||||||
LOG(TRACE) << "finished database init/upgrade";
|
LOG(TRACE) << "finished database init/upgrade";
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseFeature::openDatabases() {
|
void DatabaseFeature::openDatabases() {
|
||||||
|
@ -461,9 +465,9 @@ void DatabaseFeature::openDatabases() {
|
||||||
bool const iterateMarkersOnOpen =
|
bool const iterateMarkersOnOpen =
|
||||||
!wal::LogfileManager::instance()->hasFoundLastTick();
|
!wal::LogfileManager::instance()->hasFoundLastTick();
|
||||||
|
|
||||||
int res =
|
int res = TRI_InitServer(
|
||||||
TRI_InitServer(_server.get(), _indexPool.get(), _databasePath.c_str(), nullptr,
|
_server.get(), _indexPool.get(), _databasePath.c_str(), nullptr,
|
||||||
&defaults, !_replicationApplier, iterateMarkersOnOpen);
|
&defaults, !_replicationApplier, _disableCompactor, iterateMarkersOnOpen);
|
||||||
|
|
||||||
if (res != TRI_ERROR_NO_ERROR) {
|
if (res != TRI_ERROR_NO_ERROR) {
|
||||||
LOG(FATAL) << "cannot create server instance: out of memory";
|
LOG(FATAL) << "cannot create server instance: out of memory";
|
||||||
|
|
|
@ -38,6 +38,9 @@ class QueryRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
class DatabaseFeature final : public application_features::ApplicationFeature {
|
class DatabaseFeature final : public application_features::ApplicationFeature {
|
||||||
|
public:
|
||||||
|
static DatabaseFeature* DATABASE;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DatabaseFeature(application_features::ApplicationServer* server);
|
explicit DatabaseFeature(application_features::ApplicationServer* server);
|
||||||
|
|
||||||
|
@ -49,6 +52,11 @@ class DatabaseFeature final : public application_features::ApplicationFeature {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TRI_vocbase_t* vocbase() const { return _vocbase; }
|
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:
|
private:
|
||||||
std::string _directory;
|
std::string _directory;
|
||||||
|
@ -56,15 +64,14 @@ class DatabaseFeature final : public application_features::ApplicationFeature {
|
||||||
bool _queryTracking;
|
bool _queryTracking;
|
||||||
std::string _queryCacheMode;
|
std::string _queryCacheMode;
|
||||||
uint64_t _queryCacheEntries;
|
uint64_t _queryCacheEntries;
|
||||||
bool _checkVersion;
|
|
||||||
bool _upgrade;
|
bool _upgrade;
|
||||||
bool _skipUpgrade;
|
bool _skipUpgrade;
|
||||||
uint64_t _indexThreads;
|
uint64_t _indexThreads;
|
||||||
bool _defaultWaitForSync;
|
bool _defaultWaitForSync;
|
||||||
bool _forceSyncProperties;
|
bool _forceSyncProperties;
|
||||||
|
bool _ignoreDatafileErrors;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void checkVersion();
|
|
||||||
void openDatabases();
|
void openDatabases();
|
||||||
void closeDatabases();
|
void closeDatabases();
|
||||||
void upgradeDatabase();
|
void upgradeDatabase();
|
||||||
|
@ -78,6 +85,8 @@ class DatabaseFeature final : public application_features::ApplicationFeature {
|
||||||
std::string _databasePath;
|
std::string _databasePath;
|
||||||
std::unique_ptr<basics::ThreadPool> _indexPool;
|
std::unique_ptr<basics::ThreadPool> _indexPool;
|
||||||
bool _replicationApplier;
|
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",
|
"default API compatibility version",
|
||||||
new Int32Parameter(&_defaultApiCompatibility));
|
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(
|
options->addSection(
|
||||||
Section("http", "HttpServer features", "http options", false, false));
|
Section("http", "HttpServer features", "http options", false, false));
|
||||||
|
|
||||||
|
@ -117,6 +162,8 @@ void ServerFeature::prepare() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerFeature::start() {
|
void ServerFeature::start() {
|
||||||
|
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::start";
|
||||||
|
|
||||||
DatabaseFeature* database = dynamic_cast<DatabaseFeature*>(
|
DatabaseFeature* database = dynamic_cast<DatabaseFeature*>(
|
||||||
application_features::ApplicationServer::lookupFeature("Database"));
|
application_features::ApplicationServer::lookupFeature("Database"));
|
||||||
|
|
||||||
|
@ -124,6 +171,28 @@ void ServerFeature::start() {
|
||||||
|
|
||||||
defineHandlers();
|
defineHandlers();
|
||||||
HttpHandlerFactory::setMaintenance(false);
|
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() {
|
void ServerFeature::beginShutdown() {
|
||||||
|
@ -339,6 +408,19 @@ void ServerFeature::defineHandlers() {
|
||||||
|
|
||||||
#if 0
|
#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
|
// 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 "Basics/ArangoGlobalContext.h"
|
||||||
#include "Dispatcher/DispatcherFeature.h"
|
#include "Dispatcher/DispatcherFeature.h"
|
||||||
#include "ProgramOptions/ProgramOptions.h"
|
#include "ProgramOptions/ProgramOptions.h"
|
||||||
|
#include "RestServer/CheckVersionFeature.h"
|
||||||
#include "RestServer/DatabaseFeature.h"
|
#include "RestServer/DatabaseFeature.h"
|
||||||
#include "RestServer/EndpointFeature.h"
|
#include "RestServer/EndpointFeature.h"
|
||||||
#include "RestServer/ServerFeature.h"
|
#include "RestServer/ServerFeature.h"
|
||||||
|
@ -60,7 +61,7 @@ ArangoServer* ArangoInstance = nullptr;
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#warning TODO
|
#warning TODO
|
||||||
#if 0
|
#if 0
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
extern bool TRI_ParseMoreArgs(int argc, char* argv[]);
|
extern bool TRI_ParseMoreArgs(int argc, char* argv[]);
|
||||||
extern void TRI_StartService(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;
|
int ret = EXIT_FAILURE;
|
||||||
|
|
||||||
|
server.addFeature(new CheckVersionFeature(&server, &ret));
|
||||||
server.addFeature(new ConfigFeature(&server, name));
|
server.addFeature(new ConfigFeature(&server, name));
|
||||||
server.addFeature(new DatabaseFeature(&server));
|
server.addFeature(new DatabaseFeature(&server));
|
||||||
server.addFeature(new DispatcherFeature(&server));
|
server.addFeature(new DispatcherFeature(&server));
|
||||||
|
@ -108,10 +110,13 @@ int main(int argc, char* argv[]) {
|
||||||
logger->setThreaded(true);
|
logger->setThreaded(true);
|
||||||
server.addFeature(logger.release());
|
server.addFeature(logger.release());
|
||||||
|
|
||||||
|
#warning todo
|
||||||
|
#if 0
|
||||||
std::unique_ptr<ShutdownFeature> shutdown =
|
std::unique_ptr<ShutdownFeature> shutdown =
|
||||||
std::make_unique<ShutdownFeature>(&server, "Server");
|
std::make_unique<ShutdownFeature>(&server, "Server");
|
||||||
shutdown->disable();
|
shutdown->disable();
|
||||||
server.addFeature(shutdown.release());
|
server.addFeature(shutdown.release());
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef ARANGODB_HAVE_FORK
|
#ifdef ARANGODB_HAVE_FORK
|
||||||
server.addFeature(new DaemonFeature(&server));
|
server.addFeature(new DaemonFeature(&server));
|
||||||
|
@ -129,7 +134,6 @@ int main(int argc, char* argv[]) {
|
||||||
return context.exit(ret);
|
return context.exit(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#warning TODO
|
#warning TODO
|
||||||
#if 0
|
#if 0
|
||||||
|
|
||||||
|
|
|
@ -89,675 +89,6 @@ ApplicationV8::ApplicationV8(TRI_server_t* server,
|
||||||
TRI_ASSERT(_server != nullptr);
|
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
|
/// @brief prepares the V8 server
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include "Dispatcher/DispatcherThread.h"
|
#include "Dispatcher/DispatcherThread.h"
|
||||||
#include "ProgramOptions/ProgramOptions.h"
|
#include "ProgramOptions/ProgramOptions.h"
|
||||||
#include "ProgramOptions/Section.h"
|
#include "ProgramOptions/Section.h"
|
||||||
|
#include "RestServer/DatabaseFeature.h"
|
||||||
#include "Utils/V8TransactionContext.h"
|
#include "Utils/V8TransactionContext.h"
|
||||||
#include "V8/v8-buffer.h"
|
#include "V8/v8-buffer.h"
|
||||||
#include "V8/v8-conv.h"
|
#include "V8/v8-conv.h"
|
||||||
|
@ -47,6 +48,7 @@
|
||||||
#include "3rdParty/valgrind/valgrind.h"
|
#include "3rdParty/valgrind/valgrind.h"
|
||||||
|
|
||||||
using namespace arangodb;
|
using namespace arangodb;
|
||||||
|
using namespace arangodb::application_features;
|
||||||
using namespace arangodb::basics;
|
using namespace arangodb::basics;
|
||||||
using namespace arangodb::options;
|
using namespace arangodb::options;
|
||||||
|
|
||||||
|
@ -90,15 +92,17 @@ V8DealerFeature::V8DealerFeature(
|
||||||
_ok(false),
|
_ok(false),
|
||||||
_gcThread(nullptr),
|
_gcThread(nullptr),
|
||||||
_stopping(false),
|
_stopping(false),
|
||||||
_gcFinished(false),
|
_gcFinished(false) {
|
||||||
_contexts(nullptr) {
|
|
||||||
setOptional(false);
|
setOptional(false);
|
||||||
requiresElevatedPrivileges(false);
|
requiresElevatedPrivileges(false);
|
||||||
startsAfter("V8Platform");
|
startsAfter("V8Platform");
|
||||||
startsAfter("WorkMonitor");
|
startsAfter("WorkMonitor");
|
||||||
|
startsAfter("Database");
|
||||||
}
|
}
|
||||||
|
|
||||||
void V8DealerFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
|
void V8DealerFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
|
||||||
|
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::collectOptions";
|
||||||
|
|
||||||
options->addSection(Section("javascript", "Configure the Javascript engine",
|
options->addSection(Section("javascript", "Configure the Javascript engine",
|
||||||
"javascript options", false, false));
|
"javascript options", false, false));
|
||||||
|
|
||||||
|
@ -124,13 +128,6 @@ void V8DealerFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
|
||||||
"--javascript.v8-contexts",
|
"--javascript.v8-contexts",
|
||||||
"number of V8 contexts that are created for executing JavaScript actions",
|
"number of V8 contexts that are created for executing JavaScript actions",
|
||||||
new UInt64Parameter(&_nrContexts));
|
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) {
|
void V8DealerFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
|
||||||
|
@ -143,9 +140,12 @@ void V8DealerFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
|
||||||
FATAL_ERROR_EXIT();
|
FATAL_ERROR_EXIT();
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove trailing / from path
|
// remove trailing / from path and set path
|
||||||
_startupPath = StringUtils::rTrim(_startupPath, TRI_DIR_SEPARATOR_STR);
|
_startupPath = StringUtils::rTrim(_startupPath, TRI_DIR_SEPARATOR_STR);
|
||||||
|
|
||||||
|
_startupLoader.setDirectory(_startupPath);
|
||||||
|
ServerState::instance()->setJavaScriptPath(_startupPath);
|
||||||
|
|
||||||
// dump paths
|
// dump paths
|
||||||
{
|
{
|
||||||
std::vector<std::string> paths;
|
std::vector<std::string> paths;
|
||||||
|
@ -165,22 +165,26 @@ void V8DealerFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
|
||||||
FATAL_ERROR_EXIT();
|
FATAL_ERROR_EXIT();
|
||||||
}
|
}
|
||||||
|
|
||||||
_startupLoader.setDirectory(_startupPath);
|
|
||||||
ServerState::instance()->setJavaScriptPath(_startupPath);
|
|
||||||
|
|
||||||
// use a minimum of 1 second for GC
|
// use a minimum of 1 second for GC
|
||||||
if (_gcFrequency < 1) {
|
if (_gcFrequency < 1) {
|
||||||
_gcFrequency = 1;
|
_gcFrequency = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set a minimum of V8 contexts
|
||||||
|
if (_nrContexts < 1) {
|
||||||
|
_nrContexts = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void V8DealerFeature::start() {
|
void V8DealerFeature::start() {
|
||||||
|
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::start";
|
||||||
|
|
||||||
DEALER = this;
|
DEALER = this;
|
||||||
|
|
||||||
// setup instances
|
// setup instances
|
||||||
{
|
{
|
||||||
CONDITION_LOCKER(guard, _contextCondition);
|
CONDITION_LOCKER(guard, _contextCondition);
|
||||||
_contexts = new V8Context*[_nrContexts];
|
_contexts.resize(_nrContexts, nullptr);
|
||||||
|
|
||||||
_busyContexts.reserve(_nrContexts);
|
_busyContexts.reserve(_nrContexts);
|
||||||
_freeContexts.reserve(_nrContexts);
|
_freeContexts.reserve(_nrContexts);
|
||||||
|
@ -191,16 +195,24 @@ void V8DealerFeature::start() {
|
||||||
initializeContext(i);
|
initializeContext(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
#warning TODO needs a database I assume
|
applyContextUpdates();
|
||||||
#if 0
|
|
||||||
for (size_t i = 0; i < _nrContexts; ++i) {
|
DatabaseFeature* database = dynamic_cast<DatabaseFeature*>(
|
||||||
prepareV8Server(i, _startupFile);
|
ApplicationServer::lookupFeature("Database"));
|
||||||
}
|
|
||||||
#endif
|
loadJavascript(database->vocbase());
|
||||||
}
|
}
|
||||||
|
|
||||||
void V8DealerFeature::stop() {
|
void V8DealerFeature::stop() {
|
||||||
|
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::stop";
|
||||||
|
|
||||||
shutdownContexts();
|
shutdownContexts();
|
||||||
|
|
||||||
|
// delete GC thread after all action threads have been stopped
|
||||||
|
if (_gcThread != nullptr) {
|
||||||
|
delete _gcThread;
|
||||||
|
}
|
||||||
|
|
||||||
DEALER = nullptr;
|
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,
|
std::function<void(v8::Isolate*, v8::Handle<v8::Context>, size_t)> func,
|
||||||
TRI_vocbase_t* vocbase) {
|
TRI_vocbase_t* vocbase) {
|
||||||
|
_contextUpdates.emplace_back(func, vocbase);
|
||||||
|
}
|
||||||
|
|
||||||
|
void V8DealerFeature::applyContextUpdates() {
|
||||||
for (size_t i = 0; i < _nrContexts; ++i) {
|
for (size_t i = 0; i < _nrContexts; ++i) {
|
||||||
V8Context* context =
|
for (auto& p : _contextUpdates) {
|
||||||
V8DealerFeature::DEALER->enterContext(vocbase, true, 0);
|
V8Context* context =
|
||||||
v8::HandleScope scope(context->_isolate);
|
V8DealerFeature::DEALER->enterContext(p.second, true, 0);
|
||||||
auto localContext =
|
v8::HandleScope scope(context->_isolate);
|
||||||
v8::Local<v8::Context>::New(context->_isolate, context->_context);
|
auto localContext =
|
||||||
localContext->Enter();
|
v8::Local<v8::Context>::New(context->_isolate, context->_context);
|
||||||
|
localContext->Enter();
|
||||||
|
|
||||||
{
|
{
|
||||||
v8::Context::Scope contextScope(localContext);
|
v8::Context::Scope contextScope(localContext);
|
||||||
func(context->_isolate, localContext, i);
|
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
|
// stop GC thread
|
||||||
if (_gcThread != nullptr) {
|
if (_gcThread != nullptr) {
|
||||||
LOG(DEBUG) << "Waiting for GC Thread to finish action";
|
LOG(DEBUG) << "Waiting for GC Thread to finish action";
|
||||||
|
@ -711,19 +734,14 @@ void V8DealerFeature::shutdownContexts() {
|
||||||
{
|
{
|
||||||
CONDITION_LOCKER(guard, _contextCondition);
|
CONDITION_LOCKER(guard, _contextCondition);
|
||||||
|
|
||||||
for (size_t i = 0; i < _nrContexts; ++i) {
|
for (auto context : _contexts) {
|
||||||
shutdownV8Instance(i);
|
shutdownV8Instance(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete[] _contexts;
|
_contexts.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(DEBUG) << "Shutting down V8";
|
LOG(DEBUG) << "V( contexts are shut down";
|
||||||
|
|
||||||
// delete GC thread after all action threads have been stopped
|
|
||||||
if (_gcThread != nullptr) {
|
|
||||||
delete _gcThread;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
V8Context* V8DealerFeature::pickFreeContextForGc() {
|
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("global"), globalObj);
|
||||||
globalObj->Set(TRI_V8_ASCII_STRING("root"), 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 +
|
std::string modulesPath = _startupPath + TRI_DIR_SEPARATOR_STR +
|
||||||
"server" + TRI_DIR_SEPARATOR_STR + "modules;" +
|
"server" + TRI_DIR_SEPARATOR_STR + "modules;" +
|
||||||
_startupPath + TRI_DIR_SEPARATOR_STR +
|
_startupPath + TRI_DIR_SEPARATOR_STR +
|
||||||
"common" + TRI_DIR_SEPARATOR_STR + "modules;" +
|
"common" + TRI_DIR_SEPARATOR_STR + "modules;" +
|
||||||
_startupPath + TRI_DIR_SEPARATOR_STR + "node";
|
_startupPath + TRI_DIR_SEPARATOR_STR + "node";
|
||||||
|
|
||||||
|
TRI_InitV8UserStructures(isolate, localContext);
|
||||||
TRI_InitV8Buffer(isolate, localContext);
|
TRI_InitV8Buffer(isolate, localContext);
|
||||||
TRI_InitV8Conversions(localContext);
|
TRI_InitV8Conversions(localContext);
|
||||||
TRI_InitV8Utils(isolate, localContext, _startupPath, modulesPath);
|
TRI_InitV8Utils(isolate, localContext, _startupPath, modulesPath);
|
||||||
|
@ -879,9 +879,6 @@ void V8DealerFeature::initializeContext(size_t i) {
|
||||||
TRI_AddGlobalVariableVocbase(isolate, localContext,
|
TRI_AddGlobalVariableVocbase(isolate, localContext,
|
||||||
TRI_V8_ASCII_STRING("APP_PATH"),
|
TRI_V8_ASCII_STRING("APP_PATH"),
|
||||||
TRI_V8_STD_STRING(_appPath));
|
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) {
|
for (auto j : _definedBooleans) {
|
||||||
localContext->Global()->ForceSet(TRI_V8_STD_STRING(j.first),
|
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::Number::New(isolate, j.second),
|
||||||
v8::ReadOnly);
|
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;
|
LOG(TRACE) << "loaded Javascript files for V8 context #" << i;
|
||||||
}
|
}
|
||||||
|
|
||||||
void V8DealerFeature::shutdownV8Instance(size_t i) {
|
void V8DealerFeature::shutdownV8Instance(V8Context* context) {
|
||||||
LOG(TRACE) << "shutting down V8 context #" << i;
|
LOG(TRACE) << "shutting down V8 context #" << context->_id;
|
||||||
|
|
||||||
V8Context* context = _contexts[i];
|
|
||||||
|
|
||||||
auto isolate = context->_isolate;
|
auto isolate = context->_isolate;
|
||||||
isolate->Enter();
|
isolate->Enter();
|
||||||
|
@ -1016,5 +1017,5 @@ void V8DealerFeature::shutdownV8Instance(size_t i) {
|
||||||
|
|
||||||
delete context;
|
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);
|
ssize_t forceContext = -1);
|
||||||
void exitContext(V8Context*);
|
void exitContext(V8Context*);
|
||||||
|
|
||||||
void updateContexts(
|
void defineContextUpdate(
|
||||||
std::function<void(v8::Isolate*, v8::Handle<v8::Context>, size_t)>,
|
std::function<void(v8::Isolate*, v8::Handle<v8::Context>, size_t)>,
|
||||||
TRI_vocbase_t*);
|
TRI_vocbase_t*);
|
||||||
|
void applyContextUpdates();
|
||||||
|
|
||||||
void shutdownContexts();
|
void shutdownContexts();
|
||||||
|
|
||||||
|
@ -77,7 +78,7 @@ class V8DealerFeature final : public application_features::ApplicationFeature {
|
||||||
V8Context* pickFreeContextForGc();
|
V8Context* pickFreeContextForGc();
|
||||||
void initializeContext(size_t);
|
void initializeContext(size_t);
|
||||||
void loadJavascriptFiles(TRI_vocbase_t*, size_t);
|
void loadJavascriptFiles(TRI_vocbase_t*, size_t);
|
||||||
void shutdownV8Instance(size_t);
|
void shutdownV8Instance(V8Context*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _useActions;
|
bool _useActions;
|
||||||
|
@ -87,7 +88,7 @@ class V8DealerFeature final : public application_features::ApplicationFeature {
|
||||||
std::atomic<bool> _stopping;
|
std::atomic<bool> _stopping;
|
||||||
std::atomic<bool> _gcFinished;
|
std::atomic<bool> _gcFinished;
|
||||||
|
|
||||||
V8Context** _contexts;
|
std::vector<V8Context*> _contexts;
|
||||||
basics::ConditionVariable _contextCondition;
|
basics::ConditionVariable _contextCondition;
|
||||||
std::vector<V8Context*> _freeContexts;
|
std::vector<V8Context*> _freeContexts;
|
||||||
std::vector<V8Context*> _dirtyContexts;
|
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, bool> _definedBooleans;
|
||||||
std::map<std::string, double> _definedDoubles;
|
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 "v8-actions.h"
|
||||||
|
|
||||||
|
#include "Actions/ActionFeature.h"
|
||||||
#include "Actions/actions.h"
|
#include "Actions/actions.h"
|
||||||
#include "Basics/MutexLocker.h"
|
#include "Basics/MutexLocker.h"
|
||||||
#include "Basics/ReadLocker.h"
|
#include "Basics/ReadLocker.h"
|
||||||
|
@ -30,11 +32,11 @@
|
||||||
#include "Basics/conversions.h"
|
#include "Basics/conversions.h"
|
||||||
#include "Basics/files.h"
|
#include "Basics/files.h"
|
||||||
#include "Basics/json.h"
|
#include "Basics/json.h"
|
||||||
#include "Logger/Logger.h"
|
|
||||||
#include "Basics/tri-strings.h"
|
#include "Basics/tri-strings.h"
|
||||||
#include "Cluster/ClusterComm.h"
|
#include "Cluster/ClusterComm.h"
|
||||||
#include "Cluster/ServerState.h"
|
#include "Cluster/ServerState.h"
|
||||||
#include "HttpServer/HttpServer.h"
|
#include "HttpServer/HttpServer.h"
|
||||||
|
#include "Logger/Logger.h"
|
||||||
#include "Rest/HttpRequest.h"
|
#include "Rest/HttpRequest.h"
|
||||||
#include "Rest/HttpResponse.h"
|
#include "Rest/HttpResponse.h"
|
||||||
#include "RestServer/VocbaseContext.h"
|
#include "RestServer/VocbaseContext.h"
|
||||||
|
@ -87,8 +89,7 @@ class v8_action_t : public TRI_action_t {
|
||||||
TRI_action_result_t result;
|
TRI_action_result_t result;
|
||||||
|
|
||||||
// allow use datase execution in rest calls
|
// allow use datase execution in rest calls
|
||||||
extern bool ALLOW_USE_DATABASE_IN_REST_ACTIONS;
|
bool allowUseDatabaseInRestActions = ActionFeature::ACTION->allowUseDatabase();
|
||||||
bool allowUseDatabaseInRestActions = ALLOW_USE_DATABASE_IN_REST_ACTIONS;
|
|
||||||
|
|
||||||
if (_allowUseDatabase) {
|
if (_allowUseDatabase) {
|
||||||
allowUseDatabaseInRestActions = true;
|
allowUseDatabaseInRestActions = true;
|
||||||
|
|
|
@ -1661,18 +1661,11 @@ static void JS_ThrowCollectionNotLoaded(
|
||||||
TRI_V8_TRY_CATCH_BEGIN(isolate);
|
TRI_V8_TRY_CATCH_BEGIN(isolate);
|
||||||
v8::HandleScope scope(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) {
|
if (args.Length() == 0) {
|
||||||
bool value = TRI_GetThrowCollectionNotLoadedVocBase(vocbase);
|
bool value = TRI_GetThrowCollectionNotLoadedVocBase();
|
||||||
TRI_V8_RETURN(v8::Boolean::New(isolate, value));
|
TRI_V8_RETURN(v8::Boolean::New(isolate, value));
|
||||||
} else if (args.Length() == 1) {
|
} else if (args.Length() == 1) {
|
||||||
TRI_SetThrowCollectionNotLoadedVocBase(vocbase,
|
TRI_SetThrowCollectionNotLoadedVocBase(TRI_ObjectToBoolean(args[0]));
|
||||||
TRI_ObjectToBoolean(args[0]));
|
|
||||||
} else {
|
} else {
|
||||||
TRI_V8_THROW_EXCEPTION_USAGE("THROW_COLLECTION_NOT_LOADED(<value>)");
|
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,
|
arangodb::basics::ThreadPool* indexPool,
|
||||||
char const* basePath, char const* appPath,
|
char const* basePath, char const* appPath,
|
||||||
TRI_vocbase_defaults_t const* defaults, bool disableAppliers,
|
TRI_vocbase_defaults_t const* defaults, bool disableAppliers,
|
||||||
bool iterateMarkersOnOpen) {
|
bool disableCompactor, bool iterateMarkersOnOpen) {
|
||||||
TRI_ASSERT(server != nullptr);
|
TRI_ASSERT(server != nullptr);
|
||||||
TRI_ASSERT(basePath != nullptr);
|
TRI_ASSERT(basePath != nullptr);
|
||||||
|
|
||||||
|
@ -1196,6 +1196,7 @@ int TRI_InitServer(TRI_server_t* server,
|
||||||
// ...........................................................................
|
// ...........................................................................
|
||||||
|
|
||||||
server->_disableReplicationAppliers = disableAppliers;
|
server->_disableReplicationAppliers = disableAppliers;
|
||||||
|
server->_disableCompactor = disableCompactor;
|
||||||
|
|
||||||
server->_initialized = true;
|
server->_initialized = true;
|
||||||
|
|
||||||
|
@ -2170,7 +2171,10 @@ TRI_server_t::~TRI_server_t() {
|
||||||
auto p = _databasesLists.load();
|
auto p = _databasesLists.load();
|
||||||
delete p;
|
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, _serverIdFilename);
|
||||||
TRI_Free(TRI_CORE_MEM_ZONE, _lockFilename);
|
TRI_Free(TRI_CORE_MEM_ZONE, _lockFilename);
|
||||||
TRI_Free(TRI_CORE_MEM_ZONE, _databasePath);
|
TRI_Free(TRI_CORE_MEM_ZONE, _databasePath);
|
||||||
|
|
|
@ -80,6 +80,7 @@ struct TRI_server_t {
|
||||||
char* _appPath;
|
char* _appPath;
|
||||||
|
|
||||||
bool _disableReplicationAppliers;
|
bool _disableReplicationAppliers;
|
||||||
|
bool _disableCompactor;
|
||||||
bool _iterateMarkersOnOpen;
|
bool _iterateMarkersOnOpen;
|
||||||
bool _hasCreatedSystemDatabase;
|
bool _hasCreatedSystemDatabase;
|
||||||
bool _initialized;
|
bool _initialized;
|
||||||
|
@ -96,7 +97,8 @@ extern size_t PageSize;
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
int TRI_InitServer(TRI_server_t*, arangodb::basics::ThreadPool*, char const*,
|
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
|
/// @brief initialize globals
|
||||||
|
|
|
@ -29,29 +29,30 @@
|
||||||
|
|
||||||
#include "Aql/QueryCache.h"
|
#include "Aql/QueryCache.h"
|
||||||
#include "Aql/QueryList.h"
|
#include "Aql/QueryList.h"
|
||||||
|
#include "Basics/Exceptions.h"
|
||||||
|
#include "Basics/FileUtils.h"
|
||||||
#include "Basics/conversions.h"
|
#include "Basics/conversions.h"
|
||||||
#include "Basics/files.h"
|
#include "Basics/files.h"
|
||||||
#include "Basics/hashes.h"
|
#include "Basics/hashes.h"
|
||||||
#include "Basics/locks.h"
|
#include "Basics/locks.h"
|
||||||
#include "Logger/Logger.h"
|
|
||||||
#include "Basics/memory-map.h"
|
#include "Basics/memory-map.h"
|
||||||
#include "Basics/tri-strings.h"
|
|
||||||
#include "Basics/threads.h"
|
#include "Basics/threads.h"
|
||||||
#include "Basics/Exceptions.h"
|
#include "Basics/tri-strings.h"
|
||||||
#include "Basics/FileUtils.h"
|
#include "Logger/Logger.h"
|
||||||
|
#include "RestServer/DatabaseFeature.h"
|
||||||
#include "Utils/CollectionKeysRepository.h"
|
#include "Utils/CollectionKeysRepository.h"
|
||||||
#include "Utils/CursorRepository.h"
|
#include "Utils/CursorRepository.h"
|
||||||
#include "Utils/transactions.h"
|
#include "Utils/transactions.h"
|
||||||
|
#include "V8Server/v8-user-structures.h"
|
||||||
|
#include "VocBase/Ditch.h"
|
||||||
#include "VocBase/auth.h"
|
#include "VocBase/auth.h"
|
||||||
#include "VocBase/cleanup.h"
|
#include "VocBase/cleanup.h"
|
||||||
#include "VocBase/compactor.h"
|
#include "VocBase/compactor.h"
|
||||||
#include "VocBase/Ditch.h"
|
|
||||||
#include "VocBase/document-collection.h"
|
#include "VocBase/document-collection.h"
|
||||||
#include "VocBase/replication-applier.h"
|
#include "VocBase/replication-applier.h"
|
||||||
#include "VocBase/server.h"
|
#include "VocBase/server.h"
|
||||||
#include "VocBase/transaction.h"
|
#include "VocBase/transaction.h"
|
||||||
#include "VocBase/vocbase-defaults.h"
|
#include "VocBase/vocbase-defaults.h"
|
||||||
#include "V8Server/v8-user-structures.h"
|
|
||||||
#include "Wal/LogfileManager.h"
|
#include "Wal/LogfileManager.h"
|
||||||
|
|
||||||
#include <velocypack/Builder.h>
|
#include <velocypack/Builder.h>
|
||||||
|
@ -59,6 +60,7 @@
|
||||||
#include <velocypack/Parser.h>
|
#include <velocypack/Parser.h>
|
||||||
#include <velocypack/velocypack-aliases.h>
|
#include <velocypack/velocypack-aliases.h>
|
||||||
|
|
||||||
|
using namespace arangodb;
|
||||||
using namespace arangodb::basics;
|
using namespace arangodb::basics;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1022,7 +1024,7 @@ static int LoadCollectionVocBase(TRI_vocbase_t* vocbase,
|
||||||
TRI_WRITE_UNLOCK_STATUS_VOCBASE_COL(collection);
|
TRI_WRITE_UNLOCK_STATUS_VOCBASE_COL(collection);
|
||||||
|
|
||||||
TRI_document_collection_t* document =
|
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
|
// lock again the adjust the status
|
||||||
TRI_EVENTUAL_WRITE_LOCK_STATUS_VOCBASE_COL(collection);
|
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 << "'";
|
LOG(TRACE) << "starting compactor for database '" << vocbase->_name << "'";
|
||||||
// start compactor thread
|
// start compactor thread
|
||||||
TRI_InitThread(&vocbase->_compactor);
|
if (!vocbase->_server->_disableCompactor) {
|
||||||
TRI_StartThread(&vocbase->_compactor, nullptr, "Compactor",
|
TRI_InitThread(&vocbase->_compactor);
|
||||||
TRI_CompactorVocBase, vocbase);
|
TRI_StartThread(&vocbase->_compactor, nullptr, "Compactor",
|
||||||
vocbase->_hasCompactor = true;
|
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"
|
/// @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);
|
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"
|
/// @brief sets the "throw collection not loaded error"
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void TRI_SetThrowCollectionNotLoadedVocBase(TRI_vocbase_t* vocbase,
|
void TRI_SetThrowCollectionNotLoadedVocBase(bool value) {
|
||||||
bool value) {
|
|
||||||
ThrowCollectionNotLoaded.store(value, std::memory_order_seq_cst);
|
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"
|
/// @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"
|
/// @brief sets the "throw collection not loaded error"
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void TRI_SetThrowCollectionNotLoadedVocBase(TRI_vocbase_t*, bool);
|
void TRI_SetThrowCollectionNotLoadedVocBase(bool);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -53,6 +53,7 @@ int main(int argc, char* argv[]) {
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
server.addFeature(new CheckVersionFeature(&server));
|
||||||
server.addFeature(new ClientFeature(&server));
|
server.addFeature(new ClientFeature(&server));
|
||||||
server.addFeature(new ConfigFeature(&server, name));
|
server.addFeature(new ConfigFeature(&server, name));
|
||||||
server.addFeature(new ConsoleFeature(&server));
|
server.addFeature(new ConsoleFeature(&server));
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*jshint -W051:true */
|
/*jshint -W051:true */
|
||||||
/*global jqconsole, Symbol */
|
/*global jqconsole, Symbol */
|
||||||
/*eslint-disable */
|
/*eslint-disable */
|
||||||
global.DEFINE_MODULE('console', (function () {
|
global.DEFINE_MODULE('console', (function() {
|
||||||
'use strict';
|
'use strict';
|
||||||
/*eslint-enable */
|
/*eslint-enable */
|
||||||
|
|
||||||
|
@ -32,8 +32,6 @@ global.DEFINE_MODULE('console', (function () {
|
||||||
/// @author Copyright 2010-2013, triAGENS GmbH, Cologne, Germany
|
/// @author Copyright 2010-2013, triAGENS GmbH, Cologne, Germany
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var exports = {};
|
var exports = {};
|
||||||
var internal = require('internal');
|
var internal = require('internal');
|
||||||
var sprintf = internal.sprintf;
|
var sprintf = internal.sprintf;
|
||||||
|
@ -52,12 +50,10 @@ var groupLevel = '';
|
||||||
var timers;
|
var timers;
|
||||||
try {
|
try {
|
||||||
timers = Object.create(null);
|
timers = Object.create(null);
|
||||||
}
|
} catch (e) {
|
||||||
catch (e) {
|
|
||||||
timers = {};
|
timers = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief internal logging
|
/// @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
|
// this will work when we are in arangod but not in the browser / web interface
|
||||||
log = global.SYS_LOG;
|
log = global.SYS_LOG;
|
||||||
delete global.SYS_LOG;
|
delete global.SYS_LOG;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// this will work in the web interface
|
// this will work in the web interface
|
||||||
log = function (level, message) {
|
log = function(level, message) {
|
||||||
if (typeof jqconsole !== 'undefined') {
|
if (typeof jqconsole !== 'undefined') {
|
||||||
jqconsole.Write(message + '\n', 'jssuccess');
|
jqconsole.Write(message + '\n', 'jssuccess');
|
||||||
}
|
}
|
||||||
|
@ -82,7 +77,7 @@ else {
|
||||||
/// @brief internal logging with group level
|
/// @brief internal logging with group level
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
function logGroup (level, msg) {
|
function logGroup(level, msg) {
|
||||||
log(level, groupLevel + msg);
|
log(level, groupLevel + msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +85,7 @@ function logGroup (level, msg) {
|
||||||
/// @brief try to prettify
|
/// @brief try to prettify
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
function prepareArgs (args) {
|
function prepareArgs(args) {
|
||||||
var ShapedJson = require('internal').ShapedJson;
|
var ShapedJson = require('internal').ShapedJson;
|
||||||
var result = [];
|
var result = [];
|
||||||
|
|
||||||
|
@ -103,16 +98,17 @@ function prepareArgs (args) {
|
||||||
|
|
||||||
if (typeof arg === 'object') {
|
if (typeof arg === 'object') {
|
||||||
if (ShapedJson !== undefined && arg instanceof ShapedJson) {
|
if (ShapedJson !== undefined && arg instanceof ShapedJson) {
|
||||||
arg = inspect(arg, {prettyPrint: false});
|
arg = inspect(arg, {
|
||||||
}
|
prettyPrint: false
|
||||||
else if (arg === null) {
|
});
|
||||||
|
} else if (arg === null) {
|
||||||
arg = 'null';
|
arg = 'null';
|
||||||
}
|
} else if (arg instanceof Date || arg instanceof RegExp) {
|
||||||
else if (arg instanceof Date || arg instanceof RegExp) {
|
|
||||||
arg = String(arg);
|
arg = String(arg);
|
||||||
}
|
} else if (Object.prototype.isPrototypeOf(arg) || Array.isArray(arg)) {
|
||||||
else if (Object.prototype.isPrototypeOf(arg) || Array.isArray(arg)) {
|
arg = inspect(arg, {
|
||||||
arg = inspect(arg, {prettyPrint: false});
|
prettyPrint: false
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,12 +118,11 @@ function prepareArgs (args) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief assert
|
/// @brief assert
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
exports.assert = function (condition) {
|
exports.assert = function(condition) {
|
||||||
if (condition) {
|
if (condition) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -137,8 +132,7 @@ exports.assert = function (condition) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
msg = sprintf.apply(sprintf, prepareArgs(args));
|
msg = sprintf.apply(sprintf, prepareArgs(args));
|
||||||
}
|
} catch (e) {
|
||||||
catch (e) {
|
|
||||||
msg = msg = `${e}: ${args}`;
|
msg = msg = `${e}: ${args}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,13 +145,12 @@ exports.assert = function (condition) {
|
||||||
/// @brief debug
|
/// @brief debug
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
exports.debug = function () {
|
exports.debug = function() {
|
||||||
var msg;
|
var msg;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
msg = sprintf.apply(sprintf, prepareArgs(arguments));
|
msg = sprintf.apply(sprintf, prepareArgs(arguments));
|
||||||
}
|
} catch (e) {
|
||||||
catch (e) {
|
|
||||||
msg = `${e}: ${arguments}`;
|
msg = `${e}: ${arguments}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,13 +161,12 @@ exports.debug = function () {
|
||||||
/// @brief debugLines
|
/// @brief debugLines
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
exports.debugLines = function () {
|
exports.debugLines = function() {
|
||||||
var msg;
|
var msg;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
msg = sprintf.apply(sprintf, prepareArgs(arguments));
|
msg = sprintf.apply(sprintf, prepareArgs(arguments));
|
||||||
}
|
} catch (e) {
|
||||||
catch (e) {
|
|
||||||
msg = `${e}: ${arguments}`;
|
msg = `${e}: ${arguments}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +181,7 @@ exports.debugLines = function () {
|
||||||
/// @brief dir
|
/// @brief dir
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
exports.dir = function (object) {
|
exports.dir = function(object) {
|
||||||
logGroup('info', inspect(object));
|
logGroup('info', inspect(object));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -197,13 +189,12 @@ exports.dir = function (object) {
|
||||||
/// @brief error
|
/// @brief error
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
exports.error = function () {
|
exports.error = function() {
|
||||||
var msg;
|
var msg;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
msg = sprintf.apply(sprintf, prepareArgs(arguments));
|
msg = sprintf.apply(sprintf, prepareArgs(arguments));
|
||||||
}
|
} catch (e) {
|
||||||
catch (e) {
|
|
||||||
msg = `${e}: ${arguments}`;
|
msg = `${e}: ${arguments}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,13 +205,12 @@ exports.error = function () {
|
||||||
/// @brief errorLines
|
/// @brief errorLines
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
exports.errorLines = function () {
|
exports.errorLines = function() {
|
||||||
var msg;
|
var msg;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
msg = sprintf.apply(sprintf, prepareArgs(arguments));
|
msg = sprintf.apply(sprintf, prepareArgs(arguments));
|
||||||
}
|
} catch (e) {
|
||||||
catch (e) {
|
|
||||||
msg = `${e}: ${arguments}`;
|
msg = `${e}: ${arguments}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,13 +233,12 @@ if (global.SYS_GETLINE) {
|
||||||
/// @brief group
|
/// @brief group
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
exports.group = function () {
|
exports.group = function() {
|
||||||
var msg;
|
var msg;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
msg = sprintf.apply(sprintf, prepareArgs(arguments));
|
msg = sprintf.apply(sprintf, prepareArgs(arguments));
|
||||||
}
|
} catch (e) {
|
||||||
catch (e) {
|
|
||||||
msg = `${e}: ${arguments}`;
|
msg = `${e}: ${arguments}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,13 +250,12 @@ exports.group = function () {
|
||||||
/// @brief groupCollapsed
|
/// @brief groupCollapsed
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
exports.groupCollapsed = function () {
|
exports.groupCollapsed = function() {
|
||||||
var msg;
|
var msg;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
msg = sprintf.apply(sprintf, prepareArgs(arguments));
|
msg = sprintf.apply(sprintf, prepareArgs(arguments));
|
||||||
}
|
} catch (e) {
|
||||||
catch (e) {
|
|
||||||
msg = `${e}: ${arguments}`;
|
msg = `${e}: ${arguments}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,7 +267,7 @@ exports.groupCollapsed = function () {
|
||||||
/// @brief groupEnd
|
/// @brief groupEnd
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
exports.groupEnd = function () {
|
exports.groupEnd = function() {
|
||||||
groupLevel = groupLevel.substr(2);
|
groupLevel = groupLevel.substr(2);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -287,13 +275,12 @@ exports.groupEnd = function () {
|
||||||
/// @brief info
|
/// @brief info
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
exports.info = function () {
|
exports.info = function() {
|
||||||
var msg;
|
var msg;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
msg = sprintf.apply(sprintf, prepareArgs(arguments));
|
msg = sprintf.apply(sprintf, prepareArgs(arguments));
|
||||||
}
|
} catch (e) {
|
||||||
catch (e) {
|
|
||||||
msg = `${e}: ${arguments}`;
|
msg = `${e}: ${arguments}`;
|
||||||
}
|
}
|
||||||
logGroup('info', msg);
|
logGroup('info', msg);
|
||||||
|
@ -303,13 +290,12 @@ exports.info = function () {
|
||||||
/// @brief infoLines
|
/// @brief infoLines
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
exports.infoLines = function () {
|
exports.infoLines = function() {
|
||||||
var msg;
|
var msg;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
msg = sprintf.apply(sprintf, prepareArgs(arguments));
|
msg = sprintf.apply(sprintf, prepareArgs(arguments));
|
||||||
}
|
} catch (e) {
|
||||||
catch (e) {
|
|
||||||
msg = `${e}: ${arguments}`;
|
msg = `${e}: ${arguments}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,7 +323,7 @@ exports.logLines = exports.infoLines;
|
||||||
/// @brief time
|
/// @brief time
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
exports.time = function (label) {
|
exports.time = function(label) {
|
||||||
if (typeof label !== 'string') {
|
if (typeof label !== 'string') {
|
||||||
throw new Error('label must be a string');
|
throw new Error('label must be a string');
|
||||||
}
|
}
|
||||||
|
@ -370,7 +356,7 @@ exports.timeEnd = function(label) {
|
||||||
/// @brief trace
|
/// @brief trace
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
exports.trace = function () {
|
exports.trace = function() {
|
||||||
var err = new Error();
|
var err = new Error();
|
||||||
err.name = 'Trace';
|
err.name = 'Trace';
|
||||||
err.message = sprintf.apply(sprintf, prepareArgs(arguments));
|
err.message = sprintf.apply(sprintf, prepareArgs(arguments));
|
||||||
|
@ -388,13 +374,12 @@ exports.trace = function () {
|
||||||
/// @brief warn
|
/// @brief warn
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
exports.warn = function () {
|
exports.warn = function() {
|
||||||
var msg;
|
var msg;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
msg = sprintf.apply(sprintf, prepareArgs(arguments));
|
msg = sprintf.apply(sprintf, prepareArgs(arguments));
|
||||||
}
|
} catch (e) {
|
||||||
catch (e) {
|
|
||||||
msg = `${e}: ${arguments}`;
|
msg = `${e}: ${arguments}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,13 +390,12 @@ exports.warn = function () {
|
||||||
/// @brief warnLines
|
/// @brief warnLines
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
exports.warnLines = function () {
|
exports.warnLines = function() {
|
||||||
var msg;
|
var msg;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
msg = sprintf.apply(sprintf, prepareArgs(arguments));
|
msg = sprintf.apply(sprintf, prepareArgs(arguments));
|
||||||
}
|
} catch (e) {
|
||||||
catch (e) {
|
|
||||||
msg = `${e}: ${arguments}`;
|
msg = `${e}: ${arguments}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,5 +409,3 @@ exports.warnLines = function () {
|
||||||
|
|
||||||
return exports;
|
return exports;
|
||||||
}()));
|
}()));
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,12 @@
|
||||||
|
|
||||||
|
|
||||||
(function() {
|
(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 db = require("@arangodb").db;
|
||||||
var console = require("console");
|
var console = require("console");
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief logger
|
/// @brief logger
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
var logger = {
|
var logger = {
|
||||||
info: function (msg) {
|
info: function(msg) {
|
||||||
console.log("In database '%s': %s", db._name(), 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);
|
console.error("In database '%s': %s", db._name(), msg);
|
||||||
},
|
},
|
||||||
|
|
||||||
log: function (msg) {
|
log: function(msg) {
|
||||||
this.info(msg);
|
this.info(msg);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief CURRENT_VERSION
|
/// @brief CURRENT_VERSION
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -116,14 +114,17 @@ exports.NO_VERSION_FILE = -4;
|
||||||
|
|
||||||
exports.NO_SERVER_VERSION = -5;
|
exports.NO_SERVER_VERSION = -5;
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief checks the version
|
/// @brief checks the version
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
exports.databaseVersion = function () {
|
exports.databaseVersion = function() {
|
||||||
if (cluster.isCoordinator()) {
|
if (cluster.isCoordinator()) {
|
||||||
return { result: exports.IS_CLUSTER };
|
console.debug("skip on corrdinator");
|
||||||
|
|
||||||
|
return {
|
||||||
|
result: exports.IS_CLUSTER
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// path to the VERSION file
|
// path to the VERSION file
|
||||||
|
@ -133,25 +134,31 @@ exports.databaseVersion = function () {
|
||||||
// VERSION file exists, read its contents
|
// VERSION file exists, read its contents
|
||||||
if (fs.exists(versionFile)) {
|
if (fs.exists(versionFile)) {
|
||||||
var versionInfo = fs.read(versionFile);
|
var versionInfo = fs.read(versionFile);
|
||||||
|
console.debug("found version file: " + versionInfo);
|
||||||
|
|
||||||
if (versionInfo !== '') {
|
if (versionInfo !== '') {
|
||||||
var versionValues = JSON.parse(versionInfo);
|
var versionValues = JSON.parse(versionInfo);
|
||||||
|
|
||||||
if (versionValues && versionValues.version && ! isNaN(versionValues.version)) {
|
if (versionValues && versionValues.version && !isNaN(versionValues.version)) {
|
||||||
lastVersion = parseFloat(versionValues.version);
|
lastVersion = parseFloat(versionValues.version);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
logger.error("Cannot parse VERSION file '" + versionFile + "': '" + versionInfo + "'");
|
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 + "'");
|
logger.error("Cannot read VERSION file: '" + versionFile + "'");
|
||||||
return { result: exports.CANNOT_READ_VERSION_FILE };
|
return {
|
||||||
|
result: exports.CANNOT_READ_VERSION_FILE
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
console.debug("version file (" + versionFile + ") not found");
|
||||||
return { result: exports.NO_VERSION_FILE };
|
|
||||||
|
return {
|
||||||
|
result: exports.NO_VERSION_FILE
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract server version
|
// extract server version
|
||||||
|
@ -159,6 +166,9 @@ exports.databaseVersion = function () {
|
||||||
|
|
||||||
// version match!
|
// version match!
|
||||||
if (Math.floor(lastVersion / 100) === Math.floor(currentVersion / 100)) {
|
if (Math.floor(lastVersion / 100) === Math.floor(currentVersion / 100)) {
|
||||||
|
console.debug("version match: last version " + lastVersion +
|
||||||
|
", current version " + currentVersion);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
result: exports.VERSION_MATCH,
|
result: exports.VERSION_MATCH,
|
||||||
serverVersion: currentVersion,
|
serverVersion: currentVersion,
|
||||||
|
@ -168,6 +178,9 @@ exports.databaseVersion = function () {
|
||||||
|
|
||||||
// downgrade??
|
// downgrade??
|
||||||
if (lastVersion > currentVersion) {
|
if (lastVersion > currentVersion) {
|
||||||
|
console.debug("downgrade: last version " + lastVersion +
|
||||||
|
", current version " + currentVersion);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
result: exports.DOWNGRADE_NEEDED,
|
result: exports.DOWNGRADE_NEEDED,
|
||||||
serverVersion: currentVersion,
|
serverVersion: currentVersion,
|
||||||
|
@ -177,12 +190,20 @@ exports.databaseVersion = function () {
|
||||||
|
|
||||||
// upgrade
|
// upgrade
|
||||||
if (lastVersion < currentVersion) {
|
if (lastVersion < currentVersion) {
|
||||||
|
console.debug("upgrade: last version " + lastVersion +
|
||||||
|
", current version " + currentVersion);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
result: exports.UPGRADE_NEEDED,
|
result: exports.UPGRADE_NEEDED,
|
||||||
serverVersion: currentVersion,
|
serverVersion: currentVersion,
|
||||||
databaseVersion: lastVersion
|
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(".") {
|
_workingDirectory(".") {
|
||||||
setOptional(true);
|
setOptional(true);
|
||||||
requiresElevatedPrivileges(false);
|
requiresElevatedPrivileges(false);
|
||||||
|
startsAfter("Logger");
|
||||||
startsAfter("WorkMonitor");
|
startsAfter("WorkMonitor");
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
|
|
|
@ -38,6 +38,7 @@ RandomFeature::RandomFeature(application_features::ApplicationServer* server)
|
||||||
_randomGenerator((uint32_t) RandomGenerator::RandomType::MERSENNE) {
|
_randomGenerator((uint32_t) RandomGenerator::RandomType::MERSENNE) {
|
||||||
setOptional(false);
|
setOptional(false);
|
||||||
requiresElevatedPrivileges(false);
|
requiresElevatedPrivileges(false);
|
||||||
|
startsAfter("Logger");
|
||||||
}
|
}
|
||||||
|
|
||||||
void RandomFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
|
void RandomFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
|
||||||
|
|
|
@ -35,7 +35,10 @@ ShutdownFeature::ShutdownFeature(
|
||||||
setOptional(true);
|
setOptional(true);
|
||||||
requiresElevatedPrivileges(false);
|
requiresElevatedPrivileges(false);
|
||||||
startsAfter("Logger");
|
startsAfter("Logger");
|
||||||
startsAfter(feature);
|
|
||||||
|
if (feature != "Logger") {
|
||||||
|
startsAfter(feature);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShutdownFeature::start() {
|
void ShutdownFeature::start() {
|
||||||
|
|
|
@ -39,6 +39,7 @@ SupervisorFeature::SupervisorFeature(
|
||||||
setOptional(true);
|
setOptional(true);
|
||||||
requiresElevatedPrivileges(false);
|
requiresElevatedPrivileges(false);
|
||||||
startsAfter("Daemon");
|
startsAfter("Daemon");
|
||||||
|
startsAfter("Logger");
|
||||||
startsAfter("WorkMonitor");
|
startsAfter("WorkMonitor");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue