Fix top-down resolve re-walking graph too much.

Firing off multiple concurrent walks of the same sub-tree with the same
conditions. Data race meant every walk would proceed. Move the logic to
entry of walk function and compare under lock.

Bug: 255526010

Test: m droid

Test: m out/soong/.intermediates/packages/modules/StatsD/apex/com.android.os.statsd/android_common_com.android.os.statsd_image/NOTICE.html.gz

Change-Id: Ie30edbb2ac9eaa9aa55badfc518d51eaadbb6be6
This commit is contained in:
Bob Badour
2022-10-25 19:56:33 -07:00
parent aff9f3a77c
commit d2c28ba897

View File

@@ -171,42 +171,47 @@ func TraceTopDownConditions(lg *LicenseGraph, conditionsFn TraceConditions) {
walk = func(fnode *TargetNode, cs LicenseConditionSet, treatAsAggregate bool) { walk = func(fnode *TargetNode, cs LicenseConditionSet, treatAsAggregate bool) {
defer wg.Done() defer wg.Done()
mu.Lock() continueWalk := func() bool {
fnode.resolution |= conditionsFn(fnode) mu.Lock()
fnode.resolution |= cs defer mu.Unlock()
fnode.pure = treatAsAggregate depcs := fnode.resolution
amap[fnode] = struct{}{} _, alreadyWalked := amap[fnode]
cs = fnode.resolution if alreadyWalked {
mu.Unlock() if cs.IsEmpty() {
return false
}
if cs.Difference(depcs).IsEmpty() {
// no new conditions
// pure aggregates never need walking a 2nd time with same conditions
if treatAsAggregate {
return false
}
// non-aggregates don't need walking as non-aggregate a 2nd time
if !fnode.pure {
return false
}
// previously walked as pure aggregate; need to re-walk as non-aggregate
}
}
fnode.resolution |= conditionsFn(fnode)
fnode.resolution |= cs
fnode.pure = treatAsAggregate
amap[fnode] = struct{}{}
cs = fnode.resolution
return true
}()
if !continueWalk {
return
}
// for each dependency // for each dependency
for _, edge := range fnode.edges { for _, edge := range fnode.edges {
func(edge *TargetEdge) { // dcs holds the dpendency conditions inherited from the target
// dcs holds the dpendency conditions inherited from the target dcs := targetConditionsPropagatingToDep(lg, edge, cs, treatAsAggregate, conditionsFn)
dcs := targetConditionsPropagatingToDep(lg, edge, cs, treatAsAggregate, conditionsFn) dnode := edge.dependency
dnode := edge.dependency // add the conditions to the dependency
mu.Lock() wg.Add(1)
defer mu.Unlock() go walk(dnode, dcs, treatAsAggregate && dnode.IsContainer())
depcs := dnode.resolution
_, alreadyWalked := amap[dnode]
if !dcs.IsEmpty() && alreadyWalked {
if dcs.Difference(depcs).IsEmpty() {
// no new conditions
// pure aggregates never need walking a 2nd time with same conditions
if treatAsAggregate {
return
}
// non-aggregates don't need walking as non-aggregate a 2nd time
if !dnode.pure {
return
}
// previously walked as pure aggregate; need to re-walk as non-aggregate
}
}
// add the conditions to the dependency
wg.Add(1)
go walk(dnode, dcs, treatAsAggregate && dnode.IsContainer())
}(edge)
} }
} }