// Returns what is necessary to run request_strategy.GetRequestablePieces for primaryTorrent.
func (cl *Client) getRequestStrategyInput(primaryTorrent *Torrent) (input request_strategy.Input) {
- if primaryTorrent.storage.Capacity == nil {
+ if !primaryTorrent.hasStorageCap() {
return requestStrategyInputSingleTorrent{
requestStrategyInputCommon: cl.getRequestStrategyInputCommon(),
t: primaryTorrent,
import (
"io"
+ "sync"
+ "time"
"github.com/anacrolix/squirrel"
return
}
return &client{
- cache,
- cache.GetCapacity,
+ cache: cache,
}, nil
}
+// Creates a storage.ClientImpl from a provided squirrel.Cache. The caller is responsible for
+// closing the squirrel.Cache.
func NewWrappingClient(cache *squirrel.Cache) storage.ClientImpl {
return &client{
- cache,
- cache.GetCapacity,
+ cache: cache,
}
}
type client struct {
- *squirrel.Cache
- capacity func() (int64, bool)
+ cache *squirrel.Cache
+ capacityMu sync.Mutex
+ capacityFetched time.Time
+ capacityCap int64
+ capacityCapped bool
+}
+
+func (c *client) Close() error {
+ return c.cache.Close()
+}
+
+func (c *client) capacity() (cap int64, capped bool) {
+ c.capacityMu.Lock()
+ defer c.capacityMu.Unlock()
+ if !c.capacityFetched.IsZero() && time.Since(c.capacityFetched) < time.Second {
+ cap, capped = c.capacityCap, c.capacityCapped
+ return
+ }
+ c.capacityCap, c.capacityCapped = c.cache.GetCapacity()
+ // Should this go before or after the capacityCap and capacityCapped assignments?
+ c.capacityFetched = time.Now()
+ cap, capped = c.capacityCap, c.capacityCapped
+ return
}
func (c *client) OpenTorrent(*metainfo.Info, metainfo.Hash) (storage.TorrentImpl, error) {
- t := torrent{c.Cache}
- return storage.TorrentImpl{Piece: t.Piece, Close: t.Close, Capacity: &c.capacity}, nil
+ t := torrent{c.cache}
+ capFunc := c.capacity
+ return storage.TorrentImpl{Piece: t.Piece, Close: t.Close, Capacity: &capFunc}, nil
}
type torrent struct {