☔️ A complete Go cache library that brings you multiple ways of managing your caches

Overview

TravisBuildStatus GoDoc GoReportCard codecov

Gocache

Guess what is Gocache? a Go cache library. This is an extendable cache library that brings you a lot of features for caching data.

Overview

Here is what it brings in detail:

  • Multiple cache stores: actually in memory, redis, or your own custom store
  • A chain cache: use multiple cache with a priority order (memory then fallback to a redis shared cache for instance)
  • A loadable cache: allow you to call a callback function to put your data back in cache
  • A metric cache to let you store metrics about your caches usage (hits, miss, set success, set error, ...)
  • A marshaler to automatically marshal/unmarshal your cache values as a struct
  • Define default values in stores and override them when setting data
  • Cache invalidation by expiration time and/or using tags

Built-in stores

Built-in metrics providers

Available cache features in detail

A simple cache

Here is a simple cache instanciation with Redis but you can also look at other available stores:

Memcache

memcacheStore := store.NewMemcache(
	memcache.New("10.0.0.1:11211", "10.0.0.2:11211", "10.0.0.3:11212"),
	&store.Options{
		Expiration: 10*time.Second,
	},
)

cacheManager := cache.New(memcacheStore)
err := cacheManager.Set("my-key", []byte("my-value"), &store.Options{
	Expiration: 15*time.Second, // Override default value of 10 seconds defined in the store
})
if err != nil {
    panic(err)
}

value := cacheManager.Get("my-key")

cacheManager.Delete("my-key")

cacheManager.Clear() // Clears the entire cache, in case you want to flush all cache

Memory (using Bigcache)

bigcacheClient, _ := bigcache.NewBigCache(bigcache.DefaultConfig(5 * time.Minute))
bigcacheStore := store.NewBigcache(bigcacheClient, nil) // No otions provided (as second argument)

cacheManager := cache.New(bigcacheStore)
err := cacheManager.Set("my-key", []byte("my-value"), nil)
if err != nil {
    panic(err)
}

value := cacheManager.Get("my-key")

Memory (using Ristretto)

ristrettoCache, err := ristretto.NewCache(&ristretto.Config{
	NumCounters: 1000,
	MaxCost: 100,
	BufferItems: 64,
})
if err != nil {
    panic(err)
}
ristrettoStore := store.NewRistretto(ristrettoCache, nil)

cacheManager := cache.New(ristrettoStore)
err := cacheManager.Set("my-key", "my-value", &store.Options{Cost: 2})
if err != nil {
    panic(err)
}

value := cacheManager.Get("my-key")

cacheManager.Delete("my-key")

Redis

redisStore := store.NewRedis(redis.NewClient(&redis.Options{
	Addr: "127.0.0.1:6379",
}), nil)

cacheManager := cache.New(redisStore)
err := cacheManager.Set("my-key", "my-value", &store.Options{Expiration: 15*time.Second})
if err != nil {
    panic(err)
}

value, err := cacheManager.Get("my-key")
switch err {
	case nil:
		fmt.Printf("Get the key '%s' from the redis cache. Result: %s", "my-key", value)
	case redis.Nil:
		fmt.Printf("Failed to find the key '%s' from the redis cache.", "my-key")
	default:
	    fmt.Printf("Failed to get the value from the redis cache with key '%s': %v", "my-key", err)
}

Freecache

freecacheStore := store.NewFreecache(freecache.NewCache(1000), &Options{
	Expiration: 10 * time.Second,
})

cacheManager := cache.New(freecacheStore)
err := cacheManager.Set("by-key", []byte("my-value"), opts)
if err != nil {
	panic(err)
}

value := cacheManager.Get("my-key")

A chained cache

Here, we will chain caches in the following order: first in memory with Ristretto store, then in Redis (as a fallback):

// Initialize Ristretto cache and Redis client
ristrettoCache, err := ristretto.NewCache(&ristretto.Config{NumCounters: 1000, MaxCost: 100, BufferItems: 64})
if err != nil {
    panic(err)
}

redisClient := redis.NewClient(&redis.Options{Addr: "127.0.0.1:6379"})

// Initialize stores
ristrettoStore := store.NewRistretto(ristrettoCache, nil)
redisStore := store.NewRedis(redisClient, &store.Options{Expiration: 5*time.Second})

// Initialize chained cache
cacheManager := cache.NewChain(
    cache.New(ristrettoStore),
    cache.New(redisStore),
)

// ... Then, do what you want with your cache

Chain cache also put data back in previous caches when it's found so in this case, if ristretto doesn't have the data in its cache but redis have, data will also get setted back into ristretto (memory) cache.

A loadable cache

This cache will provide a load function that acts as a callable function and will set your data back in your cache in case they are not available:

// Initialize Redis client and store
redisClient := redis.NewClient(&redis.Options{Addr: "127.0.0.1:6379"})
redisStore := store.NewRedis(redisClient, nil)

// Initialize a load function that loads your data from a custom source
loadFunction := func(key interface{}) (interface{}, error) {
    // ... retrieve value from available source
    return &Book{ID: 1, Name: "My test amazing book", Slug: "my-test-amazing-book"}, nil
}

// Initialize loadable cache
cacheManager := cache.NewLoadable(
	loadFunction,
	cache.New(redisStore),
)

// ... Then, you can get your data and your function will automatically put them in cache(s)

Of course, you can also pass a Chain cache into the Loadable one so if your data is not available in all caches, it will bring it back in all caches.

A metric cache to retrieve cache statistics

This cache will record metrics depending on the metric provider you pass to it. Here we give a Prometheus provider:

// Initialize Redis client and store
redisClient := redis.NewClient(&redis.Options{Addr: "127.0.0.1:6379"})
redisStore := store.NewRedis(redisClient, nil)

// Initializes Prometheus metrics service
promMetrics := metrics.NewPrometheus("my-test-app")

// Initialize metric cache
cacheManager := cache.NewMetric(
	promMetrics,
	cache.New(redisStore),
)

// ... Then, you can get your data and metrics will be observed by Prometheus

A marshaler wrapper

Some caches like Redis stores and returns the value as a string so you have to marshal/unmarshal your structs if you want to cache an object. That's why we bring a marshaler service that wraps your cache and make the work for you:

// Initialize Redis client and store
redisClient := redis.NewClient(&redis.Options{Addr: "127.0.0.1:6379"})
redisStore := store.NewRedis(redisClient, nil)

// Initialize chained cache
cacheManager := cache.NewMetric(
	promMetrics,
	cache.New(redisStore),
)

// Initializes marshaler
marshal := marshaler.New(cacheManager)

key := BookQuery{Slug: "my-test-amazing-book"}
value := Book{ID: 1, Name: "My test amazing book", Slug: "my-test-amazing-book"}

err = marshal.Set(key, value)
if err != nil {
    panic(err)
}

returnedValue, err := marshal.Get(key, new(Book))
if err != nil {
    panic(err)
}

// Then, do what you want with the  value

marshal.Delete("my-key")

The only thing you have to do is to specify the struct in which you want your value to be un-marshalled as a second argument when calling the .Get() method.

Cache invalidation using tags

You can attach some tags to items you create so you can easily invalidate some of them later.

Tags are stored using the same storage you choose for your cache.

Here is an example on how to use it:

// Initialize Redis client and store
redisClient := redis.NewClient(&redis.Options{Addr: "127.0.0.1:6379"})
redisStore := store.NewRedis(redisClient, nil)

// Initialize chained cache
cacheManager := cache.NewMetric(
	promMetrics,
	cache.New(redisStore),
)

// Initializes marshaler
marshal := marshaler.New(cacheManager)

key := BookQuery{Slug: "my-test-amazing-book"}
value := Book{ID: 1, Name: "My test amazing book", Slug: "my-test-amazing-book"}

// Set an item in the cache and attach it a "book" tag
err = marshal.Set(key, value, store.Options{Tags: []string{"book"}})
if err != nil {
    panic(err)
}

// Remove all items that have the "book" tag
err := marshal.Invalidate(store.InvalidateOptions{Tags: []string{"book"}})
if err != nil {
    panic(err)
}

returnedValue, err := marshal.Get(key, new(Book))
if err != nil {
	// Should be triggered because item has been deleted so it cannot be found.
    panic(err)
}

