github.com/jonasi/terraform@v0.6.10-0.20160125170522-e865c342cc1f/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 }