Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: use generic LRU cache #1980

Merged
merged 1 commit into from
Jan 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ require (
github.com/golang/mock v1.6.0
github.com/google/gopacket v1.1.19
github.com/gorilla/websocket v1.5.0
github.com/hashicorp/golang-lru v0.5.4
github.com/hashicorp/golang-lru/v2 v2.0.1
github.com/ipfs/go-cid v0.3.2
github.com/ipfs/go-datastore v0.6.0
github.com/ipfs/go-ds-badger v0.3.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,8 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:Fecb
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/golang-lru/v2 v2.0.1 h1:5pv5N1lT1fjLg2VQ5KWc7kmucp2x/kvFOnxuVTqZ6x4=
github.com/hashicorp/golang-lru/v2 v2.0.1/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc=
Expand Down
10 changes: 4 additions & 6 deletions p2p/discovery/backoff/backoffconnector.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import (
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/peer"

lru "github.com/hashicorp/golang-lru"
lru "github.com/hashicorp/golang-lru/v2"
)

// BackoffConnector is a utility to connect to peers, but only if we have not recently tried connecting to them already
type BackoffConnector struct {
cache *lru.TwoQueueCache
cache *lru.TwoQueueCache[peer.ID, *connCacheData]
host host.Host
connTryDur time.Duration
backoff BackoffFactory
Expand All @@ -25,7 +25,7 @@ type BackoffConnector struct {
// connectionTryDuration is how long we attempt to connect to a peer before giving up
// backoff describes the strategy used to decide how long to backoff after previously attempting to connect to a peer
func NewBackoffConnector(h host.Host, cacheSize int, connectionTryDuration time.Duration, backoff BackoffFactory) (*BackoffConnector, error) {
cache, err := lru.New2Q(cacheSize)
cache, err := lru.New2Q[peer.ID, *connCacheData](cacheSize)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -59,10 +59,8 @@ func (c *BackoffConnector) Connect(ctx context.Context, peerCh <-chan peer.AddrI
}

c.mux.Lock()
val, ok := c.cache.Get(pi.ID)
var cachedPeer *connCacheData
if ok {
tv := val.(*connCacheData)
if tv, ok := c.cache.Get(pi.ID); ok {
now := time.Now()
if now.Before(tv.nextTry) {
c.mux.Unlock()
Expand Down
11 changes: 5 additions & 6 deletions p2p/host/peerstore/pstoreds/addr_book.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
pb "github.com/libp2p/go-libp2p/p2p/host/peerstore/pb"
"github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoremem"

lru "github.com/hashicorp/golang-lru"
lru "github.com/hashicorp/golang-lru/v2"
ds "github.com/ipfs/go-datastore"
"github.com/ipfs/go-datastore/query"
logging "github.com/ipfs/go-log/v2"
Expand Down Expand Up @@ -135,7 +135,7 @@ type dsAddrBook struct {
ctx context.Context
opts Options

cache cache
cache cache[peer.ID, *addrsRecord]
ds ds.Batching
gc *dsAddrBookGc
subsManager *pstoremem.AddrSubManager
Expand Down Expand Up @@ -200,11 +200,11 @@ func NewAddrBook(ctx context.Context, store ds.Batching, opts Options) (ab *dsAd
}

if opts.CacheSize > 0 {
if ab.cache, err = lru.NewARC(int(opts.CacheSize)); err != nil {
if ab.cache, err = lru.NewARC[peer.ID, *addrsRecord](int(opts.CacheSize)); err != nil {
return nil, err
}
} else {
ab.cache = new(noopCache)
ab.cache = new(noopCache[peer.ID, *addrsRecord])
}

if ab.gc, err = newAddressBookGc(ctx, ab); err != nil {
Expand All @@ -228,8 +228,7 @@ func (ab *dsAddrBook) Close() error {
//
// If the cache argument is true, the record is inserted in the cache when loaded from the datastore.
func (ab *dsAddrBook) loadRecord(id peer.ID, cache bool, update bool) (pr *addrsRecord, err error) {
if e, ok := ab.cache.Get(id); ok {
pr = e.(*addrsRecord)
if pr, ok := ab.cache.Get(id); ok {
pr.Lock()
defer pr.Unlock()

Expand Down
6 changes: 2 additions & 4 deletions p2p/host/peerstore/pstoreds/addr_book_gc.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,7 @@ func (gc *dsAddrBookGc) purgeLookahead() {
}

// if the record is in cache, we clean it and flush it if necessary.
if e, ok := gc.ab.cache.Peek(id); ok {
cached := e.(*addrsRecord)
if cached, ok := gc.ab.cache.Peek(id); ok {
cached.Lock()
if cached.clean(gc.ab.clock.Now()) {
if err = cached.flush(batch); err != nil {
Expand Down Expand Up @@ -345,8 +344,7 @@ func (gc *dsAddrBookGc) populateLookahead() {
}

// if the record is in cache, use the cached version.
if e, ok := gc.ab.cache.Peek(id); ok {
cached := e.(*addrsRecord)
if cached, ok := gc.ab.cache.Peek(id); ok {
cached.RLock()
if len(cached.Addrs) == 0 || cached.Addrs[0].Expiry > until {
cached.RUnlock()
Expand Down
34 changes: 17 additions & 17 deletions p2p/host/peerstore/pstoreds/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,39 @@ package pstoreds

// cache abstracts all methods we access from ARCCache, to enable alternate
// implementations such as a no-op one.
type cache interface {
Get(key interface{}) (value interface{}, ok bool)
Add(key, value interface{})
Remove(key interface{})
Contains(key interface{}) bool
Peek(key interface{}) (value interface{}, ok bool)
Keys() []interface{}
type cache[K comparable, V any] interface {
Get(key K) (value V, ok bool)
Add(key K, value V)
Remove(key K)
Contains(key K) bool
Peek(key K) (value V, ok bool)
Keys() []K
}

// noopCache is a dummy implementation that's used when the cache is disabled.
type noopCache struct {
type noopCache[K comparable, V any] struct {
}

var _ cache = (*noopCache)(nil)
var _ cache[int, int] = (*noopCache[int, int])(nil)

func (*noopCache) Get(key interface{}) (value interface{}, ok bool) {
return nil, false
func (*noopCache[K, V]) Get(key K) (value V, ok bool) {
return *new(V), false
}

func (*noopCache) Add(key, value interface{}) {
func (*noopCache[K, V]) Add(key K, value V) {
}

func (*noopCache) Remove(key interface{}) {
func (*noopCache[K, V]) Remove(key K) {
}

func (*noopCache) Contains(key interface{}) bool {
func (*noopCache[K, V]) Contains(key K) bool {
return false
}

func (*noopCache) Peek(key interface{}) (value interface{}, ok bool) {
return nil, false
func (*noopCache[K, V]) Peek(key K) (value V, ok bool) {
return *new(V), false
}

func (*noopCache) Keys() (keys []interface{}) {
func (*noopCache[K, V]) Keys() (keys []K) {
return keys
}