Mix this with expiration times on your caches to have a fine tuned control on how your data are cached.

Write your own custom cache

Cache respect the following interface so you can write your own (proprietary?) cache logic if needed by implementing the following interface:

type CacheInterface interface {
	Get(key interface{}) (interface{}, error)
	Set(key, object interface{}, options *store.Options) error
	Delete(key interface{}) error
	Invalidate(options store.InvalidateOptions) error
	Clear() error
	GetType() string
}

Or, in case you use a setter cache, also implement the GetCodec() method:

type SetterCacheInterface interface {
	CacheInterface

	GetCodec() codec.CodecInterface
}

As all caches available in this library implement CacheInterface, you will be able to mix your own caches with your own.

Write your own custom store

You also have the ability to write your own custom store by implementing the following interface:

type StoreInterface interface {
	Get(key interface{}) (interface{}, error)
	Set(key interface{}, value interface{}, options *Options) error
	Delete(key interface{}) error
	Invalidate(options InvalidateOptions) error
	Clear() error
	GetType() string
}

Of course, I suggest you to have a look at current caches or stores to implement your own.

Benchmarks

Benchmarks

Community

Please feel free to contribute on this library and do not hesitate to open an issue if you want to discuss about a feature.

Run tests

Generate mocks:

$ go get github.com/golang/mock/mockgen
$ make mocks

Test suite can be run with:

