1
0
Fork 0

Merge branch 'devel' of https://github.com/arangodb/arangodb into feature/alliterator

This commit is contained in:
Simon Grätzer 2017-05-31 16:38:55 +02:00
commit 36d440767b
19 changed files with 134 additions and 50 deletions

View File

@ -205,6 +205,7 @@
# #
* [Release notes](ReleaseNotes/README.md) * [Release notes](ReleaseNotes/README.md)
* [Whats New in 3.2](ReleaseNotes/NewFeatures32.md) * [Whats New in 3.2](ReleaseNotes/NewFeatures32.md)
* [Known Issues in 3.2](ReleaseNotes/KnownIssues32.md)
* [Incompatible changes in 3.2](ReleaseNotes/UpgradingChanges32.md) * [Incompatible changes in 3.2](ReleaseNotes/UpgradingChanges32.md)
* [Whats New in 3.1](ReleaseNotes/NewFeatures31.md) * [Whats New in 3.1](ReleaseNotes/NewFeatures31.md)
* [Incompatible changes in 3.1](ReleaseNotes/UpgradingChanges31.md) * [Incompatible changes in 3.1](ReleaseNotes/UpgradingChanges31.md)

View File

@ -29,6 +29,7 @@
#include "Aql/Collection.h" #include "Aql/Collection.h"
#include "Transaction/StandaloneContext.h" #include "Transaction/StandaloneContext.h"
#include "Transaction/Methods.h" #include "Transaction/Methods.h"
#include "Transaction/Options.h"
#include "VocBase/vocbase.h" #include "VocBase/vocbase.h"
namespace arangodb { namespace arangodb {
@ -41,9 +42,11 @@ class AqlTransaction final : public transaction::Methods {
AqlTransaction( AqlTransaction(
std::shared_ptr<transaction::Context> const& transactionContext, std::shared_ptr<transaction::Context> const& transactionContext,
std::map<std::string, aql::Collection*> const* collections, std::map<std::string, aql::Collection*> const* collections,
transaction::Options const& options,
bool isMainTransaction) bool isMainTransaction)
: transaction::Methods(transactionContext), : transaction::Methods(transactionContext, options),
_collections(*collections) { _collections(*collections),
_options(options) {
if (!isMainTransaction) { if (!isMainTransaction) {
addHint(transaction::Hints::Hint::LOCK_NEVER); addHint(transaction::Hints::Hint::LOCK_NEVER);
} else { } else {
@ -91,7 +94,7 @@ class AqlTransaction final : public transaction::Methods {
/// AQL query running on the coordinator /// AQL query running on the coordinator
transaction::Methods* clone() const override { transaction::Methods* clone() const override {
return new AqlTransaction(transaction::StandaloneContext::Create(vocbase()), return new AqlTransaction(transaction::StandaloneContext::Create(vocbase()),
&_collections, false); &_collections, _options, false);
} }
/// @brief lockCollections, this is needed in a corner case in AQL: we need /// @brief lockCollections, this is needed in a corner case in AQL: we need
@ -106,6 +109,7 @@ class AqlTransaction final : public transaction::Methods {
/// operation /// operation
private: private:
std::map<std::string, aql::Collection*> _collections; std::map<std::string, aql::Collection*> _collections;
transaction::Options _options;
}; };
} }

View File

@ -342,6 +342,7 @@ void Query::prepare(QueryRegistry* registry, uint64_t queryHash) {
// create the transaction object, but do not start it yet // create the transaction object, but do not start it yet
AqlTransaction* trx = new AqlTransaction( AqlTransaction* trx = new AqlTransaction(
createTransactionContext(), _collections.collections(), createTransactionContext(), _collections.collections(),
_queryOptions.transactionOptions,
_part == PART_MAIN); _part == PART_MAIN);
_trx = trx; _trx = trx;
@ -429,8 +430,8 @@ ExecutionPlan* Query::prepare() {
// create the transaction object, but do not start it yet // create the transaction object, but do not start it yet
AqlTransaction* trx = new AqlTransaction( AqlTransaction* trx = new AqlTransaction(
createTransactionContext(), _collections.collections(), createTransactionContext(), _collections.collections(),
_part == PART_MAIN); _queryOptions.transactionOptions, _part == PART_MAIN);
_trx = trx; _trx = trx;
// As soon as we start du instantiate the plan we have to clean it // As soon as we start du instantiate the plan we have to clean it
@ -919,7 +920,8 @@ QueryResult Query::explain() {
// create the transaction object, but do not start it yet // create the transaction object, but do not start it yet
_trx = new AqlTransaction(createTransactionContext(), _trx = new AqlTransaction(createTransactionContext(),
_collections.collections(), true); _collections.collections(),
_queryOptions.transactionOptions, true);
// we have an AST // we have an AST
Result res = _trx->begin(); Result res = _trx->begin();

View File

@ -172,6 +172,9 @@ void QueryOptions::fromVelocyPack(VPackSlice const& slice) {
it.next(); it.next();
} }
} }
// also handle transaction options
transactionOptions.fromVelocyPack(slice);
} }
void QueryOptions::toVelocyPack(VPackBuilder& builder, bool disableOptimizerRules) const { void QueryOptions::toVelocyPack(VPackBuilder& builder, bool disableOptimizerRules) const {
@ -216,6 +219,9 @@ void QueryOptions::toVelocyPack(VPackBuilder& builder, bool disableOptimizerRule
} }
builder.close(); // shardIds builder.close(); // shardIds
} }
// also handle transaction options
transactionOptions.toVelocyPack(builder);
builder.close(); builder.close();
} }

