diff --git a/go.mod b/go.mod index 7dcc23207..687fa51be 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/elithrar/simple-scrypt v1.3.0 github.com/go-ole/go-ole v1.2.6 github.com/google/go-cmp v0.5.9 - github.com/hashicorp/golang-lru v0.5.4 + github.com/hashicorp/golang-lru/v2 v2.0.1 github.com/juju/ratelimit v1.0.2 github.com/klauspost/compress v1.15.9 github.com/kurin/blazer v0.5.4-0.20211030221322-ba894c124ac6 diff --git a/go.sum b/go.sum index ea684718c..c5ee48075 100644 --- a/go.sum +++ b/go.sum @@ -109,8 +109,8 @@ github.com/googleapis/enterprise-certificate-proxy v0.2.0 h1:y8Yozv7SZtlU//QXbez github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= github.com/googleapis/gax-go/v2 v2.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ= github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= -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/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= diff --git a/internal/bloblru/cache.go b/internal/bloblru/cache.go index dfd9b2fd1..302ecc769 100644 --- a/internal/bloblru/cache.go +++ b/internal/bloblru/cache.go @@ -6,7 +6,7 @@ import ( "github.com/restic/restic/internal/debug" "github.com/restic/restic/internal/restic" - "github.com/hashicorp/golang-lru/simplelru" + "github.com/hashicorp/golang-lru/v2/simplelru" ) // Crude estimate of the overhead per blob: a SHA-256, a linked list node @@ -17,7 +17,7 @@ const overhead = len(restic.ID{}) + 64 // It is safe for concurrent access. type Cache struct { mu sync.Mutex - c *simplelru.LRU + c *simplelru.LRU[restic.ID, []byte] free, size int // Current and max capacity, in bytes. } @@ -33,7 +33,7 @@ func New(size int) *Cache { // The actual maximum will be smaller than size/overhead, because we // evict entries (RemoveOldest in add) to maintain our size bound. maxEntries := size / overhead - lru, err := simplelru.NewLRU(maxEntries, c.evict) + lru, err := simplelru.NewLRU[restic.ID, []byte](maxEntries, c.evict) if err != nil { panic(err) // Can only be maxEntries <= 0. } @@ -55,24 +55,21 @@ func (c *Cache) Add(id restic.ID, blob []byte) (old []byte) { c.mu.Lock() defer c.mu.Unlock() - var key interface{} = id - - if c.c.Contains(key) { // Doesn't update the recency list. + if c.c.Contains(id) { // Doesn't update the recency list. return } // This loop takes at most min(maxEntries, maxchunksize/overhead) // iterations. for size > c.free { - _, val, _ := c.c.RemoveOldest() - b := val.([]byte) + _, b, _ := c.c.RemoveOldest() if cap(b) > cap(old) { // We can only return one buffer, so pick the largest. old = b } } - c.c.Add(key, blob) + c.c.Add(id, blob) c.free -= size return old @@ -80,17 +77,15 @@ func (c *Cache) Add(id restic.ID, blob []byte) (old []byte) { func (c *Cache) Get(id restic.ID) ([]byte, bool) { c.mu.Lock() - value, ok := c.c.Get(id) + blob, ok := c.c.Get(id) c.mu.Unlock() debug.Log("bloblru.Cache: get %v, hit %v", id, ok) - blob, ok := value.([]byte) return blob, ok } -func (c *Cache) evict(key, value interface{}) { - blob := value.([]byte) +func (c *Cache) evict(key restic.ID, blob []byte) { debug.Log("bloblru.Cache: evict %v, %d bytes", key, cap(blob)) c.free += cap(blob) + overhead } diff --git a/internal/bloblru/cache_test.go b/internal/bloblru/cache_test.go index 34280e35c..aa6f4465c 100644 --- a/internal/bloblru/cache_test.go +++ b/internal/bloblru/cache_test.go @@ -1,6 +1,7 @@ package bloblru import ( + "math/rand" "testing" "github.com/restic/restic/internal/restic" @@ -50,3 +51,29 @@ func TestCache(t *testing.T) { rtest.Equals(t, cacheSize, c.size) rtest.Equals(t, cacheSize, c.free) } + +func BenchmarkAdd(b *testing.B) { + const ( + MiB = 1 << 20 + nblobs = 64 + ) + + c := New(64 * MiB) + + buf := make([]byte, 8*MiB) + ids := make([]restic.ID, nblobs) + sizes := make([]int, nblobs) + + r := rand.New(rand.NewSource(100)) + for i := range ids { + r.Read(ids[i][:]) + sizes[i] = r.Intn(8 * MiB) + } + + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + c.Add(ids[i%nblobs], buf[:sizes[i%nblobs]]) + } +}