1
0
Fork 0
This commit is contained in:
Frank Celler 2016-04-11 17:44:41 +02:00
parent 3d2cc31306
commit 922753ef3d
39 changed files with 1004 additions and 1251 deletions

View File

@ -22,6 +22,7 @@
#include "ActionFeature.h"
#include "Actions/actions.h"
#include "ProgramOptions/ProgramOptions.h"
#include "ProgramOptions/Section.h"
#include "V8Server/V8DealerFeature.h"
@ -34,7 +35,9 @@ using namespace arangodb::options;
ActionFeature* ActionFeature::ACTION = nullptr;
ActionFeature::ActionFeature(application_features::ApplicationServer* server)
: ApplicationFeature(server, "Action") {}
: ApplicationFeature(server, "Action") {
startsAfter("Logger");
}
void ActionFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::collectOptions";
@ -68,5 +71,7 @@ void ActionFeature::start() {
void ActionFeature::stop() {
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::stop";
ACTION = this;
TRI_CleanupActions();
ACTION = nullptr;
}

View File

@ -0,0 +1,164 @@
////////////////////////////////////////////////////////////////////////////////
/// 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 Kaveh Vahedipour
////////////////////////////////////////////////////////////////////////////////
#include "AgencyFeature.h"
#include "Agency/Agent.h"
#include "Logger/Logger.h"
#include "ProgramOptions/ProgramOptions.h"
#include "ProgramOptions/Section.h"
using namespace arangodb;
using namespace arangodb::basics;
using namespace arangodb::options;
using namespace arangodb::rest;
AgencyFeature::AgencyFeature(application_features::ApplicationServer* server)
: ApplicationFeature(server, "Agency"),
_size(1),
_agentId((std::numeric_limits<uint32_t>::max)()),
_minElectionTimeout(0.15),
_maxElectionTimeout(1.0),
_electionCallRateMultiplier(0.85),
_notify(false) {
setOptional(false);
requiresElevatedPrivileges(false);
startsAfter("Database");
startsAfter("Dispatcher");
startsAfter("Scheduler");
startsAfter("Server");
}
AgencyFeature::~AgencyFeature() {}
void AgencyFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::collectOptions";
options->addSection("agency", "Configure the agency");
options->addOption("--agency.size", "number of agents",
new UInt64Parameter(&_size));
options->addOption("--agency.id", "this agent's id",
new UInt32Parameter(&_agentId));
options->addOption(
"--agency.election-timeout-min",
"minimum timeout before an agent calls for new election [s]",
new DoubleParameter(&_minElectionTimeout));
options->addOption(
"--agency.election-timeout-max",
"maximum timeout before an agent calls for new election [s]",
new DoubleParameter(&_maxElectionTimeout));
options->addOption("--agency.endpoint", "agency endpoints",
new VectorParameter<StringParameter>(&_agencyEndpoints));
options->addOption("--agency.election-call-rate-multiplier",
"Multiplier (<1.0) defining how long the election timeout "
"is with respect to the minumum election timeout",
new DoubleParameter(&_electionCallRateMultiplier));
options->addOption("--agency.notify", "notify others",
new BooleanParameter(&_notify));
}
void AgencyFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::validateOptions";
_disabled = (_agentId == (std::numeric_limits<uint32_t>::max)());
if (_disabled) {
return;
}
if (_size < 1) {
LOG_TOPIC(FATAL, Logger::AGENCY)
<< "AGENCY: agency must have size greater 0";
FATAL_ERROR_EXIT();
}
if (_size % 2 == 0) {
LOG_TOPIC(FATAL, Logger::AGENCY)
<< "AGENCY: agency must have odd number of members";
FATAL_ERROR_EXIT();
}
if (_agentId >= _size) {
LOG_TOPIC(FATAL, Logger::AGENCY) << "agency.id must not be larger than or "
<< "equal to agency.size";
FATAL_ERROR_EXIT();
}
if (_minElectionTimeout <= 0.) {
LOG_TOPIC(FATAL, Logger::AGENCY)
<< "agency.election-timeout-min must not be negative!";
FATAL_ERROR_EXIT();
} else if (_minElectionTimeout < 0.15) {
LOG_TOPIC(WARN, Logger::AGENCY)
<< "very short agency.election-timeout-min!";
}
if (_maxElectionTimeout <= _minElectionTimeout) {
LOG_TOPIC(FATAL, Logger::AGENCY)
<< "agency.election-timeout-max must not be shorter than or"
<< "equal to agency.election-timeout-min.";
FATAL_ERROR_EXIT();
}
if (_maxElectionTimeout <= 2 * _minElectionTimeout) {
LOG_TOPIC(WARN, Logger::AGENCY)
<< "agency.election-timeout-max should probably be chosen longer!";
}
}
void AgencyFeature::prepare() {
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::prepare";
_agencyEndpoints.resize(_size);
}
void AgencyFeature::start() {
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::start";
if (_disabled) {
return;
}
_agent.reset(new consensus::Agent(
consensus::config_t(_agentId, _minElectionTimeout, _maxElectionTimeout,
_agencyEndpoints, _notify)));
_agent->start();
}
void AgencyFeature::stop() {
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::stop";
if (_disabled) {
return;
}
_agent->beginShutdown();
}

View File

@ -0,0 +1,66 @@
////////////////////////////////////////////////////////////////////////////////
/// 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 Kaveh Vahedipour
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGOD_AGENCY_APPLICATION_AGENCY_H
#define ARANGOD_AGENCY_APPLICATION_AGENCY_H 1
#include "ApplicationFeatures/ApplicationFeature.h"
namespace arangodb {
namespace consensus {
class Agent;
}
class AgencyFeature : virtual public application_features::ApplicationFeature {
AgencyFeature(AgencyFeature const&) = delete;
AgencyFeature& operator=(AgencyFeature const&) = delete;
public:
explicit AgencyFeature(application_features::ApplicationServer* server);
~AgencyFeature();
public:
void collectOptions(std::shared_ptr<options::ProgramOptions>) override;
void validateOptions(std::shared_ptr<options::ProgramOptions>) override;
void prepare() override final;
void start() override final;
void stop() override final;
private:
uint64_t _size; // agency size (default: 5)
uint32_t _agentId;
double _minElectionTimeout; // min election timeout
double _maxElectionTimeout; // max election timeout
std::vector<std::string> _agencyEndpoints; // agency adresses
double _electionCallRateMultiplier;
bool _notify; // interval between retry to slaves
public:
consensus::Agent* agent() const { return _agent.get(); }
private:
std::unique_ptr<consensus::Agent> _agent;
bool _disabled;
};
}
#endif

View File

@ -1,169 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
/// 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 Kaveh Vahedipour
////////////////////////////////////////////////////////////////////////////////
#ifdef _WIN32
#include "Basics/win-utils.h"
#endif
#include "Logger/Logger.h"
#include "Scheduler/PeriodicTask.h"
#include "ApplicationAgency.h"
using namespace std;
using namespace arangodb::basics;
using namespace arangodb::rest;
ApplicationAgency::ApplicationAgency()
: ApplicationFeature("agency"), _size(1), _min_election_timeout(0.15),
_max_election_timeout(1.0), _election_call_rate_mul(0.85), _notify(false),
_agent_id((std::numeric_limits<uint32_t>::max)()) {
}
ApplicationAgency::~ApplicationAgency() {}
////////////////////////////////////////////////////////////////////////////////
/// @brief sets the processor affinity
////////////////////////////////////////////////////////////////////////////////
void ApplicationAgency::setupOptions(
std::map<std::string, ProgramOptionsDescription>& options) {
options["Agency Options:help-agency"]("agency.size", &_size, "Agency size")
("agency.id", &_agent_id, "This agent's id")
("agency.election-timeout-min", &_min_election_timeout, "Minimum "
"timeout before an agent calls for new election [s]")
("agency.election-timeout-max", &_max_election_timeout, "Minimum "
"timeout before an agent calls for new election [s]")
("agency.endpoint", &_agency_endpoints, "Agency endpoints")
("agency.election_call_rate_mul [au]", &_election_call_rate_mul,
"Multiplier (<1.0) defining how long the election timeout is with respect "
"to the minumum election timeout")
("agency.notify", &_notify, "Notify others");
}
bool ApplicationAgency::afterOptionParsing (ProgramOptions& opts) {
// LOG_TOPIC(WARN, Logger::AGENCY) << "Server endpoint " << opts.has("server.endpoint");
return true;
}
bool ApplicationAgency::prepare() {
_disabled = (_agent_id == (std::numeric_limits<uint32_t>::max)());
if (_disabled) {
return true;
}
if (_size < 1) {
LOG_TOPIC(ERR, Logger::AGENCY) << "AGENCY: agency must have size greater 0";
return false;
}
if (_size % 2 == 0) {
LOG_TOPIC(ERR, Logger::AGENCY)
<< "AGENCY: agency must have odd number of members";
return false;
}
if (_agent_id == (std::numeric_limits<uint32_t>::max)()) {
LOG_TOPIC(ERR, Logger::AGENCY) << "agency.id must be specified";
return false;
}
if (_agent_id >= _size) {
LOG_TOPIC(ERR, Logger::AGENCY) << "agency.id must not be larger than or "
<< "equal to agency.size";
return false;
}
if (_min_election_timeout <= 0.) {
LOG_TOPIC(ERR, Logger::AGENCY)
<< "agency.election-timeout-min must not be negative!";
return false;
} else if (_min_election_timeout < .15) {
LOG_TOPIC(WARN, Logger::AGENCY)
<< "very short agency.election-timeout-min!";
}
if (_max_election_timeout <= _min_election_timeout) {
LOG_TOPIC(ERR, Logger::AGENCY)
<< "agency.election-timeout-max must not be shorter than or"
<< "equal to agency.election-timeout-min.";
return false;
}
if (_max_election_timeout <= 2*_min_election_timeout) {
LOG_TOPIC(WARN, Logger::AGENCY)
<< "agency.election-timeout-max should probably be chosen longer!";
}
_agency_endpoints.resize(_size);
_agent = std::unique_ptr<agent_t>(
new agent_t(arangodb::consensus::config_t(
_agent_id, _min_election_timeout, _max_election_timeout,
_agency_endpoints, _notify)));
return true;
}
bool ApplicationAgency::start() {
if (_disabled) {
return true;
}
_agent->start();
return true;
}
bool ApplicationAgency::open() { return true; }
void ApplicationAgency::close() {
if (_disabled) {
return;
}
}
void ApplicationAgency::stop() {
if (_disabled) {
return;
}
_agent->beginShutdown();
}
agent_t* ApplicationAgency::agent () const {
return _agent.get();
}

View File