View File

@ -25,6 +25,7 @@
#define ARANGOD_AQL_QUERY_OPTIONS_H 1 #define ARANGOD_AQL_QUERY_OPTIONS_H 1
#include "Basics/Common.h" #include "Basics/Common.h"
#include "Transaction/Options.h"
namespace arangodb { namespace arangodb {
namespace velocypack { namespace velocypack {
@ -58,6 +59,8 @@ struct QueryOptions {
bool inspectSimplePlans; bool inspectSimplePlans;
std::vector<std::string> optimizerRules; std::vector<std::string> optimizerRules;
std::unordered_set<std::string> shardIds; std::unordered_set<std::string> shardIds;
transaction::Options transactionOptions;
}; };
} }

View File

@ -101,7 +101,7 @@ BaseEngine::BaseEngine(TRI_vocbase_t* vocbase, VPackSlice info)
_trx = new arangodb::aql::AqlTransaction( _trx = new arangodb::aql::AqlTransaction(
arangodb::transaction::StandaloneContext::Create(vocbase), arangodb::transaction::StandaloneContext::Create(vocbase),
_collections.collections(), true); _collections.collections(), transaction::Options(), true);
// true here as last argument is crucial: it leads to the fact that the // true here as last argument is crucial: it leads to the fact that the
// created transaction is considered a "MAIN" part and will not switch // created transaction is considered a "MAIN" part and will not switch
// off collection locking completely! // off collection locking completely!

View File

@ -247,13 +247,13 @@ static void WINAPI ServiceMain(DWORD dwArgc, LPSTR* lpszArgv) {
RegisterServiceCtrlHandlerA(lpszArgv[0], (LPHANDLER_FUNCTION)ServiceCtrl); RegisterServiceCtrlHandlerA(lpszArgv[0], (LPHANDLER_FUNCTION)ServiceCtrl);
// set start pending // set start pending
SetServiceStatus(SERVICE_START_PENDING, 0, 1, 10000); SetServiceStatus(SERVICE_START_PENDING, 0, 1, 10000, 0);
ArangoGlobalContext context(ARGC, ARGV, SBIN_DIRECTORY); ArangoGlobalContext context(ARGC, ARGV, SBIN_DIRECTORY);
runServer(ARGC, ARGV, context); runServer(ARGC, ARGV, context);
// service has stopped // service has stopped
SetServiceStatus(SERVICE_STOPPED, NO_ERROR, 0, 0); SetServiceStatus(SERVICE_STOPPED, NO_ERROR, 0, 0, 0);
TRI_CloseWindowsEventlog(); TRI_CloseWindowsEventlog();
} }

View File

