From f7373fe103888c3df77a062020c98c9aad49a560 Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Tue, 24 Jul 2018 09:43:15 +0200 Subject: [PATCH] Bug fix/lock file cleanup (#5960) * Added cleanup functions class that allows to execute functions on unexpected shutdown (like FATAL_EXIT). First use: delete the LOCK file. (#5218) * Removed superfluous log message --- arangod/RestServer/LockfileFeature.cpp | 6 ++ lib/Basics/CleanupFunctions.cpp | 44 +++++++++++++ lib/Basics/CleanupFunctions.h | 88 ++++++++++++++++++++++++++ lib/Basics/Common.h | 28 ++++---- lib/CMakeLists.txt | 1 + lib/Logger/Logger.h | 2 + 6 files changed, 156 insertions(+), 13 deletions(-) create mode 100644 lib/Basics/CleanupFunctions.cpp create mode 100644 lib/Basics/CleanupFunctions.h diff --git a/arangod/RestServer/LockfileFeature.cpp b/arangod/RestServer/LockfileFeature.cpp index 4f293381e1..83cd10fb7a 100644 --- a/arangod/RestServer/LockfileFeature.cpp +++ b/arangod/RestServer/LockfileFeature.cpp @@ -79,6 +79,12 @@ void LockfileFeature::start() { << _lockFilename << "': " << TRI_errno_string(res); FATAL_ERROR_EXIT_CODE(TRI_EXIT_COULD_NOT_LOCK); } + + auto cleanup = std::make_unique( + [&] (int code, void* data) { + TRI_DestroyLockFile(_lockFilename.c_str()); + }); + CleanupFunctions::registerFunction(std::move(cleanup)); } void LockfileFeature::unprepare() { diff --git a/lib/Basics/CleanupFunctions.cpp b/lib/Basics/CleanupFunctions.cpp new file mode 100644 index 0000000000..fc1184eaae --- /dev/null +++ b/lib/Basics/CleanupFunctions.cpp @@ -0,0 +1,44 @@ +//////////////////////////////////////////////////////////////////////////////// +/// DISCLAIMER +/// +/// Copyright 2018 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 Michael Hackstein +//////////////////////////////////////////////////////////////////////////////// + +#include "CleanupFunctions.h" +#include "Basics/MutexLocker.h" + +using namespace arangodb; +using namespace arangodb::basics; + +// Init static class members +Mutex CleanupFunctions::_functionsMutex; +std::vector> CleanupFunctions::_cleanupFunctions; + +void CleanupFunctions::registerFunction(std::unique_ptr func) { + MUTEX_LOCKER(locker, _functionsMutex); + _cleanupFunctions.emplace_back(std::move(func)); +} + +void CleanupFunctions::run(int code, void* data) { + MUTEX_LOCKER(locker, _functionsMutex); + for (auto const& func : _cleanupFunctions) { + (*func)(code, data); + } + _cleanupFunctions.clear(); +} diff --git a/lib/Basics/CleanupFunctions.h b/lib/Basics/CleanupFunctions.h new file mode 100644 index 0000000000..551ec7f85f --- /dev/null +++ b/lib/Basics/CleanupFunctions.h @@ -0,0 +1,88 @@ +//////////////////////////////////////////////////////////////////////////////// +/// DISCLAIMER +/// +/// Copyright 2018 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 Michael Hackstein +//////////////////////////////////////////////////////////////////////////////// + +#ifndef ARANGODB_BASICS_CLEANUPFUNCTIONS_H +#define ARANGODB_BASICS_CLEANUPFUNCTIONS_H 1 + +#include "Basics/Common.h" + +#include "Basics/Mutex.h" + +namespace arangodb { +namespace basics { + +/** + * @brief A class to manage and handle cleanup functions on shutdown. + * Thread save execution. It is meant to collect functions that should + * be executed on every shutdown we can react to. + * e.g. FATAL errors + */ +class CleanupFunctions { + CleanupFunctions(CleanupFunctions const&) = delete; + CleanupFunctions& operator=(CleanupFunctions const&) = delete; + + // Typedefs +public: + /** + * @brief A cleanup function, will be called with the exit code + * and some data that is generated during exit (just as TRI_ExitFunction_t). + */ + typedef std::function CleanupFunction; + + // Functions +public: + /** + * @brief Register a new function to be executed during + * any "expected" exit of the server (FATAL, CTRL+C, Shutdown) + * + * @param func The function to be executed. + */ + static void registerFunction(std::unique_ptr func); + + /** + * @brief Execute all functions in _cleanupFunctions + * + * @param code The exit code provided + * @param data data given during exit + */ + static void run(int code, void* data); + +private: +/** + * @brief A lock for the cleanup functions. + * Used to make sure they are only executed once. + * This is NOT performance critical as those functions + * only kick in on startup (insert) and shutdown (execute) + */ +static Mutex _functionsMutex; + +/** + * @brief A list of functions to be executed during cleanup + */ +static std::vector> _cleanupFunctions; + + +}; +} // namespace basics +} // namespace arangodb + +#endif diff --git a/lib/Basics/Common.h b/lib/Basics/Common.h index 9fe1bf7878..90af436f30 100644 --- a/lib/Basics/Common.h +++ b/lib/Basics/Common.h @@ -215,13 +215,14 @@ typedef long suseconds_t; /// @brief aborts program execution, returning an error code /// if backtraces are enabled, a backtrace will be printed before -#define FATAL_ERROR_EXIT_CODE(code) \ - do { \ - TRI_LogBacktrace(); \ - arangodb::Logger::flush(); \ - arangodb::Logger::shutdown(); \ - TRI_EXIT_FUNCTION(code, nullptr); \ - exit(code); \ +#define FATAL_ERROR_EXIT_CODE(code) \ + do { \ + TRI_LogBacktrace(); \ + arangodb::basics::CleanupFunctions::run(code, nullptr); \ + arangodb::Logger::flush(); \ + arangodb::Logger::shutdown(); \ + TRI_EXIT_FUNCTION(code, nullptr); \ + exit(code); \ } while (0) /// @brief aborts program execution, returning an error code @@ -233,12 +234,13 @@ typedef long suseconds_t; /// @brief aborts program execution, calling std::abort /// if backtraces are enabled, a backtrace will be printed before -#define FATAL_ERROR_ABORT(...) \ - do { \ - TRI_LogBacktrace(); \ - arangodb::Logger::flush(); \ - arangodb::Logger::shutdown(); \ - std::abort(); \ +#define FATAL_ERROR_ABORT(...) \ + do { \ + TRI_LogBacktrace(); \ + arangodb::basics::CleanupFunctions::run(500, nullptr); \ + arangodb::Logger::flush(); \ + arangodb::Logger::shutdown(); \ + std::abort(); \ } while (0) #ifdef _WIN32 diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 838faa6fa1..6527654fad 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -166,6 +166,7 @@ add_library(${LIB_ARANGO} STATIC Basics/VelocyPackDumper.cpp Basics/VelocyPackHelper.cpp Basics/application-exit.cpp + Basics/CleanupFunctions.cpp Basics/conversions.cpp Basics/csv.cpp Basics/datetime.cpp diff --git a/lib/Logger/Logger.h b/lib/Logger/Logger.h index 2e524ceb77..f5c410327e 100644 --- a/lib/Logger/Logger.h +++ b/lib/Logger/Logger.h @@ -59,6 +59,8 @@ #ifndef ARANGODB_LOGGER_LOGGER_H #define ARANGODB_LOGGER_LOGGER_H 1 +#include "Basics/Common.h" +#include "Basics/CleanupFunctions.h" #include "Basics/Mutex.h" #include "Logger/LogLevel.h" #include "Logger/LogMacros.h"