java-topology/defects/prometheus/patch/prometheus-0001-dependency-map-dependencies-slice-scan.patch

75 lines
2.7 KiB
Diff
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# UNDF: UNDF-2026-000000225
--- a/rules/group.go
+++ b/rules/group.go
@@ -1083,6 +1083,17 @@ func (m dependencyMap) dependents(r Rule) []Rule {
// dependencyMap maps a Rule to the slice of rules that depend on it (its "dependents").
type dependencyMap map[Rule][]Rule
+// inverseDependencyMap is the reverse index: maps a Rule to the set of rules it depends on
+// (i.e. its "dependencies"). Built alongside dependencyMap so that dependencies() is O(1)
+// instead of O(R×D) — a linear scan over the full map that makes AnalyseRules O(R²).
+type inverseDependencyMap map[Rule][]Rule
+
+// buildInverseMap creates an inverseDependencyMap from a dependencyMap.
+// Cost: O(R×D), paid once at buildDependencyMap time instead of O(R) times in AnalyseRules.
+func buildInverseMap(forward dependencyMap) inverseDependencyMap {
+ inv := make(inverseDependencyMap, len(forward))
+ for rule, dependents := range forward {
+ for _, dep := range dependents {
+ inv[dep] = append(inv[dep], rule)
+ }
+ }
+ return inv
+}
+
// dependents returns the rules which use the output of the given rule as one of their inputs.
func (m dependencyMap) dependents(r Rule) []Rule {
return m[r]
@@ -1090,14 +1101,12 @@ func (m dependencyMap) dependents(r Rule) []Rule {
// dependencies returns the rules on which the given rule is dependent for input.
-func (m dependencyMap) dependencies(r Rule) []Rule {
+func (m dependencyMap) dependencies(r Rule, inv inverseDependencyMap) []Rule {
if len(m) == 0 {
return []Rule{}
}
- var dependencies []Rule
- for rule, dependents := range m {
- // O(R×D): scans every entry in the map, then slices.Contains on dependents.
- if slices.Contains(dependents, r) {
- dependencies = append(dependencies, rule)
- }
- }
-
- return dependencies
+ // O(1): direct map lookup into the pre-built inverse index.
+ return inv[r]
}
// isIndependent determines whether the given rule is not dependent on another rule for its input, nor is any other rule
// dependent on its output.
-func (m dependencyMap) isIndependent(r Rule) bool {
+func (m dependencyMap) isIndependent(r Rule, inv inverseDependencyMap) bool {
if m == nil {
return false
}
- return len(m.dependents(r)) == 0 && len(m.dependencies(r)) == 0
+ return len(m.dependents(r)) == 0 && len(m.dependencies(r, inv)) == 0
}
--- a/rules/manager.go
+++ b/rules/manager.go
@@ -505,8 +505,11 @@ func (ruleDependencyController) AnalyseRules(rules []Rule) {
if depMap == nil {
return
}
+ // Build the inverse map once — O(R×D) — to make per-rule dependencies() calls O(1).
+ inv := buildInverseMap(depMap)
+
for _, r := range rules {
r.SetDependentRules(depMap.dependents(r))
- r.SetDependencyRules(depMap.dependencies(r))
+ r.SetDependencyRules(depMap.dependencies(r, inv))
}
}