@ -1,126 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
/// 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 Kaveh Vahedipour
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGOD_AGENCY_APPLICATION_AGENCY_H
#define ARANGOD_AGENCY_APPLICATION_AGENCY_H 1
#include "Basics/Common.h"
#include "ApplicationServer/ApplicationFeature.h"
#include "Agency/Agent.h"
namespace arangodb {
namespace rest {
class Task;
////////////////////////////////////////////////////////////////////////////////
/// @brief application server with agency
////////////////////////////////////////////////////////////////////////////////
using agent_t = consensus::Agent;
class ApplicationAgency : virtual public arangodb::rest::ApplicationFeature {
private:
ApplicationAgency(ApplicationAgency const&);
ApplicationAgency& operator=(ApplicationAgency const&);
public:
ApplicationAgency();
~ApplicationAgency();
public:
//////////////////////////////////////////////////////////////////////////////
/// @brief builds the dispatcher queue
//////////////////////////////////////////////////////////////////////////////
void buildStandardQueue(size_t nrThreads, size_t maxSize);
//////////////////////////////////////////////////////////////////////////////
/// @brief builds the additional AQL dispatcher queue
//////////////////////////////////////////////////////////////////////////////
void buildAQLQueue(size_t nrThreads, size_t maxSize);
//////////////////////////////////////////////////////////////////////////////
/// @brief builds an additional dispatcher queue
//////////////////////////////////////////////////////////////////////////////
void buildExtraQueue(size_t name, size_t nrThreads, size_t maxSize);
//////////////////////////////////////////////////////////////////////////////
/// @brief returns the number of used threads
//////////////////////////////////////////////////////////////////////////////
size_t size();
//////////////////////////////////////////////////////////////////////////////
/// @brief sets the processor affinity
//////////////////////////////////////////////////////////////////////////////
void setProcessorAffinity(std::vector<size_t> const& cores);
void stop () override;
public:
#warning TODO
#if 0
void setupOptions(std::map<std::string,
arangodb::basics::ProgramOptionsDescription>&) override final;
bool afterOptionParsing (arangodb::basics::ProgramOptions &) override final;
#endif
bool prepare() override final;
bool start() override final;
bool open() override final;
void close() override final;
agent_t* agent() const;
private:
uint64_t _size; /**< @brief: agency size (default: 5)*/
double _min_election_timeout; /**< @brief: min election timeout */
double _max_election_timeout; /**< @brief: max election timeout */
double _election_call_rate_mul; /**< @brief: */
bool _notify;
/**< @brief interval between retry to slaves*/
std::vector<std::string> _agency_endpoints; /**< @brief agency adresses */
std::unique_ptr<agent_t> _agent;
uint32_t _agent_id;
};
}
}
#endif

View File

