diff --git a/lib/icingadb/icingadb-objects.cpp b/lib/icingadb/icingadb-objects.cpp index 04043db53..bd8e74322 100644 --- a/lib/icingadb/icingadb-objects.cpp +++ b/lib/icingadb/icingadb-objects.cpp @@ -1357,8 +1357,10 @@ void IcingaDB::UpdateState(const Checkable::Ptr& checkable, StateUpdate mode) * * @param checkable The Checkable you want to send the dependencies state update for * @param onlyDependencyGroup If set, send state updates only for this dependency group and its dependencies. + * @param seenGroups A container to track already processed DependencyGroups to avoid duplicate state updates. */ -void IcingaDB::UpdateDependenciesState(const Checkable::Ptr& checkable, const DependencyGroup::Ptr& onlyDependencyGroup) const +void IcingaDB::UpdateDependenciesState(const Checkable::Ptr& checkable, const DependencyGroup::Ptr& onlyDependencyGroup, + std::set* seenGroups) const { if (!m_Rcon || !m_Rcon->IsConnected()) { return; @@ -1396,6 +1398,18 @@ void IcingaDB::UpdateDependenciesState(const Checkable::Ptr& checkable, const De continue; } + if (seenGroups && !seenGroups->insert(dependencyGroup.get()).second) { + // Usually, if the seenGroups set is provided, IcingaDB is triggering a runtime state update for ALL + // children of a given initiator Checkable (parent). In such cases, we may end up with lots of useless + // state updates as all the children of a non-redundant group a) share the same entry in the database b) + // it doesn't matter which child triggers the state update first all the subsequent updates are just useless. + // + // Likewise, for redundancy groups, all children of a redundancy group share the same set of parents + // and thus the resulting state information would be the same from each child Checkable perspective. + // So, serializing the redundancy group state information only once is sufficient. + continue; + } + auto dependencies(dependencyGroup->GetDependenciesForChild(checkable.get())); std::sort(dependencies.begin(), dependencies.end(), [](const Dependency::Ptr& lhs, const Dependency::Ptr& rhs) { return lhs->GetParent() < rhs->GetParent(); @@ -3096,9 +3110,10 @@ void IcingaDB::StateChangeHandler(const ConfigObject::Ptr& object, const CheckRe void IcingaDB::ReachabilityChangeHandler(const std::set& children) { for (const IcingaDB::Ptr& rw : ConfigType::GetObjectsByType()) { + std::set seenGroups; for (auto& checkable : children) { rw->UpdateState(checkable, StateUpdate::Full); - rw->UpdateDependenciesState(checkable); + rw->UpdateDependenciesState(checkable, nullptr, &seenGroups); } } } diff --git a/lib/icingadb/icingadb.hpp b/lib/icingadb/icingadb.hpp index 39a899efc..af58a977d 100644 --- a/lib/icingadb/icingadb.hpp +++ b/lib/icingadb/icingadb.hpp @@ -114,7 +114,8 @@ private: std::vector* runtimeUpdates, const DependencyGroup::Ptr& onlyDependencyGroup = nullptr); void InsertObjectDependencies(const ConfigObject::Ptr& object, const String typeName, std::map>& hMSets, std::vector& runtimeUpdates, bool runtimeUpdate); - void UpdateDependenciesState(const Checkable::Ptr& checkable, const DependencyGroup::Ptr& onlyDependencyGroup = nullptr) const; + void UpdateDependenciesState(const Checkable::Ptr& checkable, const DependencyGroup::Ptr& onlyDependencyGroup = nullptr, + std::set* seenGroups = nullptr) const; void UpdateState(const Checkable::Ptr& checkable, StateUpdate mode); void SendConfigUpdate(const ConfigObject::Ptr& object, bool runtimeUpdate); void CreateConfigUpdate(const ConfigObject::Ptr& object, const String type, std::map>& hMSets,