Skip to content

Commit 32fc9bc

Browse files
committed
revproxy: better handling of memory cache size and expiration
Use a typed cache, and keep track of the size of the data payload instead of just the number of elements.
1 parent 2213bb2 commit 32fc9bc

File tree

4 files changed

+33
-30
lines changed

4 files changed

+33
-30
lines changed

go.mod

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/tailscale/go-cache-plugin
22

3-
go 1.23.0
3+
go 1.23.1
44

55
require (
66
github.com/aws/aws-sdk-go-v2/config v1.27.28
@@ -9,11 +9,11 @@ require (
99
github.com/creachadair/command v0.1.14
1010
github.com/creachadair/flax v0.0.1
1111
github.com/creachadair/gocache v0.0.0-20240904225701-6c4617815112
12-
github.com/creachadair/mds v0.18.1
12+
github.com/creachadair/mds v0.19.2
1313
github.com/creachadair/mhttp v0.0.0-20240904023549-156b88d21c62
14+
github.com/creachadair/scheddle v0.0.0-20240907053453-f3bdd9f33c58
1415
github.com/creachadair/taskgroup v0.9.1
1516
github.com/creachadair/tlsutil v0.0.0-20240901051800-c769f173a559
16-
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da
1717
github.com/goproxy/goproxy v0.17.2
1818
golang.org/x/sync v0.8.0
1919
golang.org/x/sys v0.22.0
@@ -41,6 +41,7 @@ require (
4141
github.com/aws/smithy-go v1.20.4 // indirect
4242
github.com/beorn7/perks v1.0.1 // indirect
4343
github.com/cespare/xxhash/v2 v2.2.0 // indirect
44+
github.com/creachadair/msync v0.2.1 // indirect
4445
github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 // indirect
4546
github.com/google/uuid v1.6.0 // indirect
4647
github.com/prometheus/client_golang v1.19.1 // indirect

go.sum

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,14 @@ github.com/creachadair/flax v0.0.1 h1:it+joEf9aEUalaV7XWll/pk6zA4/FbNvMImW9q/lS8
4848
github.com/creachadair/flax v0.0.1/go.mod h1:K8bFvn8hMdAljQkaKNc7I3os5Wk36JxkyCkfdZ7S8d4=
4949
github.com/creachadair/gocache v0.0.0-20240904225701-6c4617815112 h1:FSlFO2eztBGGzp67D2z/eeNe5U+AZyj4g/CjKf0AHbo=
5050
github.com/creachadair/gocache v0.0.0-20240904225701-6c4617815112/go.mod h1:vkGW73GdzBPQZJdFlPBZVzFcG7lTxIgDY0+U30mp3xs=
51-
github.com/creachadair/mds v0.18.1 h1:lq2JufNm5Vfkdolf9Z+2shiw7r8XJgLSZniLHUFYJcI=
52-
github.com/creachadair/mds v0.18.1/go.mod h1:4b//mUiL8YldH6TImXjmW45myzTLNS1LLjOmrk888eg=
51+
github.com/creachadair/mds v0.19.2 h1:I5OdjsrG2jqGklMcyv50Iqo6gTrwUSIpIJVSnlVw85c=
52+
github.com/creachadair/mds v0.19.2/go.mod h1:4b//mUiL8YldH6TImXjmW45myzTLNS1LLjOmrk888eg=
5353
github.com/creachadair/mhttp v0.0.0-20240904023549-156b88d21c62 h1:6OEfFAgnbvhEDAR83DBUbvImn68DH2NpqcXrwID9Vbs=
5454
github.com/creachadair/mhttp v0.0.0-20240904023549-156b88d21c62/go.mod h1:Vito16r0HqXVEcwjz5Z9PLdFEbX016lCOV6iVgH06tc=
55+
github.com/creachadair/msync v0.2.1 h1:nBrUkGnk+vhEO+fe6fEMcT6Reo/C9Oc4s62bL4Bj/Wo=
56+
github.com/creachadair/msync v0.2.1/go.mod h1:fMAB2Ihnsojvz5nRxqzEEUmHgW2/CEKY64VPP4VskSY=
57+
github.com/creachadair/scheddle v0.0.0-20240907053453-f3bdd9f33c58 h1:ZH2lplzOAJitYaaf427wVWo8tijhPZedhvbNXGwnTAs=
58+
github.com/creachadair/scheddle v0.0.0-20240907053453-f3bdd9f33c58/go.mod h1:/IRMmOFNVSrAMzgcOYcdGOFJf4RU4UurRHvMykHEzJc=
5559
github.com/creachadair/taskgroup v0.9.1 h1:oam4POtt6PpmUr4us+ycUUfb2mPWc0RmIycte2oWoWw=
5660
github.com/creachadair/taskgroup v0.9.1/go.mod h1:9oDDPt/5QPS4iylvPMC81GRlj+1je8AFDbjUh4zaQWo=
5761
github.com/creachadair/tlsutil v0.0.0-20240901051800-c769f173a559 h1:8hlU8ebt2lI//6sFj6ICE6mN6c6Uvj4588XilSqpmu8=
@@ -64,8 +68,6 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
6468
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
6569
github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 h1:ymLjT4f35nQbASLnvxEde4XOBL+Sn7rFuV+FOJqkljg=
6670
github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0/go.mod h1:6daplAwHHGbUGib4990V3Il26O0OC4aRyvewaaAihaA=
67-
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
68-
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
6971
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
7072
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
7173
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=

lib/revproxy/cache.go

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"time"
1818

1919
"github.com/creachadair/atomicfile"
20+
"github.com/creachadair/scheddle"
2021
"github.com/creachadair/taskgroup"
2122
)
2223

@@ -75,29 +76,22 @@ func (s *Server) cacheStoreS3(hash string, hdr http.Header, body []byte) taskgro
7576

7677
// cacheLoadMemory reads cached headers and body from the memory cache.
7778
func (s *Server) cacheLoadMemory(hash string) ([]byte, http.Header, error) {
78-
s.mcacheMu.Lock()
79-
defer s.mcacheMu.Unlock()
80-
v, ok := s.mcache.Get(hash)
79+
e, ok := s.mcache.Get(hash)
8180
if !ok {
8281
return nil, nil, fs.ErrNotExist
8382
}
84-
entry := v.(memCacheEntry)
85-
if time.Now().After(entry.expires) {
86-
s.mcache.Remove(hash)
87-
return nil, nil, errors.New("entry expired")
88-
}
89-
return entry.body, entry.header, nil
83+
return e.body, e.header, nil
9084
}
9185

9286
// cacheStoreMemory writes the contents of body to the memory cache.
9387
func (s *Server) cacheStoreMemory(hash string, maxAge time.Duration, hdr http.Header, body []byte) {
94-
s.mcacheMu.Lock()
95-
defer s.mcacheMu.Unlock()
96-
s.mcache.Add(hash, memCacheEntry{
97-
header: trimCacheHeader(hdr),
98-
body: body,
99-
expires: time.Now().Add(maxAge),
88+
s.mcache.Put(hash, memCacheEntry{
89+
header: trimCacheHeader(hdr),
90+
body: body,
10091
})
92+
s.expire.After(maxAge, scheddle.Run(func() {
93+
s.mcache.Remove(hash)
94+
}))
10195
}
10296

10397
var keepHeader = []string{
@@ -158,7 +152,6 @@ func setXCacheInfo(h http.Header, result, hash string) {
158152

159153
// memCacheEntry is the format of entries in the memory cache.
160154
type memCacheEntry struct {
161-
header http.Header
162-
body []byte
163-
expires time.Time
155+
header http.Header
156+
body []byte
164157
}

lib/revproxy/revproxy.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ import (
3131
"sync"
3232
"time"
3333

34+
"github.com/creachadair/mds/cache"
35+
"github.com/creachadair/scheddle"
3436
"github.com/creachadair/taskgroup"
35-
"github.com/golang/groupcache/lru"
3637
"github.com/tailscale/go-cache-plugin/lib/s3util"
3738
)
3839

@@ -89,9 +90,8 @@ type Server struct {
8990
initOnce sync.Once
9091
tasks *taskgroup.Group
9192
start func(taskgroup.Task) *taskgroup.Group
92-
93-
mcacheMu sync.Mutex // protects mcache
94-
mcache *lru.Cache // short-lived mutable objects
93+
mcache *cache.Cache[string, memCacheEntry] // short-lived mutable objects
94+
expire *scheddle.Queue // cache expirations
9595

9696
reqReceived expvar.Int // total requests received
9797
reqMemoryHit expvar.Int // hit in memory cache (volatile)
@@ -114,7 +114,14 @@ func (s *Server) init() {
114114
s.initOnce.Do(func() {
115115
nt := runtime.NumCPU()
116116
s.tasks, s.start = taskgroup.New(nil).Limit(nt)
117-
s.mcache = lru.New(1 << 16)
117+
s.mcache = cache.New(cache.Config[string, memCacheEntry]{
118+
Limit: 10 << 20,
119+
Store: cache.LRU[string, memCacheEntry](),
120+
Size: func(e memCacheEntry) int64 {
121+
return int64(len(e.body))
122+
},
123+
})
124+
s.expire = scheddle.NewQueue(nil)
118125
})
119126
}
120127

0 commit comments

Comments
 (0)