Skip to content

Commit e083b31

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 223bd04 commit e083b31

File tree

2 files changed

+8
-16
lines changed

2 files changed

+8
-16
lines changed

lib/icinga/checkable-dependency.cpp

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ size_t Checkable::GetAllChildrenCount() const
314314

315315
std::set<Checkable::Ptr> Checkable::GetAllChildren() const
316316
{
317-
std::set<Checkable::Ptr> children = GetChildren();
317+
std::set<Checkable::Ptr> children;
318318

319319
GetAllChildrenInternal(children, 0);
320320

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

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

357349
/**

lib/icinga/checkable.hpp

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

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

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

0 commit comments

Comments
 (0)