Checkable: Emit boost signals when changing dependency groups at runtime

This commit is contained in:
Yonas Habteab 2025-02-07 16:51:00 +01:00
parent b462028b4f
commit 806fff950c
5 changed files with 52 additions and 22 deletions

View File

@ -75,7 +75,7 @@ static std::variant<Checkable*, String> GetDependencyGroupKey(const Dependency::
*/
void Checkable::AddDependency(const Dependency::Ptr& dependency)
{
std::lock_guard lock(m_DependencyMutex);
std::unique_lock lock(m_DependencyMutex);
auto dependencyGroupKey(GetDependencyGroupKey(dependency));
if (!m_DependencyGroupsPushedToRegistry) {
@ -88,27 +88,38 @@ void Checkable::AddDependency(const Dependency::Ptr& dependency)
}
std::set<Dependency::Ptr> dependencies;
bool removeGroup(false);
DependencyGroup::Ptr existingGroup;
if (auto it(m_DependencyGroups.find(dependencyGroupKey)); it != m_DependencyGroups.end()) {
dependencies = DependencyGroup::Unregister(it->second, this);
existingGroup = it->second;
std::tie(dependencies, removeGroup) = DependencyGroup::Unregister(existingGroup, this);
m_DependencyGroups.erase(it);
}
dependencies.emplace(dependency);
m_DependencyGroups.emplace(
dependencyGroupKey,
DependencyGroup::Register(new DependencyGroup(dependency->GetRedundancyGroup(), dependencies))
);
auto dependencyGroup(DependencyGroup::Register(new DependencyGroup(dependency->GetRedundancyGroup(), dependencies)));
m_DependencyGroups.emplace(dependencyGroupKey, dependencyGroup);
lock.unlock();
if (existingGroup) {
dependencies.erase(dependency);
DependencyGroup::OnChildRemoved(existingGroup, {dependencies.begin(), dependencies.end()}, removeGroup);
}
DependencyGroup::OnChildRegistered(this, dependencyGroup);
}
/**
* Remove the provided dependency from the current Checkable list of dependencies.
*
* @param dependency The dependency to remove.
* @param runtimeRemoved Whether the given dependency object is being removed at runtime.
*/
void Checkable::RemoveDependency(const Dependency::Ptr& dependency)
void Checkable::RemoveDependency(const Dependency::Ptr& dependency, bool runtimeRemoved)
{
std::lock_guard lock(m_DependencyMutex);
std::unique_lock lock(m_DependencyMutex);
auto dependencyGroupKey(GetDependencyGroupKey(dependency));
auto it = m_DependencyGroups.find(dependencyGroupKey);
@ -116,15 +127,27 @@ void Checkable::RemoveDependency(const Dependency::Ptr& dependency)
return;
}
std::set<Dependency::Ptr> dependencies(DependencyGroup::Unregister(it->second, this));
DependencyGroup::Ptr existingGroup(it->second);
auto [dependencies, removeGroup] = DependencyGroup::Unregister(existingGroup, this);
m_DependencyGroups.erase(it);
dependencies.erase(dependency);
DependencyGroup::Ptr newDependencyGroup;
if (!dependencies.empty()) {
m_DependencyGroups.emplace(
dependencyGroupKey,
DependencyGroup::Register(new DependencyGroup(dependency->GetRedundancyGroup(), dependencies))
);
newDependencyGroup = DependencyGroup::Register(new DependencyGroup(dependency->GetRedundancyGroup(), dependencies));
m_DependencyGroups.emplace(dependencyGroupKey, newDependencyGroup);
}
lock.unlock();
if (runtimeRemoved) {
dependencies.emplace(dependency);
DependencyGroup::OnChildRemoved(existingGroup, {dependencies.begin(), dependencies.end()}, removeGroup);
if (newDependencyGroup) {
DependencyGroup::OnChildRegistered(this, newDependencyGroup);
}
}
}

View File

