浏览代码

Data race: sharedPullerState WriteAt+Close

Jakob Borg 11 年之前
父节点
当前提交
90de5659ea
共有 1 个文件被更改,包括 17 次插入3 次删除
  1. 17 3
      internal/model/sharedpullerstate.go

+ 17 - 3
internal/model/sharedpullerstate.go

@@ -16,6 +16,7 @@
 package model
 
 import (
+	"io"
 	"os"
 	"path/filepath"
 	"sync"
@@ -57,9 +58,22 @@ type pullerProgress struct {
 	BytesTotal          int64
 }
 
+// A lockedWriterAt synchronizes WriteAt calls with an external mutex.
+// WriteAt() is goroutine safe by itself, but not against for example Close().
+type lockedWriterAt struct {
+	mut *sync.Mutex
+	wr  io.WriterAt
+}
+
+func (w lockedWriterAt) WriteAt(p []byte, off int64) (n int, err error) {
+	w.mut.Lock()
+	defer w.mut.Unlock()
+	return w.wr.WriteAt(p, off)
+}
+
 // tempFile returns the fd for the temporary file, reusing an open fd
 // or creating the file as necessary.
-func (s *sharedPullerState) tempFile() (*os.File, error) {
+func (s *sharedPullerState) tempFile() (io.WriterAt, error) {
 	s.mut.Lock()
 	defer s.mut.Unlock()
 
@@ -70,7 +84,7 @@ func (s *sharedPullerState) tempFile() (*os.File, error) {
 
 	// If the temp file is already open, return the file descriptor
 	if s.fd != nil {
-		return s.fd, nil
+		return lockedWriterAt{&s.mut, s.fd}, nil
 	}
 
 	// Ensure that the parent directory is writable. This is
@@ -106,7 +120,7 @@ func (s *sharedPullerState) tempFile() (*os.File, error) {
 	// Same fd will be used by all writers
 	s.fd = fd
 
-	return fd, nil
+	return lockedWriterAt{&s.mut, s.fd}, nil
 }
 
 // sourceFile opens the existing source file for reading