mirror of https://gitee.com/bigwinds/arangodb
progress report and windows minidump
This commit is contained in:
parent
190dd674d8
commit
6248f419f1
|
@ -150,6 +150,7 @@ void ApplicationServer::run(int argc, char* argv[]) {
|
||||||
// collect options from all features
|
// collect options from all features
|
||||||
// in this phase, all features are order-independent
|
// in this phase, all features are order-independent
|
||||||
_state = ServerState::IN_COLLECT_OPTIONS;
|
_state = ServerState::IN_COLLECT_OPTIONS;
|
||||||
|
reportServerProgress(_state);
|
||||||
collectOptions();
|
collectOptions();
|
||||||
|
|
||||||
// setup dependency, but ignore any failure for now
|
// setup dependency, but ignore any failure for now
|
||||||
|
@ -164,6 +165,7 @@ void ApplicationServer::run(int argc, char* argv[]) {
|
||||||
|
|
||||||
// validate options of all features
|
// validate options of all features
|
||||||
_state = ServerState::IN_VALIDATE_OPTIONS;
|
_state = ServerState::IN_VALIDATE_OPTIONS;
|
||||||
|
reportServerProgress(_state);
|
||||||
validateOptions();
|
validateOptions();
|
||||||
|
|
||||||
// enable automatic features
|
// enable automatic features
|
||||||
|
@ -181,6 +183,7 @@ void ApplicationServer::run(int argc, char* argv[]) {
|
||||||
// if they want other features to access them, or if they want to access
|
// if they want other features to access them, or if they want to access
|
||||||
// these files with dropped privileges
|
// these files with dropped privileges
|
||||||
_state = ServerState::IN_PREPARE;
|
_state = ServerState::IN_PREPARE;
|
||||||
|
reportServerProgress(_state);
|
||||||
prepare();
|
prepare();
|
||||||
|
|
||||||
// permanently drop the privileges
|
// permanently drop the privileges
|
||||||
|
@ -188,17 +191,22 @@ void ApplicationServer::run(int argc, char* argv[]) {
|
||||||
|
|
||||||
// start features. now features are allowed to start threads, write files etc.
|
// start features. now features are allowed to start threads, write files etc.
|
||||||
_state = ServerState::IN_START;
|
_state = ServerState::IN_START;
|
||||||
|
reportServerProgress(_state);
|
||||||
start();
|
start();
|
||||||
|
|
||||||
// wait until we get signaled the shutdown request
|
// wait until we get signaled the shutdown request
|
||||||
|
_state = ServerState::IN_WAIT;
|
||||||
|
reportServerProgress(_state);
|
||||||
wait();
|
wait();
|
||||||
|
|
||||||
// stop all features
|
// stop all features
|
||||||
_state = ServerState::IN_STOP;
|
_state = ServerState::IN_STOP;
|
||||||
|
reportServerProgress(_state);
|
||||||
stop();
|
stop();
|
||||||
|
|
||||||
// stopped
|
// stopped
|
||||||
_state = ServerState::STOPPED;
|
_state = ServerState::STOPPED;
|
||||||
|
reportServerProgress(_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
// signal the server to shut down
|
// signal the server to shut down
|
||||||
|
@ -253,6 +261,7 @@ void ApplicationServer::collectOptions() {
|
||||||
apply([this](ApplicationFeature* feature) {
|
apply([this](ApplicationFeature* feature) {
|
||||||
LOG_TOPIC(TRACE, Logger::STARTUP) << feature->name() << "::loadOptions";
|
LOG_TOPIC(TRACE, Logger::STARTUP) << feature->name() << "::loadOptions";
|
||||||
feature->collectOptions(_options);
|
feature->collectOptions(_options);
|
||||||
|
reportFeatureProgress(_state, feature->name());
|
||||||
}, true);
|
}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,11 +311,13 @@ void ApplicationServer::parseOptions(int argc, char* argv[]) {
|
||||||
void ApplicationServer::validateOptions() {
|
void ApplicationServer::validateOptions() {
|
||||||
LOG_TOPIC(TRACE, Logger::STARTUP) << "ApplicationServer::validateOptions";
|
LOG_TOPIC(TRACE, Logger::STARTUP) << "ApplicationServer::validateOptions";
|
||||||
|
|
||||||
for (auto it = _orderedFeatures.begin(); it != _orderedFeatures.end(); ++it) {
|
for (auto feature : _orderedFeatures) {
|
||||||
if ((*it)->isEnabled()) {
|
if (feature->isEnabled()) {
|
||||||
LOG_TOPIC(TRACE, Logger::STARTUP) << (*it)->name() << "::validateOptions";
|
LOG_TOPIC(TRACE, Logger::STARTUP) << feature->name()
|
||||||
(*it)->validateOptions(_options);
|
<< "::validateOptions";
|
||||||
(*it)->state(FeatureState::VALIDATED);
|
feature->validateOptions(_options);
|
||||||
|
feature->state(FeatureState::VALIDATED);
|
||||||
|
reportFeatureProgress(_state, feature->name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -437,9 +448,9 @@ void ApplicationServer::prepare() {
|
||||||
// we start with elevated privileges
|
// we start with elevated privileges
|
||||||
bool privilegesElevated = true;
|
bool privilegesElevated = true;
|
||||||
|
|
||||||
for (auto it = _orderedFeatures.begin(); it != _orderedFeatures.end(); ++it) {
|
for (auto feature : _orderedFeatures) {
|
||||||
if ((*it)->isEnabled()) {
|
if (feature->isEnabled()) {
|
||||||
bool const requiresElevated = (*it)->requiresElevatedPrivileges();
|
bool const requiresElevated = feature->requiresElevatedPrivileges();
|
||||||
|
|
||||||
if (requiresElevated != privilegesElevated) {
|
if (requiresElevated != privilegesElevated) {
|
||||||
// must change privileges for the feature
|
// must change privileges for the feature
|
||||||
|
@ -453,9 +464,9 @@ void ApplicationServer::prepare() {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
LOG_TOPIC(TRACE, Logger::STARTUP) << (*it)->name() << "::prepare";
|
LOG_TOPIC(TRACE, Logger::STARTUP) << feature->name() << "::prepare";
|
||||||
(*it)->prepare();
|
feature->prepare();
|
||||||
(*it)->state(FeatureState::PREPARED);
|
feature->state(FeatureState::PREPARED);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
// restore original privileges
|
// restore original privileges
|
||||||
if (!privilegesElevated) {
|
if (!privilegesElevated) {
|
||||||
|
@ -463,6 +474,8 @@ void ApplicationServer::prepare() {
|
||||||
}
|
}
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reportFeatureProgress(_state, feature->name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -470,21 +483,22 @@ void ApplicationServer::prepare() {
|
||||||
void ApplicationServer::start() {
|
void ApplicationServer::start() {
|
||||||
LOG_TOPIC(TRACE, Logger::STARTUP) << "ApplicationServer::start";
|
LOG_TOPIC(TRACE, Logger::STARTUP) << "ApplicationServer::start";
|
||||||
|
|
||||||
for (auto it = _orderedFeatures.begin(); it != _orderedFeatures.end(); ++it) {
|
for (auto feature : _orderedFeatures) {
|
||||||
LOG_TOPIC(TRACE, Logger::STARTUP) << (*it)->name() << "::start";
|
LOG_TOPIC(TRACE, Logger::STARTUP) << feature->name() << "::start";
|
||||||
(*it)->start();
|
feature->start();
|
||||||
(*it)->state(FeatureState::STARTED);
|
feature->state(FeatureState::STARTED);
|
||||||
|
reportFeatureProgress(_state, feature->name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplicationServer::stop() {
|
void ApplicationServer::stop() {
|
||||||
LOG_TOPIC(TRACE, Logger::STARTUP) << "ApplicationServer::stop";
|
LOG_TOPIC(TRACE, Logger::STARTUP) << "ApplicationServer::stop";
|
||||||
|
|
||||||
for (auto it = _orderedFeatures.rbegin(); it != _orderedFeatures.rend();
|
for (auto feature : _orderedFeatures) {
|
||||||
++it) {
|
LOG_TOPIC(TRACE, Logger::STARTUP) << feature->name() << "::stop";
|
||||||
LOG_TOPIC(TRACE, Logger::STARTUP) << (*it)->name() << "::stop";
|
feature->stop();
|
||||||
(*it)->stop();
|
feature->state(FeatureState::STOPPED);
|
||||||
(*it)->state(FeatureState::STOPPED);
|
reportFeatureProgress(_state, feature->name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -538,3 +552,16 @@ void ApplicationServer::dropPrivilegesPermanently() {
|
||||||
|
|
||||||
_privilegesDropped = true;
|
_privilegesDropped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ApplicationServer::reportServerProgress(ServerState state) {
|
||||||
|
for (auto reporter : _progressReports) {
|
||||||
|
reporter._state(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApplicationServer::reportFeatureProgress(ServerState state,
|
||||||
|
std::string const& name) {
|
||||||
|
for (auto reporter : _progressReports) {
|
||||||
|
reporter._feature(state, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -36,6 +36,23 @@ class ProgramOptions;
|
||||||
namespace application_features {
|
namespace application_features {
|
||||||
class ApplicationFeature;
|
class ApplicationFeature;
|
||||||
|
|
||||||
|
enum class ServerState {
|
||||||
|
UNINITIALIZED,
|
||||||
|
IN_COLLECT_OPTIONS,
|
||||||
|
IN_VALIDATE_OPTIONS,
|
||||||
|
IN_PREPARE,
|
||||||
|
IN_START,
|
||||||
|
IN_WAIT,
|
||||||
|
IN_STOP,
|
||||||
|
STOPPED
|
||||||
|
};
|
||||||
|
|
||||||
|
class ProgressHandler {
|
||||||
|
public:
|
||||||
|
std::function<void(ServerState)> _state;
|
||||||
|
std::function<void(ServerState, std::string const& featureName)> _feature;
|
||||||
|
};
|
||||||
|
|
||||||
// the following phases exists:
|
// the following phases exists:
|
||||||
//
|
//
|
||||||
// `collectOptions`
|
// `collectOptions`
|
||||||
|
@ -91,16 +108,6 @@ class ApplicationServer {
|
||||||
ApplicationServer& operator=(ApplicationServer const&) = delete;
|
ApplicationServer& operator=(ApplicationServer const&) = delete;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum class ServerState {
|
|
||||||
UNINITIALIZED,
|
|
||||||
IN_COLLECT_OPTIONS,
|
|
||||||
IN_VALIDATE_OPTIONS,
|
|
||||||
IN_PREPARE,
|
|
||||||
IN_START,
|
|
||||||
IN_STOP,
|
|
||||||
STOPPED
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class FeatureState {
|
enum class FeatureState {
|
||||||
UNINITIALIZED,
|
UNINITIALIZED,
|
||||||
INITIALIZED,
|
INITIALIZED,
|
||||||
|
@ -116,6 +123,7 @@ class ApplicationServer {
|
||||||
}
|
}
|
||||||
static bool isPrepared() {
|
static bool isPrepared() {
|
||||||
return server != nullptr && (server->_state == ServerState::IN_START ||
|
return server != nullptr && (server->_state == ServerState::IN_START ||
|
||||||
|
server->_state == ServerState::IN_WAIT ||
|
||||||
server->_state == ServerState::IN_STOP);
|
server->_state == ServerState::IN_STOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,6 +197,10 @@ class ApplicationServer {
|
||||||
// return the server state
|
// return the server state
|
||||||
ServerState state() const { return _state; }
|
ServerState state() const { return _state; }
|
||||||
|
|
||||||
|
void addReporter(ProgressHandler reporter) {
|
||||||
|
_progressReports.emplace_back(reporter);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// look up a feature and return a pointer to it. may be nullptr
|
// look up a feature and return a pointer to it. may be nullptr
|
||||||
static ApplicationFeature* lookupFeature(std::string const&);
|
static ApplicationFeature* lookupFeature(std::string const&);
|
||||||
|
@ -244,6 +256,9 @@ class ApplicationServer {
|
||||||
void dropPrivilegesTemporarily();
|
void dropPrivilegesTemporarily();
|
||||||
void dropPrivilegesPermanently();
|
void dropPrivilegesPermanently();
|
||||||
|
|
||||||
|
void reportServerProgress(ServerState);
|
||||||
|
void reportFeatureProgress(ServerState, std::string const&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// the current state
|
// the current state
|
||||||
ServerState _state = ServerState::UNINITIALIZED;
|
ServerState _state = ServerState::UNINITIALIZED;
|
||||||
|
@ -265,6 +280,9 @@ class ApplicationServer {
|
||||||
|
|
||||||
// whether or not to dump dependencies
|
// whether or not to dump dependencies
|
||||||
bool _dumpDependencies = false;
|
bool _dumpDependencies = false;
|
||||||
|
|
||||||
|
// reporter for progress
|
||||||
|
std::vector<ProgressHandler> _progressReports;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
#include "ApplicationFeatures/TempFeature.h"
|
#include "ApplicationFeatures/TempFeature.h"
|
||||||
|
|
||||||
|
#include "Basics/ArangoGlobalContext.h"
|
||||||
#include "Basics/files.h"
|
#include "Basics/files.h"
|
||||||
#include "Logger/Logger.h"
|
#include "Logger/Logger.h"
|
||||||
#include "ProgramOptions/ProgramOptions.h"
|
#include "ProgramOptions/ProgramOptions.h"
|
||||||
|
@ -58,4 +59,11 @@ void TempFeature::start() {
|
||||||
// must be used after drop privileges and be called to set it to avoid raise
|
// must be used after drop privileges and be called to set it to avoid raise
|
||||||
// conditions
|
// conditions
|
||||||
TRI_GetTempPath();
|
TRI_GetTempPath();
|
||||||
|
|
||||||
|
// signal that the temp path is available
|
||||||
|
auto context = ArangoGlobalContext::CONTEXT;
|
||||||
|
|
||||||
|
if (context != nullptr) {
|
||||||
|
context->tempPathAvailable();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,10 @@
|
||||||
|
|
||||||
#include "ArangoGlobalContext.h"
|
#include "ArangoGlobalContext.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <DbgHelp.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "Basics/debugging.h"
|
#include "Basics/debugging.h"
|
||||||
#include "Basics/files.h"
|
#include "Basics/files.h"
|
||||||
#include "Logger/LogAppender.h"
|
#include "Logger/LogAppender.h"
|
||||||
|
@ -30,10 +34,6 @@
|
||||||
|
|
||||||
using namespace arangodb;
|
using namespace arangodb;
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
static void ReopenLog(int) { LogAppender::reopen(); }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void AbortHandler(int signum) {
|
static void AbortHandler(int signum) {
|
||||||
TRI_PrintBacktrace();
|
TRI_PrintBacktrace();
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -44,11 +44,77 @@ static void AbortHandler(int signum) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
static void ReopenLog(int) { LogAppender::reopen(); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
static std::string miniDumpFilename = "c:\\arangodpanic.dmp";
|
||||||
|
|
||||||
|
LONG CALLBACK unhandledExceptionHandler(EXCEPTION_POINTERS* e) {
|
||||||
|
#if ARANGODB_ENABLE_BACKTRACE
|
||||||
|
|
||||||
|
if ((e != nullptr) && (e->ExceptionRecord != nullptr)) {
|
||||||
|
LOG_FATAL_WINDOWS("Unhandled exception: %d",
|
||||||
|
(int)e->ExceptionRecord->ExceptionCode);
|
||||||
|
} else {
|
||||||
|
LOG_FATAL_WINDOWS("Unhandled exception without ExceptionCode!");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string bt;
|
||||||
|
TRI_GetBacktrace(bt);
|
||||||
|
std::cerr << bt << std::endl;
|
||||||
|
LOG_FATAL_WINDOWS(bt.c_str());
|
||||||
|
|
||||||
|
HANDLE hFile =
|
||||||
|
CreateFile(miniDumpFilename.c_str(), GENERIC_WRITE, FILE_SHARE_READ, 0,
|
||||||
|
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
|
|
||||||
|
if (hFile == INVALID_HANDLE_VALUE) {
|
||||||
|
LOG_FATAL_WINDOWS("could not open minidump file : %lu", GetLastError());
|
||||||
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
MINIDUMP_EXCEPTION_INFORMATION exceptionInfo;
|
||||||
|
exceptionInfo.ThreadId = GetCurrentThreadId();
|
||||||
|
exceptionInfo.ExceptionPointers = e;
|
||||||
|
exceptionInfo.ClientPointers = FALSE;
|
||||||
|
|
||||||
|
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile,
|
||||||
|
MINIDUMP_TYPE(MiniDumpWithIndirectlyReferencedMemory |
|
||||||
|
MiniDumpScanMemory | MiniDumpWithFullMemory),
|
||||||
|
e ? &exceptionInfo : nullptr, nullptr, nullptr);
|
||||||
|
|
||||||
|
if (hFile) {
|
||||||
|
CloseHandle(hFile);
|
||||||
|
hFile = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_FATAL_WINDOWS("wrote minidump: %s", miniDumpFilename.c_str());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ((e != nullptr) && (e->ExceptionRecord != nullptr)) {
|
||||||
|
LOG_FATAL_WINDOWS("Unhandled exception: %d - will crash now.",
|
||||||
|
(int)e->ExceptionRecord->ExceptionCode);
|
||||||
|
} else {
|
||||||
|
LOG_FATAL_WINDOWS(
|
||||||
|
"Unhandled exception without ExceptionCode - will crash now.!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ArangoGlobalContext* ArangoGlobalContext::CONTEXT = nullptr;
|
ArangoGlobalContext* ArangoGlobalContext::CONTEXT = nullptr;
|
||||||
|
|
||||||
ArangoGlobalContext::ArangoGlobalContext(int argc, char* argv[])
|
ArangoGlobalContext::ArangoGlobalContext(int argc, char* argv[])
|
||||||
: _binaryName(TRI_BinaryName(argv[0])), _ret(EXIT_FAILURE) {
|
: _binaryName(TRI_BinaryName(argv[0])), _ret(EXIT_FAILURE) {
|
||||||
ADB_WindowsEntryFunction();
|
ADB_WindowsEntryFunction();
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
SetUnhandledExceptionFilter(unhandledExceptionHandler);
|
||||||
|
#endif
|
||||||
|
|
||||||
TRIAGENS_REST_INITIALIZE();
|
TRIAGENS_REST_INITIALIZE();
|
||||||
CONTEXT = this;
|
CONTEXT = this;
|
||||||
}
|
}
|
||||||
|
@ -184,3 +250,11 @@ void ArangoGlobalContext::runStartupChecks() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ArangoGlobalContext::tempPathAvailable() {
|
||||||
|
#ifdef _WIN32
|
||||||
|
miniDumpFilename = TRI_GetTempPath();
|
||||||
|
|
||||||
|
miniDumpFilename +=
|
||||||
|
"\\minidump_" + std::to_string(GetCurrentProcessId()) + ".dmp";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
|
@ -42,6 +42,7 @@ class ArangoGlobalContext {
|
||||||
void maskAllSignals();
|
void maskAllSignals();
|
||||||
void unmaskStandardSignals();
|
void unmaskStandardSignals();
|
||||||
void runStartupChecks();
|
void runStartupChecks();
|
||||||
|
void tempPathAvailable();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string _binaryName;
|
std::string _binaryName;
|
||||||
|
|
Loading…
Reference in New Issue