view.deleteFragment should hold the lock while altering fragments

If you delete a fragment while something else is calling allFragments,
you can cause a race. This almost never happens in practice, because
deleting fragments is rare, and the only likely overlap would be with
something like the holder cache flush, which only happens once a
minute. But if you slowed down the rest of the tests enough, and ran
with -race, you might see it.

We check v.fragments directly instead of calling v.Fragment, because
v.Fragment also needs a lock, and we don't want to drop the lock between
the check for existence and the delete operation.
This commit is contained in:
Seebs 2019-06-26 16:11:44 -05:00
parent 03cb21afbd
commit b2fb51be1f

View file

@ -278,7 +278,9 @@ func (v *view) newFragment(path string, shard uint64) *fragment {
// deleteFragment removes the fragment from the view.
func (v *view) deleteFragment(shard uint64) error {
fragment := v.Fragment(shard)
v.mu.Lock()
defer v.mu.Unlock()
fragment := v.fragments[shard]
if fragment == nil {
return ErrFragmentNotFound
}