mirror of
https://github.com/Icinga/icinga2.git
synced 2025-09-25 02:37:44 +02:00
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.
This commit is contained in:
parent
43f1e6f3a1
commit
63e9ef58ba
@ -25,6 +25,14 @@ DependencyStateChecker::DependencyStateChecker(DependencyType dt)
|
||||
*/
|
||||
bool DependencyStateChecker::IsReachable(Checkable::ConstPtr checkable, int rstack)
|
||||
{
|
||||
// If the reachability of this checkable was already computed, return it directly. Otherwise, already create a
|
||||
// temporary map entry that says that this checkable is unreachable so that the different cases returning false
|
||||
// don't have to deal with updating the cache, but only the final return true does. Cyclic dependencies are invalid,
|
||||
// hence recursive calls won't access the potentially not yet correct cached value.
|
||||
if (auto [it, inserted] = m_Cache.insert({checkable, false}); !inserted) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
if (rstack > Dependency::MaxDependencyRecursionLevel) {
|
||||
Log(LogWarning, "Checkable")
|
||||
<< "Too many nested dependencies (>" << Dependency::MaxDependencyRecursionLevel << ") for checkable '"
|
||||
@ -53,6 +61,9 @@ bool DependencyStateChecker::IsReachable(Checkable::ConstPtr checkable, int rsta
|
||||
}
|
||||
}
|
||||
|
||||
// Note: This must do the map lookup again. The iterator from above must not be used as a m_Cache.insert() inside a
|
||||
// recursive may have invalidated it.
|
||||
m_Cache[checkable] = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -250,6 +250,7 @@ public:
|
||||
|
||||
private:
|
||||
DependencyType m_DependencyType;
|
||||
std::unordered_map<Checkable::ConstPtr, bool> m_Cache;
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user