$ go test -v ./...
Comments
  • Wrong type for method Del when initialize Redis Store

    Wrong type for method Del when initialize Redis Store

    I want to implement a chained cache with Redis and BigCache. I don't have problem to declare Bigcache store, but have problem with redis. I using redis from "github.com/go-redis/redis", gocache store and gocache cache

    this is how i declare my cache:

    var LocationCache *cache.ChainCache
    
    func createCache(host string) *cache.ChainCache {
    	redisClient := redis.NewClient(&redis.Options{Addr: host})
    	bigcacheClient, _ := bigcache.NewBigCache(bigcache.DefaultConfig(720 * time.Hour))
    	bigcacheStorage := store.NewBigcache(bigcacheClient, nil)
    	redisStorage := store.NewRedis(redisClient, nil)
    
    	LocationCache = cache.NewChain(
    		cache.New(bigcacheStorage),
    		cache.New(redisStorage))
    	return LocationCache
    }
    

    But it give me this error: cannot use redisClient (variable of type *redis.Client) as store.RedisClientInterface value in argument to store.NewRedis: wrong type for method Del"

    Is anyone can help me? Thanks

    opened by Yosafat1997 5
  • go mod unable to get latest version v2.2.0

    go mod unable to get latest version v2.2.0

    go mod tidy

    go: finding module for package github.com/eko/gocache github.com/eko/gocache: module github.com/eko/[email protected] found (v1.2.0), but does not contain package github.com/eko/gocache

    import (
    	"github.com/eko/gocache"
    )
    
    func main() {
       //some code
    }
    
    opened by herozzm 4
  • Use hset for invalidate tag list instead of a string

    Use hset for invalidate tag list instead of a string

    The redis store uses a csv string in redis to keep the cache keys for each tag. This redis entry that keep all keys in csv format can grow fast if we group a lot of entries under the same tag. When accessing it, this big string is loaded in memory. This result to a big memory allocation/de-allocation every time an entry with a tag is written into the cache. To fix this issue, we need to change the format of the tag key. It would be better to use a hset. This way, we can read/write only the entry we need.

    opened by plbouchard 4
  • Implement GetWithTTL for Freecache

    Implement GetWithTTL for Freecache

    Freecache doesn't implement interface function GetWithTTL. I assume that the person that added Freecache integration didn't pull the latest changes from master.

    opened by corinapurcarea 4
  • Fix data races by removing unguarded goroutines; run mod tidy

    Fix data races by removing unguarded goroutines; run mod tidy

    Fixes #15

    • Remove goroutines that are causing data races
    • Also ran go mod tidy to remove unneeded modules

    Before

    $ go test -v -race ./...
    
    ...
    ==================
    WARNING: DATA RACE
    Read at 0x00c00014a9c8 by goroutine 58:
      reflect.typedmemmove()
          /usr/local/Cellar/go/1.13.4/libexec/src/runtime/mbarrier.go:177 +0x0
      reflect.packEface()
          /usr/local/Cellar/go/1.13.4/libexec/src/reflect/value.go:119 +0x103
      reflect.valueInterface()
          /usr/local/Cellar/go/1.13.4/libexec/src/reflect/value.go:1033 +0x16f
      fmt.(*pp).printValue()
          /usr/local/Cellar/go/1.13.4/libexec/src/reflect/value.go:1003 +0x38f7
      fmt.(*pp).printValue()
          /usr/local/Cellar/go/1.13.4/libexec/src/fmt/print.go:880 +0x25da
      fmt.(*pp).printArg()
          /usr/local/Cellar/go/1.13.4/libexec/src/fmt/print.go:716 +0x2ee
      fmt.(*pp).doPrintf()
          /usr/local/Cellar/go/1.13.4/libexec/src/fmt/print.go:1126 +0x912
      fmt.Sprintf()
          /usr/local/Cellar/go/1.13.4/libexec/src/fmt/print.go:219 +0x73
      github.com/stretchr/testify/mock.Arguments.Diff()
          /Users/markphelps/go/pkg/mod/github.com/stretchr/[email protected]/mock/mock.go:687 +0xf1a
      github.com/stretchr/testify/mock.(*Mock).findExpectedCall()
          /Users/markphelps/go/pkg/mod/github.com/stretchr/[email protected]/mock/mock.go:269 +0x16a
      github.com/stretchr/testify/mock.(*Mock).MethodCalled()
          /Users/markphelps/go/pkg/mod/github.com/stretchr/[email protected]/mock/mock.go:348 +0xb3
      github.com/stretchr/testify/mock.(*Mock).Called()
          /Users/markphelps/go/pkg/mod/github.com/stretchr/[email protected]/mock/mock.go:338 +0x1e4
      github.com/eko/gocache/test/mocks/metrics.(*MetricsInterface).RecordFromCodec()
          /Users/markphelps/workspace/gocache/test/mocks/metrics/metrics_interface.go:21 +0xaa
    
    Previous write at 0x00c00014a9c8 by goroutine 57:
      github.com/stretchr/testify/mock.(*Mock).MethodCalled()
          /Users/markphelps/go/pkg/mod/github.com/stretchr/[email protected]/mock/mock.go:385 +0x7b6
      github.com/stretchr/testify/mock.(*Mock).Called()
          /Users/markphelps/go/pkg/mod/github.com/stretchr/[email protected]/mock/mock.go:338 +0x1e4
      github.com/eko/gocache/test/mocks/codec.(*CodecInterface).GetStore()
          /Users/markphelps/workspace/gocache/test/mocks/codec/codec_interface.go:83 +0x63
      github.com/eko/gocache/cache.(*ChainCache).setUntil()
          /Users/markphelps/workspace/gocache/cache/chain.go:90 +0x13b
    
    Goroutine 58 (running) created at:
      github.com/eko/gocache/cache.(*MetricCache).updateMetrics()
          /Users/markphelps/workspace/gocache/cache/metric.go:65 +0x1bd
      github.com/eko/gocache/cache.(*MetricCache).updateMetrics()
          /Users/markphelps/workspace/gocache/cache/metric.go:61 +0xff
      github.com/eko/gocache/cache.(*MetricCache).Get()
          /Users/markphelps/workspace/gocache/cache/metric.go:31 +0xcb
      github.com/eko/gocache/cache.TestMetricGetWhenChainCache()
          /Users/markphelps/workspace/gocache/cache/metric_test.go:83 +0x714
      testing.tRunner()
          /usr/local/Cellar/go/1.13.4/libexec/src/testing/testing.go:909 +0x199
    
    Goroutine 57 (finished) created at:
      github.com/eko/gocache/cache.(*ChainCache).Get()
          /Users/markphelps/workspace/gocache/cache/chain.go:37 +0x383
      github.com/eko/gocache/cache.(*MetricCache).Get()
          /Users/markphelps/workspace/gocache/cache/metric.go:29 +0x75
      github.com/eko/gocache/cache.TestMetricGetWhenChainCache()
          /Users/markphelps/workspace/gocache/cache/metric_test.go:83 +0x714
      testing.tRunner()
          /usr/local/Cellar/go/1.13.4/libexec/src/testing/testing.go:909 +0x199
    ==================
    ==================
    WARNING: DATA RACE
    Read at 0x00c00014a9f8 by goroutine 58:
      reflect.typedmemmove()
          /usr/local/Cellar/go/1.13.4/libexec/src/runtime/mbarrier.go:177 +0x0
    --- FAIL: TestMetricSet (0.00s)
      reflect.packEface()
          /usr/local/Cellar/go/1.13.4/libexec/src/reflect/value.go:119 +0x103
        testing.go:853: race detected during execution of test
      reflect.valueInterface()
          /usr/local/Cellar/go/1.13.4/libexec/src/reflect/value.go:1033 +0x16f
      fmt.(*pp).printValue()
          /usr/local/Cellar/go/1.13.4/libexec/src/reflect/value.go:1003 +0x38f7
      fmt.(*pp).printValue()
          /usr/local/Cellar/go/1.13.4/libexec/src/fmt/print.go:880 +0x25da
      fmt.(*pp).printArg()
          /usr/local/Cellar/go/1.13.4/libexec/src/fmt/print.go:716 +0x2ee
      fmt.(*pp).doPrintf()
          /usr/local/Cellar/go/1.13.4/libexec/src/fmt/print.go:1126 +0x912
      fmt.Sprintf()
          /usr/local/Cellar/go/1.13.4/libexec/src/fmt/print.go:219 +0x73
      github.com/stretchr/testify/mock.Arguments.Diff()
          /Users/markphelps/go/pkg/mod/github.com/stretchr/[email protected]/mock/mock.go:687 +0xf1a
      github.com/stretchr/testify/mock.(*Mock).findExpectedCall()
          /Users/markphelps/go/pkg/mod/github.com/stretchr/[email protected]/mock/mock.go:269 +0x16a
      github.com/stretchr/testify/mock.(*Mock).MethodCalled()
          /Users/markphelps/go/pkg/mod/github.com/stretchr/[email protected]/mock/mock.go:348 +0xb3
      github.com/stretchr/testify/mock.(*Mock).Called()
          /Users/markphelps/go/pkg/mod/github.com/stretchr/[email protected]/mock/mock.go:338 +0x1e4
      github.com/eko/gocache/test/mocks/metrics.(*MetricsInterface).RecordFromCodec()
          /Users/markphelps/workspace/gocache/test/mocks/metrics/metrics_interface.go:21 +0xaa
    
    Previous write at 0x00c00014a9f8 by goroutine 57:
      sync/atomic.AddInt32()
          /usr/local/Cellar/go/1.13.4/libexec/src/runtime/race_amd64.s:269 +0xb
      sync.(*Mutex).Unlock()
          /usr/local/Cellar/go/1.13.4/libexec/src/sync/mutex.go:186 +0x51
      github.com/stretchr/testify/mock.(*Mock).MethodCalled()
          /Users/markphelps/go/pkg/mod/github.com/stretchr/[email protected]/mock/mock.go:405 +0x921
      github.com/stretchr/testify/mock.(*Mock).Called()
          /Users/markphelps/go/pkg/mod/github.com/stretchr/[email protected]/mock/mock.go:338 +0x1e4
      github.com/eko/gocache/test/mocks/codec.(*CodecInterface).GetStore()
          /Users/markphelps/workspace/gocache/test/mocks/codec/codec_interface.go:83 +0x63
      github.com/eko/gocache/cache.(*ChainCache).setUntil()
          /Users/markphelps/workspace/gocache/cache/chain.go:90 +0x13b
    
    Goroutine 58 (running) created at:
      github.com/eko/gocache/cache.(*MetricCache).updateMetrics()
          /Users/markphelps/workspace/gocache/cache/metric.go:65 +0x1bd
      github.com/eko/gocache/cache.(*MetricCache).updateMetrics()
          /Users/markphelps/workspace/gocache/cache/metric.go:61 +0xff
      github.com/eko/gocache/cache.(*MetricCache).Get()
          /Users/markphelps/workspace/gocache/cache/metric.go:31 +0xcb
      github.com/eko/gocache/cache.TestMetricGetWhenChainCache()
          /Users/markphelps/workspace/gocache/cache/metric_test.go:83 +0x714
      testing.tRunner()
          /usr/local/Cellar/go/1.13.4/libexec/src/testing/testing.go:909 +0x199
    === RUN   TestMetricDelete
    
    Goroutine 57 (finished) created at:
      github.com/eko/gocache/cache.(*ChainCache).Get()
          /Users/markphelps/workspace/gocache/cache/chain.go:37 +0x383
      github.com/eko/gocache/cache.(*MetricCache).Get()
          /Users/markphelps/workspace/gocache/cache/metric.go:29 +0x75
      github.com/eko/gocache/cache.TestMetricGetWhenChainCache()
          /Users/markphelps/workspace/gocache/cache/metric_test.go:83 +0x714
      testing.tRunner()
          /usr/local/Cellar/go/1.13.4/libexec/src/testing/testing.go:909 +0x199
    ==================
    ==================
    WARNING: DATA RACE
    Read at 0x00c0001f6870 by goroutine 58:
      reflect.typedmemmove()
          /usr/local/Cellar/go/1.13.4/libexec/src/runtime/mbarrier.go:177 +0x0
      reflect.packEface()
          /usr/local/Cellar/go/1.13.4/libexec/src/reflect/value.go:119 +0x103
      reflect.valueInterface()
          /usr/local/Cellar/go/1.13.4/libexec/src/reflect/value.go:1033 +0x16f
      fmt.(*pp).printValue()
          /usr/local/Cellar/go/1.13.4/libexec/src/reflect/value.go:1003 +0x38f7
      fmt.(*pp).printValue()
          /usr/local/Cellar/go/1.13.4/libexec/src/fmt/print.go:869 +0xec7
      fmt.(*pp).printValue()
          /usr/local/Cellar/go/1.13.4/libexec/src/fmt/print.go:810 +0x283f
      fmt.(*pp).printValue()
          /usr/local/Cellar/go/1.13.4/libexec/src/fmt/print.go:810 +0x283f
      fmt.(*pp).printValue()
          /usr/local/Cellar/go/1.13.4/libexec/src/fmt/print.go:880 +0x25da
      fmt.(*pp).printArg()
          /usr/local/Cellar/go/1.13.4/libexec/src/fmt/print.go:716 +0x2ee
      fmt.(*pp).doPrintf()
          /usr/local/Cellar/go/1.13.4/libexec/src/fmt/print.go:1126 +0x912
      fmt.Sprintf()
          /usr/local/Cellar/go/1.13.4/libexec/src/fmt/print.go:219 +0x73
      github.com/stretchr/testify/mock.Arguments.Diff()
          /Users/markphelps/go/pkg/mod/github.com/stretchr/[email protected]/mock/mock.go:687 +0xf1a
      github.com/stretchr/testify/mock.(*Mock).findExpectedCall()
          /Users/markphelps/go/pkg/mod/github.com/stretchr/[email protected]/mock/mock.go:269 +0x16a
      github.com/stretchr/testify/mock.(*Mock).MethodCalled()
          /Users/markphelps/go/pkg/mod/github.com/stretchr/[email protected]/mock/mock.go:348 +0xb3
      github.com/stretchr/testify/mock.(*Mock).Called()
          /Users/markphelps/go/pkg/mod/github.com/stretchr/[email protected]/mock/mock.go:338 +0x1e4
      github.com/eko/gocache/test/mocks/metrics.(*MetricsInterface).RecordFromCodec()
          /Users/markphelps/workspace/gocache/test/mocks/metrics/metrics_interface.go:21 +0xaa
    
    Previous write at 0x00c0001f6870 by goroutine 57:
      github.com/stretchr/testify/mock.(*Mock).MethodCalled()
          /Users/markphelps/go/pkg/mod/github.com/stretchr/[email protected]/mock/mock.go:385 +0x775
      github.com/stretchr/testify/mock.(*Mock).Called()
          /Users/markphelps/go/pkg/mod/github.com/stretchr/[email protected]/mock/mock.go:338 +0x1e4
      github.com/eko/gocache/test/mocks/codec.(*CodecInterface).GetStore()
          /Users/markphelps/workspace/gocache/test/mocks/codec/codec_interface.go:83 +0x63
      github.com/eko/gocache/cache.(*ChainCache).setUntil()
          /Users/markphelps/workspace/gocache/cache/chain.go:90 +0x13b
    
    Goroutine 58 (running) created at:
      github.com/eko/gocache/cache.(*MetricCache).updateMetrics()
          /Users/markphelps/workspace/gocache/cache/metric.go:65 +0x1bd
      github.com/eko/gocache/cache.(*MetricCache).updateMetrics()
          /Users/markphelps/workspace/gocache/cache/metric.go:61 +0xff
      github.com/eko/gocache/cache.(*MetricCache).Get()
          /Users/markphelps/workspace/gocache/cache/metric.go:31 +0xcb
      github.com/eko/gocache/cache.TestMetricGetWhenChainCache()
          /Users/markphelps/workspace/gocache/cache/metric_test.go:83 +0x714
      testing.tRunner()
          /usr/local/Cellar/go/1.13.4/libexec/src/testing/testing.go:909 +0x199
    
    Goroutine 57 (finished) created at:
      github.com/eko/gocache/cache.(*ChainCache).Get()
          /Users/markphelps/workspace/gocache/cache/chain.go:37 +0x383
      github.com/eko/gocache/cache.(*MetricCache).Get()
          /Users/markphelps/workspace/gocache/cache/metric.go:29 +0x75
      github.com/eko/gocache/cache.TestMetricGetWhenChainCache()
          /Users/markphelps/workspace/gocache/cache/metric_test.go:83 +0x714
      testing.tRunner()
          /usr/local/Cellar/go/1.13.4/libexec/src/testing/testing.go:909 +0x199
    ==================
    --- FAIL: TestMetricDelete (0.00s)
        testing.go:853: race detected during execution of test
    === RUN   TestMetricDeleteWhenError
    --- PASS: TestMetricDeleteWhenError (0.00s)
    === RUN   TestMetricInvalidate
    ==================
    WARNING: DATA RACE
    Read at 0x00c0002dcba0 by goroutine 58:
      reflect.Value.String()
          /usr/local/Cellar/go/1.13.4/libexec/src/reflect/value.go:1845 +0x5d
      fmt.(*pp).printValue()
          /usr/local/Cellar/go/1.13.4/libexec/src/fmt/print.go:761 +0x3156
      fmt.(*pp).printValue()
          /usr/local/Cellar/go/1.13.4/libexec/src/fmt/print.go:869 +0xec7
      fmt.(*pp).printValue()
          /usr/local/Cellar/go/1.13.4/libexec/src/fmt/print.go:810 +0x283f
      fmt.(*pp).printValue()
          /usr/local/Cellar/go/1.13.4/libexec/src/fmt/print.go:869 +0xec7
      fmt.(*pp).printValue()
          /usr/local/Cellar/go/1.13.4/libexec/src/fmt/print.go:810 +0x283f
      fmt.(*pp).printValue()
          /usr/local/Cellar/go/1.13.4/libexec/src/fmt/print.go:810 +0x283f
      fmt.(*pp).printValue()
          /usr/local/Cellar/go/1.13.4/libexec/src/fmt/print.go:880 +0x25da
      fmt.(*pp).printArg()
          /usr/local/Cellar/go/1.13.4/libexec/src/fmt/print.go:716 +0x2ee
      fmt.(*pp).doPrintf()
          /usr/local/Cellar/go/1.13.4/libexec/src/fmt/print.go:1126 +0x912
      fmt.Sprintf()
          /usr/local/Cellar/go/1.13.4/libexec/src/fmt/print.go:219 +0x73
      github.com/stretchr/testify/mock.Arguments.Diff()
          /Users/markphelps/go/pkg/mod/github.com/stretchr/[email protected]/mock/mock.go:687 +0xf1a
      github.com/stretchr/testify/mock.(*Mock).findExpectedCall()
          /Users/markphelps/go/pkg/mod/github.com/stretchr/[email protected]/mock/mock.go:269 +0x16a
      github.com/stretchr/testify/mock.(*Mock).MethodCalled()
          /Users/markphelps/go/pkg/mod/github.com/stretchr/[email protected]/mock/mock.go:348 +0xb3
      github.com/stretchr/testify/mock.(*Mock).Called()
          /Users/markphelps/go/pkg/mod/github.com/stretchr/[email protected]/mock/mock.go:338 +0x1e4
      github.com/eko/gocache/test/mocks/metrics.(*MetricsInterface).RecordFromCodec()
          /Users/markphelps/workspace/gocache/test/mocks/metrics/metrics_interface.go:21 +0xaa
    
    Previous write at 0x00c0002dcba0 by goroutine 57:
      github.com/stretchr/testify/assert.CallerInfo()
          /Users/markphelps/go/pkg/mod/github.com/stretchr/[email protected]/assert/assertions.go:146 +0x3c3
      github.com/stretchr/testify/mock.(*Mock).MethodCalled()
          /Users/markphelps/go/pkg/mod/github.com/stretchr/[email protected]/mock/mock.go:385 +0x57e
      github.com/stretchr/testify/mock.(*Mock).Called()
          /Users/markphelps/go/pkg/mod/github.com/stretchr/[email protected]/mock/mock.go:338 +0x1e4
      github.com/eko/gocache/test/mocks/codec.(*CodecInterface).GetStore()
          /Users/markphelps/workspace/gocache/test/mocks/codec/codec_interface.go:83 +0x63
      github.com/eko/gocache/cache.(*ChainCache).setUntil()
          /Users/markphelps/workspace/gocache/cache/chain.go:90 +0x13b
    
    Goroutine 58 (running) created at:
      github.com/eko/gocache/cache.(*MetricCache).updateMetrics()
          /Users/markphelps/workspace/gocache/cache/metric.go:65 +0x1bd
      github.com/eko/gocache/cache.(*MetricCache).updateMetrics()
          /Users/markphelps/workspace/gocache/cache/metric.go:61 +0xff
      github.com/eko/gocache/cache.(*MetricCache).Get()
          /Users/markphelps/workspace/gocache/cache/metric.go:31 +0xcb
      github.com/eko/gocache/cache.TestMetricGetWhenChainCache()
          /Users/markphelps/workspace/gocache/cache/metric_test.go:83 +0x714
      testing.tRunner()
          /usr/local/Cellar/go/1.13.4/libexec/src/testing/testing.go:909 +0x199
    
    Goroutine 57 (finished) created at:
      github.com/eko/gocache/cache.(*ChainCache).Get()
          /Users/markphelps/workspace/gocache/cache/chain.go:37 +0x383
      github.com/eko/gocache/cache.(*MetricCache).Get()
          /Users/markphelps/workspace/gocache/cache/metric.go:29 +0x75
      github.com/eko/gocache/cache.TestMetricGetWhenChainCache()
          /Users/markphelps/workspace/gocache/cache/metric_test.go:83 +0x714
      testing.tRunner()
          /usr/local/Cellar/go/1.13.4/libexec/src/testing/testing.go:909 +0x199
    ==================
    --- FAIL: TestMetricInvalidate (0.00s)
        testing.go:853: race detected during execution of test
    ...
    FAIL
    

    After

    $ go test -v -race ./...
    
    ...
    === RUN   TestRistrettoGetType
    --- PASS: TestRistrettoGetType (0.00s)
    PASS
    ok      github.com/eko/gocache/store    (cached)
    ?       github.com/eko/gocache/test/mocks/cache [no test files]
    ?       github.com/eko/gocache/test/mocks/codec [no test files]
    ?       github.com/eko/gocache/test/mocks/metrics       [no test files]
    ?       github.com/eko/gocache/test/mocks/store [no test files]
    ?       github.com/eko/gocache/test/mocks/store/clients [no test files]
    
    opened by markphelps 4
  • Fix for applyOptionsWithDefault not keeping unmodified options

    Fix for applyOptionsWithDefault not keeping unmodified options

    I assume this was just an oversight. I was expecting that any specified options would override defaults, but unspecified options would still use the default options.

    IE:

    // Given
    defaultOptions := &Options{
    	expiration: 25 * time.Second,
    }
    
    // When
    options := applyOptionsWithDefault(defaultOptions, WithCost(7))
    
    // Then
    assert.Equal(t, int64(7), options.cost)
    assert.Equal(t, 25*time.Second, options.expiration)
    
    opened by sgtsquiggs 3
  • It's impossible to create my own cache

    It's impossible to create my own cache

    The options struct is not public, so it's not really viable to implement my own cache since I can't use the v3 Option type. Option is just a func that takes private struct as input so I can't use it in my own package. I think the options struct should be public.

    opened by wexder 3
  • Redis V8

    Redis V8

    Hi there! I'm about to upgrade redis lib to V8. I wanted to know, before I start, if there is any particular reason of using v7 instead of v8? and why the upgrade isn't done today?

    Any considerations I should know?

    Thanks in advance.

    Jose.-

    opened by josefld 3
  • remove-log: drop logging in two places

    remove-log: drop logging in two places

    • it didn't appear that logging is absolutely necessary because errors are returned
    • this can be cumbersome if you use a structured logger
    • libraries probably shouldn't write to stdout/stderr
    opened by elisarver 3
  • Do not hash key if its type is string

    Do not hash key if its type is string

    For keys that already have string type, hashing could be skipped. Reasons to do so:

    • integration tests will be easier to do mainly because the method that does the hashing is not public;
    • some cache mechanism like Redis Pub/Sub need a pattern to listen for events;
    opened by corinapurcarea 3
  • There is a bug in the Invalidate method in the redis store

    There is a bug in the Invalidate method in the redis store

    I'm not sure of the correct fix. But here is the problem

    In the setTags function of RedisStore

    You set the tag for the key like so

    s.Set(tagKey, []byte(strings.Join(cacheKeys, ",")), &Options{
    			Expiration: 720 * time.Hour,
    })
    

    Then in Invalidate function of RedisStore

    You guys do the following

    	result, err := s.Get(tagKey)
    			if err != nil {
    				fmt.Println("Didn't find tag!!")
    				return nil
    			}
    
    			var cacheKeys = []string{}
    			if bytes, ok := result.([]byte); ok {
    				cacheKeys = strings.Split(string(bytes), ",")
    			}
    
    

    You type assert the result to a []byte.

    But this assert fails because result is actually of type string

    As you can see if you look at the implementation of RedisStore Get

    func (s *RedisStore) Get(key interface{}) (interface{}, error) { return s.client.Get(key.(string)).Result() }

    But the Result function returns a (string,error)

    I think what you want is this

    func (s *RedisStore) Get(key interface{}) (interface{}, error) { return s.client.Get(key.(string)).Bytes() }

    At least this is the change I made to my local copy to get Invalidate to work.

    opened by neitzj 3
  • Rueidis Store Implementation

    Rueidis Store Implementation

    Hello! I've been using GoCache for a while, nice work! But I missed a store for Rueidis, since they are doing an amazing job implementing pipelines to connect to redis. So, I've implemented it plus a simple test and benchmark. I hope it could be a good headstart for who wants to use it as well. My initial benchmark using it, gave me impressive results already.

    BenchmarkRueidisSet
    BenchmarkRueidisSet/1
    BenchmarkRueidisSet/1-12  	    6609	    221181 ns/op
    BenchmarkRueidisSet/2
    BenchmarkRueidisSet/2-12  	    2064	    498759 ns/op
    BenchmarkRueidisSet/4
    BenchmarkRueidisSet/4-12  	    1207	   1003580 ns/op
    BenchmarkRueidisSet/8
    BenchmarkRueidisSet/8-12  	     602	   2601575 ns/op
    BenchmarkRueidisSet/16
    BenchmarkRueidisSet/16-12 	     306	   3627170 ns/op
    BenchmarkRueidisSet/32
    BenchmarkRueidisSet/32-12 	     100	  11226917 ns/op
    BenchmarkRueidisSet/64
    BenchmarkRueidisSet/64-12 	      74	  15380498 ns/op
    BenchmarkRueidisSet/128
    BenchmarkRueidisSet/128-12         	      42	  37239654 ns/op
    BenchmarkRueidisSet/256
    BenchmarkRueidisSet/256-12         	      13	  90185656 ns/op
    BenchmarkRueidisSet/512
    BenchmarkRueidisSet/512-12         	      10	 161984402 ns/op
    BenchmarkRueidisSet/1024
    BenchmarkRueidisSet/1024-12        	       5	 249825490 ns/op
    
    BenchmarkRueidisGet
    BenchmarkRueidisGet/1
    BenchmarkRueidisGet/1-12  	 1587728	       779.9 ns/op
    BenchmarkRueidisGet/2
    BenchmarkRueidisGet/2-12  	  708728	      1543 ns/op
    BenchmarkRueidisGet/4
    BenchmarkRueidisGet/4-12  	  383166	      3113 ns/op
    BenchmarkRueidisGet/8
    BenchmarkRueidisGet/8-12  	  171426	      6146 ns/op
    BenchmarkRueidisGet/16
    BenchmarkRueidisGet/16-12 	  122622	     12512 ns/op
    BenchmarkRueidisGet/32
    BenchmarkRueidisGet/32-12 	   57300	     25042 ns/op
    BenchmarkRueidisGet/64
    BenchmarkRueidisGet/64-12 	   26070	     47883 ns/op
    BenchmarkRueidisGet/128
    BenchmarkRueidisGet/128-12         	   12382	     98872 ns/op
    BenchmarkRueidisGet/256
    BenchmarkRueidisGet/256-12         	    5871	    197406 ns/op
    BenchmarkRueidisGet/512
    BenchmarkRueidisGet/512-12         	    2850	    392506 ns/op
    BenchmarkRueidisGet/1024
    BenchmarkRueidisGet/1024-12        	    1311	    810502 ns/op
    

    Commit logs:

    • client implementation
    • bench tests
    • client tests (set/get)
    opened by rwrz 1
  • Cannot write reliable tests for cache invalidation

    Cannot write reliable tests for cache invalidation

    I am testing a cache that I've written on top of eko/gocache. I need to wait for an invalidation to occur before I can move on to my next step. Currently I am waiting for the invalidation via:

    	// wait for cache invalidation
    	assert.Eventually(t, func() bool {
    		_, err = s.localStore.Get(ctx, key)
    		return err != nil
    	}, 10*time.Second, 10*time.Millisecond, "timed out waiting for local store")
    

    this loops for 10 seconds, checking every 10 milliseconds to see if the value has been ejected.

    Usually this passes, but sometimes it does not pass. I cannot figure out why this sometimes fails.

    I am using Invalidate and not Delete, so it is invalidating via the tag.

    Local store in this case is Ristretto.

    opened by sgtsquiggs 0
  • Cannot implement StoreInterface's Invalidate method

    Cannot implement StoreInterface's Invalidate method

    Cannot figure out how we're supposed to implement Invalidate since the invalidation options are private. Cannot retrieve the tags that would be passed to the function.

    opened by sgtsquiggs 3
  • bigcache GetWithTTL not supported

    bigcache GetWithTTL not supported

    The bigcache implementation of GetWithTTL is just a hard coded 0 duration but with no indication in API it will not work as intended.

    I suggest instead returning an error that lets the user know that the method is in fact not supported and it should not be relied upon.

    Current behavior:

    // GetWithTTL returns data stored from a given key and its corresponding TTL
    func (s *BigcacheStore) GetWithTTL(ctx context.Context, key any) (any, time.Duration, error) {
    	item, err := s.Get(ctx, key)
    	return item, 0, err
    }
    

    Proposed change:

    ErrNotImplemented = errors.New("Method not implemented for codec")
    
    // GetWithTTL returns data stored from a given key and its corresponding TTL
    func (s *BigcacheStore) GetWithTTL(ctx context.Context, key any) (any, time.Duration, error) {
    	return nil, 0, store.ErrNotImplemented
    }
    
    opened by melpomene 0
  • [Suggestion] Split built-in store implementations out into their own Go modules?

    [Suggestion] Split built-in store implementations out into their own Go modules?

    Having all the different built-in store implementations in the same one Go module means that their dependencies are also pulled in when using eko/gocahce.

    If the built-in implementations were moved to their own sub-modules with their own go.mod files, it would enable a much smaller dependency tree narrowed to only what you're actively using.

    This should avoid issues like #144 for everyone not actively using the Pegasus store, since they wouldn't be pulling in the pegasus client package as a dependency.

    For me this has become a bit of an issue at the moment while trying to use gocache within a custom Traefik plugin. Traefik runs plugins via Yaegi, which means you cannot have anything in the dependency tree that uses the unsafe or syscall packages.

    I'm fully aware a change like this would be a major breaking change, but I'd like to maybe get the discussion started.

    Also, if it would help, I'd be happy to take a stab at the separation myself and submit a PR.

    opened by jimeh 0
  • Suggestion for an easier interface

    Suggestion for an easier interface

    I wrote and maintain pagoda, a rapid, full-stack web development starter kit. I included gocache to provide a flexible way to handle caching that wouldn't have to be changed if you opt for a different cache provider. While I think this module is great, I found the interface to be somewhat cumbersome to deal with so I wrote a wrapper on top of it that I think turned out pretty well. Since this is something I'd like available in other projects, I thought I'd see if it's something you'd be interested in bringing in.

    Here is the overall explanation of how it works and what is available. And here is the client code that provides that.

    For quick reference, here is an example:

    err := cache.
        Set().
        Key("my-key").
        Tags("tag1", "tag2").
        Expiration(time.Hour * 2).
        Data(myData).
        Save(ctx)
    
    opened by mikestefanello 0
