diff --git a/lib/base/registry.hpp b/lib/base/registry.hpp index 5a8ac26f754..e2ef6784fb5 100644 --- a/lib/base/registry.hpp +++ b/lib/base/registry.hpp @@ -4,9 +4,13 @@ #define REGISTRY_H #include "base/i2-base.hpp" +#include "base/atomic.hpp" +#include "base/exception.hpp" #include "base/string.hpp" -#include -#include +#include "base/singleton.hpp" +#include +#include +#include #include namespace icinga @@ -17,22 +21,31 @@ namespace icinga * * @ingroup base */ -template +template class Registry { public: - typedef std::map ItemMap; + typedef std::unordered_map ItemMap; + + static Registry* GetInstance() + { + return Singleton::GetInstance(); + } void Register(const String& name, const T& item) { - std::unique_lock lock(m_Mutex); + std::unique_lock lock (m_Mutex); + + if (m_Frozen) { + BOOST_THROW_EXCEPTION(std::logic_error("Registry is read-only and must not be modified.")); + } - RegisterInternal(name, item, lock); + m_Items[name] = item; } T GetItem(const String& name) const { - std::unique_lock lock(m_Mutex); + auto lock (ReadLockUnlessFrozen()); auto it = m_Items.find(name); @@ -44,33 +57,36 @@ class Registry ItemMap GetItems() const { - std::unique_lock lock(m_Mutex); + auto lock (ReadLockUnlessFrozen()); return m_Items; /* Makes a copy of the map. */ } - boost::signals2::signal OnRegistered; - boost::signals2::signal OnUnregistered; - -private: - mutable std::mutex m_Mutex; - typename Registry::ItemMap m_Items; - - void RegisterInternal(const String& name, const T& item, std::unique_lock& lock) + /** + * Freeze the registry, preventing further updates. + * + * This only prevents inserting, replacing or deleting values from the registry. + * This operation has no effect on objects referenced by the values, these remain mutable if they were before. + */ + void Freeze() { - bool old_item = false; - - if (m_Items.erase(name) > 0) - old_item = true; + std::unique_lock lock (m_Mutex); - m_Items[name] = item; + m_Frozen.store(true); + } - lock.unlock(); +private: + mutable std::shared_mutex m_Mutex; + Atomic m_Frozen {false}; + ItemMap m_Items; - if (old_item) - OnUnregistered(name); + std::shared_lock ReadLockUnlessFrozen() const + { + if (m_Frozen.load(std::memory_order_relaxed)) { + return {}; + } - OnRegistered(name, item); + return std::shared_lock(m_Mutex); } }; diff --git a/lib/db_ido/dbtype.cpp b/lib/db_ido/dbtype.cpp index c5476b179d0..8006171ceb2 100644 --- a/lib/db_ido/dbtype.cpp +++ b/lib/db_ido/dbtype.cpp @@ -133,8 +133,3 @@ std::set DbType::GetAllTypes() return result; } - -DbTypeRegistry *DbTypeRegistry::GetInstance() -{ - return Singleton::GetInstance(); -} diff --git a/lib/db_ido/dbtype.hpp b/lib/db_ido/dbtype.hpp index c8ebc450409..b210aabb3f8 100644 --- a/lib/db_ido/dbtype.hpp +++ b/lib/db_ido/dbtype.hpp @@ -6,7 +6,6 @@ #include "db_ido/i2-db_ido.hpp" #include "base/object.hpp" #include "base/registry.hpp" -#include "base/singleton.hpp" #include namespace icinga @@ -57,17 +56,6 @@ class DbType final : public Object ObjectMap m_Objects; }; -/** - * A registry for DbType objects. - * - * @ingroup ido - */ -class DbTypeRegistry : public Registry -{ -public: - static DbTypeRegistry *GetInstance(); -}; - /** * Factory function for DbObject-based classes. * diff --git a/lib/remote/apiaction.cpp b/lib/remote/apiaction.cpp index ccde28190b8..ae31581d55e 100644 --- a/lib/remote/apiaction.cpp +++ b/lib/remote/apiaction.cpp @@ -1,10 +1,13 @@ /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ #include "remote/apiaction.hpp" -#include "base/singleton.hpp" using namespace icinga; +INITIALIZE_ONCE_WITH_PRIORITY([]{ + ApiActionRegistry::GetInstance()->Freeze(); +}, InitializePriority::FreezeNamespaces); + ApiAction::ApiAction(std::vector types, Callback action) : m_Types(std::move(types)), m_Callback(std::move(action)) { } @@ -28,8 +31,3 @@ void ApiAction::Register(const String& name, const ApiAction::Ptr& action) { ApiActionRegistry::GetInstance()->Register(name, action); } - -ApiActionRegistry *ApiActionRegistry::GetInstance() -{ - return Singleton::GetInstance(); -} diff --git a/lib/remote/apiaction.hpp b/lib/remote/apiaction.hpp index 2bb98b1b6bb..8d803d04f07 100644 --- a/lib/remote/apiaction.hpp +++ b/lib/remote/apiaction.hpp @@ -45,11 +45,7 @@ class ApiAction final : public Object * * @ingroup remote */ -class ApiActionRegistry : public Registry -{ -public: - static ApiActionRegistry *GetInstance(); -}; +using ApiActionRegistry = Registry; #define REGISTER_APIACTION(name, types, callback) \ INITIALIZE_ONCE([]() { \ diff --git a/lib/remote/apifunction.cpp b/lib/remote/apifunction.cpp index f153dcb467a..563a5519fdf 100644 --- a/lib/remote/apifunction.cpp +++ b/lib/remote/apifunction.cpp @@ -1,10 +1,13 @@ /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ #include "remote/apifunction.hpp" -#include "base/singleton.hpp" using namespace icinga; +INITIALIZE_ONCE_WITH_PRIORITY([]{ + ApiFunctionRegistry::GetInstance()->Freeze(); +}, InitializePriority::FreezeNamespaces); + ApiFunction::ApiFunction(const char* name, Callback function) : m_Name(name), m_Callback(std::move(function)) { } @@ -23,8 +26,3 @@ void ApiFunction::Register(const String& name, const ApiFunction::Ptr& function) { ApiFunctionRegistry::GetInstance()->Register(name, function); } - -ApiFunctionRegistry *ApiFunctionRegistry::GetInstance() -{ - return Singleton::GetInstance(); -} diff --git a/lib/remote/apifunction.hpp b/lib/remote/apifunction.hpp index ea8b7cf1e46..2b0f3ed00fc 100644 --- a/lib/remote/apifunction.hpp +++ b/lib/remote/apifunction.hpp @@ -47,11 +47,7 @@ class ApiFunction final : public Object * * @ingroup base */ -class ApiFunctionRegistry : public Registry -{ -public: - static ApiFunctionRegistry *GetInstance(); -}; +using ApiFunctionRegistry = Registry; #define REGISTER_APIFUNCTION(name, ns, callback) \ INITIALIZE_ONCE([]() { \ diff --git a/lib/remote/eventqueue.cpp b/lib/remote/eventqueue.cpp index 819f95a6ae6..fa7ab0c160a 100644 --- a/lib/remote/eventqueue.cpp +++ b/lib/remote/eventqueue.cpp @@ -4,7 +4,6 @@ #include "remote/eventqueue.hpp" #include "remote/filterutility.hpp" #include "base/io-engine.hpp" -#include "base/singleton.hpp" #include "base/logger.hpp" #include "base/utility.hpp" #include @@ -125,11 +124,6 @@ void EventQueue::Register(const String& name, const EventQueue::Ptr& function) EventQueueRegistry::GetInstance()->Register(name, function); } -EventQueueRegistry *EventQueueRegistry::GetInstance() -{ - return Singleton::GetInstance(); -} - std::mutex EventsInbox::m_FiltersMutex; std::map EventsInbox::m_Filters ({{"", EventsInbox::Filter{1, Expression::Ptr()}}}); diff --git a/lib/remote/eventqueue.hpp b/lib/remote/eventqueue.hpp index 833714f9d09..7b8b7e94147 100644 --- a/lib/remote/eventqueue.hpp +++ b/lib/remote/eventqueue.hpp @@ -59,11 +59,7 @@ class EventQueue final : public Object * * @ingroup base */ -class EventQueueRegistry : public Registry -{ -public: - static EventQueueRegistry *GetInstance(); -}; +using EventQueueRegistry = Registry; enum class EventType : uint_fast8_t {