depgraph: fix data races

This commit is contained in:
Mitchell Hashimoto 2014-07-01 10:09:20 -07:00
parent d970cec8eb
commit bce5d55a85
1 changed files with 14 additions and 2 deletions

View File

@ -9,6 +9,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"sort" "sort"
"sync"
"github.com/hashicorp/terraform/digraph" "github.com/hashicorp/terraform/digraph"
) )
@ -217,6 +218,7 @@ CHECK_CYCLES:
// then introduce a lock in your callback. // then introduce a lock in your callback.
func (g *Graph) Walk(fn WalkFunc) error { func (g *Graph) Walk(fn WalkFunc) error {
// Set so we don't callback for a single noun multiple times // Set so we don't callback for a single noun multiple times
var seenMapL sync.RWMutex
seenMap := make(map[*Noun]chan struct{}) seenMap := make(map[*Noun]chan struct{})
seenMap[g.Root] = make(chan struct{}) seenMap[g.Root] = make(chan struct{})
@ -236,7 +238,9 @@ func (g *Graph) Walk(fn WalkFunc) error {
// Go through each dependency and run that first // Go through each dependency and run that first
for _, dep := range current.Deps { for _, dep := range current.Deps {
if _, ok := seenMap[dep.Target]; !ok { if _, ok := seenMap[dep.Target]; !ok {
seenMapL.Lock()
seenMap[dep.Target] = make(chan struct{}) seenMap[dep.Target] = make(chan struct{})
seenMapL.Unlock()
tovisit = append(tovisit, dep.Target) tovisit = append(tovisit, dep.Target)
} }
} }
@ -244,12 +248,20 @@ func (g *Graph) Walk(fn WalkFunc) error {
// Spawn off a goroutine to execute our callback once // Spawn off a goroutine to execute our callback once
// all our dependencies are satisified. // all our dependencies are satisified.
go func(current *Noun) { go func(current *Noun) {
defer close(seenMap[current]) seenMapL.RLock()
closeCh := seenMap[current]
seenMapL.RUnlock()
defer close(closeCh)
// Wait for all our dependencies // Wait for all our dependencies
for _, dep := range current.Deps { for _, dep := range current.Deps {
seenMapL.RLock()
ch := seenMap[dep.Target]
seenMapL.RUnlock()
select { select {
case <-seenMap[dep.Target]: case <-ch:
case <-quitCh: case <-quitCh:
return return
} }