client.go | 2 +- connection.go | 2 ++ request_strategy.go | 12 +++++++++--- diff --git a/client.go b/client.go index 620b4b62158b8e3d9487968ddb2887b9b64dbf46..0990c6e0affb4534ba7357b0a23a4a0d1f523c49 100644 --- a/client.go +++ b/client.go @@ -1043,7 +1043,7 @@ metadataChanged: sync.Cond{ 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()) }) diff --git a/connection.go b/connection.go index 0c25e3432a7a52d45b94532428908f14509b11bb..4c106cca5a3dcdbc131f4ea4974f563dc8c88f98 100644 --- a/connection.go +++ b/connection.go @@ -545,7 +545,9 @@ } 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) }) } diff --git a/request_strategy.go b/request_strategy.go index e2e2c1289b628267a0a974721af9f1dfd0c017aa..bcf6ac639b3ba78116e469ffba2e7a58e32e18b4 100644 --- a/request_strategy.go +++ b/request_strategy.go @@ -1,6 +1,7 @@ package torrent import ( + "sync" "time" "github.com/anacrolix/missinggo/v2/bitmap" @@ -79,20 +80,25 @@ // reached. 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, } } }