From e852dcacdd5775ed96245a89e675750e5baa811d Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Mon, 20 Aug 2018 14:29:22 +0300 Subject: [PATCH] MXS-2008 Provide single entrypoint for initializing maxbase Everything of maxbase can now be initialized by a call to maxbase_init(); (from a C-program) or maxbase::init(); from a C++-program and finalized with calls to either maxbase_finish() or maxbase::finish(). Creating an instance maxbase::MaxBase will take care of both operations. --- maxutils/maxbase/include/maxbase/log.h | 6 + maxutils/maxbase/include/maxbase/maxbase.h | 34 ++++ maxutils/maxbase/include/maxbase/maxbase.hh | 109 ++++++++++++ .../maxbase/include/maxbase/messagequeue.hh | 22 +-- maxutils/maxbase/include/maxbase/worker.hh | 21 +-- maxutils/maxbase/src/CMakeLists.txt | 1 + maxutils/maxbase/src/log.cc | 5 + maxutils/maxbase/src/maxbase.cc | 155 ++++++++++++++++++ maxutils/maxbase/src/test/test_worker.cc | 7 +- 9 files changed, 324 insertions(+), 36 deletions(-) create mode 100644 maxutils/maxbase/include/maxbase/maxbase.h create mode 100644 maxutils/maxbase/include/maxbase/maxbase.hh create mode 100644 maxutils/maxbase/src/maxbase.cc diff --git a/maxutils/maxbase/include/maxbase/log.h b/maxutils/maxbase/include/maxbase/log.h index 9e5a80067..ee0524650 100644 --- a/maxutils/maxbase/include/maxbase/log.h +++ b/maxutils/maxbase/include/maxbase/log.h @@ -115,6 +115,12 @@ bool mxb_log_init(const char* ident, */ void mxb_log_finish(void); +/** + * @brief Has the log been initialized. + * + * @return True if the log has been initialized, false otherwise. + */ +bool mxb_log_inited(); /** * Rotate the log * diff --git a/maxutils/maxbase/include/maxbase/maxbase.h b/maxutils/maxbase/include/maxbase/maxbase.h new file mode 100644 index 000000000..3247c7563 --- /dev/null +++ b/maxutils/maxbase/include/maxbase/maxbase.h @@ -0,0 +1,34 @@ +#pragma once +/* + * Copyright (c) 2016 MariaDB Corporation Ab + * + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file and at www.mariadb.com/bsl11. + * + * Change Date: 2022-01-01 + * + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2 or later of the General + * Public License. + */ + +#include + +/** + * @brief Initializes the maxbase library + * + * Initializes the maxbase library, except for the log that must + * be initialized separately, before or after this function is + * called. + * + * @return True, if maxbase could be initialized, false otherwise. + */ +bool maxbase_init(); + +/** + * @brief Finalizes the maxbase library + * + * This function should be called before program exit, if @c maxbase_init() + * returned true. + */ +void maxbase_finish(); diff --git a/maxutils/maxbase/include/maxbase/maxbase.hh b/maxutils/maxbase/include/maxbase/maxbase.hh new file mode 100644 index 000000000..b866f3915 --- /dev/null +++ b/maxutils/maxbase/include/maxbase/maxbase.hh @@ -0,0 +1,109 @@ +#pragma once +/* + * Copyright (c) 2016 MariaDB Corporation Ab + * + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file and at www.mariadb.com/bsl11. + * + * Change Date: 2022-01-01 + * + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2 or later of the General + * Public License. + */ + +#include +#include +#include +#include + +namespace maxbase +{ + +/** + * @brief Initializes the maxbase library + * + * This function should be called before any other functionality of + * maxbase is used. A notable exception is the maxbase log that can + * be initialized and used independently. + * + * Note that if an instance of @c MaxBase is created, it will call + * both @init and @finish. + * + * @return True, if maxbase could be initialized, false otherwise. + */ +bool init(); + +/** + * @brief Finalizes the maxbase library + * + * This function should be called before program exit, if @c init() + * returned true. + */ +void finish(); + + +/** + * @class MaxBase + * + * A simple utility RAII class where the constructor initializes maxbase + * (and optionally the log) and the destructor finalizes it. + */ +class MaxBase +{ + MaxBase(const MaxBase&) = delete; + MaxBase& operator=(const MaxBase&) = delete; + +public: + /** + * @brief Initializes MaxBase but not the MaxBase log. + */ + MaxBase() + : m_log_inited(false) + { + if (!maxbase_init()) + { + throw std::runtime_error("Initialization of maxbase failed."); + } + } + + /** + * @brief Initializes MaxBase and the MaxBase log. + * + * @see mxb_log_init + * + * @throws std::runtime_error if the initialization failed. + */ + MaxBase(const char* zIdent, + const char* zLogdir, + const char* zFilename, + mxb_log_target_t target, + mxb_log_context_provider_t context_provider); + + /** + * @brief Initializes MaxBase and the MaxBase log. + * + * @see mxb_log_init + * + * @throws std::runtime_error if the initialization failed. + */ + MaxBase(mxb_log_target_t target) + : MaxBase(nullptr, ".", nullptr, target, nullptr) + { + } + + ~MaxBase() + { + if (m_log_inited) + { + mxb_log_finish(); + } + + maxbase::finish(); + } + +private: + bool m_log_inited; +}; + +} diff --git a/maxutils/maxbase/include/maxbase/messagequeue.hh b/maxutils/maxbase/include/maxbase/messagequeue.hh index cfe569ac3..f34ba4096 100644 --- a/maxutils/maxbase/include/maxbase/messagequeue.hh +++ b/maxutils/maxbase/include/maxbase/messagequeue.hh @@ -18,6 +18,7 @@ namespace maxbase { +class MaxBase; class MessageQueue; class Worker; @@ -116,21 +117,6 @@ public: typedef MessageQueueHandler Handler; typedef MessageQueueMessage Message; - /** - * Initializes the message queue mechanism. To be called once at - * process startup. - * - * @return True if the initialization succeeded, false otherwise. - */ - static bool init(); - - - /** - * Finalizes the message queue mechanism. To be called once at - * process shutdown, if the initialization succeeded. - */ - static void finish(); - /** * Creates a @c MessageQueue with the provided handler. * @@ -190,6 +176,12 @@ public: */ Worker* remove_from_worker(); +public: + // TODO: Make private once all callers have been modified. + friend class MaxBase; + static bool init(); + static void finish(); + private: MessageQueue(Handler* pHandler, int read_fd, int write_fd); diff --git a/maxutils/maxbase/include/maxbase/worker.hh b/maxutils/maxbase/include/maxbase/worker.hh index 5f55097d6..3981fab22 100644 --- a/maxutils/maxbase/include/maxbase/worker.hh +++ b/maxutils/maxbase/include/maxbase/worker.hh @@ -559,22 +559,6 @@ public: }; }; - /** - * Initialize the worker mechanism. - * - * To be called once at process startup. - * - * @return True if the initialization succeeded, false otherwise. - */ - static bool init(); - - /** - * Finalize the worker mechanism. - * - * To be called once at process shutdown. - */ - static void finish(); - enum { MAX_EVENTS = 1000 @@ -990,6 +974,11 @@ protected: */ static void resolve_poll_error(int fd, int err, int op); +public: + // TODO: Make private once all callers have beed modified. + static bool init(); + static void finish(); + private: class DelayedCall; friend class DelayedCall; diff --git a/maxutils/maxbase/src/CMakeLists.txt b/maxutils/maxbase/src/CMakeLists.txt index 8705721be..527352bea 100644 --- a/maxutils/maxbase/src/CMakeLists.txt +++ b/maxutils/maxbase/src/CMakeLists.txt @@ -3,6 +3,7 @@ add_library(maxbase STATIC eventcount.cc log.cc logger.cc + maxbase.cc messagequeue.cc semaphore.cc stopwatch.cc diff --git a/maxutils/maxbase/src/log.cc b/maxutils/maxbase/src/log.cc index fd8fe240f..2473440d3 100644 --- a/maxutils/maxbase/src/log.cc +++ b/maxutils/maxbase/src/log.cc @@ -500,6 +500,11 @@ void mxb_log_finish(void) this_unit.context_provider = nullptr; } +bool mxb_log_inited() +{ + return this_unit.sLogger && this_unit.sMessage_registry; +} + void mxb_log_set_augmentation(int bits) { this_unit.augmentation = bits & MXB_LOG_AUGMENTATION_MASK; diff --git a/maxutils/maxbase/src/maxbase.cc b/maxutils/maxbase/src/maxbase.cc new file mode 100644 index 000000000..966876915 --- /dev/null +++ b/maxutils/maxbase/src/maxbase.cc @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2016 MariaDB Corporation Ab + * + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file and at www.mariadb.com/bsl11. + * + * Change Date: 2022-01-01 + * + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2 or later of the General + * Public License. + */ + +#include +#include +#include +#include + +namespace +{ + +using namespace maxbase; + +typedef bool (*init_function_t)(); +typedef void (*finish_function_t)(); + +#define MAXBASE_COMPONENT(X) { &X::init, &X::finish } + +struct maxbase_component_t +{ + init_function_t init; + finish_function_t finish; +}; + +const maxbase_component_t maxbase_components[] = +{ + MAXBASE_COMPONENT(MessageQueue), + MAXBASE_COMPONENT(Worker), +}; + +const int N_COMPONENTS = sizeof(maxbase_components)/sizeof(maxbase_components[0]); + +} + +namespace maxbase +{ + +MaxBase::MaxBase(const char* zIdent, + const char* zLogdir, + const char* zFilename, + mxb_log_target_t target, + mxb_log_context_provider_t context_provider) + : m_log_inited(false) +{ + const char* zMessage = nullptr; + + if (maxbase::init()) + { + m_log_inited = mxb_log_init(zIdent, zLogdir, zFilename, target, context_provider); + + if (!m_log_inited) + { + zMessage = + "The initialization of the MaxScale base library succeeded, but the " + "initialization of the MaxScale log failed."; + } + } + else + { + zMessage = "The initialization of the MaxScale base library failed."; + } + + if (zMessage) + { + throw std::runtime_error(zMessage); + } +} + +bool init() +{ + bool rv = false; + bool log_exists = mxb_log_inited(); + bool log_inited_locally = false; + + if (!log_exists) + { + // We temporarily initialize a log logging to stdout, so that it is possible + // to log in the initialization functions. This should always succeed. + log_inited_locally = mxb_log_init(MXB_LOG_TARGET_STDOUT); + + if (log_inited_locally) + { + log_exists = true; + } + else + { + // Out of luck, just write to stderr. + fprintf(stderr, "MaxScale: Fatal error, could not initialize a temporary log.\n"); + } + } + + if (log_exists) + { + int i; + for (i = 0; i < N_COMPONENTS; ++i) + { + if (!maxbase_components[i].init()) + { + break; + } + } + + if (i == N_COMPONENTS) + { + rv = true; + } + else if (i != 0) + { + // We need to finalize in reverse order the components that + // successfully were initialized. + for (int j = i - 1; j >= 0; --j) + { + maxbase_components[j].finish(); + } + } + } + + if (log_inited_locally) + { + // Finalize the temporary log. + mxb_log_finish(); + } + + return rv; +} + +void finish() +{ + for (int i = N_COMPONENTS - 1; i >= 0; --i) + { + maxbase_components[i].finish(); + } +} + +} + +bool maxbase_init() +{ + return maxbase::init(); +} + +void maxbase_finish() +{ + return maxbase::finish(); +} diff --git a/maxutils/maxbase/src/test/test_worker.cc b/maxutils/maxbase/src/test/test_worker.cc index 878866865..a238597bd 100644 --- a/maxutils/maxbase/src/test/test_worker.cc +++ b/maxutils/maxbase/src/test/test_worker.cc @@ -13,7 +13,7 @@ #include #include -#include +#include #include using namespace maxbase; @@ -123,10 +123,7 @@ int run() int main() { - mxb::Log log(MXB_LOG_TARGET_STDOUT); - - maxbase::MessageQueue::init(); - maxbase::Worker::init(); + mxb::MaxBase mxb(MXB_LOG_TARGET_STDOUT); return run(); }