From e3a7ee079a0a65e824e9752a20b35bb9f6be9d95 Mon Sep 17 00:00:00 2001 From: Yonas Habteab Date: Fri, 8 Mar 2024 09:58:32 +0100 Subject: [PATCH] Introduce RAII style `ObjectNameLock` class --- lib/remote/CMakeLists.txt | 1 + lib/remote/configobjectslock.cpp | 39 ++++++++++++++++++++++++++++++++ lib/remote/configobjectslock.hpp | 39 ++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 lib/remote/configobjectslock.cpp create mode 100644 lib/remote/configobjectslock.hpp diff --git a/lib/remote/CMakeLists.txt b/lib/remote/CMakeLists.txt index 2c5a0326a..740b112b4 100644 --- a/lib/remote/CMakeLists.txt +++ b/lib/remote/CMakeLists.txt @@ -14,6 +14,7 @@ set(remote_SOURCES apilistener-authority.cpp apiuser.cpp apiuser.hpp apiuser-ti.hpp configfileshandler.cpp configfileshandler.hpp + configobjectslock.cpp configobjectslock.hpp configobjectutility.cpp configobjectutility.hpp configpackageshandler.cpp configpackageshandler.hpp configpackageutility.cpp configpackageutility.hpp diff --git a/lib/remote/configobjectslock.cpp b/lib/remote/configobjectslock.cpp new file mode 100644 index 000000000..ba59a0db3 --- /dev/null +++ b/lib/remote/configobjectslock.cpp @@ -0,0 +1,39 @@ +/* Icinga 2 | (c) 2022 Icinga GmbH | GPLv2+ */ + +#include "remote/configobjectslock.hpp" + +using namespace icinga; + +std::mutex ObjectNameLock::m_Mutex; +std::condition_variable ObjectNameLock::m_CV; +std::map> ObjectNameLock::m_LockedObjectNames; + +/** + * Locks the specified object name of the given type and unlocks it upon destruction of the instance of this class. + * + * If it is already locked, the call blocks until the lock is released. + * + * @param Type::Ptr ptype The type of the object you want to lock + * @param String objName The object name you want to lock + */ +ObjectNameLock::ObjectNameLock(const Type::Ptr& ptype, const String& objName): m_ObjectName{objName}, m_Type{ptype} +{ + std::unique_lock lock(m_Mutex); + m_CV.wait(lock, [this]{ + auto& locked = m_LockedObjectNames[m_Type.get()]; + return locked.find(m_ObjectName) == locked.end(); + }); + + // Add the object name to the locked list to block all other threads that try + // to process a message affecting the same object. + m_LockedObjectNames[ptype.get()].emplace(objName); +} + +ObjectNameLock::~ObjectNameLock() +{ + { + std::unique_lock lock(m_Mutex); + m_LockedObjectNames[m_Type.get()].erase(m_ObjectName); + } + m_CV.notify_all(); +} diff --git a/lib/remote/configobjectslock.hpp b/lib/remote/configobjectslock.hpp new file mode 100644 index 000000000..5add769d2 --- /dev/null +++ b/lib/remote/configobjectslock.hpp @@ -0,0 +1,39 @@ +/* Icinga 2 | (c) 2023 Icinga GmbH | GPLv2+ */ + +#pragma once + +#include "base/type.hpp" +#include "base/string.hpp" +#include +#include +#include +#include + +namespace icinga +{ + +/** + * Allows you to easily lock/unlock a specific object of a given type by its name. + * + * That way, locking an object "this" of type Host does not affect an object "this" of + * type "Service" nor an object "other" of type "Host". + * + * @ingroup remote + */ +class ObjectNameLock +{ +public: + ObjectNameLock(const Type::Ptr& ptype, const String& objName); + + ~ObjectNameLock(); + +private: + String m_ObjectName; + Type::Ptr m_Type; + + static std::mutex m_Mutex; + static std::condition_variable m_CV; + static std::map> m_LockedObjectNames; +}; + +}