github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/dag/dag.go (about)

     1  package dag
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"sort"
     7  	"strings"
     8  	"sync"
     9  	"time"
    10  
    11  	"github.com/hashicorp/go-multierror"
    12  )
    13  
    14  // AcyclicGraph is a specialization of Graph that cannot have cycles. With
    15  // this property, we get the property of sane graph traversal.
    16  type AcyclicGraph struct {
    17  	Graph
    18  }
    19  
    20  // WalkFunc is the callback used for walking the graph.
    21  type WalkFunc func(Vertex) error
    22  
    23  // DepthWalkFunc is a walk function that also receives the current depth of the
    24  // walk as an argument
    25  type DepthWalkFunc func(Vertex, int) error
    26  
    27  // Returns a Set that includes every Vertex yielded by walking down from the
    28  // provided starting Vertex v.
    29  func (g *AcyclicGraph) Ancestors(v Vertex) (*Set, error) {
    30  	s := new(Set)
    31  	start := AsVertexList(g.DownEdges(v))
    32  	memoFunc := func(v Vertex, d int) error {
    33  		s.Add(v)
    34  		return nil
    35  	}
    36  
    37  	if err := g.DepthFirstWalk(start, memoFunc); err != nil {
    38  		return nil, err
    39  	}
    40  
    41  	return s, nil
    42  }
    43  
    44  // Returns a Set that includes every Vertex yielded by walking up from the
    45  // provided starting Vertex v.
    46  func (g *AcyclicGraph) Descendents(v Vertex) (*Set, error) {
    47  	s := new(Set)
    48  	start := AsVertexList(g.UpEdges(v))
    49  	memoFunc := func(v Vertex, d int) error {
    50  		s.Add(v)
    51  		return nil
    52  	}
    53  
    54  	if err := g.ReverseDepthFirstWalk(start, memoFunc); err != nil {
    55  		return nil, err
    56  	}
    57  
    58  	return s, nil
    59  }
    60  
    61  // Root returns the root of the DAG, or an error.
    62  //
    63  // Complexity: O(V)
    64  func (g *AcyclicGraph) Root() (Vertex, error) {
    65  	roots := make([]Vertex, 0, 1)
    66  	for _, v := range g.Vertices() {
    67  		if g.UpEdges(v).Len() == 0 {
    68  			roots = append(roots, v)
    69  		}
    70  	}
    71  
    72  	if len(roots) > 1 {
    73  		// TODO(mitchellh): make this error message a lot better
    74  		return nil, fmt.Errorf("multiple roots: %#v", roots)
    75  	}
    76  
    77  	if len(roots) == 0 {
    78  		return nil, fmt.Errorf("no roots found")
    79  	}
    80  
    81  	return roots[0], nil
    82  }
    83  
    84  // TransitiveReduction performs the transitive reduction of graph g in place.
    85  // The transitive reduction of a graph is a graph with as few edges as
    86  // possible with the same reachability as the original graph. This means
    87  // that if there are three nodes A => B => C, and A connects to both
    88  // B and C, and B connects to C, then the transitive reduction is the
    89  // same graph with only a single edge between A and B, and a single edge
    90  // between B and C.
    91  //
    92  // The graph must be valid for this operation to behave properly. If
    93  // Validate() returns an error, the behavior is undefined and the results
    94  // will likely be unexpected.
    95  //
    96  // Complexity: O(V(V+E)), or asymptotically O(VE)
    97  func (g *AcyclicGraph) TransitiveReduction() {
    98  	// For each vertex u in graph g, do a DFS starting from each vertex
    99  	// v such that the edge (u,v) exists (v is a direct descendant of u).
   100  	//
   101  	// For each v-prime reachable from v, remove the edge (u, v-prime).
   102  	for _, u := range g.Vertices() {
   103  		uTargets := g.DownEdges(u)
   104  		vs := AsVertexList(g.DownEdges(u))
   105  
   106  		g.DepthFirstWalk(vs, func(v Vertex, d int) error {
   107  			shared := uTargets.Intersection(g.DownEdges(v))
   108  			for _, vPrime := range AsVertexList(shared) {
   109  				g.RemoveEdge(BasicEdge(u, vPrime))
   110  			}
   111  
   112  			return nil
   113  		})
   114  	}
   115  }
   116  
   117  // Validate validates the DAG. A DAG is valid if it has a single root
   118  // with no cycles.
   119  func (g *AcyclicGraph) Validate() error {
   120  	if _, err := g.Root(); err != nil {
   121  		return err
   122  	}
   123  
   124  	// Look for cycles of more than 1 component
   125  	var err error
   126  	cycles := g.Cycles()
   127  	if len(cycles) > 0 {
   128  		for _, cycle := range cycles {
   129  			cycleStr := make([]string, len(cycle))
   130  			for j, vertex := range cycle {
   131  				cycleStr[j] = VertexName(vertex)
   132  			}
   133  
   134  			err = multierror.Append(err, fmt.Errorf(
   135  				"Cycle: %s", strings.Join(cycleStr, ", ")))
   136  		}
   137  	}
   138  
   139  	// Look for cycles to self
   140  	for _, e := range g.Edges() {
   141  		if e.Source() == e.Target() {
   142  			err = multierror.Append(err, fmt.Errorf(
   143  				"Self reference: %s", VertexName(e.Source())))
   144  		}
   145  	}
   146  
   147  	return err
   148  }
   149  
   150  func (g *AcyclicGraph) Cycles() [][]Vertex {
   151  	var cycles [][]Vertex
   152  	for _, cycle := range StronglyConnected(&g.Graph) {
   153  		if len(cycle) > 1 {
   154  			cycles = append(cycles, cycle)
   155  		}
   156  	}
   157  	return cycles
   158  }
   159  
   160  // Walk walks the graph, calling your callback as each node is visited.
   161  // This will walk nodes in parallel if it can. Because the walk is done
   162  // in parallel, the error returned will be a multierror.
   163  func (g *AcyclicGraph) Walk(cb WalkFunc) error {
   164  	// Cache the vertices since we use it multiple times
   165  	vertices := g.Vertices()
   166  
   167  	// Build the waitgroup that signals when we're done
   168  	var wg sync.WaitGroup
   169  	wg.Add(len(vertices))
   170  	doneCh := make(chan struct{})
   171  	go func() {
   172  		defer close(doneCh)
   173  		wg.Wait()
   174  	}()
   175  
   176  	// The map of channels to watch to wait for vertices to finish
   177  	vertMap := make(map[Vertex]chan struct{})
   178  	for _, v := range vertices {
   179  		vertMap[v] = make(chan struct{})
   180  	}
   181  
   182  	// The map of whether a vertex errored or not during the walk
   183  	var errLock sync.Mutex
   184  	var errs error
   185  	errMap := make(map[Vertex]bool)
   186  	for _, v := range vertices {
   187  		// Build our list of dependencies and the list of channels to
   188  		// wait on until we start executing for this vertex.
   189  		deps := AsVertexList(g.DownEdges(v))
   190  		depChs := make([]<-chan struct{}, len(deps))
   191  		for i, dep := range deps {
   192  			depChs[i] = vertMap[dep]
   193  		}
   194  
   195  		// Get our channel so that we can close it when we're done
   196  		ourCh := vertMap[v]
   197  
   198  		// Start the goroutine to wait for our dependencies
   199  		readyCh := make(chan bool)
   200  		go func(v Vertex, deps []Vertex, chs []<-chan struct{}, readyCh chan<- bool) {
   201  			// First wait for all the dependencies
   202  			for i, ch := range chs {
   203  			DepSatisfied:
   204  				for {
   205  					select {
   206  					case <-ch:
   207  						break DepSatisfied
   208  					case <-time.After(time.Second * 5):
   209  						log.Printf("[DEBUG] vertex %s, waiting for: %s",
   210  							VertexName(v), VertexName(deps[i]))
   211  					}
   212  				}
   213  				log.Printf("[DEBUG] vertex %s, got dep: %s",
   214  					VertexName(v), VertexName(deps[i]))
   215  			}
   216  
   217  			// Then, check the map to see if any of our dependencies failed
   218  			errLock.Lock()
   219  			defer errLock.Unlock()
   220  			for _, dep := range deps {
   221  				if errMap[dep] {
   222  					errMap[v] = true
   223  					readyCh <- false
   224  					return
   225  				}
   226  			}
   227  
   228  			readyCh <- true
   229  		}(v, deps, depChs, readyCh)
   230  
   231  		// Start the goroutine that executes
   232  		go func(v Vertex, doneCh chan<- struct{}, readyCh <-chan bool) {
   233  			defer close(doneCh)
   234  			defer wg.Done()
   235  
   236  			var err error
   237  			if ready := <-readyCh; ready {
   238  				err = cb(v)
   239  			}
   240  
   241  			errLock.Lock()
   242  			defer errLock.Unlock()
   243  			if err != nil {
   244  				errMap[v] = true
   245  				errs = multierror.Append(errs, err)
   246  			}
   247  		}(v, ourCh, readyCh)
   248  	}
   249  
   250  	<-doneCh
   251  	return errs
   252  }
   253  
   254  // simple convenience helper for converting a dag.Set to a []Vertex
   255  func AsVertexList(s *Set) []Vertex {
   256  	rawList := s.List()
   257  	vertexList := make([]Vertex, len(rawList))
   258  	for i, raw := range rawList {
   259  		vertexList[i] = raw.(Vertex)
   260  	}
   261  	return vertexList
   262  }
   263  
   264  type vertexAtDepth struct {
   265  	Vertex Vertex
   266  	Depth  int
   267  }
   268  
   269  // depthFirstWalk does a depth-first walk of the graph starting from
   270  // the vertices in start. This is not exported now but it would make sense
   271  // to export this publicly at some point.
   272  func (g *AcyclicGraph) DepthFirstWalk(start []Vertex, f DepthWalkFunc) error {
   273  	seen := make(map[Vertex]struct{})
   274  	frontier := make([]*vertexAtDepth, len(start))
   275  	for i, v := range start {
   276  		frontier[i] = &vertexAtDepth{
   277  			Vertex: v,
   278  			Depth:  0,
   279  		}
   280  	}
   281  	for len(frontier) > 0 {
   282  		// Pop the current vertex
   283  		n := len(frontier)
   284  		current := frontier[n-1]
   285  		frontier = frontier[:n-1]
   286  
   287  		// Check if we've seen this already and return...
   288  		if _, ok := seen[current.Vertex]; ok {
   289  			continue
   290  		}
   291  		seen[current.Vertex] = struct{}{}
   292  
   293  		// Visit the current node
   294  		if err := f(current.Vertex, current.Depth); err != nil {
   295  			return err
   296  		}
   297  
   298  		// Visit targets of this in a consistent order.
   299  		targets := AsVertexList(g.DownEdges(current.Vertex))
   300  		sort.Sort(byVertexName(targets))
   301  		for _, t := range targets {
   302  			frontier = append(frontier, &vertexAtDepth{
   303  				Vertex: t,
   304  				Depth:  current.Depth + 1,
   305  			})
   306  		}
   307  	}
   308  
   309  	return nil
   310  }
   311  
   312  // reverseDepthFirstWalk does a depth-first walk _up_ the graph starting from
   313  // the vertices in start.
   314  func (g *AcyclicGraph) ReverseDepthFirstWalk(start []Vertex, f DepthWalkFunc) error {
   315  	seen := make(map[Vertex]struct{})
   316  	frontier := make([]*vertexAtDepth, len(start))
   317  	for i, v := range start {
   318  		frontier[i] = &vertexAtDepth{
   319  			Vertex: v,
   320  			Depth:  0,
   321  		}
   322  	}
   323  	for len(frontier) > 0 {
   324  		// Pop the current vertex
   325  		n := len(frontier)
   326  		current := frontier[n-1]
   327  		frontier = frontier[:n-1]
   328  
   329  		// Check if we've seen this already and return...
   330  		if _, ok := seen[current.Vertex]; ok {
   331  			continue
   332  		}
   333  		seen[current.Vertex] = struct{}{}
   334  
   335  		// Visit the current node
   336  		if err := f(current.Vertex, current.Depth); err != nil {
   337  			return err
   338  		}
   339  
   340  		// Visit targets of this in a consistent order.
   341  		targets := AsVertexList(g.UpEdges(current.Vertex))
   342  		sort.Sort(byVertexName(targets))
   343  		for _, t := range targets {
   344  			frontier = append(frontier, &vertexAtDepth{
   345  				Vertex: t,
   346  				Depth:  current.Depth + 1,
   347  			})
   348  		}
   349  	}
   350  
   351  	return nil
   352  }
   353  
   354  // byVertexName implements sort.Interface so a list of Vertices can be sorted
   355  // consistently by their VertexName
   356  type byVertexName []Vertex
   357  
   358  func (b byVertexName) Len() int      { return len(b) }
   359  func (b byVertexName) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
   360  func (b byVertexName) Less(i, j int) bool {
   361  	return VertexName(b[i]) < VertexName(b[j])
   362  }