github.com/blacked/terraform@v0.6.2-0.20150806163846-669c4ad71586/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 }