Skip to content

Commit

Permalink
支持 github.com/patrickmn/go-cache
Browse files Browse the repository at this point in the history
  • Loading branch information
mingye.fan authored and mingye.fan committed Mar 20, 2021
1 parent 2facae2 commit 39e232c
Show file tree
Hide file tree
Showing 16 changed files with 1,074 additions and 490 deletions.
1 change: 1 addition & 0 deletions Makefile
Expand Up @@ -10,3 +10,4 @@ mocks:
mockgen -source=store/redis.go -destination=test/mocks/store/clients/redis_interface.go -package=mocks
mockgen -source=store/ristretto.go -destination=test/mocks/store/clients/ristretto_interface.go -package=mocks
mockgen -source=store/freecache.go -destination=test/mocks/store/clients/freecache_interface.go -package=mocks
mockgen -source=store/go_cache.go -destination=test/mocks/store/clients/go_cache_interface.go -package=mocks
1 change: 1 addition & 0 deletions go.mod
Expand Up @@ -9,6 +9,7 @@ require (
github.com/dgraph-io/ristretto v0.0.3
github.com/go-redis/redis/v7 v7.4.0
github.com/golang/mock v1.5.0
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/prometheus/client_golang v1.9.0
github.com/stretchr/testify v1.7.0
github.com/vmihailenco/msgpack v4.0.4+incompatible
Expand Down
29 changes: 3 additions & 26 deletions go.sum

Large diffs are not rendered by default.

144 changes: 144 additions & 0 deletions store/go_cache.go
@@ -0,0 +1,144 @@
package store

import (
"errors"
"fmt"
time "time"
)

const (
// GoCacheType represents the storage type as a string value
GoCacheType = "go-cache"
// GoCacheTagPattern represents the tag pattern to be used as a key in specified storage
GoCacheTagPattern = "gocache_tag_%s"
)

// GoCacheClientInterface represents a github.com/patrickmn/go-cache client
type GoCacheClientInterface interface {
Get(k string) (interface{}, bool)
GetWithExpiration(k string) (interface{}, time.Time, bool)
Set(k string, x interface{}, d time.Duration)
Delete(k string)
Flush()
}

// GoCacheStore is a store for GoCache (memory) library
type GoCacheStore struct {
client GoCacheClientInterface
options *Options
}

// NewGoCache creates a new store to GoCache (memory) library instance
func NewGoCache(client GoCacheClientInterface, options *Options) *GoCacheStore {
if options == nil {
options = &Options{}
}

return &GoCacheStore{
client: client,
options: options,
}
}

// Get returns data stored from a given key
func (s *GoCacheStore) Get(key interface{}) (interface{}, error) {
var err error
keyStr := key.(string)
value, exists := s.client.Get(keyStr)
if !exists {
err = errors.New("Value not found in GoCache store")
}

return value, err
}

// GetWithTTL returns data stored from a given key and its corresponding TTL
func (s *GoCacheStore) GetWithTTL(key interface{}) (interface{}, time.Duration, error) {
data, t, exists := s.client.GetWithExpiration(key.(string))
if !exists {
return data, 0, errors.New("Value not found in GoCache store")
}
duration := t.Sub(time.Now())
return data, duration, nil
}

// Set defines data in GoCache memoey cache for given key identifier
func (s *GoCacheStore) Set(key interface{}, value interface{}, options *Options) error {

if options == nil {
options = s.options
}

s.client.Set(key.(string), value, options.ExpirationValue())

if tags := options.TagsValue(); len(tags) > 0 {
s.setTags(key, tags)
}

return nil
}

func (s *GoCacheStore) setTags(key interface{}, tags []string) {
for _, tag := range tags {
var tagKey = fmt.Sprintf(GoCacheTagPattern, tag)
var cacheKeys map[string]struct{}

if result, err := s.Get(tagKey); err == nil {
if bytes, ok := result.(map[string]struct{}); ok {
cacheKeys = bytes
}
}
if _, exists := cacheKeys[key.(string)]; exists {
continue
}

if cacheKeys == nil {
cacheKeys = make(map[string]struct{})
}

cacheKeys[key.(string)] = struct{}{}

s.client.Set(tagKey, cacheKeys, 720*time.Hour)
}
}

// Delete removes data in GoCache memoey cache for given key identifier
func (s *GoCacheStore) Delete(key interface{}) error {
s.client.Delete(key.(string))
return nil
}

// Invalidate invalidates some cache data in GoCache memoey cache for given options
func (s *GoCacheStore) Invalidate(options InvalidateOptions) error {
if tags := options.TagsValue(); len(tags) > 0 {
for _, tag := range tags {
var tagKey = fmt.Sprintf(GoCacheTagPattern, tag)
result, err := s.Get(tagKey)
if err != nil {
return nil
}

var cacheKeys map[string]struct{}
if bytes, ok := result.(map[string]struct{}); ok {
cacheKeys = bytes
}

for cacheKey := range cacheKeys {
_ = s.Delete(cacheKey)
}
}
}

return nil
}

// GetType returns the store type
func (s *GoCacheStore) GetType() string {
return GoCacheType
}

// Clear resets all data in the store
func (s *GoCacheStore) Clear() error {
s.client.Flush()
return nil
}
49 changes: 49 additions & 0 deletions store/go_cache_bench_test.go
@@ -0,0 +1,49 @@
package store

import (
"fmt"
"github.com/patrickmn/go-cache"
"math"
"testing"
"time"
)

func BenchmarkGoCacheSet(b *testing.B) {
client := cache.New(10*time.Second, 30*time.Second)

store := NewGoCache(client, nil)

for k := 0.; k <= 10; k++ {
n := int(math.Pow(2, k))
b.Run(fmt.Sprintf("%d", n), func(b *testing.B) {
for i := 0; i < b.N*n; i++ {
key := fmt.Sprintf("test-%d", n)
value := []byte(fmt.Sprintf("value-%d", n))

store.Set(key, value, &Options{
Tags: []string{fmt.Sprintf("tag-%d", n)},
})
}
})
}
}

func BenchmarkGoCacheGet(b *testing.B) {
client := cache.New(10*time.Second, 30*time.Second)

store := NewGoCache(client, nil)

key := "test"
value := []byte("value")

store.Set(key, value, nil)

for k := 0.; k <= 10; k++ {
n := int(math.Pow(2, k))
b.Run(fmt.Sprintf("%d", n), func(b *testing.B) {
for i := 0; i < b.N*n; i++ {
_, _ = store.Get(key)
}
})
}
}

0 comments on commit 39e232c

Please sign in to comment.