github.com/argoproj/argo-cd/v3@v3.2.1/util/cache/inmemory.go (about)

     1  package cache
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/gob"
     7  	"fmt"
     8  	"time"
     9  
    10  	gocache "github.com/patrickmn/go-cache"
    11  )
    12  
    13  func NewInMemoryCache(expiration time.Duration) *InMemoryCache {
    14  	return &InMemoryCache{
    15  		memCache: gocache.New(expiration, 1*time.Minute),
    16  	}
    17  }
    18  
    19  func init() {
    20  	gob.Register([]any{})
    21  }
    22  
    23  // compile-time validation of adherence of the CacheClient contract
    24  var _ CacheClient = &InMemoryCache{}
    25  
    26  type InMemoryCache struct {
    27  	memCache *gocache.Cache
    28  }
    29  
    30  func (i *InMemoryCache) Set(item *Item) error {
    31  	var buf bytes.Buffer
    32  	err := gob.NewEncoder(&buf).Encode(item.Object)
    33  	if err != nil {
    34  		return err
    35  	}
    36  	if item.CacheActionOpts.DisableOverwrite {
    37  		// go-redis doesn't throw an error on Set with NX, so absorbing here to keep the interface consistent
    38  		_ = i.memCache.Add(item.Key, buf, item.CacheActionOpts.Expiration)
    39  	} else {
    40  		i.memCache.Set(item.Key, buf, item.CacheActionOpts.Expiration)
    41  	}
    42  	return nil
    43  }
    44  
    45  func (i *InMemoryCache) Rename(oldKey string, newKey string, expiration time.Duration) error {
    46  	bufIf, found := i.memCache.Get(oldKey)
    47  	if !found {
    48  		return ErrCacheMiss
    49  	}
    50  	i.memCache.Set(newKey, bufIf, expiration)
    51  	i.memCache.Delete(oldKey)
    52  	return nil
    53  }
    54  
    55  // HasSame returns true if key with the same value already present in cache
    56  func (i *InMemoryCache) HasSame(key string, obj any) (bool, error) {
    57  	var buf bytes.Buffer
    58  	err := gob.NewEncoder(&buf).Encode(obj)
    59  	if err != nil {
    60  		return false, err
    61  	}
    62  
    63  	bufIf, found := i.memCache.Get(key)
    64  	if !found {
    65  		return false, nil
    66  	}
    67  	existingBuf, ok := bufIf.(bytes.Buffer)
    68  	if !ok {
    69  		panic(fmt.Errorf("InMemoryCache has unexpected entry: %v", existingBuf))
    70  	}
    71  	return bytes.Equal(buf.Bytes(), existingBuf.Bytes()), nil
    72  }
    73  
    74  func (i *InMemoryCache) Get(key string, obj any) error {
    75  	bufIf, found := i.memCache.Get(key)
    76  	if !found {
    77  		return ErrCacheMiss
    78  	}
    79  	buf := bufIf.(bytes.Buffer)
    80  	return gob.NewDecoder(&buf).Decode(obj)
    81  }
    82  
    83  func (i *InMemoryCache) Delete(key string) error {
    84  	i.memCache.Delete(key)
    85  	return nil
    86  }
    87  
    88  func (i *InMemoryCache) Flush() {
    89  	i.memCache.Flush()
    90  }
    91  
    92  func (i *InMemoryCache) OnUpdated(_ context.Context, _ string, _ func() error) error {
    93  	return nil
    94  }
    95  
    96  func (i *InMemoryCache) NotifyUpdated(_ string) error {
    97  	return nil
    98  }
    99  
   100  // Items return a list of items in the cache; requires passing a constructor function
   101  // so that the items can be decoded from gob format.
   102  func (i *InMemoryCache) Items(createNewObject func() any) (map[string]any, error) {
   103  	result := map[string]any{}
   104  
   105  	for key, value := range i.memCache.Items() {
   106  		buf := value.Object.(bytes.Buffer)
   107  		obj := createNewObject()
   108  		err := gob.NewDecoder(&buf).Decode(obj)
   109  		if err != nil {
   110  			return nil, err
   111  		}
   112  
   113  		result[key] = obj
   114  	}
   115  
   116  	return result, nil
   117  }