Skip to content

Commit 4e33fa8

Browse files
authored
Merge pull request #293 from eko/fixed-chain-cache-when-same-type
Fixed chain cache type when 2 caches of same type given
2 parents 40f450c + 7129ed6 commit 4e33fa8

18 files changed

Lines changed: 212 additions & 44 deletions

File tree

.github/workflows/all.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,20 @@ name: Test
33
on:
44
push:
55
branches:
6-
- '*'
6+
- "*"
77
pull_request:
88
branches:
9-
- '*'
9+
- "*"
1010

1111
jobs:
1212
test_lib:
1313
runs-on: ubuntu-latest
1414
strategy:
1515
matrix:
16-
go_version: ['1.22']
16+
go_version: ["1.25"]
1717
steps:
18-
- uses: actions/checkout@v3
19-
- uses: actions/setup-go@v3
18+
- uses: actions/checkout@v5
19+
- uses: actions/setup-go@v6
2020
with:
2121
go-version: ${{ matrix.go_version }}
2222

@@ -27,7 +27,7 @@ jobs:
2727
runs-on: ubuntu-latest
2828
strategy:
2929
matrix:
30-
go_version: ['1.22']
30+
go_version: ["1.25"]
3131
store:
3232
- bigcache
3333
- freecache
@@ -39,8 +39,8 @@ jobs:
3939
- rediscluster
4040
- ristretto
4141
steps:
42-
- uses: actions/checkout@v3
43-
- uses: actions/setup-go@v3
42+
- uses: actions/checkout@v5
43+
- uses: actions/setup-go@v6
4444
with:
4545
go-version: ${{ matrix.go_version }}
4646

example/loadable/go.mod

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
module github.com/eko/gocache/example/metrics
2+
3+
go 1.25.0
4+
5+
require (
6+
github.com/dgraph-io/ristretto v0.2.0
7+
github.com/eko/gocache/lib/v4 v4.2.0
8+
github.com/eko/gocache/store/ristretto/v4 v4.2.2
9+
)
10+
11+
replace (
12+
github.com/eko/gocache/lib/v4 => ../../lib/
13+
github.com/eko/gocache/store/ristretto/v4 => ../../store/ristretto/
14+
)
15+
16+
require (
17+
github.com/beorn7/perks v1.0.1 // indirect
18+
github.com/cespare/xxhash/v2 v2.3.0 // indirect
19+
github.com/dustin/go-humanize v1.0.1 // indirect
20+
github.com/pkg/errors v0.9.1 // indirect
21+
github.com/prometheus/client_golang v1.19.0 // indirect
22+
github.com/prometheus/client_model v0.6.1 // indirect
23+
github.com/prometheus/common v0.52.3 // indirect
24+
github.com/prometheus/procfs v0.13.0 // indirect
25+
go.uber.org/mock v0.4.0 // indirect
26+
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect
27+
golang.org/x/sync v0.7.0 // indirect
28+
golang.org/x/sys v0.19.0 // indirect
29+
google.golang.org/protobuf v1.33.0 // indirect
30+
)

example/loadable/go.sum

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
2+
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
3+
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
4+
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
5+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
6+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
7+
github.com/dgraph-io/ristretto v0.2.0 h1:XAfl+7cmoUDWW/2Lx8TGZQjjxIQ2Ley9DSf52dru4WE=
8+
github.com/dgraph-io/ristretto v0.2.0/go.mod h1:8uBHCU/PBV4Ag0CJrP47b9Ofby5dqWNh4FicAdoqFNU=
9+
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y=
10+
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
11+
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
12+
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
13+
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
14+
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
15+
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
16+
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
17+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
18+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
19+
github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
20+
github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
21+
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
22+
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
23+
github.com/prometheus/common v0.52.3 h1:5f8uj6ZwHSscOGNdIQg6OiZv/ybiK2CO2q2drVZAQSA=
24+
github.com/prometheus/common v0.52.3/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U=
25+
github.com/prometheus/procfs v0.13.0 h1:GqzLlQyfsPbaEHaQkO7tbDlriv/4o5Hudv6OXHGKX7o=
26+
github.com/prometheus/procfs v0.13.0/go.mod h1:cd4PFCR54QLnGKPaKGA6l+cfuNXtht43ZKY6tow0Y1g=
27+
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
28+
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
29+
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
30+
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
31+
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY=
32+
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
33+
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
34+
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
35+
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
36+
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
37+
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
38+
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
39+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
40+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