@ -197,7 +197,7 @@ std::pair<bool, int32_t> RocksDBKey::geoValues(rocksdb::Slice const& slice) {
uint64_t val = uint64_t val =
uint64FromPersistent(slice.data() + sizeof(char) + sizeof(uint64_t)); uint64FromPersistent(slice.data() + sizeof(char) + sizeof(uint64_t));
bool isSlot = ((val & 0xFFULL) > 0); // lowest byte is 0xFF if true bool isSlot = ((val & 0xFFULL) > 0); // lowest byte is 0xFF if true
return std::pair<bool, int32_t>(isSlot, (val >> 32)); return std::pair<bool, int32_t>(isSlot, static_cast<int32_t>(val >> 32));
} }
std::string const& RocksDBKey::string() const { return _buffer; } std::string const& RocksDBKey::string() const { return _buffer; }

View File

@ -438,8 +438,6 @@ RocksDBOperationResult RocksDBTransactionState::addOperation(
// "transaction size" counters have reached their limit // "transaction size" counters have reached their limit
if (_options.intermediateCommitCount <= numOperations || if (_options.intermediateCommitCount <= numOperations ||
_options.intermediateCommitSize <= newSize) { _options.intermediateCommitSize <= newSize) {
LOG_TOPIC(ERR, Logger::FIXME) << "INTERMEDIATE COMMIT!";
internalCommit(); internalCommit();
_numInserts = 0; _numInserts = 0;
_numUpdates = 0; _numUpdates = 0;

View File

@ -23,6 +23,10 @@
#include "Options.h" #include "Options.h"
#include <velocypack/Builder.h>
#include <velocypack/Slice.h>
#include <velocypack/velocypack-aliases.h>
using namespace arangodb::transaction; using namespace arangodb::transaction;
uint64_t Options::defaultMaxTransactionSize = UINT64_MAX; uint64_t Options::defaultMaxTransactionSize = UINT64_MAX;
@ -42,3 +46,44 @@ void Options::setLimits(uint64_t maxTransactionSize, uint64_t intermediateCommit
defaultIntermediateCommitSize = intermediateCommitSize; defaultIntermediateCommitSize = intermediateCommitSize;
defaultIntermediateCommitCount = intermediateCommitCount; defaultIntermediateCommitCount = intermediateCommitCount;
} }
void Options::fromVelocyPack(arangodb::velocypack::Slice const& slice) {
VPackSlice value;
value = slice.get("lockTimeout");
if (value.isNumber()) {
lockTimeout = value.getNumber<double>();
}
value = slice.get("maxTransactionSize");
if (value.isNumber()) {
maxTransactionSize = value.getNumber<uint64_t>();
}
value = slice.get("intermediateCommitSize");
if (value.isNumber()) {
intermediateCommitSize = value.getNumber<uint64_t>();
}
value = slice.get("intermediateCommitCount");
if (value.isNumber()) {
intermediateCommitCount = value.getNumber<uint64_t>();
}
value = slice.get("allowImplicitCollections");
if (value.isBool()) {
allowImplicitCollections = value.getBool();
}
value = slice.get("waitForSync");
if (value.isBool()) {
waitForSync = value.getBool();
}
}
/// @brief add the options to an opened vpack builder
void Options::toVelocyPack(arangodb::velocypack::Builder& builder) const {
TRI_ASSERT(builder.isOpenObject());
builder.add("lockTimeout", VPackValue(lockTimeout));
builder.add("maxTransactionSize", VPackValue(maxTransactionSize));
builder.add("intermediateCommitSize", VPackValue(intermediateCommitSize));
builder.add("intermediateCommitCount", VPackValue(intermediateCommitCount));
builder.add("allowImplicitCollections", VPackValue(allowImplicitCollections));
builder.add("waitForSync", VPackValue(waitForSync));
}

View File

@ -27,12 +27,25 @@
#include "Basics/Common.h" #include "Basics/Common.h"
namespace arangodb { namespace arangodb {
namespace velocypack {
class Builder;
class Slice;
}
namespace transaction { namespace transaction {
struct Options { struct Options {
Options(); Options();
/// @brief adjust the global default values for transactions
static void setLimits(uint64_t maxTransactionSize, uint64_t intermediateCommitSize, uint64_t intermediateCommitCount); static void setLimits(uint64_t maxTransactionSize, uint64_t intermediateCommitSize, uint64_t intermediateCommitCount);
/// @brief read the options from a vpack slice
void fromVelocyPack(arangodb::velocypack::Slice const&);
/// @brief add the options to an opened vpack builder
void toVelocyPack(arangodb::velocypack::Builder&) const;
static constexpr double defaultLockTimeout = 900.0; static constexpr double defaultLockTimeout = 900.0;
static uint64_t defaultMaxTransactionSize; static uint64_t defaultMaxTransactionSize;
static uint64_t defaultIntermediateCommitSize; static uint64_t defaultIntermediateCommitSize;

View File

@ -1401,7 +1401,7 @@ void TRI_InitV8Actions(v8::Isolate* isolate, v8::Handle<v8::Context> context) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#ifdef ARANGODB_ENABLE_FAILURE_TESTS #ifdef ARANGODB_ENABLE_FAILURE_TESTS
static bool clusterSendToAllServers( static int clusterSendToAllServers(
std::string const& dbname, std::string const& dbname,
std::string const& path, // Note: Has to be properly encoded! std::string const& path, // Note: Has to be properly encoded!
arangodb::rest::RequestType const& method, std::string const& body) { arangodb::rest::RequestType const& method, std::string const& body) {

View File

@ -816,7 +816,7 @@ void ImportHelper::sendJsonBuffer(char const* str, size_t len, bool isObject) {
SenderThread* ImportHelper::findSender() { SenderThread* ImportHelper::findSender() {
while (!_senderThreads.empty()) { while (!_senderThreads.empty()) {
for (std::unique_ptr<SenderThread>& t : _senderThreads) { for (auto const& t : _senderThreads) {
if (t->hasError()) { if (t->hasError()) {
_hasError = true; _hasError = true;
_errorMessage = t->errorMessage(); _errorMessage = t->errorMessage();
@ -825,7 +825,7 @@ SenderThread* ImportHelper::findSender() {
return t.get(); return t.get();
} }
} }
usleep(500000); usleep(100000);
} }
return nullptr; return nullptr;
} }
@ -833,7 +833,7 @@ SenderThread* ImportHelper::findSender() {
void ImportHelper::waitForSenders() { void ImportHelper::waitForSenders() {
while (!_senderThreads.empty()) { while (!_senderThreads.empty()) {
uint32_t numIdle = 0; uint32_t numIdle = 0;
for (std::unique_ptr<SenderThread>& t : _senderThreads) { for (auto const& t : _senderThreads) {
if (t->idle() || t->hasError()) { if (t->idle() || t->hasError()) {
numIdle++; numIdle++;
} }

View File

@ -68,8 +68,8 @@ void SenderThread::sendData(std::string const& url,
_data.swap(data); _data.swap(data);
// wake up the thread that may be waiting in run() // wake up the thread that may be waiting in run()
_idle = false;
CONDITION_LOCKER(guard, _condition); CONDITION_LOCKER(guard, _condition);
_idle = false;
guard.broadcast(); guard.broadcast();
} }
@ -80,6 +80,8 @@ void SenderThread::run() {
guard.wait(); guard.wait();
} }
if (isStopping()) { if (isStopping()) {
CONDITION_LOCKER(guard, _condition);
_idle = true;
return; return;
} }
try { try {
@ -96,8 +98,10 @@ void SenderThread::run() {
_url.clear(); _url.clear();
_data.reset(); _data.reset();
} }
CONDITION_LOCKER(guard, _condition);
_idle = true; _idle = true;
} catch (...) { } catch (...) {
CONDITION_LOCKER(guard, _condition);
_hasError = true; _hasError = true;
_idle = true; _idle = true;
} }

View File

@ -57,11 +57,11 @@ class SenderThread : public arangodb::Thread {
void sendData(std::string const& url, basics::StringBuffer* sender); void sendData(std::string const& url, basics::StringBuffer* sender);
bool idle() { return _idle; } bool idle() const { return _idle; }
bool hasError() { return _hasError; } bool hasError() const { return _hasError; }
std::string const& errorMessage() { return _errorMessage; } std::string const& errorMessage() const { return _errorMessage; }
void beginShutdown() override; void beginShutdown() override;

View File

@ -594,7 +594,7 @@ void ApplicationServer::start() {
} }
} }
} }
shutdownFatalError();
// throw exception so the startup aborts // throw exception so the startup aborts
THROW_ARANGO_EXCEPTION_MESSAGE(res, std::string("startup aborted: ") + TRI_errno_string(res)); THROW_ARANGO_EXCEPTION_MESSAGE(res, std::string("startup aborted: ") + TRI_errno_string(res));
} }

View File

@ -36,6 +36,7 @@ class ProgramOptions;
namespace application_features { namespace application_features {
class ApplicationFeature; class ApplicationFeature;
// handled i.e. in WindowsServiceFeature.cpp
enum class ServerState { enum class ServerState {
UNINITIALIZED, UNINITIALIZED,
IN_COLLECT_OPTIONS, IN_COLLECT_OPTIONS,

View File

@ -368,7 +368,7 @@ void DeleteService (bool force) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void SetServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, void SetServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode,
DWORD dwCheckPoint, DWORD dwWaitHint) { DWORD dwCheckPoint, DWORD dwWaitHint, DWORD exitCode) {
// disable control requests until the service is started // disable control requests until the service is started
SERVICE_STATUS ss; SERVICE_STATUS ss;
@ -381,9 +381,11 @@ void SetServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode,
// initialize ss structure // initialize ss structure
ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS; ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ss.dwServiceSpecificExitCode = 0;
ss.dwCurrentState = dwCurrentState; ss.dwCurrentState = dwCurrentState;
ss.dwWin32ExitCode = dwWin32ExitCode; ss.dwWin32ExitCode = dwWin32ExitCode;
ss.dwServiceSpecificExitCode = exitCode;
ss.dwCheckPoint = dwCheckPoint; ss.dwCheckPoint = dwCheckPoint;
ss.dwWaitHint = dwWaitHint; ss.dwWaitHint = dwWaitHint;
@ -407,7 +409,7 @@ void SetServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode,
/// really up and running. /// really up and running.
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
void WindowsServiceFeature::startupProgress () { void WindowsServiceFeature::startupProgress () {
SetServiceStatus(SERVICE_START_PENDING, NO_ERROR, _progress++, 20000); SetServiceStatus(SERVICE_START_PENDING, NO_ERROR, _progress++, 20000, 0);
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -416,7 +418,7 @@ void WindowsServiceFeature::startupProgress () {
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
void WindowsServiceFeature::startupFinished () { void WindowsServiceFeature::startupFinished () {
// startup finished - signalize we're running. // startup finished - signalize we're running.
SetServiceStatus(SERVICE_RUNNING, NO_ERROR, 0, 0); SetServiceStatus(SERVICE_RUNNING, NO_ERROR, 0, 0, 0);
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -425,7 +427,7 @@ void WindowsServiceFeature::startupFinished () {
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
void WindowsServiceFeature::shutDownBegins () { void WindowsServiceFeature::shutDownBegins () {
// startup finished - signalize we're running. // startup finished - signalize we're running.
SetServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, 0, 0); SetServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, 0, 0, 0);
} }
@ -435,7 +437,7 @@ void WindowsServiceFeature::shutDownBegins () {
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
void WindowsServiceFeature::shutDownComplete () { void WindowsServiceFeature::shutDownComplete () {
// startup finished - signalize we're running. // startup finished - signalize we're running.
SetServiceStatus(SERVICE_STOPPED, NO_ERROR, 0, 0); SetServiceStatus(SERVICE_STOPPED, NO_ERROR, 0, 0, 0);
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -444,7 +446,16 @@ void WindowsServiceFeature::shutDownComplete () {
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
void WindowsServiceFeature::shutDownFailure () { void WindowsServiceFeature::shutDownFailure () {
// startup finished - signalize we're running. // startup finished - signalize we're running.
SetServiceStatus(SERVICE_STOP, ERROR_FAIL_RESTART, 0, 0); SetServiceStatus(SERVICE_STOP, ERROR_SERVICE_SPECIFIC_ERROR, 0, 0, 1);
}
//////////////////////////////////////////////////////////////////////////////
/// @brief wrap ArangoDB server so we can properly emmit a status on shutdown
/// starting
//////////////////////////////////////////////////////////////////////////////
void WindowsServiceFeature::abortFailure () {
// startup finished - signalize we're running.
SetServiceStatus(SERVICE_STOP, ERROR_SERVICE_SPECIFIC_ERROR, 0, 0, 2);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -470,7 +481,7 @@ void WINAPI ServiceCtrl(DWORD dwCtrlCode) {
// stop service // stop service
if (dwCtrlCode == SERVICE_CONTROL_STOP || if (dwCtrlCode == SERVICE_CONTROL_STOP ||
dwCtrlCode == SERVICE_CONTROL_SHUTDOWN) { dwCtrlCode == SERVICE_CONTROL_SHUTDOWN) {
SetServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, 0, 0); SetServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, 0, 0, 0);
if (ArangoInstance != nullptr && ArangoInstance->_server != nullptr) { if (ArangoInstance != nullptr && ArangoInstance->_server != nullptr) {
ArangoInstance->_server->beginShutdown(); ArangoInstance->_server->beginShutdown();
@ -480,28 +491,10 @@ void WINAPI ServiceCtrl(DWORD dwCtrlCode) {
} }
} }
} else { } else {
SetServiceStatus(dwState, NO_ERROR, 0, 0); SetServiceStatus(dwState, NO_ERROR, 0, 0, 0);
} }
} }
////////////////////////////////////////////////////////////////////////////////
/// @brief parse windows specific commandline options
////////////////////////////////////////////////////////////////////////////////
/*
bool TRI_ParseMoreArgs(int argc, char* argv[]) {
SetUnhandledExceptionFilter(unhandledExceptionHandler);
} else if (TRI_EqualString(argv[1], "--uninstall-service")) {
bool force = ((argc > 2) && !strcmp(argv[2], "--force"));
DeleteService(argc, argv, force);
exit(EXIT_SUCCESS);
}
}
return false;
}
*/
WindowsServiceFeature::WindowsServiceFeature(application_features::ApplicationServer* server) WindowsServiceFeature::WindowsServiceFeature(application_features::ApplicationServer* server)
: ApplicationFeature(server, "WindowsService"), : ApplicationFeature(server, "WindowsService"),
_server(server){ _server(server){
@ -556,6 +549,14 @@ void WindowsServiceFeature::collectOptions(std::shared_ptr<ProgramOptions> optio
new BooleanParameter(&_stopWaitService)); new BooleanParameter(&_stopWaitService));
} }
void WindowsServiceFeature::abortService() {
if (ArangoInstance != nullptr) {
ArangoInstance->_server = nullptr;
ArangoInstance->abortFailure();
}
exit(EXIT_FAILURE);
}
void WindowsServiceFeature::validateOptions(std::shared_ptr<ProgramOptions> options) { void WindowsServiceFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
if (!TRI_InitWindowsEventLog()) { if (!TRI_InitWindowsEventLog()) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@ -570,6 +571,8 @@ void WindowsServiceFeature::validateOptions(std::shared_ptr<ProgramOptions> opti
else if (_forceUninstall) { else if (_forceUninstall) {
} }
else if (_startAsService) { else if (_startAsService) {
TRI_SetWindowsServiceAbortFunction(abortService);
ProgressHandler reporter{ ProgressHandler reporter{
[this](ServerState state) { [this](ServerState state) {
switch (state) { switch (state) {
@ -585,6 +588,9 @@ void WindowsServiceFeature::validateOptions(std::shared_ptr<ProgramOptions> opti
case ServerState::IN_START: case ServerState::IN_START:
this->startupProgress(); this->startupProgress();
break; break;
case ServerState::ABORT:
this->shutDownFailure();
break;
case ServerState::UNINITIALIZED: case ServerState::UNINITIALIZED:
case ServerState::STOPPED: case ServerState::STOPPED:
break; break;

View File

@ -28,7 +28,7 @@
extern SERVICE_STATUS_HANDLE ServiceStatus; extern SERVICE_STATUS_HANDLE ServiceStatus;
void SetServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, void SetServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode,
DWORD dwCheckPoint, DWORD dwWaitHint); DWORD dwCheckPoint, DWORD dwWaitHint, DWORD exitCode);
void WINAPI ServiceCtrl(DWORD dwCtrlCode); void WINAPI ServiceCtrl(DWORD dwCtrlCode);
@ -51,7 +51,8 @@ class WindowsServiceFeature final : public application_features::ApplicationFeat
void shutDownBegins (); void shutDownBegins ();
void shutDownComplete (); void shutDownComplete ();
void shutDownFailure (); void shutDownFailure ();
void abortFailure();
static void abortService();
public: public:
bool _installService = false; bool _installService = false;
bool _unInstallService = false; bool _unInstallService = false;