Skip to content

Commit 63e9ef5

Browse files
committed
Prevent worst-case exponential complexity in dependency evaluation
So far, calling Checkable::IsReachable() traversed all possible paths to it's parents. In case a parent is reachable via multiple paths, all it's parents were evaluated multiple times, result in a worst-case exponential complexity. With this commit, the implementation keeps track of which checkables were already visited and uses the already-computed reachability instead of repeating the computation, ensuring a worst-case linear runtime within the graph size.
1 parent 43f1e6f commit 63e9ef5

File tree

2 files changed

+12
-0
lines changed

2 files changed

+12
-0
lines changed

lib/icinga/dependency-state.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ DependencyStateChecker::DependencyStateChecker(DependencyType dt)
2525
*/
2626
bool DependencyStateChecker::IsReachable(Checkable::ConstPtr checkable, int rstack)
2727
{
28+
// If the reachability of this checkable was already computed, return it directly. Otherwise, already create a
29+
// temporary map entry that says that this checkable is unreachable so that the different cases returning false
30+
// don't have to deal with updating the cache, but only the final return true does. Cyclic dependencies are invalid,
31+
// hence recursive calls won't access the potentially not yet correct cached value.
32+
if (auto [it, inserted] = m_Cache.insert({checkable, false}); !inserted) {
33+
return it->second;
34+
}
35+
2836
if (rstack > Dependency::MaxDependencyRecursionLevel) {
2937
Log(LogWarning, "Checkable")
3038
<< "Too many nested dependencies (>" << Dependency::MaxDependencyRecursionLevel << ") for checkable '"
@@ -53,6 +61,9 @@ bool DependencyStateChecker::IsReachable(Checkable::ConstPtr checkable, int rsta
5361
}
5462
}
5563

64+
// Note: This must do the map lookup again. The iterator from above must not be used as a m_Cache.insert() inside a
65+
// recursive may have invalidated it.
66+
m_Cache[checkable] = true;
5667
return true;
5768
}
5869

lib/icinga/dependency.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ class DependencyStateChecker
250250

251251
private:
252252
DependencyType m_DependencyType;
253+
std::unordered_map<Checkable::ConstPtr, bool> m_Cache;
253254
};
254255

255256
}

0 commit comments

Comments
 (0)