example/loadable/main.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"time"
7+
8+
"github.com/dgraph-io/ristretto"
9+
"github.com/eko/gocache/lib/v4/cache"
10+
"github.com/eko/gocache/lib/v4/metrics"
11+
"github.com/eko/gocache/lib/v4/store"
12+
store_ristretto "github.com/eko/gocache/store/ristretto/v4"
13+
)
14+
15+
func main() {
16+
ctx := context.Background()
17+
18+
ristrettoClient1, err := ristretto.NewCache(
19+
&ristretto.Config{
20+
NumCounters: 1_000,
21+
MaxCost: 100_000_000,
22+
BufferItems: 64,
23+
},
24+
)
25+
if err != nil {
26+
panic(err)
27+
}
28+
29+
ristrettoClient2, err := ristretto.NewCache(
30+
&ristretto.Config{
31+
NumCounters: 1_000,
32+
MaxCost: 100_000_000,
33+
BufferItems: 64,
34+
},
35+
)
36+
if err != nil {
37+
panic(err)
38+
}
39+
40+
// First: memory store
41+
memoryStore1 := store_ristretto.NewRistretto(
42+
ristrettoClient1,
43+
store.WithExpiration(1*time.Minute),
44+
)
45+
memoryCache1 := cache.New[[]byte](memoryStore1)
46+
47+
// Second: memory store
48+
memoryStore2 := store_ristretto.NewRistretto(
49+
ristrettoClient2,
50+
store.WithExpiration(1*time.Minute),
51+
)
52+
memoryCache2 := cache.New[[]byte](memoryStore2)
53+
54+
// Chain cache
55+
chainCache := cache.NewChain[[]byte](
56+
memoryCache1,
57+
memoryCache2,
58+
)
59+
60+
// Wrap chain cache with metrics cache
61+
promMetrics := metrics.NewPrometheus(
62+
"manifest-api",
63+
)
64+
65+
metricCache := cache.NewMetric[[]byte](
66+
promMetrics,
67+
chainCache,
68+
)
69+
70+
// Loadable
71+
loadableCache := cache.NewLoadable[[]byte](
72+
func(ctx context.Context, key any) ([]byte, []store.Option, error) {
73+
return []byte(`ok-1`), nil, nil
74+
},
75+
metricCache,
76+
)
77+
78+
loadableCache.Set(ctx, "my-key-1", []byte(`value-1`))
79+
time.Sleep(100 * time.Millisecond)
80+
81+
// Remove from first cache, will be fetch from second cache and
82+
// set back to first cache.
83+
memoryCache1.Delete(ctx, "my-key-1")
84+
time.Sleep(100 * time.Millisecond)
85+
86+
// Ensure value has been cached in both.
87+
value1, _ := memoryCache1.Get(ctx, "my-key-1")
88+
time.Sleep(100 * time.Millisecond)
89+
fmt.Println("value1:", string(value1))
90+
91+
value2, _ := memoryCache2.Get(ctx, "my-key-1")
92+
time.Sleep(100 * time.Millisecond)
93+
fmt.Println("value2:", string(value2))
94+
95+
// Retrieve final value.
96+
value, err := loadableCache.Get(ctx, "my-key-1")
97+
if err != nil {
98+
panic(err)
99+
}
100+
time.Sleep(100 * time.Millisecond)
101+
fmt.Println("final:", string(value))
102+
103+
// Retrieve from every cache independently.
104+
value12, _ := memoryCache1.Get(ctx, "my-key-1")
105+
time.Sleep(100 * time.Millisecond)
106+
fmt.Println("value1:", string(value12))
107+
108+
value22, _ := memoryCache2.Get(ctx, "my-key-1")
109+
time.Sleep(100 * time.Millisecond)
110+
fmt.Println("value2:", string(value22))
111+
}

lib/cache/chain.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ const (
1515
)
1616

