Merge pull request #4824 from MichaelEischer/fix-cache-race
bloblru: Fix flaky test due to race condition
This commit is contained in:
commit
3d4a620089
1 changed files with 19 additions and 10 deletions
|
@ -97,10 +97,16 @@ func (c *Cache) GetOrCompute(id restic.ID, compute func() ([]byte, error)) ([]by
|
||||||
// check for parallel download or start our own
|
// check for parallel download or start our own
|
||||||
finish := make(chan struct{})
|
finish := make(chan struct{})
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
waitForResult, isDownloading := c.inProgress[id]
|
waitForResult, isComputing := c.inProgress[id]
|
||||||
if !isDownloading {
|
if !isComputing {
|
||||||
c.inProgress[id] = finish
|
c.inProgress[id] = finish
|
||||||
|
}
|
||||||
|
c.mu.Unlock()
|
||||||
|
|
||||||
|
if isComputing {
|
||||||
|
// wait for result of parallel download
|
||||||
|
<-waitForResult
|
||||||
|
} else {
|
||||||
// remove progress channel once finished here
|
// remove progress channel once finished here
|
||||||
defer func() {
|
defer func() {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
|
@ -109,15 +115,18 @@ func (c *Cache) GetOrCompute(id restic.ID, compute func() ([]byte, error)) ([]by
|
||||||
close(finish)
|
close(finish)
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
c.mu.Unlock()
|
|
||||||
|
|
||||||
if isDownloading {
|
// try again. This is necessary independent of whether isComputing is true or not.
|
||||||
// wait for result of parallel download
|
// The calls to `c.Get()` and checking/adding the entry in `c.inProgress` are not atomic,
|
||||||
<-waitForResult
|
// thus the item might have been computed in the meantime.
|
||||||
blob, ok := c.Get(id)
|
// The following scenario would compute() the value multiple times otherwise:
|
||||||
if ok {
|
// Goroutine A does not find a value in the initial call to `c.Get`, then goroutine B
|
||||||
return blob, nil
|
// takes over, caches the computed value and cleans up its channel in c.inProgress.
|
||||||
}
|
// Then goroutine A continues, does not detect a parallel computation and would try
|
||||||
|
// to call compute() again.
|
||||||
|
blob, ok = c.Get(id)
|
||||||
|
if ok {
|
||||||
|
return blob, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// download it
|
// download it
|
||||||
|
|
Loading…
Reference in a new issue