]> Sergey Matveev's repositories - btrtrc.git/commitdiff
Fix race in writes to closed provider
authorMatt Joiner <anacrolix@gmail.com>
Tue, 19 Jan 2021 04:25:56 +0000 (15:25 +1100)
committerMatt Joiner <anacrolix@gmail.com>
Mon, 25 Jan 2021 04:54:37 +0000 (15:54 +1100)
storage/sqlite/sqlite-storage.go

index 83be6e8d566bd0bd98cc8942f528d92961f49a0e..cb2ab1b973533764a6f79a85b8f9d1915ef15e8a 100644 (file)
@@ -347,7 +347,8 @@ type provider struct {
        pool     ConnPool
        writes   chan<- writeRequest
        opts     ProviderOpts
-       closed   sync.Once
+       closeMu  sync.RWMutex
+       closed   bool
        closeErr error
 }
 
@@ -382,12 +383,16 @@ func (p *provider) WriteConsecutiveChunks(prefix string, w io.Writer) (written i
 }
 
 func (me *provider) Close() error {
-       me.closed.Do(func() {
-               if me.writes != nil {
-                       close(me.writes)
-               }
-               me.closeErr = me.pool.Close()
-       })
+       me.closeMu.Lock()
+       defer me.closeMu.Unlock()
+       if me.closed {
+               return me.closeErr
+       }
+       if me.writes != nil {
+               close(me.writes)
+       }
+       me.closeErr = me.pool.Close()
+       me.closed = true
        return me.closeErr
 }
 
@@ -481,11 +486,17 @@ func getLabels(skip int) pprof.LabelSet {
 func (p *provider) withConn(with withConn, write bool, skip int) error {
        if write && p.opts.BatchWrites {
                done := make(chan error)
+               p.closeMu.RLock()
+               if p.closed {
+                       p.closeMu.RUnlock()
+                       return errors.New("closed")
+               }
                p.writes <- writeRequest{
                        query:  with,
                        done:   done,
                        labels: getLabels(skip + 1),
                }
+               p.closeMu.RUnlock()
                return <-done
        } else {
                conn := p.pool.Get(context.TODO())