Skip to content

Commit

Permalink
Fix race in Lister.Finished which was causing the tests to be unreliable
Browse files Browse the repository at this point in the history
  • Loading branch information
ncw committed Jan 19, 2017
1 parent e2bf9eb commit b6848a3
Showing 1 changed file with 22 additions and 16 deletions.
38 changes: 22 additions & 16 deletions fs/lister.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ type listerResult struct {
Err error
}

// Lister objects are used for conniltrolling listing of Fs objects
// Lister objects are used for controlling listing of Fs objects
type Lister struct {
mu sync.RWMutex
buffer int
abort bool
results chan listerResult
finished sync.Once
level int
filter *Filter
err error
mu sync.RWMutex
buffer int
abort bool
results chan listerResult
closeOnce sync.Once
level int
filter *Filter
err error
}

// NewLister creates a Lister object.
Expand Down Expand Up @@ -172,6 +172,15 @@ func (o *Lister) IncludeDirectory(remote string) bool {
return o.filter.IncludeDirectory(remote)
}

// finished closes the results channel and sets abort - must be called
// with o.mu held.
func (o *Lister) finished() {
o.closeOnce.Do(func() {
close(o.results)
o.abort = true
})
}

// SetError will set an error state, and will cause the listing to
// be aborted.
// Multiple goroutines can set the error state concurrently,
Expand All @@ -181,19 +190,16 @@ func (o *Lister) SetError(err error) {
if err != nil && !o.abort {
o.err = err
o.results <- listerResult{Err: err}
o.finished()
}
o.mu.Unlock()
o.Finished()
}

// Finished should be called when listing is finished
func (o *Lister) Finished() {
o.finished.Do(func() {
o.mu.Lock()
o.abort = true
close(o.results)
o.mu.Unlock()
})
o.mu.Lock()
o.finished()
o.mu.Unlock()
}

// IsFinished returns whether the directory listing is finished or not
Expand Down

0 comments on commit b6848a3

Please sign in to comment.