Releases(v3.1.2)
  • v3.1.2(Nov 10, 2022)

    What's Changed

    • Bump github.com/prometheus/client_golang from 1.12.2 to 1.13.0 by @dependabot in https://github.com/eko/gocache/pull/163
    • Bump github.com/coocood/freecache from 1.2.1 to 1.2.2 by @dependabot in https://github.com/eko/gocache/pull/164
    • Fix for applyOptionsWithDefault not keeping unmodified options by @sgtsquiggs in https://github.com/eko/gocache/pull/169
    • Bump github.com/dgraph-io/ristretto from 0.1.0 to 0.1.1 by @dependabot in https://github.com/eko/gocache/pull/170
    • Bump github.com/stretchr/testify from 1.8.0 to 1.8.1 by @dependabot in https://github.com/eko/gocache/pull/173
    • Bump github.com/coocood/freecache from 1.2.2 to 1.2.3 by @dependabot in https://github.com/eko/gocache/pull/174
    • Bump github.com/prometheus/client_golang from 1.13.0 to 1.13.1 by @dependabot in https://github.com/eko/gocache/pull/177
    • Bump github.com/prometheus/client_golang from 1.13.1 to 1.14.0 by @dependabot in https://github.com/eko/gocache/pull/179
    • chore: fixed unit tests and upgraded dependencies by @eko in https://github.com/eko/gocache/pull/180

    New Contributors

    • @sgtsquiggs made their first contribution in https://github.com/eko/gocache/pull/169

    Full Changelog: https://github.com/eko/gocache/compare/v3.1.1...v3.1.2

    Source code(tar.gz)
    Source code(zip)
  • v3.1.1(Jul 13, 2022)

    What's Changed

    • Update README.md - fixing go-redis link by @ralbt in https://github.com/eko/gocache/pull/154
    • Bump github.com/stretchr/testify from 1.7.2 to 1.7.4 by @dependabot in https://github.com/eko/gocache/pull/156
    • change style use tools gofumpt golangci-lint by @fmyxyz in https://github.com/eko/gocache/pull/155
    • Bump github.com/stretchr/testify from 1.7.4 to 1.7.5 by @dependabot in https://github.com/eko/gocache/pull/157
    • Bump github.com/stretchr/testify from 1.7.5 to 1.8.0 by @dependabot in https://github.com/eko/gocache/pull/158
    • Make store options publicly available by @eko in https://github.com/eko/gocache/pull/160

    New Contributors

    • @ralbt made their first contribution in https://github.com/eko/gocache/pull/154

    Full Changelog: https://github.com/eko/gocache/compare/v3.1.0...v3.1.1

    Source code(tar.gz)
    Source code(zip)
  • v3.1.0(Jun 14, 2022)

    What's Changed

    • Bump github.com/stretchr/testify from 1.7.1 to 1.7.2 by @dependabot in https://github.com/eko/gocache/pull/149
    • chain set to run set on all cache stores by @Ashtonian in https://github.com/eko/gocache/pull/146
    • add standard not found error by @Ashtonian in https://github.com/eko/gocache/pull/142
    • Updated error messages to be in lowercase by @eko in https://github.com/eko/gocache/pull/152

    New Contributors

    • @Ashtonian made their first contribution in https://github.com/eko/gocache/pull/146

    Full Changelog: https://github.com/eko/gocache/compare/v3.0.1...v3.1.0

    Source code(tar.gz)
    Source code(zip)
  • v3.0.1(Jun 6, 2022)

    What's Changed

    • Fix Loadable cache NPE when setting loaded value by @braginini in https://github.com/eko/gocache/pull/148

    New Contributors

    • @braginini made their first contribution in https://github.com/eko/gocache/pull/148

    Full Changelog: https://github.com/eko/gocache/compare/v3.0.0...v3.0.1

    Source code(tar.gz)
    Source code(zip)
  • v3.0.0(May 26, 2022)

    What's Changed

    • Reworked options to be variadics by @eko https://github.com/eko/gocache/pull/143
    • Added generics support by @eko in https://github.com/eko/gocache/pull/139

    This version have breaking changes in the 2 following changes:

    Reworked options

    We've updated options to use variadics instead of having a hard options argument at the end and often have to give nil.

    Instead of this:

    err := cacheManager.Set(ctx, "my-key", "my-value", nil)
    

    you will now be able to remove the nil argument:

    err := cacheManager.Set(ctx, "my-key", "my-value")
    

    and if you have some options to pass:

    err := cacheManager.Set(
        ctx,
        "my-key",
        "my-value",
        store.WithExpiration(10 * time.Second),
        store.WithTags([]string{"my-amazing-tag"}),
    )
    

    Generics support

    We have updated code base to use generics: you could still give any, such as the following:

    cacheManager := cache.New[any](redisStore)
    

    or, if you know you will store only a certain object, directly pass it:

    cacheManager := cache.New[*Book](redisStore)
    

    Full Changelog: https://github.com/eko/gocache/compare/v2.3.1...v3.0.0

    Source code(tar.gz)
    Source code(zip)
  • v2.3.1(May 22, 2022)

    What's Changed

    • Updated readme with install instructions by @coolblknerd in https://github.com/eko/gocache/pull/132
    • Bump github.com/smartystreets/assertions from 1.2.1 to 1.13.0 by @dependabot in https://github.com/eko/gocache/pull/133
    • Bump github.com/prometheus/client_golang from 1.12.1 to 1.12.2 by @dependabot in https://github.com/eko/gocache/pull/137
    • Bump github.com/spf13/cast from 1.4.1 to 1.5.0 by @dependabot in https://github.com/eko/gocache/pull/136
    • Make setTags method concurrency-safe by @Magomogo in https://github.com/eko/gocache/pull/138

    New Contributors

    • @coolblknerd made their first contribution in https://github.com/eko/gocache/pull/132
    • @Magomogo made their first contribution in https://github.com/eko/gocache/pull/138

    Full Changelog: https://github.com/eko/gocache/compare/v2.3.0...v2.3.1

    Source code(tar.gz)
    Source code(zip)
  • v2.3.0(Apr 13, 2022)

    What's Changed

    • Bump github.com/prometheus/client_golang from 1.12.0 to 1.12.1 by @dependabot in https://github.com/eko/gocache/pull/125
    • Bump github.com/coocood/freecache from 1.2.0 to 1.2.1 by @dependabot in https://github.com/eko/gocache/pull/128
    • Bump github.com/go-redis/redis/v8 from 8.11.4 to 8.11.5 by @dependabot in https://github.com/eko/gocache/pull/130
    • Bump github.com/stretchr/testify from 1.7.0 to 1.7.1 by @dependabot in https://github.com/eko/gocache/pull/129

    Full Changelog: https://github.com/eko/gocache/compare/v2.2.0...v2.3.0

    Source code(tar.gz)
    Source code(zip)
  • v2.2.0(Jan 23, 2022)

    What's Changed

    • Bump github.com/go-redis/redis/v8 from 8.9.0 to 8.10.0 by @dependabot in https://github.com/eko/gocache/pull/94
    • Bump github.com/dgraph-io/ristretto from 0.0.3 to 0.1.0 by @dependabot in https://github.com/eko/gocache/pull/95
    • mutex on codec to prevent race conditions by @coolka in https://github.com/eko/gocache/pull/97
    • Bump github.com/prometheus/client_golang from 1.10.0 to 1.11.0 by @dependabot in https://github.com/eko/gocache/pull/96
    • Bump github.com/golang/mock from 1.5.0 to 1.6.0 by @dependabot in https://github.com/eko/gocache/pull/98
    • Fix Race Condition in Memcached Store, Close Loadable to Stop Setter Routine by @terev in https://github.com/eko/gocache/pull/100
    • Bump github.com/go-redis/redis/v8 from 8.10.0 to 8.11.0 by @dependabot in https://github.com/eko/gocache/pull/102
    • Add patrickmn/go-cache to README by @Stoakes in https://github.com/eko/gocache/pull/103
    • Bump github.com/go-redis/redis/v8 from 8.11.0 to 8.11.1 by @dependabot in https://github.com/eko/gocache/pull/107
    • Bump github.com/spf13/cast from 1.3.1 to 1.4.0 by @dependabot in https://github.com/eko/gocache/pull/106
    • Bump github.com/go-redis/redis/v8 from 8.11.1 to 8.11.2 by @dependabot in https://github.com/eko/gocache/pull/108
    • fix instanciation typo by @derekperkins in https://github.com/eko/gocache/pull/110
    • Bump github.com/go-redis/redis/v8 from 8.11.2 to 8.11.3 by @dependabot in https://github.com/eko/gocache/pull/109
    • Bump github.com/spf13/cast from 1.4.0 to 1.4.1 by @dependabot in https://github.com/eko/gocache/pull/111
    • Bump github.com/go-redis/redis/v8 from 8.11.3 to 8.11.4 by @dependabot in https://github.com/eko/gocache/pull/112
    • Bumped to go 1.17 by @eko in https://github.com/eko/gocache/pull/113
    • Bump github.com/smartystreets/goconvey from 1.6.4 to 1.6.6 by @dependabot in https://github.com/eko/gocache/pull/115
    • Update LICENSE by @yashmit178 in https://github.com/eko/gocache/pull/116
    • Bump github.com/smartystreets/goconvey from 1.6.6 to 1.6.7 by @dependabot in https://github.com/eko/gocache/pull/117
    • Bump github.com/smartystreets/goconvey from 1.6.7 to 1.7.2 by @dependabot in https://github.com/eko/gocache/pull/119
    • Bump github.com/smartystreets/assertions from 1.2.0 to 1.2.1 by @dependabot in https://github.com/eko/gocache/pull/120
    • Bump github.com/coocood/freecache from 1.1.1 to 1.2.0 by @dependabot in https://github.com/eko/gocache/pull/121
    • Bump github.com/prometheus/client_golang from 1.11.0 to 1.12.0 by @dependabot in https://github.com/eko/gocache/pull/124
    • feat: Support for a key that would implement it's own key generator by @meDavidNS in https://github.com/eko/gocache/pull/123

    New Contributors

    • @coolka made their first contribution in https://github.com/eko/gocache/pull/97
    • @terev made their first contribution in https://github.com/eko/gocache/pull/100
    • @Stoakes made their first contribution in https://github.com/eko/gocache/pull/103
    • @derekperkins made their first contribution in https://github.com/eko/gocache/pull/110
    • @yashmit178 made their first contribution in https://github.com/eko/gocache/pull/116
    • @meDavidNS made their first contribution in https://github.com/eko/gocache/pull/123

    Full Changelog: https://github.com/eko/gocache/compare/v2.1.0...v2.2.0

    Source code(tar.gz)
    Source code(zip)
  • v2.1.0(Jun 1, 2021)

    What's Changed

    • Bump major version by @okhowang in https://github.com/eko/gocache/pull/93
    • Added context to loadFunction by @okhowang in https://github.com/eko/gocache/pull/92

    New Contributors

    • @okhowang made their first contribution in https://github.com/eko/gocache/pull/93

    Full Changelog: https://github.com/eko/gocache/compare/v2.0.0...v2.1.0

    Source code(tar.gz)
    Source code(zip)
  • v2.0.0(May 28, 2021)

    ⚠️ This is a new major release because of API BC break: context was added to all cache methods.

    New Features

    a61fbe3 Added context to cache methods

    Fixes

    4699aca fix: fix cacheManager use error with redis and pegasus

    Other

    b2b1571 Bump github.com/go-redis/redis/v8 from 8.8.3 to 8.9.0 4b757ae Bump github.com/go-redis/redis/v8 from 8.8.2 to 8.8.3 ef7808a Update README.md

    Source code(tar.gz)
    Source code(zip)
  • v1.2.0(May 2, 2021)

    New Features

    6f0b55f Moved from travis-ci to github actions f5dcbee feat: add apache pegasus store

    Fixes

    f2a0586 fix: rebase latest and resolve comment 6ab2bc0 fixed rediscluster_test add context.TODO() aa3f31c fixed rediscluster_test ffd7fde fix: return an error instead panic as a fallback in bigcache store

    Other

    610ce4b Upgrade to GitHub-native Dependabot 6f7b7b8 build(deps): bump github.com/go-redis/redis/v8 from 8.8.0 to 8.8.2 5efb409 docs(readme): add descriptions about how to deal with the returned error from the redis storage ddc81b3 build(deps): bump github.com/go-redis/redis/v8 from 8.7.1 to 8.8.0 afb1aba mr 39e232c 支持 github.com/patrickmn/go-cache 51d1e1a build(deps): bump github.com/prometheus/client_golang 6ff1f44 update redis client to version 8 add redis cluster client tests 26e7da1 build(deps): bump github.com/golang/mock from 1.4.4 to 1.5.0 f23aa7d update bigcache version

    Source code(tar.gz)
    Source code(zip)
  • v1.1.1(Jan 20, 2021)

    New Features

    371ff1e Using simple set redis commands to invalidate tags (#3) 203d229 Replaced the tags csv string by a hset

    Other

    601b20d Ran go mod tidy e82ef1c build(deps): bump github.com/stretchr/testify from 1.6.1 to 1.7.0 30ca7e3 build(deps): bump github.com/prometheus/client_golang 08eee2f Upgraded to go 1.15 and google.golang.org/appengine go v1.6.7

    Source code(tar.gz)
    Source code(zip)
  • v1.1.0(Nov 2, 2020)

    New Features

    a7ab8a7 Implement GetWithTTL for freecache 46a7306 implement interface function f31406a added new store (freecache) ab7dc64 propagate TTL 26e0f71 supporting ristretto ttl

    Fixes

    81bfa26 Removed strings.ToLower on cache key 8adc7b7 remove-log: drop logging in two places a3941db Do not hash key if its type is string 99d5369 fixing tests a9a0f81 doc: fix cache.Options => store.Options e3e61d7 doc: fix bigcache with wrong value type 24c4223 docs: fixed typo in README file 80c1102 Fix redis tags: redis client is returning strings

    Other

    cb3adf2 build(deps): bump github.com/prometheus/client_golang 9e5334e add test for invalid key 5579dbd more tests c36606f Added more tests 1db2250 go mod tidy b1c560c update documentation 0bc17c6 add tests for GetWithTTL 91984f7 tidy go sum 6fd2efd update documentation 0966a70 update tests 3810cba add gitignore 7f5df68 adding more test coverage 5663aac reverting proto support to give as separate PR fa5190f running go mod tidy c76d860 revert go.sum 6e3cd45 test coverage added 5f6b57c build(deps): bump github.com/golang/mock from 1.4.3 to 1.4.4 8fa11e5 build(deps): bump github.com/dgraph-io/ristretto from 0.0.2 to 0.0.3 7d3ab73 build(deps): bump github.com/prometheus/client_golang 497836c build(deps): bump github.com/prometheus/client_golang 0b50739 build(deps): bump github.com/stretchr/testify from 1.6.0 to 1.6.1 ef103e8 build(deps): bump github.com/go-redis/redis/v7 from 7.3.0 to 7.4.0 4d3fd48 build(deps): bump github.com/stretchr/testify from 1.5.1 to 1.6.0 8b9ffef build(deps): bump github.com/go-redis/redis/v7 from 7.2.0 to 7.3.0 70f9205 revert d9c5f5b test with go1.13-issue with using forks in other projects 04e814f build(deps): bump github.com/prometheus/client_golang 3a8bb97 build(deps): bump github.com/prometheus/client_golang b65b9d3 build(deps): bump github.com/golang/mock from 1.4.1 to 1.4.3 9923c46 build(deps): bump github.com/prometheus/client_golang 5ca9b93 Upgrade to go1.14 b85d8c5 build(deps): bump github.com/golang/mock from 1.4.0 to 1.4.1 79b65cf build(deps): bump github.com/go-redis/redis/v7 from 7.1.0 to 7.2.0 c798b07 build(deps): bump github.com/stretchr/testify from 1.4.0 to 1.5.1 3896b7a build(deps): bump github.com/go-redis/redis/v7 from 7.0.1 to 7.1.0 3ab560a build(deps): bump github.com/go-redis/redis/v7 1ce8623 build(deps): bump github.com/prometheus/client_golang a9fa870 build(deps): bump github.com/go-redis/redis/v7 7b615f6 build(deps): bump github.com/prometheus/client_golang 5ded7b2 build(deps): bump github.com/golang/mock from 1.3.1 to 1.4.0 f3f6db0 build(deps): bump github.com/go-redis/redis/v7 edd0dad build(deps): bump github.com/prometheus/client_golang

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Dec 8, 2019)

    New Features

    140d01b Using promauto to initialize the metric and testutil in tests 7847237 feat: added Clear() method to flush all cache data 16d5e61 docs: added some store benchmarks

    Fixes

    3b46630 fix(tests): replace mockery by gomock and fix race conditions 19c7bf8 test: rework unit tests to isolate mocks and add missing cases 0627751 style: fixed mispelling words and missing comments

    Other

    2c2e7d2 build(deps): bump github.com/coreos/etcd 871607c build(deps): bump github.com/prometheus/client_golang f9ee181 docs: updated README.md with custom cache/store interfaces 256357e doc: added codecov badge 9de424d ci: added codecov to .travis.yml

    Source code(tar.gz)
    Source code(zip)
  • v0.2.0(Oct 19, 2019)

    New Features

    ff78752 feat: added cache invalidation by tags 238e4ef feat: added cache & store delete() method

    Other

    8de72e9 Added .github files

    Source code(tar.gz)
    Source code(zip)
  • v0.1.0(Oct 15, 2019)

    New Features

    d28a9c2 feat: allow store options override in Set() method 4e751dc feat(store): added bigcache 23439ea feat(cache): added options 7f5503c feat(store): added memcache support

    Fixes

    bd0c5fb fix(README): typo in code example

    Other

    e78581a BREAKING CHANGE: renamed eko/gache to eko/gocache 41b785b docs: added README and travis.yml

    Source code(tar.gz)
    Source code(zip)
Owner
Vincent Composieux
Freelance web architect who loves code and infrastructure. Issue solver around various technologies.
Vincent Composieux
Fast in-memory key:value store/cache with TTL

MCache library go-mcache - this is a fast key:value storage. Its major advantage is that, being essentially a thread-safe . map[string]interface{} wit

O.J 86 Nov 11, 2022
Cache Slow Database Queries

Cache Slow Database Queries This package is used to cache the results of slow database queries in memory or Redis. It can be used to cache any form of

null 120 Nov 13, 2022
Golang LRU cache

golang-lru This provides the lru package which implements a fixed-size thread safe LRU cache. It is based on the cache in Groupcache. Documentation Fu

HashiCorp 3.2k Nov 27, 2022
A fast little LRU cache for Go

tinylru A fast little LRU cache. Getting Started Installing To start using tinylru, install Go and run go get: $ go get -u github.com/tidwall/tinylru

Josh Baker 126 Oct 14, 2022
A skip list of arbitrary elements that can be filtered using roaring bitmaps stored in an LRU cache

Skipfilter This package provides a data structure that combines a skiplist with a roaring bitmap cache. This library was created to efficiently filter

Kevin Burns 22 Aug 4, 2022
A threadsafe single-value cache for Go with a simple but flexible API

SVCache SVCache is a threadsafe, single-value cache with a simple but flexible API. When there is no fresh value in the cache, an attempt to retrieve

