github.com/binbinly/pkg@v0.0.11-0.20240321014439-f4fbf666eb0f/cache/memory.go (about)

     1  package cache
     2  
     3  import (
     4  	"context"
     5  	"reflect"
     6  	"time"
     7  
     8  	"github.com/dgraph-io/ristretto"
     9  	"github.com/pkg/errors"
    10  )
    11  
    12  type memoryCache struct {
    13  	client *ristretto.Cache
    14  	opts   Options
    15  }
    16  
    17  // NewMemoryCache create a memory cache
    18  func NewMemoryCache(opts ...Option) Cache {
    19  	o := NewOptions(opts...)
    20  	// see: https://dgraph.io/blog/post/introducing-ristretto-high-perf-go-cache/
    21  	//		https://www.start.io/blog/we-chose-ristretto-cache-for-go-heres-why/
    22  	config := &ristretto.Config{
    23  		NumCounters: 1e7,     // number of keys to track frequency of (10M).
    24  		MaxCost:     1 << 30, // maximum cost of cache (1GB).
    25  		BufferItems: 64,      // number of keys per Get buffer.
    26  	}
    27  	store, _ := ristretto.NewCache(config)
    28  	return &memoryCache{
    29  		client: store,
    30  		opts:   o,
    31  	}
    32  }
    33  
    34  // Set add cache
    35  func (m *memoryCache) Set(ctx context.Context, key string, val any, expiration time.Duration) error {
    36  	buf, err := m.opts.codec.Marshal(val)
    37  	if err != nil {
    38  		return errors.Wrapf(err, "[cache.menery] marshal data err, value is %+v", val)
    39  	}
    40  	cacheKey, err := BuildCacheKey(m.opts.prefix, key)
    41  	if err != nil {
    42  		return err
    43  	}
    44  	m.client.SetWithTTL(cacheKey, buf, 0, expiration)
    45  	return nil
    46  }
    47  
    48  // Get data
    49  func (m *memoryCache) Get(ctx context.Context, key string, val any) error {
    50  	cacheKey, err := BuildCacheKey(m.opts.prefix, key)
    51  	if err != nil {
    52  		return err
    53  	}
    54  	data, ok := m.client.Get(cacheKey)
    55  	if !ok {
    56  		return nil
    57  	}
    58  	if data == NotFoundPlaceholder {
    59  		return ErrPlaceholder
    60  	}
    61  
    62  	if err = m.opts.codec.Unmarshal(data.([]byte), val); err != nil {
    63  		return errors.Wrapf(err, "unmarshal data error, key=%s, cacheKey=%s type=%v, json is %+v ",
    64  			key, cacheKey, reflect.TypeOf(val), string(data.([]byte)))
    65  	}
    66  	return nil
    67  }
    68  
    69  // Del 删除
    70  func (m *memoryCache) Del(ctx context.Context, keys ...string) error {
    71  	if len(keys) == 0 {
    72  		return nil
    73  	}
    74  
    75  	key := keys[0]
    76  	cacheKey, err := BuildCacheKey(m.opts.prefix, key)
    77  	if err != nil {
    78  		return err
    79  	}
    80  	m.client.Del(cacheKey)
    81  	return nil
    82  }
    83  
    84  // MultiSet 批量set
    85  func (m *memoryCache) MultiSet(ctx context.Context, valMap map[string]any, expiration time.Duration) error {
    86  	panic("implement me")
    87  }
    88  
    89  // MultiGet 批量获取
    90  func (m *memoryCache) MultiGet(ctx context.Context, keys []string, valueMap any, newObject func() any) error {
    91  	panic("implement me")
    92  }
    93  
    94  func (m *memoryCache) SetCacheWithNotFound(ctx context.Context, key string) error {
    95  	if m.client.Set(key, NotFoundPlaceholder, int64(DefaultNotFoundExpireTime)) {
    96  		return nil
    97  	}
    98  	return ErrSetMemoryWithNotFound
    99  }