@ -189,7 +189,7 @@ public:
void PushDependencyGroupsToRegistry();
std::vector<intrusive_ptr<DependencyGroup>> GetDependencyGroups() const;
void AddDependency(const intrusive_ptr<Dependency>& dependency);
void RemoveDependency(const intrusive_ptr<Dependency>& dependency);
void RemoveDependency(const intrusive_ptr<Dependency>& dependency, bool runtimeRemoved = false);
std::vector<intrusive_ptr<Dependency> > GetDependencies() const;
bool HasAnyDependencies() const;

View File

@ -5,6 +5,9 @@
using namespace icinga;
boost::signals2::signal<void(const Checkable::Ptr&, const DependencyGroup::Ptr&)> DependencyGroup::OnChildRegistered;
boost::signals2::signal<void(const DependencyGroup::Ptr&, const std::vector<Dependency::Ptr>&, bool)> DependencyGroup::OnChildRemoved;
std::mutex DependencyGroup::m_RegistryMutex;
DependencyGroup::RegistryType DependencyGroup::m_Registry;
@ -36,15 +39,15 @@ DependencyGroup::Ptr DependencyGroup::Register(const DependencyGroup::Ptr& depen
* @param dependencyGroup The dependency group to unregister the child Checkable from.
* @param child The child Checkable to detach from the dependency group.
*
* @return - Returns the dependency objects of the child Checkable that were member of the provided dependency group.
* @return - Returns the dependency objects of the child Checkable that were member of the provided dependency group
* and a boolean indicating whether the dependency group has been erased from the global registry.
*/
std::set<Dependency::Ptr> DependencyGroup::Unregister(const DependencyGroup::Ptr& dependencyGroup, const Checkable::Ptr& child)
std::pair<std::set<Dependency::Ptr>, bool> DependencyGroup::Unregister(const DependencyGroup::Ptr& dependencyGroup, const Checkable::Ptr& child)
{
std::lock_guard lock(m_RegistryMutex);
std::vector<Dependency::Ptr> dependencies;
if (auto it(m_Registry.find(dependencyGroup)); it != m_Registry.end()) {
const auto& existingGroup(*it);
dependencies = existingGroup->GetDependenciesForChild(child.get());
auto existingGroup(*it);
auto dependencies(existingGroup->GetDependenciesForChild(child.get()));
for (const auto& dependency : dependencies) {
existingGroup->RemoveDependency(dependency);
@ -53,8 +56,9 @@ std::set<Dependency::Ptr> DependencyGroup::Unregister(const DependencyGroup::Ptr
if (existingGroup->IsEmpty()) {
m_Registry.erase(it);
}
return {{dependencies.begin(), dependencies.end()}, existingGroup->IsEmpty()};
}
return {dependencies.begin(), dependencies.end()};
return {{}, false};
}
/**

View File

@ -259,7 +259,7 @@ void Dependency::Stop(bool runtimeRemoved)
{
ObjectImpl<Dependency>::Stop(runtimeRemoved);
GetChild()->RemoveDependency(this);
GetChild()->RemoveDependency(this, runtimeRemoved);
GetParent()->RemoveReverseDependency(this);
}

View File

@ -136,7 +136,7 @@ public:
DependencyGroup(String name, const std::set<Dependency::Ptr>& dependencies);
static DependencyGroup::Ptr Register(const DependencyGroup::Ptr& dependencyGroup);
static std::set<Dependency::Ptr> Unregister(const DependencyGroup::Ptr& dependencyGroup, const Checkable::Ptr& child);
static std::pair<std::set<Dependency::Ptr>, bool> Unregister(const DependencyGroup::Ptr& dependencyGroup, const Checkable::Ptr& child);
static size_t GetRegistrySize();
static CompositeKeyType MakeCompositeKeyFor(const Dependency::Ptr& dependency);
@ -171,6 +171,9 @@ public:
State GetState(DependencyType dt = DependencyState, int rstack = 0) const;
static boost::signals2::signal<void(const Checkable::Ptr&, const DependencyGroup::Ptr&)> OnChildRegistered;
static boost::signals2::signal<void(const DependencyGroup::Ptr&, const std::vector<Dependency::Ptr>&, bool)> OnChildRemoved;
private:
void CopyDependenciesTo(const DependencyGroup::Ptr& dest);