softwaretechnik.berlin 1 Jan 23, 2022
A tree like tool help you to explore data structures in your redis server

Redis-view is a tree like tool help you explore data structures in your redis server

dreamersdw 19 Mar 17, 2022
Graphoscope: a solution to access multiple independent data sources from a common UI and show data relations as a graph

Graphoscope A solution to access multiple independent data sources from a common UI and show data relations as a graph: Contains a list of by default

CERT.LV 29 May 26, 2022
Stalin sort in multiple languages!

stalin-sort Stalin sort in multiple languages, contributions are welcome! Motivation This repo is motivated by this tweet, this tweet contains a refer

CaKrome 0 Jan 14, 2022
The Go library that will drive you to AOP world!

Beyond The Golang library that will drive you to the AOP paradigm world! Check Beyond Documentation What's AOP? In computing, aspect-oriented programm

Wesovi Labs 51 Nov 24, 2022
Mapreduce - A in-process MapReduce tool to help you to optimize service response time.

mapreduce English | 简体中文 Why we have this repo? mapreduce is part of go-zero, but a few people asked if mapreduce can be used separately. But I recomm

Kevin Wan 122 Oct 15, 2022
Custom generic HTTP handler providing automatic JSON decoding/encoding of HTTP request/response to your concrete types

gap Custom generic HTTP handler providing automatic JSON decoding/encoding of HTTP request/response to your concrete types. gap.Wrap allows to use the

