Speed up finding dependency cycles
parallelVisit supports mutating the dependency graph while it is being visited by proceeding until there are no modules with their dependencies satisfied, and then checking if there are modules that haven't been visited yet. If so, it assumes there was a newly introduced dependency cycle and tries to find it to return as an error. Finding the dependency cycle could traverse outside of the cycle. If the dependency cycle occurs near the bottom of the dependency graph, that traversal could be both long and wide, leading to very long runtimes. Memoize traversed modules that were not found to be part of the dependency cycle to prevent repeated traversals. Fixes: 186572387 Test: introduce cycle into libc, m nothing Test: Test_parallelVisit Change-Id: I38d0749dbedffbe8a39e433d97fbe08486451321
This commit is contained in:
parent
9021eef07b
commit
9793b0a5e0
1 changed files with 10 additions and 0 deletions
10
context.go
10
context.go
|
@ -2081,6 +2081,11 @@ func parallelVisit(modules []*moduleInfo, order visitOrderer, limit int,
|
|||
// modules to the modules that would have been unblocked when that module finished, i.e
|
||||
// the reverse of the visitOrderer.
|
||||
|
||||
// In order to reduce duplicated work, once a module has been checked and determined
|
||||
// not to be part of a cycle add it and everything that depends on it to the checked
|
||||
// map.
|
||||
checked := make(map[*moduleInfo]struct{})
|
||||
|
||||
var check func(module, end *moduleInfo) []*moduleInfo
|
||||
check = func(module, end *moduleInfo) []*moduleInfo {
|
||||
if module.waitingCount == -1 {
|
||||
|
@ -2092,6 +2097,10 @@ func parallelVisit(modules []*moduleInfo, order visitOrderer, limit int,
|
|||
return []*moduleInfo{module}
|
||||
}
|
||||
|
||||
if _, alreadyChecked := checked[module]; alreadyChecked {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, dep := range order.propagate(module) {
|
||||
cycle := check(dep, end)
|
||||
if cycle != nil {
|
||||
|
@ -2105,6 +2114,7 @@ func parallelVisit(modules []*moduleInfo, order visitOrderer, limit int,
|
|||
}
|
||||
}
|
||||
|
||||
checked[module] = struct{}{}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue