Fix race in Lister.Finished which was causing the tests to be unreliable

This commit is contained in:
Nick Craig-Wood 2017-01-19 18:01:31 +00:00
parent e2bf9eb8e9
commit b6848a3edb

View file

@ -11,13 +11,13 @@ type listerResult struct {
Err error 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 { type Lister struct {
mu sync.RWMutex mu sync.RWMutex
buffer int buffer int
abort bool abort bool
results chan listerResult results chan listerResult
finished sync.Once closeOnce sync.Once
level int level int
filter *Filter filter *Filter
err error err error
@ -172,6 +172,15 @@ func (o *Lister) IncludeDirectory(remote string) bool {
return o.filter.IncludeDirectory(remote) 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 // SetError will set an error state, and will cause the listing to
// be aborted. // be aborted.
// Multiple goroutines can set the error state concurrently, // Multiple goroutines can set the error state concurrently,
@ -181,19 +190,16 @@ func (o *Lister) SetError(err error) {
if err != nil && !o.abort { if err != nil && !o.abort {
o.err = err o.err = err
o.results <- listerResult{Err: err} o.results <- listerResult{Err: err}
o.finished()
} }
o.mu.Unlock() o.mu.Unlock()
o.Finished()
} }
// Finished should be called when listing is finished // Finished should be called when listing is finished
func (o *Lister) Finished() { func (o *Lister) Finished() {
o.finished.Do(func() {
o.mu.Lock() o.mu.Lock()
o.abort = true o.finished()
close(o.results)
o.mu.Unlock() o.mu.Unlock()
})
} }
// IsFinished returns whether the directory listing is finished or not // IsFinished returns whether the directory listing is finished or not