-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Jimmie Han <hanjinming@outlook.com>
- Loading branch information
Showing
12 changed files
with
494 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
// Copyright (c) The Thanos Authors. | ||
// Licensed under the Apache License 2.0. | ||
|
||
package cache | ||
|
||
import ( | ||
"context" | ||
"time" | ||
|
||
"github.com/go-kit/kit/log" | ||
"github.com/go-kit/kit/log/level" | ||
"github.com/prometheus/client_golang/prometheus" | ||
"github.com/prometheus/client_golang/prometheus/promauto" | ||
"github.com/thanos-io/thanos/pkg/cacheutil" | ||
) | ||
|
||
// RedisCache is a redis cache. | ||
type RedisCache struct { | ||
logger log.Logger | ||
redisClient *cacheutil.RedisClient | ||
name string | ||
|
||
// Metrics. | ||
requests prometheus.Counter | ||
hits prometheus.Counter | ||
} | ||
|
||
// NewRedisCache makes a new RedisCache. | ||
func NewRedisCache(name string, logger log.Logger, redisClient *cacheutil.RedisClient, reg prometheus.Registerer) *RedisCache { | ||
c := &RedisCache{ | ||
logger: logger, | ||
redisClient: redisClient, | ||
name: name, | ||
} | ||
|
||
c.requests = promauto.With(reg).NewCounter(prometheus.CounterOpts{ | ||
Name: "thanos_cache_redis_requests_total", | ||
Help: "Total number of items requests to redis.", | ||
ConstLabels: prometheus.Labels{"name": name}, | ||
}) | ||
|
||
c.hits = promauto.With(reg).NewCounter(prometheus.CounterOpts{ | ||
Name: "thanos_cache_redis_hits_total", | ||
Help: "Total number of items requests to the cache that were a hit.", | ||
ConstLabels: prometheus.Labels{"name": name}, | ||
}) | ||
|
||
level.Info(logger).Log("msg", "created redis cache") | ||
|
||
return c | ||
} | ||
|
||
// Store data identified by keys. | ||
func (c *RedisCache) Store(ctx context.Context, data map[string][]byte, ttl time.Duration) { | ||
c.redisClient.SetMulti(ctx, data, ttl) | ||
} | ||
|
||
// Fetch fetches multiple keys and returns a map containing cache hits, along with a list of missing keys. | ||
// In case of error, it logs and return an empty cache hits map. | ||
func (c *RedisCache) Fetch(ctx context.Context, keys []string) map[string][]byte { | ||
c.requests.Add(float64(len(keys))) | ||
results := c.redisClient.GetMulti(ctx, keys) | ||
c.hits.Add(float64(len(results))) | ||
return results | ||
} | ||
|
||
func (c *RedisCache) Name() string { | ||
return c.name | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
package cache | ||
|
||
import ( | ||
"context" | ||
"os" | ||
"testing" | ||
"time" | ||
|
||
"github.com/alicebob/miniredis/v2" | ||
"github.com/go-kit/kit/log" | ||
"github.com/prometheus/client_golang/prometheus" | ||
prom_testutil "github.com/prometheus/client_golang/prometheus/testutil" | ||
"github.com/thanos-io/thanos/pkg/cacheutil" | ||
"github.com/thanos-io/thanos/pkg/testutil" | ||
) | ||
|
||
func TestRedisCache(t *testing.T) { | ||
// Init some data to conveniently define test cases later one. | ||
key1 := "key1" | ||
key2 := "key2" | ||
key3 := "key3" | ||
value1 := []byte{1} | ||
value2 := []byte{2} | ||
value3 := []byte{3} | ||
|
||
type args struct { | ||
data map[string][]byte | ||
fetchKeys []string | ||
} | ||
type want struct { | ||
hits map[string][]byte | ||
} | ||
tests := []struct { | ||
name string | ||
args args | ||
want want | ||
}{ | ||
{ | ||
name: "all hit", | ||
args: args{ | ||
data: map[string][]byte{ | ||
key1: value1, | ||
key2: value2, | ||
key3: value3, | ||
}, | ||
fetchKeys: []string{key1, key2, key3}, | ||
}, | ||
want: want{ | ||
hits: map[string][]byte{ | ||
key1: value1, | ||
key2: value2, | ||
key3: value3, | ||
}, | ||
}, | ||
}, | ||
{ | ||
name: "partial hit", | ||
args: args{ | ||
data: map[string][]byte{ | ||
key1: value1, | ||
key2: value2, | ||
}, | ||
fetchKeys: []string{key1, key2, key3}, | ||
}, | ||
want: want{ | ||
hits: map[string][]byte{ | ||
key1: value1, | ||
key2: value2, | ||
}, | ||
}, | ||
}, | ||
{ | ||
name: "not hit", | ||
args: args{ | ||
data: map[string][]byte{}, | ||
fetchKeys: []string{key1, key2, key3}, | ||
}, | ||
want: want{ | ||
hits: map[string][]byte{}, | ||
}, | ||
}, | ||
} | ||
s, err := miniredis.Run() | ||
if err != nil { | ||
testutil.Ok(t, err) | ||
} | ||
defer s.Close() | ||
logger := log.NewLogfmtLogger(os.Stderr) | ||
reg := prometheus.NewRegistry() | ||
cfg := cacheutil.RedisClientConfig{ | ||
Addr: s.Addr(), | ||
DialTimeout: time.Second, | ||
ReadTimeout: time.Second, | ||
WriteTimeout: time.Second, | ||
MinIdleConns: 10, | ||
MaxConnAge: time.Minute * 10, | ||
IdleTimeout: time.Minute * 5, | ||
} | ||
c, err := cacheutil.NewRedisClientWithConfig(logger, t.Name(), cfg, reg) | ||
if err != nil { | ||
testutil.Ok(t, err) | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
defer s.FlushAll() | ||
c := NewRedisCache(tt.name, logger, c, reg) | ||
// Store the cache expected before running the test. | ||
ctx := context.Background() | ||
c.Store(ctx, tt.args.data, time.Hour) | ||
|
||
// Fetch postings from cached and assert on it. | ||
hits := c.Fetch(ctx, tt.args.fetchKeys) | ||
testutil.Equals(t, tt.want.hits, hits) | ||
|
||
// Assert on metrics. | ||
testutil.Equals(t, float64(len(tt.args.fetchKeys)), prom_testutil.ToFloat64(c.requests)) | ||
testutil.Equals(t, float64(len(tt.want.hits)), prom_testutil.ToFloat64(c.hits)) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.