github.com/hobbeswalsh/terraform@v0.3.7-0.20150619183303-ad17cf55a0fa/dag/dag.go (about)

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