Skip to content

Commit 215057f

Browse files
committed
Rewrite Checkable::GetAllChildrenInternal() method
The previous wasn't per-se wrong, but it was way too inefficient. With this commit each and every Checkable is going to be visited only once, and we won't traverse the same Checkable's children multiple times somewhere in the dependency chain.
1 parent 31c1591 commit 215057f

File tree

2 files changed

+10
-18
lines changed

2 files changed

+10
-18
lines changed

lib/icinga/checkable-dependency.cpp

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
using namespace icinga;
88

99
/**
10-
* The maximum number of dependency recursion levels allowed.
10+
* The maximum number of allowed dependency recursion levels.
1111
*
1212
* This is a subjective limit how deep the dependency tree should be allowed to go, as anything beyond this level
1313
* is just madness and will likely result in a stack overflow or other undefined behavior.
@@ -315,7 +315,7 @@ size_t Checkable::GetAllChildrenCount() const
315315

316316
std::set<Checkable::Ptr> Checkable::GetAllChildren() const
317317
{
318-
std::set<Checkable::Ptr> children = GetChildren();
318+
std::set<Checkable::Ptr> children;
319319

320320
GetAllChildrenInternal(children, 0);
321321

@@ -328,31 +328,23 @@ std::set<Checkable::Ptr> Checkable::GetAllChildren() const
328328
* Note, this function performs a recursive call chain traversing all the children of the current Checkable
329329
* up to a certain limit (256). When that limit is reached, it will log a warning message and abort the operation.
330330
*
331-
* @param children - The set of children to be filled with all the children of the current Checkable.
331+
* @param seenChildren - A container to store all the traversed children into.
332332
* @param level - The current level of recursion.
333333
*/
334-
void Checkable::GetAllChildrenInternal(std::set<Checkable::Ptr>& children, int level) const
334+
void Checkable::GetAllChildrenInternal(std::set<Checkable::Ptr>& seenChildren, int level) const
335335
{
336336
if (level > l_MaxDependencyRecursionLevel) {
337337
Log(LogWarning, "Checkable")
338338
<< "Too many nested dependencies (>" << l_MaxDependencyRecursionLevel << ") for checkable '" << GetName() << "': aborting traversal.";
339-
return ;
339+
return;
340340
}
341341

342-
std::set<Checkable::Ptr> localChildren;
343-
344-
for (const Checkable::Ptr& checkable : children) {
345-
if (auto cChildren(checkable->GetChildren()); !cChildren.empty()) {
346-
GetAllChildrenInternal(cChildren, level + 1);
347-
localChildren.insert(cChildren.begin(), cChildren.end());
348-
}
349-
350-
if (level != 0) { // Recursion level 0 is the initiator, so checkable is already in the set.
351-
localChildren.insert(checkable);
342+
for (const Checkable::Ptr& checkable : GetChildren()) {
343+
if (seenChildren.find(checkable) == seenChildren.end()) {
344+
seenChildren.emplace(checkable);
345+
checkable->GetAllChildrenInternal(seenChildren, level + 1);
352346
}
353347
}
354-
355-
children.insert(localChildren.begin(), localChildren.end());
356348
}
357349

358350
/**

lib/icinga/checkable.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ class Checkable : public ObjectImpl<Checkable>
264264
std::unordered_set<intrusive_ptr<DependencyGroup>, HashDependencyGroup, EqualDependencyGroups> m_DependencyGroups;
265265
std::set<intrusive_ptr<Dependency> > m_ReverseDependencies;
266266

267-
void GetAllChildrenInternal(std::set<Checkable::Ptr>& children, int level = 0) const;
267+
void GetAllChildrenInternal(std::set<Checkable::Ptr>& seenChildren, int level = 0) const;
268268

269269
/* Flapping */
270270
static const std::map<String, int> m_FlappingStateFilterMap;

0 commit comments

Comments
 (0)