completely prune inter-module dependencies

There was a missing outer loop for catching inverse module dependencies
when pruning nodes for destroy. Since the need to "register" the fully
destroyed modules no longer exists, the extra complication of pruning
the modules as a whole from the leaves inward is no longer required.
While it is technically still a valid optimization to reduce iterations,
the extra comparisons required to backtrack for transitive dependencies
don't amount to much, and having a single nested loop is much easier to
maintain.
This commit is contained in:
James Bardin 2020-08-18 16:34:44 -04:00
parent d844d02b87
commit a6776eaa94
1 changed files with 4 additions and 63 deletions

View File

@ -2,7 +2,6 @@ package terraform
import (
"log"
"sort"
"github.com/hashicorp/terraform/addrs"
"github.com/hashicorp/terraform/states"
@ -188,69 +187,9 @@ func (t *pruneUnusedNodesTransformer) Transform(g *Graph) error {
// dependencies from child modules, freeing up nodes in the parent module
// to also be removed.
// First collect the nodes into their respective modules based on
// configuration path.
moduleMap := make(map[string]pruneUnusedNodesMod)
for _, v := range g.Vertices() {
var path addrs.Module
switch v := v.(type) {
case GraphNodeModulePath:
path = v.ModulePath()
default:
continue
}
m := moduleMap[path.String()]
m.addr = path
m.nodes = append(m.nodes, v)
nodes := g.Vertices()
moduleMap[path.String()] = m
}
// now we need to restructure the modules so we can sort them
var modules []pruneUnusedNodesMod
for _, mod := range moduleMap {
modules = append(modules, mod)
}
// Sort them by path length, longest first, so that we start with the
// deepest modules. The order of modules at the same tree level doesn't
// matter, we just need to ensure that child modules are processed before
// parent modules.
sort.Slice(modules, func(i, j int) bool {
return len(modules[i].addr) > len(modules[j].addr)
})
for _, mod := range modules {
mod.removeUnused(g)
}
return nil
}
// pruneUnusedNodesMod is a container to hold the nodes that belong to a
// particular configuration module for the pruneUnusedNodesTransformer
type pruneUnusedNodesMod struct {
addr addrs.Module
nodes []dag.Vertex
}
// Remove any unused locals, variables, outputs and expanders. Since module
// closers can also lookup expansion info to detect orphaned instances, disable
// them if their associated expander is removed.
func (m *pruneUnusedNodesMod) removeUnused(g *Graph) {
// We modify the nodes slice during processing here.
// Make a copy so no one is surprised by this changing in the future.
nodes := make([]dag.Vertex, len(m.nodes))
copy(nodes, m.nodes)
// since we have no defined structure within the module, just cycle through
// the nodes in each module until there are no more removals
removed := true
for {
if !removed {
return
}
for removed := true; removed; {
removed = false
for i := 0; i < len(nodes); i++ {
@ -307,4 +246,6 @@ func (m *pruneUnusedNodesMod) removeUnused(g *Graph) {
}()
}
}
return nil
}