archiver: Fix race condition resulting in files containing null IDs

In some rare cases files could be created which contain null IDs (all
zero) in their content list. This was caused by a race condition between
growing the `Content` slice and inserting the blob IDs into it. In some
cases the blob ID was written to the old slice, which a short time
afterwards was replaced with a larger copy, that did not yet contain the
blob ID.
This commit is contained in:
Michael Eischer 2022-11-10 20:19:37 +01:00
parent 5f9ac2b165
commit 5756c96c9f
2 changed files with 8 additions and 0 deletions

View file

@ -48,14 +48,19 @@ func TestBlobSaver(t *testing.T) {
var wait sync.WaitGroup var wait sync.WaitGroup
var results []SaveBlobResponse var results []SaveBlobResponse
var lock sync.Mutex
wait.Add(20) wait.Add(20)
for i := 0; i < 20; i++ { for i := 0; i < 20; i++ {
buf := &Buffer{Data: []byte(fmt.Sprintf("foo%d", i))} buf := &Buffer{Data: []byte(fmt.Sprintf("foo%d", i))}
idx := i idx := i
lock.Lock()
results = append(results, SaveBlobResponse{}) results = append(results, SaveBlobResponse{})
lock.Unlock()
b.Save(ctx, restic.DataBlob, buf, func(res SaveBlobResponse) { b.Save(ctx, restic.DataBlob, buf, func(res SaveBlobResponse) {
lock.Lock()
results[idx] = res results[idx] = res
lock.Unlock()
wait.Done() wait.Done()
}) })
} }

View file

@ -199,7 +199,10 @@ func (s *FileSaver) saveFile(ctx context.Context, chnker *chunker.Chunker, snPat
// add a place to store the saveBlob result // add a place to store the saveBlob result
pos := idx pos := idx
lock.Lock()
node.Content = append(node.Content, restic.ID{}) node.Content = append(node.Content, restic.ID{})
lock.Unlock()
s.saveBlob(ctx, restic.DataBlob, buf, func(sbr SaveBlobResponse) { s.saveBlob(ctx, restic.DataBlob, buf, func(sbr SaveBlobResponse) {
lock.Lock() lock.Lock()