diff --git a/lib/remote/configobjectslock.cpp b/lib/remote/configobjectslock.cpp index e529c832b..f2165f2ce 100644 --- a/lib/remote/configobjectslock.cpp +++ b/lib/remote/configobjectslock.cpp @@ -1,13 +1,16 @@ /* Icinga 2 | (c) 2022 Icinga GmbH | GPLv2+ */ -#ifndef _WIN32 - -#include "base/shared-memory.hpp" #include "remote/configobjectslock.hpp" + +#ifndef _WIN32 +#include "base/shared-memory.hpp" #include +#endif /* _WIN32 */ using namespace icinga; +#ifndef _WIN32 + // On *nix one process may write config objects while another is loading the config, so this uses IPC. static SharedMemory l_ConfigObjectsMutex; @@ -22,3 +25,37 @@ ConfigObjectsSharedLock::ConfigObjectsSharedLock(std::try_to_lock_t) } #endif /* _WIN32 */ + +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 index ee909815f..6b75139b6 100644 --- a/lib/remote/configobjectslock.hpp +++ b/lib/remote/configobjectslock.hpp @@ -2,7 +2,12 @@ #pragma once +#include "base/type.hpp" +#include "base/string.hpp" +#include +#include #include +#include #ifndef _WIN32 #include @@ -69,4 +74,29 @@ private: #endif /* _WIN32 */ + +/** + * 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; +}; + }