@ -1,74 +0,0 @@
namespace arangodb {
extern ConfigFeature CONFIG_FEATURE;
extern LoggerFeature LOGGER_FEATURE;
extern SslFeature SSL_FEATURE;
#if 0
options["Hidden Options"]
#ifdef ARANGODB_HAVE_SETUID
("uid", &_uid, "switch to user-id after reading config files")
#endif
#ifdef ARANGODB_HAVE_SETGID
("gid", &_gid, "switch to group-id after reading config files")
#endif
;
#if defined(ARANGODB_HAVE_SETUID) || defined(ARANGODB_HAVE_SETGID)
options["General Options:help-admin"]
#ifdef ARANGODB_HAVE_GETPPID
("exit-on-parent-death", &_exitOnParentDeath, "exit if parent dies")
#endif
("watch-process", &_watchParent,
"exit if process with given PID dies");
#endif
#endif
#warning TODO
#if 0
// .............................................................................
// UID and GID
// .............................................................................
extractPrivileges();
dropPrivilegesPermanently();
return true;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief checks if the parent is still alive
////////////////////////////////////////////////////////////////////////////////
bool ApplicationServer::checkParent() {
// check our parent, if it died given up
#ifdef ARANGODB_HAVE_GETPPID
if (_exitOnParentDeath && getppid() == 1) {
LOG(INFO) << "parent has died";
return false;
}
#endif
// unfortunately even though windows has <signal.h>, there is no
// kill method defined. Notice that the kill below is not to terminate
// the process.
#ifdef TRI_HAVE_SIGNAL_H
if (_watchParent != 0) {
#ifdef TRI_HAVE_POSIX
int res = kill(_watchParent, 0);
#else
int res = -1;
#endif
if (res != 0) {
LOG(INFO) << "parent " << _watchParent << " has died";
return false;
}
}
#endif
return true;
}
#endif

View File

@ -220,6 +220,7 @@ void Collection::fillIndexes() const {
// we rather look at the local indexes.
// FIXME: Remove fillIndexesDBServer later, when it is clear that we
// will never have to do this.
#warning TODO Remove fillIndexesDBServer later, when it is clear that we will never have to do this.
#if 0
if (arangodb::ServerState::instance()->isDBServer(role) &&
documentCollection()->_info._planId > 0) {

View File

@ -70,7 +70,7 @@ add_executable(${BIN_ARANGOD}
Actions/RestActionHandler.cpp
Actions/actions.cpp
Agency/Agent.cpp
# Agency/ApplicationAgency.cpp
Agency/AgencyFeature.cpp
Agency/Constituent.cpp
Agency/State.cpp
Agency/Store.cpp
@ -139,7 +139,7 @@ add_executable(${BIN_ARANGOD}
Aql/grammar.cpp
Aql/tokens.cpp
Cluster/AgencyComm.cpp
# TODO Cluster/ApplicationCluster.cpp
Cluster/ClusterFeature.cpp
Cluster/ClusterComm.cpp
Cluster/ClusterInfo.cpp
Cluster/ClusterMethods.cpp

View File

@ -1,266 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
/// 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 Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGOD_CLUSTER_APPLICATION_CLUSTER_H
#define ARANGOD_CLUSTER_APPLICATION_CLUSTER_H 1
#include "Basics/Common.h"
#include "ApplicationServer/ApplicationFeature.h"
struct TRI_server_t;
namespace arangodb {
namespace rest {
class ApplicationDispatcher;
}
class ApplicationV8;
class HeartbeatThread;
////////////////////////////////////////////////////////////////////////////////
/// @brief sharding feature configuration
////////////////////////////////////////////////////////////////////////////////
class ApplicationCluster : public rest::ApplicationFeature {
private:
ApplicationCluster(ApplicationCluster const&) = delete;
ApplicationCluster& operator=(ApplicationCluster const&) = delete;
public:
ApplicationCluster(TRI_server_t*, arangodb::rest::ApplicationDispatcher*,
arangodb::ApplicationV8*);
~ApplicationCluster();
public:
//////////////////////////////////////////////////////////////////////////////
/// @brief disable the heartbeat (used for testing)
//////////////////////////////////////////////////////////////////////////////
void disableHeartbeat() { _disableHeartbeat = true; }
//////////////////////////////////////////////////////////////////////////////
/// @brief whether or not the cluster is enabled
//////////////////////////////////////////////////////////////////////////////
inline bool enabled() const { return _enableCluster; }
public:
#warning TODO
// void setupOptions(std::map<std::string, basics::ProgramOptionsDescription>&) override final;
bool prepare() override final;
bool open() override final;
bool start() override final;
void close() override final;
void stop() override final;
private:
//////////////////////////////////////////////////////////////////////////////
/// @brief server
//////////////////////////////////////////////////////////////////////////////
TRI_server_t* _server;
//////////////////////////////////////////////////////////////////////////////
/// @brief dispatcher
//////////////////////////////////////////////////////////////////////////////
arangodb::rest::ApplicationDispatcher* _dispatcher;
//////////////////////////////////////////////////////////////////////////////
/// @brief v8 dispatcher
//////////////////////////////////////////////////////////////////////////////
arangodb::ApplicationV8* _applicationV8;
//////////////////////////////////////////////////////////////////////////////
/// @brief thread for heartbeat
//////////////////////////////////////////////////////////////////////////////
HeartbeatThread* _heartbeat;
//////////////////////////////////////////////////////////////////////////////
/// @brief heartbeat interval (in milliseconds)
//////////////////////////////////////////////////////////////////////////////
uint64_t _heartbeatInterval;
////////////////////////////////////////////////////////////////////////////////
/// @brief was docuBlock clusterAgencyEndpoint
////////////////////////////////////////////////////////////////////////////////
std::vector<std::string> _agencyEndpoints;
////////////////////////////////////////////////////////////////////////////////
/// @brief was docuBlock clusterAgencyPrefix
////////////////////////////////////////////////////////////////////////////////
std::string _agencyPrefix;
////////////////////////////////////////////////////////////////////////////////
/// @brief was docuBlock clusterMyLocalInfo
////////////////////////////////////////////////////////////////////////////////
std::string _myLocalInfo;
////////////////////////////////////////////////////////////////////////////////
/// @brief was docuBlock clusterMyId
////////////////////////////////////////////////////////////////////////////////
std::string _myId;
////////////////////////////////////////////////////////////////////////////////
/// @brief was docuBlock clusterMyRole
////////////////////////////////////////////////////////////////////////////////
std::string _myRole;
////////////////////////////////////////////////////////////////////////////////
/// @brief was docuBlock clusterMyAddress
////////////////////////////////////////////////////////////////////////////////
std::string _myAddress;
////////////////////////////////////////////////////////////////////////////////
/// @brief was docuBlock clusterUsername
////////////////////////////////////////////////////////////////////////////////
std::string _username;
////////////////////////////////////////////////////////////////////////////////
/// @brief was docuBlock clusterPassword
////////////////////////////////////////////////////////////////////////////////
std::string _password;
//////////////////////////////////////////////////////////////////////////////
/// @brief data path for the cluster
///
/// @CMDOPT{\--cluster.data-path @CA{path}}
///
/// The default directory where the databases for the cluster processes are
/// stored.
//////////////////////////////////////////////////////////////////////////////
std::string _dataPath;
//////////////////////////////////////////////////////////////////////////////
/// @brief log path for the cluster
///
/// @CMDOPT{\--cluster.log-path @CA{path}}
///
/// The default directory where the log files for the cluster processes are
/// stored.
//////////////////////////////////////////////////////////////////////////////
std::string _logPath;
//////////////////////////////////////////////////////////////////////////////
/// @brief agent path for the cluster
///
/// @CMDOPT{\--cluster.agent-path @CA{path}}
///
/// The path to agent executable.
//////////////////////////////////////////////////////////////////////////////
std::string _agentPath;
//////////////////////////////////////////////////////////////////////////////
/// @brief arangod path for the cluster
///
/// @CMDOPT{\--cluster.arangod-path @CA{path}}
///
/// The path to arangod executable.
//////////////////////////////////////////////////////////////////////////////
std::string _arangodPath;
//////////////////////////////////////////////////////////////////////////////
/// @brief DBserver config for the cluster
///
/// @CMDOPT{\--cluster.dbserver-config @CA{path}}
///
/// The configuration file for the DBserver.
//////////////////////////////////////////////////////////////////////////////
std::string _dbserverConfig;
//////////////////////////////////////////////////////////////////////////////
/// @brief coordinator config for the cluster
///
/// @CMDOPT{\--cluster.coordinator-config @CA{path}}
///
/// The configuration file for the coordinator.
//////////////////////////////////////////////////////////////////////////////
std::string _coordinatorConfig;
//////////////////////////////////////////////////////////////////////////////
/// @brief disable the dispatcher frontend
///
/// @CMDOPT{\--server.disable-dispatcher-interface @CA{flag}}
///
/// If @LIT{true} the server can be used as dispatcher for a cluster. If you
/// enable this option, you should secure access to the dispatcher with a
/// password.
///
/// The default is @LIT{true}.
//////////////////////////////////////////////////////////////////////////////
bool _disableDispatcherFrontend;
//////////////////////////////////////////////////////////////////////////////
/// @brief disable the dispatcher kickstarter
///
/// @CMDOPT{\--server.disable-dispatcher-kickstarter @CA{flag}}
///
/// If @LIT{true} the server can be used as kickstarter to start processes for
/// a
/// cluster. If you enable this option, you should secure access to the
/// dispatcher with a password.
///
/// The default is @LIT{true}.
//////////////////////////////////////////////////////////////////////////////
bool _disableDispatcherKickstarter;
//////////////////////////////////////////////////////////////////////////////
/// @brief whether or not the cluster feature is enabled
//////////////////////////////////////////////////////////////////////////////
bool _enableCluster;
//////////////////////////////////////////////////////////////////////////////
/// @brief flag for turning off heartbeat (used for testing)
//////////////////////////////////////////////////////////////////////////////
bool _disableHeartbeat;
};
}
#endif

View File

@ -21,7 +21,7 @@
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#include "ApplicationCluster.h"
#include "ClusterFeature.h"
#include "Basics/FileUtils.h"
#include "Basics/JsonHelper.h"
@ -31,130 +31,128 @@
#include "Cluster/ClusterInfo.h"
#include "Cluster/HeartbeatThread.h"
#include "Cluster/ServerState.h"
#include "Dispatcher/ApplicationDispatcher.h"
#include "Endpoint/Endpoint.h"
#include "Logger/Logger.h"
#include "ProgramOptions/ProgramOptions.h"
#include "ProgramOptions/Section.h"
#include "SimpleHttpClient/ConnectionManager.h"
// #include "V8Server/ApplicationV8.h"
#include "VocBase/server.h"
using namespace arangodb;
using namespace arangodb::basics;
using namespace arangodb::options;
ApplicationCluster::ApplicationCluster(
TRI_server_t* server, arangodb::rest::ApplicationDispatcher* dispatcher,
ApplicationV8* applicationV8)
: ApplicationFeature("Sharding"),
_server(server),
_dispatcher(dispatcher),
_applicationV8(applicationV8),
_heartbeat(nullptr),
_heartbeatInterval(0),
_agencyEndpoints(),
_agencyPrefix(),
_myId(),
_myAddress(),
ClusterFeature::ClusterFeature(application_features::ApplicationServer* server)
: ApplicationFeature(server, "Cluster"),
_username("root"),
_password(),
_dataPath(),
_logPath(),
_agentPath(),
_arangodPath(),
_dbserverConfig(),
_coordinatorConfig(),
_disableDispatcherFrontend(true),
_disableDispatcherKickstarter(true),
_dispatcherFrontend(false),
_kickstarter(false),
_enableCluster(false),
_heartbeatThread(nullptr),
_heartbeatInterval(0),
_disableHeartbeat(false) {
TRI_ASSERT(_dispatcher != nullptr);
setOptional(false);
requiresElevatedPrivileges(false);
startsAfter("Database");
startsAfter("Dispatcher");
startsAfter("Scheduler");
}
ApplicationCluster::~ApplicationCluster() {
delete _heartbeat;
ClusterFeature::~ClusterFeature() {
delete _heartbeatThread;
// delete connection manager instance
auto cm = httpclient::ConnectionManager::instance();
delete cm;
}
#warning TODO
#if 0
void ApplicationCluster::setupOptions(
std::map<std::string, basics::ProgramOptionsDescription>& options) {
options["Cluster options:help-cluster"]("cluster.agency-endpoint",
&_agencyEndpoints,
"agency endpoint to connect to")(
"cluster.agency-prefix", &_agencyPrefix, "agency prefix")(
"cluster.my-local-info", &_myLocalInfo, "this server's local info")(
"cluster.my-id", &_myId, "this server's id")(
"cluster.my-address", &_myAddress, "this server's endpoint")(
"cluster.my-role", &_myRole, "this server's role")(
"cluster.username", &_username,
"username used for cluster-internal communication")(
"cluster.password", &_password,
"password used for cluster-internal communication")(
"cluster.data-path", &_dataPath, "path to cluster database directory")(
"cluster.log-path", &_logPath, "path to log directory for the cluster")(
"cluster.agent-path", &_agentPath, "path to the agent for the cluster")(
"cluster.arangod-path", &_arangodPath,
"path to the arangod for the cluster")(
"cluster.dbserver-config", &_dbserverConfig,
"path to the DBserver configuration")(
"cluster.coordinator-config", &_coordinatorConfig,
"path to the coordinator configuration")(
"cluster.disable-dispatcher-frontend", &_disableDispatcherFrontend,
"do not show the dispatcher interface")(
"cluster.disable-dispatcher-kickstarter", &_disableDispatcherKickstarter,
"disable the kickstarter functionality");
void ClusterFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::collectOptions";
options->addSection("cluster", "Configure the cluster");
options->addOption("--cluster.agency-endpoint",
"agency endpoint to connect to",
new VectorParameter<StringParameter>(&_agencyEndpoints));
options->addOption("--cluster.agency-prefix", "agency prefix",
new StringParameter(&_agencyPrefix));
options->addOption("--cluster.my-local-info", "this server's local info",
new StringParameter(&_myLocalInfo));
options->addOption("--cluster.my-id", "this server's id",
new StringParameter(&_myId));
options->addOption("--cluster.my-role", "this server's role",
new StringParameter(&_myRole));
options->addOption("--cluster.my-address", "this server's endpoint",
new StringParameter(&_myAddress));
options->addOption("--cluster.username",
"username used for cluster-internal communication",
new StringParameter(&_username));
options->addOption("--cluster.password",
"password used for cluster-internal communication",
new StringParameter(&_password));
options->addOption("--cluster.data-path",
"path to cluster database directory",
new StringParameter(&_dataPath));
options->addOption("--cluster.log-path",
"path to log directory for the cluster",
new StringParameter(&_logPath));
options->addOption("--cluster.arangod-path",
"path to the arangod for the cluster",
new StringParameter(&_arangodPath));
options->addOption("--cluster.agent-path",
"path to the agent for the cluster",
new StringParameter(&_agentPath));
options->addOption("--cluster.dbserver-config",
"path to the DBserver configuration",
new StringParameter(&_dbserverConfig));
options->addOption("--cluster.coordinator-config",
"path to the coordinator configuration",
new StringParameter(&_coordinatorConfig));
options->addOption("--cluster.dispatcher-frontend",
"show the dispatcher interface",
new BooleanParameter(&_dispatcherFrontend));
options->addOption("--cluster.kickstarter", "enable the kickstarter",
new BooleanParameter(&_kickstarter));
}
#endif
bool ApplicationCluster::prepare() {
// set authentication data
ServerState::instance()->setAuthentication(_username, _password);
void ClusterFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::validateOptions";
// overwrite memory area
_username = _password = "someotherusername";
ServerState::instance()->setDataPath(_dataPath);
ServerState::instance()->setLogPath(_logPath);
ServerState::instance()->setAgentPath(_agentPath);
ServerState::instance()->setArangodPath(_arangodPath);
ServerState::instance()->setDBserverConfig(_dbserverConfig);
ServerState::instance()->setCoordinatorConfig(_coordinatorConfig);
ServerState::instance()->setDisableDispatcherFrontend(
_disableDispatcherFrontend);
ServerState::instance()->setDisableDispatcherKickstarter(
_disableDispatcherKickstarter);
// initialize ConnectionManager library
httpclient::ConnectionManager::initialize();
// initialize ClusterComm library
// must call initialize while still single-threaded
ClusterComm::initialize();
if (_disabled) {
// if ApplicationFeature is disabled
_enableCluster = false;
ServerState::instance()->setRole(ServerState::ROLE_SINGLE);
return true;
}
// check the cluster state
// check if the cluster is enabled
_enableCluster = !_agencyEndpoints.empty();
if (!_enableCluster) {
ServerState::instance()->setRole(ServerState::ROLE_SINGLE);
return;
}
// validate --cluster.agency-endpoint (currently a noop)
if (_agencyEndpoints.empty()) {
LOG(FATAL)
<< "must at least specify one endpoint in --cluster.agency-endpoint";
FATAL_ERROR_EXIT();
}
// validate
if (_agencyPrefix.empty()) {
_agencyPrefix = "arango";
}
if (!enabled()) {
ServerState::instance()->setRole(ServerState::ROLE_SINGLE);
return true;
}
ServerState::instance()->setClusterEnabled();
// validate --cluster.agency-prefix
size_t found = _agencyPrefix.find_first_not_of(
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/");
@ -164,28 +162,6 @@ bool ApplicationCluster::prepare() {
FATAL_ERROR_EXIT();
}
// register the prefix with the communicator
AgencyComm::setPrefix(_agencyPrefix);
// validate --cluster.agency-endpoint
if (_agencyEndpoints.empty()) {
LOG(FATAL)
<< "must at least specify one endpoint in --cluster.agency-endpoint";
FATAL_ERROR_EXIT();
}
for (size_t i = 0; i < _agencyEndpoints.size(); ++i) {
std::string const unified = Endpoint::unifiedForm(_agencyEndpoints[i]);
if (unified.empty()) {
LOG(FATAL) << "invalid endpoint '" << _agencyEndpoints[i]
<< "' specified for --cluster.agency-endpoint";
FATAL_ERROR_EXIT();
}
AgencyComm::addEndpoint(unified);
}
// validate --cluster.my-id
if (_myId.empty()) {
if (_myLocalInfo.empty()) {
@ -208,19 +184,64 @@ bool ApplicationCluster::prepare() {
FATAL_ERROR_EXIT();
}
}
}
void ClusterFeature::prepare() {
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::prepare";
ServerState::instance()->setAuthentication(_username, _password);
ServerState::instance()->setDataPath(_dataPath);
ServerState::instance()->setLogPath(_logPath);
ServerState::instance()->setAgentPath(_agentPath);
ServerState::instance()->setArangodPath(_arangodPath);
ServerState::instance()->setDBserverConfig(_dbserverConfig);
ServerState::instance()->setCoordinatorConfig(_coordinatorConfig);
ServerState::instance()->setDisableDispatcherFrontend(!_dispatcherFrontend);
ServerState::instance()->setDisableDispatcherKickstarter(!_kickstarter);
// initialize ConnectionManager library
httpclient::ConnectionManager::initialize();
// create an instance (this will not yet create a thread)
ClusterComm::instance();
}
#warning TODO split into methods
void ClusterFeature::start() {
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::start";
// initialize ClusterComm library, must call initialize only once
ClusterComm::initialize();
// return if cluster is disabled
if (!_enableCluster) {
return;
}
ServerState::instance()->setClusterEnabled();
// register the prefix with the communicator
AgencyComm::setPrefix(_agencyPrefix);
for (size_t i = 0; i < _agencyEndpoints.size(); ++i) {
std::string const unified = Endpoint::unifiedForm(_agencyEndpoints[i]);
if (unified.empty()) {
LOG(FATAL) << "invalid endpoint '" << _agencyEndpoints[i]
<< "' specified for --cluster.agency-endpoint";
FATAL_ERROR_EXIT();
}
AgencyComm::addEndpoint(unified);
}
// Now either _myId is set properly or _myId is empty and _myLocalInfo and
// _myAddress are set.
if (!_myAddress.empty()) {
ServerState::instance()->setAddress(_myAddress);
}
// initialize ConnectionManager library
// httpclient::ConnectionManager::initialize();
// initialize ClusterComm library
// must call initialize while still single-threaded
// ClusterComm::initialize();
// disable error logging for a while
ClusterComm::instance()->enableConnectionErrorLogging(false);
@ -233,18 +254,21 @@ bool ApplicationCluster::prepare() {
}
ServerState::instance()->setLocalInfo(_myLocalInfo);
if (!_myId.empty()) {
ServerState::instance()->setId(_myId);
}
if (!_myRole.empty()) {
ServerState::RoleEnum role = ServerState::stringToRole(_myRole);
if (role == ServerState::ROLE_SINGLE ||
role == ServerState::ROLE_UNDEFINED) {
LOG(FATAL) << "Invalid role provided. Possible values: PRIMARY, "
"SECONDARY, COORDINATOR";
FATAL_ERROR_EXIT();
}
if (!ServerState::instance()->registerWithRole(role)) {
LOG(FATAL) << "Couldn't register at agency.";
FATAL_ERROR_EXIT();
@ -260,6 +284,13 @@ bool ApplicationCluster::prepare() {
FATAL_ERROR_EXIT();
}
if (role == ServerState::ROLE_SINGLE) {
LOG(FATAL) << "determined single-server role for server '" << _myId
<< "'. Please check the configurarion in the agency ("
<< endpoints << ")";
FATAL_ERROR_EXIT();
}
if (_myId.empty()) {
_myId = ServerState::instance()->getId(); // has been set by getRole!
}
@ -269,6 +300,7 @@ bool ApplicationCluster::prepare() {
// no address given, now ask the agency for our address
_myAddress = ServerState::instance()->getAddress();
}
// if nonempty, it has already been set above
// If we are a coordinator, we wait until at least one DBServer is there,
@ -276,30 +308,21 @@ bool ApplicationCluster::prepare() {
// any collection:
if (role == ServerState::ROLE_COORDINATOR) {
ClusterInfo* ci = ClusterInfo::instance();
do {
while (true) {
LOG(INFO) << "Waiting for a DBserver to show up...";
ci->loadCurrentDBServers();
std::vector<ServerID> DBServers = ci->getCurrentDBServers();
if (DBServers.size() > 0) {
LOG(INFO) << "Found a DBserver.";
break;
}
sleep(1);
} while (true);
};
}
return true;
}
bool ApplicationCluster::start() {
if (!enabled()) {
return true;
}
std::string const endpoints = AgencyComm::getEndpointsString();
ServerState::RoleEnum role = ServerState::instance()->getRole();
if (_myAddress.empty()) {
LOG(FATAL) << "unable to determine internal address for server '" << _myId
<< "'. Please specify --cluster.my-address or configure the "
@ -360,42 +383,33 @@ bool ApplicationCluster::start() {
}
// start heartbeat thread
_heartbeat = new HeartbeatThread(_server, _dispatcher, _applicationV8,
_heartbeatInterval * 1000, 5);
_heartbeatThread = new HeartbeatThread(_heartbeatInterval * 1000, 5);
if (_heartbeat == nullptr) {
if (_heartbeatThread == nullptr) {
LOG(FATAL) << "unable to start cluster heartbeat thread";
FATAL_ERROR_EXIT();
}
if (!_heartbeat->init() || !_heartbeat->start()) {
if (!_heartbeatThread->init() || !_heartbeatThread->start()) {
LOG(FATAL) << "heartbeat could not connect to agency endpoints ("
<< endpoints << ")";
FATAL_ERROR_EXIT();
}
while (!_heartbeat->isReady()) {
while (!_heartbeatThread->isReady()) {
// wait until heartbeat is ready
usleep(10000);
}
}
return true;
}
bool ApplicationCluster::open() {
if (!enabled()) {
return true;
}
AgencyComm comm;
AgencyCommResult result;
bool success;
do {
while (true) {
AgencyCommLocker locker("Current", "WRITE");
success = locker.successful();
if (success) {
VPackBuilder builder;
try {
@ -421,10 +435,9 @@ bool ApplicationCluster::open() {
if (success) {
break;
}
sleep(1);
} while (true);
ServerState::RoleEnum role = ServerState::instance()->getRole();
sleep(1);
}
if (role == ServerState::ROLE_COORDINATOR) {
ServerState::instance()->setState(ServerState::STATE_SERVING);
@ -433,28 +446,26 @@ bool ApplicationCluster::open() {
} else if (role == ServerState::ROLE_SECONDARY) {
ServerState::instance()->setState(ServerState::STATE_SYNCING);
}
return true;
DispatcherFeature::DISPATCHER->buildAqlQueue();
}
void ApplicationCluster::close() {
if (!enabled()) {
return;
void ClusterFeature::stop() {
if (_enableCluster) {
if (_heartbeatThread != nullptr) {
_heartbeatThread->beginShutdown();
}
// change into shutdown state
ServerState::instance()->setState(ServerState::STATE_SHUTDOWN);
AgencyComm comm;
comm.sendServerState(0.0);
}
if (_heartbeat != nullptr) {
_heartbeat->beginShutdown();
}
// change into shutdown state
ServerState::instance()->setState(ServerState::STATE_SHUTDOWN);
AgencyComm comm;
comm.sendServerState(0.0);
}
void ApplicationCluster::stop() {
ClusterComm::cleanup();
if (!enabled()) {
if (!_enableCluster) {
return;
}
@ -464,10 +475,6 @@ void ApplicationCluster::stop() {
AgencyComm comm;
comm.sendServerState(0.0);
if (_heartbeat != nullptr) {
_heartbeat->beginShutdown();
}
{
AgencyCommLocker locker("Current", "WRITE");
@ -486,7 +493,7 @@ void ApplicationCluster::stop() {
}
}
while (_heartbeat->isRunning()) {
while (_heartbeatThread->isRunning()) {
usleep(50000);
}

View File

@ -0,0 +1,82 @@
////////////////////////////////////////////////////////////////////////////////
/// 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 Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGOD_CLUSTER_CLUSTER_FEATURE_H
#define ARANGOD_CLUSTER_CLUSTER_FEATURE_H 1
#include "Basics/Common.h"
#include "ApplicationFeatures/ApplicationFeature.h"
namespace arangodb {
class HeartbeatThread;
class ClusterFeature : public application_features::ApplicationFeature {
public:
ClusterFeature(application_features::ApplicationServer*);
~ClusterFeature();
public:
// disable the heartbeat (used for testing)
#warning TODO
// void disableHeartbeat() { _disableHeartbeat = true; }
// whether or not the cluster is enabled
#warning TODO
// inline bool enabled() const { return _enableCluster; }
public:
void collectOptions(std::shared_ptr<options::ProgramOptions>) override;
void validateOptions(std::shared_ptr<options::ProgramOptions>) override;
void prepare() override;
void start() override;
void stop() override;
private:
std::vector<std::string> _agencyEndpoints;
std::string _agencyPrefix;
std::string _myLocalInfo;
std::string _myId;
std::string _myRole;
std::string _myAddress;
std::string _username;
std::string _password;
std::string _dataPath;
std::string _logPath;
std::string _arangodPath;
std::string _agentPath;
std::string _dbserverConfig;
std::string _coordinatorConfig;
bool _dispatcherFrontend;
bool _kickstarter;
private:
bool _enableCluster;
HeartbeatThread* _heartbeatThread;
uint64_t _heartbeatInterval;
bool _disableHeartbeat;
};
}
#endif

View File

@ -22,6 +22,7 @@
////////////////////////////////////////////////////////////////////////////////
#include "HeartbeatThread.h"
#include "Basics/ConditionLocker.h"
#include "Basics/JsonHelper.h"
#include "Logger/Logger.h"
@ -32,10 +33,9 @@
#include "Cluster/ClusterMethods.h"
#include "Cluster/ServerJob.h"
#include "Cluster/ServerState.h"
// #include "Dispatcher/ApplicationDispatcher.h"
#include "Dispatcher/Dispatcher.h"
#include "Dispatcher/DispatcherFeature.h"
#include "Dispatcher/Job.h"
// #include "V8Server/ApplicationV8.h"
#include "V8/v8-globals.h"
#include "V8Server/v8-vocbase.h"
#include "VocBase/auth.h"
@ -50,14 +50,9 @@ volatile sig_atomic_t HeartbeatThread::HasRunOnce = 0;
/// @brief constructs a heartbeat thread
////////////////////////////////////////////////////////////////////////////////
HeartbeatThread::HeartbeatThread(
TRI_server_t* server, arangodb::rest::ApplicationDispatcher* dispatcher,
ApplicationV8* applicationV8, uint64_t interval,
uint64_t maxFailsBeforeWarning)
HeartbeatThread::HeartbeatThread(uint64_t interval,
uint64_t maxFailsBeforeWarning)
: Thread("Heartbeat"),
_server(server),
_dispatcher(dispatcher),
_applicationV8(applicationV8),
_statusLock(),
_agency(),
_condition(),
@ -68,10 +63,8 @@ HeartbeatThread::HeartbeatThread(
_numFails(0),
_numDispatchedJobs(0),
_lastDispatchedJobResult(false),
_versionThatTriggeredLastJob(0),
_ready(false) {
TRI_ASSERT(_dispatcher != nullptr);
}
_versionThatTriggeredLastJob(0),
_ready(false) {}
////////////////////////////////////////////////////////////////////////////////
/// @brief destroys a heartbeat thread
@ -376,7 +369,7 @@ void HeartbeatThread::runCoordinator() {
uint64_t currentVersion =
arangodb::basics::VelocyPackHelper::stringUInt64(
it->second._vpack->slice());
if (currentVersion > lastCurrentVersionNoticed) {
lastCurrentVersionNoticed = currentVersion;
@ -385,7 +378,6 @@ void HeartbeatThread::runCoordinator() {
}
}
if (shouldSleep) {
double remain = interval - (TRI_microtime() - start);
@ -616,19 +608,17 @@ bool HeartbeatThread::handlePlanChangeDBServer(uint64_t currentPlanVersion) {
}
// schedule a job for the change
std::unique_ptr<arangodb::rest::Job> job(
new ServerJob(this, _server, _applicationV8));
std::unique_ptr<arangodb::rest::Job> job(new ServerJob(this));
#warning TODO
#if 0
if (_dispatcher->dispatcher()->addJob(job) == TRI_ERROR_NO_ERROR) {
auto dispatcher = DispatcherFeature::DISPATCHER;
if (dispatcher->addJob(job) == TRI_ERROR_NO_ERROR) {
++_numDispatchedJobs;
_versionThatTriggeredLastJob = currentPlanVersion;
LOG(TRACE) << "scheduled plan update handler";
return true;
}
#endif
LOG(ERR) << "could not schedule plan update handler";

View File

@ -24,12 +24,12 @@
#ifndef ARANGOD_CLUSTER_HEARTBEAT_THREAD_H
#define ARANGOD_CLUSTER_HEARTBEAT_THREAD_H 1
#include "Basics/Common.h"
#include "Basics/Thread.h"
#include "Basics/ConditionVariable.h"
#include "Basics/Mutex.h"
#include "Basics/Thread.h"
#include "Logger/Logger.h"
#include "Cluster/AgencyComm.h"
#include "Logger/Logger.h"
struct TRI_server_t;
struct TRI_vocbase_t;
@ -42,14 +42,11 @@ class ApplicationDispatcher;
class ApplicationV8;
class HeartbeatThread : public Thread {
private:
HeartbeatThread(HeartbeatThread const&);
HeartbeatThread& operator=(HeartbeatThread const&);
HeartbeatThread(HeartbeatThread const&) = delete;
HeartbeatThread& operator=(HeartbeatThread const&) = delete;
public:
HeartbeatThread(TRI_server_t*, arangodb::rest::ApplicationDispatcher*,
ApplicationV8*, uint64_t, uint64_t);
HeartbeatThread(uint64_t, uint64_t);
~HeartbeatThread();
public:
@ -154,18 +151,6 @@ class HeartbeatThread : public Thread {
TRI_server_t* _server;
//////////////////////////////////////////////////////////////////////////////
/// @brief Job dispatcher
//////////////////////////////////////////////////////////////////////////////
arangodb::rest::ApplicationDispatcher* _dispatcher;
//////////////////////////////////////////////////////////////////////////////
/// @brief v8 dispatcher
//////////////////////////////////////////////////////////////////////////////
ApplicationV8* _applicationV8;
//////////////////////////////////////////////////////////////////////////////
/// @brief status lock
//////////////////////////////////////////////////////////////////////////////

View File

@ -24,12 +24,13 @@
#include "ServerJob.h"
#include "Basics/MutexLocker.h"
#include "Logger/Logger.h"
#include "Cluster/HeartbeatThread.h"
#include "Cluster/ClusterInfo.h"
#include "Cluster/HeartbeatThread.h"
#include "Dispatcher/DispatcherQueue.h"
#include "Logger/Logger.h"
#include "V8/v8-utils.h"
// #include "V8Server/ApplicationV8.h"
#include "V8Server/V8Context.h"
#include "V8Server/V8DealerFeature.h"
#include "VocBase/server.h"
#include "VocBase/vocbase.h"
@ -42,12 +43,9 @@ static arangodb::Mutex ExecutorLock;
/// @brief constructs a new db server job
////////////////////////////////////////////////////////////////////////////////
ServerJob::ServerJob(HeartbeatThread* heartbeat, TRI_server_t* server,
ApplicationV8* applicationV8)
ServerJob::ServerJob(HeartbeatThread* heartbeat)
: Job("HttpServerJob"),
_heartbeat(heartbeat),
_server(server),
_applicationV8(applicationV8),
_shutdown(0),
_abandon(false) {}
@ -90,10 +88,9 @@ void ServerJob::cleanup(DispatcherQueue* queue) {
////////////////////////////////////////////////////////////////////////////////
bool ServerJob::execute() {
#warning TODO
#if 0
// default to system database
TRI_vocbase_t* const vocbase = TRI_UseDatabaseServer(_server, TRI_VOC_SYSTEM_DATABASE);
TRI_vocbase_t* const vocbase =
TRI_UseDatabaseServer(_server, TRI_VOC_SYSTEM_DATABASE);
if (vocbase == nullptr) {
// database is gone
@ -102,15 +99,15 @@ bool ServerJob::execute() {
TRI_DEFER(TRI_ReleaseVocBase(vocbase));
ApplicationV8::V8Context* context =
_applicationV8->enterContext(vocbase, true);
V8Context* context = V8DealerFeature::DEALER->enterContext(vocbase, true);
if (context == nullptr) {
return false;
}
bool ok = true;
auto isolate = context->isolate;
auto isolate = context->_isolate;
try {
v8::HandleScope scope(isolate);
@ -121,7 +118,8 @@ bool ServerJob::execute() {
v8::Handle<v8::Value> res = TRI_ExecuteJavaScriptString(
isolate, isolate->GetCurrentContext(), content, file, false);
if (res->IsBoolean() && res->IsTrue()) {
LOG(ERR) << "An error occurred whilst executing the handlePlanChange in JavaScript.";
LOG(ERR) << "An error occurred whilst executing the handlePlanChange in "
"JavaScript.";
ok = false; // The heartbeat thread will notice this!
}
// invalidate our local cache, even if an error occurred
@ -129,8 +127,7 @@ bool ServerJob::execute() {
} catch (...) {
}
_applicationV8->exitContext(context);
V8DealerFeature::DEALER->exitContext(context);
return ok;
#endif
}

View File

@ -24,38 +24,22 @@
#ifndef ARANGOD_CLUSTER_SERVER_JOB_H
#define ARANGOD_CLUSTER_SERVER_JOB_H 1
#include "Basics/Common.h"
#include "Dispatcher/Job.h"
#include "Basics/Exceptions.h"
#include "Basics/Mutex.h"
#include "Dispatcher/Job.h"
struct TRI_server_t;
namespace arangodb {
class HeartbeatThread;
class ApplicationV8;
////////////////////////////////////////////////////////////////////////////////
/// @brief general server job
////////////////////////////////////////////////////////////////////////////////
class ServerJob : public arangodb::rest::Job {
private:
ServerJob(ServerJob const&) = delete;
ServerJob& operator=(ServerJob const&) = delete;
public:
//////////////////////////////////////////////////////////////////////////////
/// @brief constructs a new db server job
//////////////////////////////////////////////////////////////////////////////
ServerJob(HeartbeatThread* heartbeat, TRI_server_t* server,
ApplicationV8* applicationV8);
//////////////////////////////////////////////////////////////////////////////
/// @brief destructs a db server job
//////////////////////////////////////////////////////////////////////////////
ServerJob(HeartbeatThread* heartbeat);
~ServerJob();
public:
@ -104,12 +88,6 @@ class ServerJob : public arangodb::rest::Job {
TRI_server_t* _server;
//////////////////////////////////////////////////////////////////////////////
/// @brief v8 dispatcher
//////////////////////////////////////////////////////////////////////////////
ApplicationV8* _applicationV8;
protected:
//////////////////////////////////////////////////////////////////////////////
/// @brief shutdown in progress

View File

@ -43,10 +43,10 @@ DispatcherFeature::DispatcherFeature(
: ApplicationFeature(server, "Dispatcher"),
_nrStandardThreads(8),
_nrAqlThreads(0),
_queueSize(16384),
_startAqlQueue(false) {
_queueSize(16384) {
setOptional(true);
requiresElevatedPrivileges(false);
startsAfter("FileDescriptorsFeature");
startsAfter("Logger");
startsAfter("Scheduler");
startsAfter("WorkMonitor");
@ -96,10 +96,6 @@ void DispatcherFeature::start() {
buildDispatcher();
buildStandardQueue();
if (_startAqlQueue) {
buildAqlQueue();
}
V8DealerFeature* dealer = dynamic_cast<V8DealerFeature*>(
ApplicationServer::lookupFeature("V8Dealer"));
@ -143,28 +139,3 @@ void DispatcherFeature::setProcessorAffinity(std::vector<size_t> const& cores) {
_dispatcher->setProcessorAffinity(Dispatcher::STANDARD_QUEUE, cores);
#endif
}
#warning TODO
#if 0
// now we can create the queues
if (startServer) {
if (role == ServerState::ROLE_COORDINATOR ||
role == ServerState::ROLE_PRIMARY ||
role == ServerState::ROLE_SECONDARY) {
_applicationDispatcher->buildAQLQueue(_dispatcherThreads,
(int)_dispatcherQueueSize);
}
}
== == == == == == == == == == == == == == == == == == == == == == == == == == ==
== == == == == == == == == == == == ==
if (!startServer) {
_applicationDispatcher->disable();
}
== == == == == == == == == == == == == == == == == == == == == == == == == == ==
== == == == == == == == == == == == ==
#endif

View File

@ -63,7 +63,6 @@ class DispatcherFeature final
uint64_t _nrStandardThreads;
uint64_t _nrAqlThreads;
uint64_t _queueSize;
bool _startAqlQueue;
};
}

View File

@ -22,6 +22,7 @@
#include "DatabaseFeature.h"
#include "Aql/QueryCache.h"
#include "Aql/QueryRegistry.h"
#include "Basics/StringUtils.h"
#include "Basics/ThreadPool.h"
@ -66,6 +67,7 @@ DatabaseFeature::DatabaseFeature(ApplicationServer* server)
_upgrade(false) {
setOptional(false);
requiresElevatedPrivileges(false);
startsAfter("FileDescriptorsFeature");
startsAfter("Language");
startsAfter("Logger");
startsAfter("Random");
@ -122,19 +124,6 @@ void DatabaseFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
options->addOption("--query.tracking", "wether to track queries",
new BooleanParameter(&_queryTracking));
#warning TODO
#if 0
// set global query tracking flag
arangodb::aql::Query::DisableQueryTracking(_disableQueryTracking);
// configure the query cache
{
std::pair<std::string, size_t> cacheProperties{_queryCacheMode,
_queryCacheMaxResults};
arangodb::aql::QueryCache::instance()->setProperties(cacheProperties);
}
#endif
options->addOption("--query.cache-mode",
"mode for the AQL query cache (on, off, demand)",
new StringParameter(&_queryCacheMode));
@ -179,6 +168,18 @@ void DatabaseFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
}
}
void DatabaseFeature::prepare() {
// set global query tracking flag
arangodb::aql::Query::DisableQueryTracking(!_queryTracking);
// configure the query cache
{
std::pair<std::string, size_t> cacheProperties{_queryCacheMode,
_queryCacheEntries};
arangodb::aql::QueryCache::instance()->setProperties(cacheProperties);
}
}
void DatabaseFeature::start() {
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::start";
@ -187,7 +188,7 @@ void DatabaseFeature::start() {
// sanity check
if (_checkVersion && _upgrade) {
LOG(FATAL) << "cannot specify both '--database.check-version' and "
"'--database.upgrade'";
"'--database.upgrade'";
FATAL_ERROR_EXIT();
}
@ -322,14 +323,12 @@ void DatabaseFeature::openDatabases() {
_indexPool.reset(new ThreadPool(_indexThreads, "IndexBuilder"));
}
#warning appPath
bool const iterateMarkersOnOpen =
!wal::LogfileManager::instance()->hasFoundLastTick();
int res = TRI_InitServer(
_server.get(), _indexPool.get(), _databasePath.c_str(), nullptr,
&defaults, !_replicationApplier, _disableCompactor, iterateMarkersOnOpen);
_server.get(), _indexPool.get(), _databasePath.c_str(), &defaults,
!_replicationApplier, _disableCompactor, iterateMarkersOnOpen);
if (res != TRI_ERROR_NO_ERROR) {
LOG(FATAL) << "cannot create server instance: out of memory";
@ -353,12 +352,6 @@ void DatabaseFeature::openDatabases() {
void DatabaseFeature::closeDatabases() {
TRI_ASSERT(_server != nullptr);
// cleanup actions
#warning TODO
#if 0
TRI_CleanupActions();
#endif
// stop the replication appliers so all replication transactions can end
if (_replicationApplier) {
TRI_StopReplicationAppliersServer(_server.get());
@ -368,51 +361,3 @@ void DatabaseFeature::closeDatabases() {
// write to the logs
wal::LogfileManager::instance()->stop();
}
#if 0
// and add the feature to the application server
_applicationServer->addFeature(wal::LogfileManager::instance());
// run upgrade script
bool performUpgrade = false;
if (_applicationServer->programOptions().has("upgrade")) {
performUpgrade = true;
// --upgrade disables all replication appliers
_disableReplicationApplier = true;
if (_applicationCluster != nullptr) {
_applicationCluster->disable(); // TODO
}
}
// skip an upgrade even if VERSION is missing
// .............................................................................
// prepare the various parts of the Arango server
// .............................................................................
KeyGenerator::Initialize();
// open all databases
bool const iterateMarkersOnOpen =
!wal::LogfileManager::instance()->hasFoundLastTick();
openDatabases(checkVersion, performUpgraden, iterateMarkersOnOpen);
if (!checkVersion) {
}
// fetch the system database
TRI_vocbase_t* vocbase =
TRI_UseDatabaseServer(_server, TRI_VOC_SYSTEM_DATABASE);
if (vocbase == nullptr) {
LOG(FATAL)
<< "No _system database found in database directory. Cannot start!";
FATAL_ERROR_EXIT();
}
TRI_ASSERT(vocbase != nullptr);
#endif

View File

@ -47,6 +47,7 @@ class DatabaseFeature final : public application_features::ApplicationFeature {
public:
void collectOptions(std::shared_ptr<options::ProgramOptions>) override;
void validateOptions(std::shared_ptr<options::ProgramOptions>) override;
void prepare() override;
void start() override;
void stop() override;

View File

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

View File

@ -82,6 +82,7 @@ ServerFeature::ServerFeature(application_features::ApplicationServer* server,
_consoleThread(nullptr) {
setOptional(true);
requiresElevatedPrivileges(false);
startsAfter("Cluster");
startsAfter("Database");
startsAfter("Dispatcher");
startsAfter("Scheduler");
@ -236,6 +237,8 @@ void ServerFeature::prepare() {
buildHandlerFactory();
HttpHandlerFactory::setMaintenance(true);
adjustFileDescriptors();
}
void ServerFeature::start() {
@ -245,6 +248,15 @@ void ServerFeature::start() {
V8DealerFeature::DEALER->loadJavascript(vocbase, "server/server.js");
_httpOptions._vocbase = vocbase;
if (_operationMode != OperationMode::MODE_CONSOLE) {
auto scheduler = dynamic_cast<SchedulerFeature*>(
ApplicationServer::lookupFeature("Scheduler"));
if (scheduler != nullptr) {
scheduler->buildControlCHandler();
}
}
defineHandlers();
HttpHandlerFactory::setMaintenance(false);
@ -670,6 +682,7 @@ void ServerFeature::defineHandlers() {
#endif
}
#warning TODO
#if 0
template <typename T>

View File

@ -22,6 +22,7 @@
#include "UpgradeFeature.h"
#include "Cluster/ClusterFeature.h"
#include "ProgramOptions/ProgramOptions.h"
#include "ProgramOptions/Section.h"
#include "RestServer/DatabaseFeature.h"
@ -48,6 +49,7 @@ UpgradeFeature::UpgradeFeature(
setOptional(false);
requiresElevatedPrivileges(false);
startsAfter("CheckVersion");
startsAfter("Cluser");
startsAfter("Database");
startsAfter("V8Dealer");
}
@ -88,6 +90,10 @@ void UpgradeFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
ApplicationServer::lookupFeature("Database"));
database->disableReplicationApplier();
database->enableUpgrade();
ClusterFeature* cluster = dynamic_cast<ClusterFeature*>(
ApplicationServer::lookupFeature("Cluster"));
cluster->disable();
}
void UpgradeFeature::start() {

View File

@ -23,6 +23,7 @@
#include "Basics/Common.h"
#include "Agency/AgencyFeature.h"
#include "ApplicationFeatures/ConfigFeature.h"
#include "ApplicationFeatures/DaemonFeature.h"
#include "ApplicationFeatures/LanguageFeature.h"
@ -35,6 +36,7 @@
#include "ApplicationFeatures/V8PlatformFeature.h"
#include "ApplicationFeatures/WorkMonitorFeature.h"
#include "Basics/ArangoGlobalContext.h"
#include "Cluster/ClusterFeature.h"
#include "Dispatcher/DispatcherFeature.h"
#include "ProgramOptions/ProgramOptions.h"
#include "RestServer/CheckVersionFeature.h"
@ -90,16 +92,19 @@ int main(int argc, char* argv[]) {
application_features::ApplicationServer server(options);
std::vector<std::string> nonServerFeatures = {
"Action", "Daemon", "Dispatcher", "Endpoint",
"Server", "Scheduler", "Ssl", "Supervisor"};
"Action", "Cluster", "Daemon", "Dispatcher", "Endpoint",
"Server", "Scheduler", "Ssl", "Supervisor"};
int ret = EXIT_FAILURE;
server.addFeature(new AgencyFeature(&server));
server.addFeature(new CheckVersionFeature(&server, &ret, nonServerFeatures));
server.addFeature(new ClusterFeature(&server));
server.addFeature(new ConfigFeature(&server, name));
server.addFeature(new DatabaseFeature(&server));
server.addFeature(new DispatcherFeature(&server));
server.addFeature(new EndpointFeature(&server));
server.addFeature(new FileDescriptorsFeature(&server));
server.addFeature(new LanguageFeature(&server));
server.addFeature(new LoggerFeature(&server, true));
server.addFeature(new RandomFeature(&server));

View File

@ -48,10 +48,10 @@ SchedulerFeature::SchedulerFeature(
_nrSchedulerThreads(2),
_backend(0),
_showBackends(false),
_scheduler(nullptr),
_enableControlCHandler(true) {
_scheduler(nullptr) {
setOptional(true);
requiresElevatedPrivileges(false);
startsAfter("FileDescriptorsFeature");
startsAfter("Logger");
startsAfter("WorkMonitor");
}
@ -293,28 +293,21 @@ void SchedulerFeature::buildScheduler() {
}
void SchedulerFeature::buildControlCHandler() {
if (_scheduler == nullptr) {
LOG(FATAL) << "no scheduler is known, cannot create control-c handler";
FATAL_ERROR_EXIT();
}
if (_enableControlCHandler) {
#ifdef WIN32
int result = SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, true);
int result = SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, true);
if (result == 0) {
LOG(WARN) << "unable to install control-c handler";
}
#else
Task* controlC = new ControlCTask(server());
int res = _scheduler->registerTask(controlC);
if (res == TRI_ERROR_NO_ERROR) {
_tasks.emplace_back(controlC);
}
#endif
if (result == 0) {
LOG(WARN) << "unable to install control-c handler";
}
#else
Task* controlC = new ControlCTask(server());
int res = _scheduler->registerTask(controlC);
if (res == TRI_ERROR_NO_ERROR) {
_tasks.emplace_back(controlC);
}
#endif
// hangup handler
#ifndef WIN32
@ -328,25 +321,7 @@ void SchedulerFeature::buildControlCHandler() {
#endif
}
#warning TODO
#if 0
if (mode == OperationMode::MODE_CONSOLE) {
_applicationScheduler->disableControlCHandler();
}
if (!startServer) {
_applicationScheduler->disable();
}
================================================================================
void ApplicationScheduler::setProcessorAffinity(
std::vector<size_t> const& cores) {
void SchedulerFeature::setProcessorAffinity(std::vector<size_t> const& cores) {
#ifdef TRI_HAVE_THREAD_AFFINITY
size_t j = 0;
@ -365,121 +340,3 @@ void ApplicationScheduler::setProcessorAffinity(
}
#endif
}
void ApplicationScheduler::disableControlCHandler() {
_disableControlCHandler = true;
}
void ApplicationScheduler::setupOptions(
std::map<std::string, ProgramOptionsDescription>& options) {
// .............................................................................
// command line options
// .............................................................................
options["General Options:help-admin"]("show-io-backends",
"show available io backends");
// .............................................................................
// application server options
// .............................................................................
options["Server Options:help-admin"]
#ifdef _WIN32
// ...........................................................................
// since we are trying to use libev, then only select is available
// no point in allowing this to be configured at this stage. Perhaps if we
// eventually write a native libev we can offer something.
// ...........................................................................
//("scheduler.backend", &_backend, "1: select, 2: poll, 4: epoll")
#else
("scheduler.backend", &_backend, "1: select, 2: poll, 4: epoll")
#endif
#ifdef TRI_HAVE_GETRLIMIT
("server.descriptors-minimum", &_descriptorMinimum,
"minimum number of file descriptors needed to start")
#endif
;
}
bool ApplicationScheduler::afterOptionParsing(
arangodb::basics::ProgramOptions& options) {
// show io backends
if (options.has("show-io-backends")) {
std::cout << "available io backends are: "
<< SchedulerLibev::availableBackends() << std::endl;
TRI_EXIT_FUNCTION(EXIT_SUCCESS, nullptr);
}
// adjust file descriptors
adjustFileDescriptors();
return true;
}
void ApplicationScheduler::adjustFileDescriptors() {
#ifdef TRI_HAVE_GETRLIMIT
if (0 < _descriptorMinimum) {
struct rlimit rlim;
int res = getrlimit(RLIMIT_NOFILE, &rlim);
if (res != 0) {
LOG(FATAL) << "cannot get the file descriptor limit: " << strerror(errno); FATAL_ERROR_EXIT();
}
LOG(DEBUG) << "file-descriptors (nofiles) hard limit is " << StringifyLimitValue(rlim.rlim_max)
<< ", soft limit is " << StringifyLimitValue(rlim.rlim_cur);
bool changed = false;
if (rlim.rlim_max < _descriptorMinimum) {
LOG(DEBUG) << "hard limit " << rlim.rlim_max << " is too small, trying to raise";
rlim.rlim_max = _descriptorMinimum;
rlim.rlim_cur = _descriptorMinimum;
res = setrlimit(RLIMIT_NOFILE, &rlim);
if (res < 0) {
LOG(FATAL) << "cannot raise the file descriptor limit to " << _descriptorMinimum << ": " << strerror(errno); FATAL_ERROR_EXIT();
}
changed = true;
} else if (rlim.rlim_cur < _descriptorMinimum) {
LOG(DEBUG) << "soft limit " << rlim.rlim_cur << " is too small, trying to raise";
rlim.rlim_cur = _descriptorMinimum;
res = setrlimit(RLIMIT_NOFILE, &rlim);
if (res < 0) {
LOG(FATAL) << "cannot raise the file descriptor limit to " << _descriptorMinimum << ": " << strerror(errno); FATAL_ERROR_EXIT();
}
changed = true;
}
if (changed) {
res = getrlimit(RLIMIT_NOFILE, &rlim);
if (res != 0) {
LOG(FATAL) << "cannot get the file descriptor limit: " << strerror(errno); FATAL_ERROR_EXIT();
}
LOG(INFO) << "file-descriptors (nofiles) new hard limit is " << StringifyLimitValue(rlim.rlim_max)
<< ", new soft limit is " << ", soft limit is " << StringifyLimitValue(rlim.rlim_cur);
}
// the select backend has more restrictions
if (_backend == 1) {
if (FD_SETSIZE < _descriptorMinimum) {
LOG(FATAL) << "i/o backend 'select' has been selected, which supports only " << FD_SETSIZE << " descriptors, but " << _descriptorMinimum << " are required"; FATAL_ERROR_EXIT();
}
}
}
#endif
}
#endif

View File

@ -59,7 +59,6 @@ class SchedulerFeature final : public application_features::ApplicationFeature {
private:
rest::Scheduler* _scheduler;
std::vector<rest::Task*> _tasks;
bool _enableControlCHandler;
};
}

View File

@ -99,9 +99,10 @@ V8DealerFeature::V8DealerFeature(
_forceNrContexts(0) {
setOptional(false);
requiresElevatedPrivileges(false);
startsAfter("Action");
startsAfter("Database");
startsAfter("V8Platform");
startsAfter("WorkMonitor");
startsAfter("Database");
}
void V8DealerFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
@ -149,19 +150,6 @@ void V8DealerFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
_startupLoader.setDirectory(_startupPath);
ServerState::instance()->setJavaScriptPath(_startupPath);
// 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.";
@ -177,6 +165,20 @@ void V8DealerFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
void V8DealerFeature::start() {
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::start";
// 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, ", ");
}
// set singleton
DEALER = this;
// try to guess a suitable number of contexts

View File

@ -77,6 +77,8 @@ class V8DealerFeature final : public application_features::ApplicationFeature {
void shutdownContexts();
std::string const& appPath() const { return _appPath; }
private:
V8Context* pickFreeContextForGc();
void initializeContext(size_t);

View File

@ -50,6 +50,7 @@
#include "VocBase/vocbase.h"
#include "Wal/LogfileManager.h"
#include "Wal/Marker.h"
#include "V8Server/V8DealerFeature.h"
using namespace arangodb;
using namespace arangodb::basics;
@ -513,7 +514,10 @@ static int OpenDatabases(TRI_server_t* server, bool isUpgrade) {
// create app directories
// .........................................................................
res = CreateApplicationDirectory(databaseName.c_str(), server->_appPath);
auto appPath = (V8DealerFeature::DEALER == nullptr
? std::string()
: V8DealerFeature::DEALER->appPath());
res = CreateApplicationDirectory(databaseName.c_str(), appPath.c_str());
if (res != TRI_ERROR_NO_ERROR) {
break;
@ -1040,8 +1044,12 @@ static void DatabaseManager(void* data) {
<< "'";
// remove apps directory for database
if (database->_isOwnAppsDirectory && strlen(server->_appPath) > 0) {
path = TRI_Concatenate3File(server->_appPath, "_db", database->_name);
auto appPath = (V8DealerFeature::DEALER == nullptr
? std::string()
: V8DealerFeature::DEALER->appPath());
if (database->_isOwnAppsDirectory && !appPath.empty()) {
path = TRI_Concatenate3File(appPath.c_str(), "_db", database->_name);
if (path != nullptr) {
if (TRI_IsDirectory(path)) {
@ -1119,13 +1127,11 @@ static void DatabaseManager(void* data) {
/// @brief initialize a server instance with configuration
////////////////////////////////////////////////////////////////////////////////
#warning appPath lives in V8DealerFeature - remove here
int TRI_InitServer(TRI_server_t* server,
arangodb::basics::ThreadPool* indexPool,
char const* basePath, char const* appPath,
TRI_vocbase_defaults_t const* defaults, bool disableAppliers,
bool disableCompactor, bool iterateMarkersOnOpen) {
char const* basePath, TRI_vocbase_defaults_t const* defaults,
bool disableAppliers, bool disableCompactor,
bool iterateMarkersOnOpen) {
TRI_ASSERT(server != nullptr);
TRI_ASSERT(basePath != nullptr);
@ -1171,21 +1177,6 @@ int TRI_InitServer(TRI_server_t* server,
return TRI_ERROR_OUT_OF_MEMORY;
}
if (appPath == nullptr) {
server->_appPath = nullptr;
} else {
server->_appPath = TRI_DuplicateString(TRI_CORE_MEM_ZONE, appPath);
if (server->_appPath == nullptr) {
TRI_Free(TRI_CORE_MEM_ZONE, server->_serverIdFilename);
TRI_Free(TRI_CORE_MEM_ZONE, server->_lockFilename);
TRI_Free(TRI_CORE_MEM_ZONE, server->_databasePath);
TRI_Free(TRI_CORE_MEM_ZONE, server->_basePath);
return TRI_ERROR_OUT_OF_MEMORY;
}
}
// ...........................................................................
// server defaults
// ...........................................................................
@ -1209,7 +1200,7 @@ int TRI_InitServer(TRI_server_t* server,
////////////////////////////////////////////////////////////////////////////////
void TRI_InitServerGlobals() {
ServerIdentifier = RandomGenerator::interval((uint16_t) UINT16_MAX);
ServerIdentifier = RandomGenerator::interval((uint16_t)UINT16_MAX);
PageSize = (size_t)getpagesize();
memset(&ServerId, 0, sizeof(TRI_server_id_t));
}
@ -1332,29 +1323,32 @@ int TRI_StartServer(TRI_server_t* server, bool checkVersion,
// create shared application directories
// ...........................................................................
if (server->_appPath != nullptr && strlen(server->_appPath) > 0 &&
!TRI_IsDirectory(server->_appPath)) {
auto appPath =
(V8DealerFeature::DEALER == nullptr ? std::string()
: V8DealerFeature::DEALER->appPath());
if (!appPath.empty() && !TRI_IsDirectory(appPath.c_str())) {
long systemError;
std::string errorMessage;
bool res = TRI_CreateRecursiveDirectory(server->_appPath, systemError,
bool res = TRI_CreateRecursiveDirectory(appPath.c_str(), systemError,
errorMessage);
if (res) {
LOG(INFO) << "created --javascript.app-path directory '"
<< server->_appPath << "'.";
LOG(INFO) << "created --javascript.app-path directory '" << appPath
<< "'.";
} else {
LOG(ERR) << "unable to create --javascript.app-path directory '"
<< server->_appPath << "': " << errorMessage;
<< appPath << "': " << errorMessage;
return TRI_ERROR_SYS_ERROR;
}
}
// create subdirectories if not yet present
res = CreateBaseApplicationDirectory(server->_appPath, "_db");
res = CreateBaseApplicationDirectory(appPath.c_str(), "_db");
// system directory is in a read-only location
// if (res == TRI_ERROR_NO_ERROR) {
// res = CreateBaseApplicationDirectory(server->_appPath, "system");
// res = CreateBaseApplicationDirectory(appPath, "system");
// }
if (res != TRI_ERROR_NO_ERROR) {
@ -1608,11 +1602,11 @@ int TRI_CreateDatabaseServer(TRI_server_t* server, TRI_voc_tick_t databaseId,
server->_databasePath, dirname.c_str()));
if (arangodb::wal::LogfileManager::instance()->isInRecovery()) {
LOG(TRACE) << "creating database '" << name << "', directory '"
<< path << "'";
LOG(TRACE) << "creating database '" << name << "', directory '" << path
<< "'";
} else {
LOG(INFO) << "creating database '" << name << "', directory '"
<< path << "'";
LOG(INFO) << "creating database '" << name << "', directory '" << path
<< "'";
}
vocbase = TRI_OpenVocBase(server, path.c_str(), databaseId, name, defaults,
@ -1647,7 +1641,10 @@ int TRI_CreateDatabaseServer(TRI_server_t* server, TRI_voc_tick_t databaseId,
}
// create application directories
CreateApplicationDirectory(vocbase->_name, server->_appPath);
auto appPath = (V8DealerFeature::DEALER == nullptr
? std::string()
: V8DealerFeature::DEALER->appPath());
CreateApplicationDirectory(vocbase->_name, appPath.c_str());
if (!arangodb::wal::LogfileManager::instance()->isInRecovery()) {
TRI_ReloadAuthInfo(vocbase);
@ -2165,7 +2162,6 @@ TRI_server_t::TRI_server_t()
_databasePath(nullptr),
_lockFilename(nullptr),
_serverIdFilename(nullptr),
_appPath(nullptr),
_disableReplicationAppliers(false),
_iterateMarkersOnOpen(false),
_hasCreatedSystemDatabase(false),
@ -2178,10 +2174,6 @@ TRI_server_t::~TRI_server_t() {
auto p = _databasesLists.load();
delete p;
if (_appPath != nullptr) {
TRI_Free(TRI_CORE_MEM_ZONE, _appPath);
}
TRI_Free(TRI_CORE_MEM_ZONE, _serverIdFilename);
TRI_Free(TRI_CORE_MEM_ZONE, _lockFilename);
TRI_Free(TRI_CORE_MEM_ZONE, _databasePath);

View File

@ -78,7 +78,6 @@ struct TRI_server_t {
char* _databasePath;
char* _lockFilename;
char* _serverIdFilename;
char* _appPath;
bool _disableReplicationAppliers;
bool _disableCompactor;
@ -98,8 +97,7 @@ extern size_t PageSize;
////////////////////////////////////////////////////////////////////////////////
int TRI_InitServer(TRI_server_t*, arangodb::basics::ThreadPool*, char const*,
char const*, TRI_vocbase_defaults_t const*, bool, bool,
bool);
TRI_vocbase_defaults_t const*, bool, bool, bool);
////////////////////////////////////////////////////////////////////////////////
/// @brief initialize globals

View File

@ -0,0 +1,135 @@
////////////////////////////////////////////////////////////////////////////////
/// 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 Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#include "FileDescriptorsFeature.h"
using namespace arangodb;
using namespace arangodb::basics;
using namespace arangodb::options;
FileDescriptorsFeature::FileDescriptorsFeature(
application_features::ApplicationServer* server)
: ApplicationFeature(server, "FileDescriptors") {
setOptional(false);
requiresElevatedPrivileges(false);
startsAfter("Logger");
}
void FileDescriptorsFeature::collectOptions(
std::shared_ptr<ProgramOptions> options) {
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::collectOptions";
#ifdef TRI_HAVE_GETRLIMIT
options->addSection("server", "Server features");
options->addOption("--server.descriptors-minimum",
"minimum number of file descriptors needed to start",
new UInt64Parameter(&_descriptorMinimum));
#endif
}
void FileDescriptorsFeature::prepare() {
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::prepare";
adjustFileDescriptors();
}
void FileDescriptors::adjustFileDescriptors() {
#ifdef TRI_HAVE_GETRLIMIT
if (0 < _descriptorMinimum) {
struct rlimit rlim;
int res = getrlimit(RLIMIT_NOFILE, &rlim);
if (res != 0) {
LOG(FATAL) << "cannot get the file descriptor limit: " << strerror(errno);
FATAL_ERROR_EXIT();
}
LOG(DEBUG) << "file-descriptors (nofiles) hard limit is "
<< StringifyLimitValue(rlim.rlim_max) << ", soft limit is "
<< StringifyLimitValue(rlim.rlim_cur);
bool changed = false;
if (rlim.rlim_max < _descriptorMinimum) {
LOG(DEBUG) << "hard limit " << rlim.rlim_max
<< " is too small, trying to raise";
rlim.rlim_max = _descriptorMinimum;
rlim.rlim_cur = _descriptorMinimum;
res = setrlimit(RLIMIT_NOFILE, &rlim);
if (res < 0) {
LOG(FATAL) << "cannot raise the file descriptor limit to "
<< _descriptorMinimum << ": " << strerror(errno);
FATAL_ERROR_EXIT();
}
changed = true;
} else if (rlim.rlim_cur < _descriptorMinimum) {
LOG(DEBUG) << "soft limit " << rlim.rlim_cur
<< " is too small, trying to raise";
rlim.rlim_cur = _descriptorMinimum;
res = setrlimit(RLIMIT_NOFILE, &rlim);
if (res < 0) {
LOG(FATAL) << "cannot raise the file descriptor limit to "
<< _descriptorMinimum << ": " << strerror(errno);
FATAL_ERROR_EXIT();
}
changed = true;
}
if (changed) {
res = getrlimit(RLIMIT_NOFILE, &rlim);
if (res != 0) {
LOG(FATAL) << "cannot get the file descriptor limit: "
<< strerror(errno);
FATAL_ERROR_EXIT();
}
LOG(INFO) << "file-descriptors (nofiles) new hard limit is "
<< StringifyLimitValue(rlim.rlim_max) << ", new soft limit is "
<< ", soft limit is " << StringifyLimitValue(rlim.rlim_cur);
}
// the select backend has more restrictions
if (_backend == 1) {
if (FD_SETSIZE < _descriptorMinimum) {
LOG(FATAL)
<< "i/o backend 'select' has been selected, which supports only "
<< FD_SETSIZE << " descriptors, but " << _descriptorMinimum
<< " are required";
FATAL_ERROR_EXIT();
}
}
}
#endif
}

View File

@ -0,0 +1,42 @@
////////////////////////////////////////////////////////////////////////////////
/// 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 Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGOD_CLUSTER_FILE_DESCRIPTORS_FEATURE_H
#define ARANGOD_CLUSTER_FILE_DESCRIPTORS_FEATURE_H 1
#include "Basics/Common.h"
#include "ApplicationFeatures/ApplicationFeature.h"
namespace arangodb {
class ClusterFeature : public application_features::ApplicationFeature {
public:
ClusterFeature(application_features::ApplicationServer*);
public:
void collectOptions(std::shared_ptr<options::ProgramOptions>) override;
void prepare() override;
};
}
#endif

View File

@ -63,6 +63,11 @@ void LanguageFeature::prepare() {
FATAL_ERROR_EXIT();
}
}
void LanguageFeature::start() {
LOG_TOPIC(TRACE, Logger::STARTUP) << name() << "::start";
std::string languageName;
if (Utf8Helper::DefaultUtf8Helper.getCollatorCountry() != "") {

View File

@ -33,6 +33,7 @@ class LanguageFeature final : public application_features::ApplicationFeature {
public:
void collectOptions(std::shared_ptr<options::ProgramOptions>) override;
void prepare() override;
void start() override;
private:
std::string _language;

View File

@ -28,7 +28,7 @@
namespace arangodb {
class LoggerFeature final : public application_features::ApplicationFeature {
public:
explicit LoggerFeature(application_features::ApplicationServer* server, bool threaded);
LoggerFeature(application_features::ApplicationServer* server, bool threaded);
public:
void collectOptions(std::shared_ptr<options::ProgramOptions>) override;

View File

@ -0,0 +1,42 @@
////////////////////////////////////////////////////////////////////////////////
/// 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 Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#include "NonceFeature.h"
NonceFeature(application_features::ApplicationServer*);
void NonceFeature::validate() {}
void NonceFeature::prepare() {
uint32_t optionNonceHashSize = 0;
if (0 < _hashSize) {
Nonce::create(_hashSize);
}
}
void NonceFeature::start() {
LOG(DEBUG) << "setting nonce hash size to " << _hashSize;
}
void NonceFeature::stop() { Nonce::destroy(); }

View File

@ -0,0 +1,42 @@
////////////////////////////////////////////////////////////////////////////////
/// 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 Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGOD_CLUSTER_FILE_NONCE_FEATURE_H
#define ARANGOD_CLUSTER_FILE_NONCE_FEATURE_H 1
#include "Basics/Common.h"
#include "ApplicationFeatures/ApplicationFeature.h"
namespace arangodb {
class NonceFeature : public application_features::ApplicationFeature {
public:
NonceFeature(application_features::ApplicationServer*);
public:
void collectOptions(std::shared_ptr<options::ProgramOptions>) override;
void prepare() override;
};
}
#endif

View File

@ -1,3 +1,77 @@
#warning TODO
#if 0
options["Hidden Options"]
#ifdef ARANGODB_HAVE_SETUID
("uid", &_uid, "switch to user-id after reading config files")
#endif
#ifdef ARANGODB_HAVE_SETGID
("gid", &_gid, "switch to group-id after reading config files")
#endif
;
#if defined(ARANGODB_HAVE_SETUID) || defined(ARANGODB_HAVE_SETGID)
options["General Options:help-admin"]
#ifdef ARANGODB_HAVE_GETPPID
("exit-on-parent-death", &_exitOnParentDeath, "exit if parent dies")
#endif
("watch-process", &_watchParent,
"exit if process with given PID dies");
#endif
#endif
#warning TODO
#if 0
// .............................................................................
// UID and GID
// .............................................................................
extractPrivileges();
dropPrivilegesPermanently();
return true;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief checks if the parent is still alive
////////////////////////////////////////////////////////////////////////////////
bool ApplicationServer::checkParent() {
// check our parent, if it died given up
#ifdef ARANGODB_HAVE_GETPPID
if (_exitOnParentDeath && getppid() == 1) {
LOG(INFO) << "parent has died";
return false;
}
#endif
// unfortunately even though windows has <signal.h>, there is no
// kill method defined. Notice that the kill below is not to terminate
// the process.
#ifdef TRI_HAVE_SIGNAL_H
if (_watchParent != 0) {
#ifdef TRI_HAVE_POSIX
int res = kill(_watchParent, 0);
#else
int res = -1;
#endif
if (res != 0) {
LOG(INFO) << "parent " << _watchParent << " has died";
return false;
}
}
#endif
return true;
}
#endif
#if 0
void ApplicationServer::extractPrivileges() {
#ifdef ARANGODB_HAVE_SETGID
if (_gid.empty()) {
@ -125,3 +199,4 @@ void ApplicationServer::dropPrivilegesPermanently() {
#endif
}
#endif

View File

@ -92,6 +92,7 @@ if (MSVC)
else ()
set(LIB_ARANGO_POSIX
ApplicationFeatures/DaemonFeature.cpp
ApplicationFeatures/PrivilegeFeature.cpp
ApplicationFeatures/SupervisorFeature.cpp
Basics/locks-posix.cpp
Basics/memory-map-posix.cpp
@ -139,9 +140,11 @@ add_library(${LIB_ARANGO} STATIC
ApplicationFeatures/ClientFeature.cpp
ApplicationFeatures/ConfigFeature.cpp
ApplicationFeatures/ConsoleFeature.cpp
ApplicationFeatures/FileDescriptorsFeature.cpp
ApplicationFeatures/LanguageFeature.cpp
ApplicationFeatures/LoggerFeature.cpp
ApplicationFeatures/RandomFeature.cpp
ApplicationFeatures/NonceFeature.cpp
ApplicationFeatures/ShutdownFeature.cpp
ApplicationFeatures/SslFeature.cpp
ApplicationFeatures/TempFeature.cpp

View File

@ -1,15 +1,10 @@
#!/usr/bin/perl
################################################################################
### @brief updates preamble of C/C++ files
###
### @file
###
### DISCLAIMER
###
### Copyright holder is triAGENS GmbH, Cologne, Germany
### Copyright holder is ArangoDB GmbH, Cologne, Germany
###
### @author Dr. Frank Celler
### @author Copyright 2009-2010, triAGENS GmbH, Cologne, Germany
################################################################################
eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'