1717
type chainKeyValue[T any] struct {
18-
key any
19-
value T
20-
ttl time.Duration
21-
storeType *string
18+
key any
19+
value T
20+
ttl time.Duration
21+
cacheAddress *string
2222
}
2323

2424
// ChainCache represents the configuration needed by a cache aggregator
@@ -43,7 +43,9 @@ func NewChain[T any](caches ...SetterCacheInterface[T]) *ChainCache[T] {
4343
func (c *ChainCache[T]) setter() {
4444
for item := range c.setChannel {
4545
for _, cache := range c.caches {
46-
if item.storeType != nil && *item.storeType == cache.GetCodec().GetStore().GetType() {
46+
cacheAddress := fmt.Sprintf("%p", cache)
47+
48+
if item.cacheAddress != nil && *item.cacheAddress == cacheAddress {
4749
break
4850
}
4951

@@ -59,11 +61,12 @@ func (c *ChainCache[T]) Get(ctx context.Context, key any) (T, error) {
5961
var ttl time.Duration
6062

6163
for _, cache := range c.caches {
62-
storeType := cache.GetCodec().GetStore().GetType()
64+
cacheAddress := fmt.Sprintf("%p", cache)
65+
6366
object, ttl, err = cache.GetWithTTL(ctx, key)
6467
if err == nil {
6568
// Set the value back until this cache layer
66-
c.setChannel <- &chainKeyValue[T]{key, object, ttl, &storeType}
69+
c.setChannel <- &chainKeyValue[T]{key, object, ttl, &cacheAddress}
6770
return object, nil
6871
}
6972
}

lib/cache/chain_test.go

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -144,26 +144,12 @@ func TestChainGetWhenNotAvailableInAnyCache(t *testing.T) {
144144
ctx := context.Background()
145145

146146
// Cache 1
147-
store1 := store.NewMockStoreInterface(ctrl)
148-
store1.EXPECT().GetType().Return("store1")
149-
150-
codec1 := codec.NewMockCodecInterface(ctrl)
151-
codec1.EXPECT().GetStore().Return(store1)
152-
153147
cache1 := NewMockSetterCacheInterface[any](ctrl)
154-
cache1.EXPECT().GetCodec().Return(codec1)
155148
cache1.EXPECT().GetWithTTL(ctx, "my-key").Return(nil, 0*time.Second,
156149
errors.New("unable to find in cache 1"))
157150

158151
// Cache 2
159-
store2 := store.NewMockStoreInterface(ctrl)
160-
store2.EXPECT().GetType().Return("store2")
161-
162-
codec2 := codec.NewMockCodecInterface(ctrl)
163-
codec2.EXPECT().GetStore().Return(store2)
164-
165152
cache2 := NewMockSetterCacheInterface[any](ctrl)
166-
cache2.EXPECT().GetCodec().Return(codec2)
167153
cache2.EXPECT().GetWithTTL(ctx, "my-key").Return(nil, 0*time.Second,
168154
errors.New("unable to find in cache 2"))
169155

@@ -176,7 +162,7 @@ func TestChainGetWhenNotAvailableInAnyCache(t *testing.T) {
176162
time.Sleep(100 * time.Millisecond)
177163

178164
// Then
179-
assert.Equal(t, errors.New("unable to find in cache 2"), err)
165+
assert.ErrorContains(t, err, "unable to find in cache 2")
180166
assert.Equal(t, nil, value)
181167
}
182168

lib/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/eko/gocache/lib/v4
22

3-
go 1.22
3+
go 1.25
44

55
require (
66
github.com/prometheus/client_golang v1.19.0

store/bigcache/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/eko/gocache/store/bigcache/v4
22

3-
go 1.22
3+
go 1.25
44

55
require (
66
github.com/allegro/bigcache/v3 v3.1.0

store/freecache/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/eko/gocache/store/freecache/v4
22

3-
go 1.22
3+
go 1.25
44

55
require (
66
github.com/coocood/freecache v1.2.3

store/go_cache/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/eko/gocache/store/go_cache/v4
22

3-
go 1.22
3+
go 1.25
44

55
require (
66
github.com/eko/gocache/lib/v4 v4.1.6

0 commit comments

Comments
 (0)