Ectobit 1 Aug 28, 2022
GoStruct2Table - format your struct like a table.

GoStruct2Table format your struct like a table. Installing $ go get -u -v github.com/runningzyp/GoStruct2Table Simple Example import parser "github.c

YunpengZhan 10 Aug 15, 2022
A small flexible merge library in go

conjungo A merge utility designed for flexibility and customizability. The library has a single simple point of entry that works out of the box for mo

InVision 108 Nov 24, 2022
Golang string comparison and edit distance algorithms library, featuring : Levenshtein, LCS, Hamming, Damerau levenshtein (OSA and Adjacent transpositions algorithms), Jaro-Winkler, Cosine, etc...

Go-edlib : Edit distance and string comparison library Golang string comparison and edit distance algorithms library featuring : Levenshtein, LCS, Ham

Hugo Bollon 365 Nov 20, 2022
Go native library for fast point tracking and K-Nearest queries

Geo Index Geo Index library Overview Splits the earth surface in a grid. At each cell we can store data, such as list of points, count of points, etc.

Hailo Network IP Ltd 342 Nov 19, 2022
Data structure and algorithm library for go, designed to provide functions similar to C++ STL

GoSTL English | 简体中文 Introduction GoSTL is a data structure and algorithm library for go, designed to provide functions similar to C++ STL, but more p

stirlingx 747 Nov 24, 2022
Zero allocation Nullable structures in one library with handy conversion functions, marshallers and unmarshallers

nan - No Allocations Nevermore Package nan - Zero allocation Nullable structures in one library with handy conversion functions, marshallers and unmar

Andrey Kuzmin 63 Nov 25, 2022
A Go library for an efficient implementation of a skip list: https://godoc.org/github.com/MauriceGit/skiplist

Fast Skiplist Implementation This Go-library implements a very fast and efficient Skiplist that can be used as direct substitute for a balanced tree o

Maurice Tollmien 239 Nov 25, 2022