]> Sergey Matveev's repositories - btrtrc.git/commitdiff
Fix race in requestStrategyThree request timeout callback
authorMatt Joiner <anacrolix@gmail.com>
Mon, 20 Jan 2020 00:51:24 +0000 (11:51 +1100)
committerMatt Joiner <anacrolix@gmail.com>
Mon, 20 Jan 2020 00:51:24 +0000 (11:51 +1100)
client.go
connection.go
request_strategy.go

index 620b4b62158b8e3d9487968ddb2887b9b64dbf46..0990c6e0affb4534ba7357b0a23a4a0d1f523c49 100644 (file)
--- a/client.go
+++ b/client.go
@@ -1043,7 +1043,7 @@ func (cl *Client) newTorrent(ih metainfo.Hash, specStorage storage.ClientImpl) (
                        L: cl.locker(),
                },
        }
-       t.requestStrategy = cl.config.DefaultRequestStrategy(t.requestStrategyCallbacks())
+       t.requestStrategy = cl.config.DefaultRequestStrategy(t.requestStrategyCallbacks(), &cl._mu)
        t.logger = cl.logger.WithValues(t).WithText(func(m log.Msg) string {
                return fmt.Sprintf("%v: %s", t, m.Text())
        })
index 0c25e3432a7a52d45b94532428908f14509b11bb..4c106cca5a3dcdbc131f4ea4974f563dc8c88f98 100644 (file)
@@ -545,7 +545,9 @@ func (cn *connection) request(r request, mw messageWriter) bool {
 
 func (rs requestStrategyThree) onSentRequest(r request) {
        rs.lastRequested[r] = time.AfterFunc(rs.duplicateRequestTimeout, func() {
+               rs.timeoutLocker.Lock()
                delete(rs.lastRequested, r)
+               rs.timeoutLocker.Unlock()
                rs.callbacks.requestTimedOut(r)
        })
 }
index e2e2c1289b628267a0a974721af9f1dfd0c017aa..bcf6ac639b3ba78116e469ffba2e7a58e32e18b4 100644 (file)
@@ -1,6 +1,7 @@
 package torrent
 
 import (
+       "sync"
        "time"
 
        "github.com/anacrolix/missinggo/v2/bitmap"
@@ -79,20 +80,25 @@ func (requestStrategyTwo) ShouldRequestWithoutBias(cn requestStrategyConnection)
 type requestStrategyThree struct {
        // How long to avoid duplicating a pending request.
        duplicateRequestTimeout time.Duration
+
+       callbacks requestStrategyCallbacks
+
        // The last time we requested a chunk. Deleting the request from any connection will clear this
        // value.
        lastRequested map[request]*time.Timer
-       callbacks     requestStrategyCallbacks
+       // The lock to take when running a request timeout handler.
+       timeoutLocker sync.Locker
 }
 
-type requestStrategyMaker func(callbacks requestStrategyCallbacks) requestStrategy
+type requestStrategyMaker func(callbacks requestStrategyCallbacks, clientLocker sync.Locker) requestStrategy
 
 func requestStrategyThreeMaker(duplicateRequestTimeout time.Duration) requestStrategyMaker {
-       return func(callbacks requestStrategyCallbacks) requestStrategy {
+       return func(callbacks requestStrategyCallbacks, clientLocker sync.Locker) requestStrategy {
                return requestStrategyThree{
                        duplicateRequestTimeout: duplicateRequestTimeout,
                        callbacks:               callbacks,
                        lastRequested:           make(map[request]*time.Timer),
+                       timeoutLocker:           clientLocker,
                }
        }
 }