github.com/angenalZZZ/gofunc@v0.0.0-20210507121333-48ff1be3917b/data/cache/chain.go (about)

     1  package cache
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/angenalZZZ/gofunc/data/cache/store"
     6  	"github.com/angenalZZZ/gofunc/f"
     7  	"github.com/panjf2000/ants/v2"
     8  	"time"
     9  )
    10  
    11  const (
    12  	// ChainType represents the chain cache type as a string value
    13  	ChainType = "chain"
    14  )
    15  
    16  // chainKeyValue transport in the channel
    17  type chainKeyValue struct {
    18  	idx     int
    19  	key     string
    20  	value   interface{}
    21  	options *store.Options
    22  }
    23  
    24  // ChainCache represents the configuration needed by a cache aggregator
    25  type ChainCache struct {
    26  	caches []StorageInterface
    27  	pool   *ants.PoolWithFunc
    28  }
    29  
    30  // NewChain create a new cache aggregator
    31  func NewChain(caches ...StorageInterface) *ChainCache {
    32  	chain := &ChainCache{caches: caches}
    33  
    34  	chain.pool, _ = ants.NewPoolWithFunc(100000, func(payload interface{}) {
    35  		if payload == nil {
    36  			return
    37  		}
    38  		if set, ok := payload.(*chainKeyValue); ok {
    39  			_ = chain.caches[set.idx].Set(set.key, set.value, set.options)
    40  		}
    41  	}, ants.WithOptions(ants.Options{
    42  		ExpiryDuration:   ants.DefaultCleanIntervalTime,
    43  		PreAlloc:         true,
    44  		Nonblocking:      true,
    45  		MaxBlockingTasks: 0,
    46  		PanicHandler: func(err interface{}) {
    47  			_ = fmt.Errorf(" GoHttpHandle/worker: %s\n %v", f.Now().LocalTimeString(), err)
    48  		},
    49  	}))
    50  	return chain
    51  }
    52  
    53  // Get returns the value stored in cache if it exists
    54  func (c *ChainCache) Get(key string) (value interface{}, err error) {
    55  	for i, cache := range c.caches {
    56  		value, err = cache.Get(key)
    57  		if err == nil {
    58  			// Set the value back until this cache layer
    59  			if i == 0 {
    60  				return value, nil
    61  			}
    62  			option, err := cache.TTL(key)
    63  			if err != nil {
    64  				return value, nil
    65  			}
    66  			for ; i >= 0; i-- {
    67  				if err = c.pool.Invoke(&chainKeyValue{
    68  					idx:   i,
    69  					key:   key,
    70  					value: value,
    71  					options: &store.Options{
    72  						Expiration: option,
    73  					},
    74  				}); err != nil {
    75  					_ = fmt.Errorf("unable to set item into cache with store '%s': %v", cache.GetCodec().GetStore().GetType(), err)
    76  					continue
    77  				}
    78  			}
    79  			return value, nil
    80  		}
    81  	}
    82  	return
    83  }
    84  
    85  // Set sets a value in available caches
    86  func (c *ChainCache) Set(key string, value interface{}, options *store.Options) error {
    87  	for i, cache := range c.caches {
    88  		if i == 0 && options.Async == false {
    89  			err := cache.Set(key, value, options)
    90  			if err != nil {
    91  				storeType := cache.GetCodec().GetStore().GetType()
    92  				return fmt.Errorf("unable to set item into cache with store '%s': %v", storeType, err)
    93  			}
    94  		} else {
    95  			if err := c.pool.Invoke(&chainKeyValue{
    96  				idx:     i,
    97  				key:     key,
    98  				value:   value,
    99  				options: options,
   100  			}); err != nil {
   101  				storeType := cache.GetCodec().GetStore().GetType()
   102  				return fmt.Errorf("unable to set item into cache with store '%s': %v", storeType, err)
   103  			}
   104  		}
   105  	}
   106  	return nil
   107  }
   108  
   109  // Delete removes a value from all available caches
   110  func (c *ChainCache) Delete(key string) error {
   111  	for _, cache := range c.caches {
   112  		_ = cache.Delete(key)
   113  	}
   114  	return nil
   115  }
   116  
   117  // TTL returns an expiration time
   118  func (c *ChainCache) TTL(key string) (time.Duration, error) {
   119  	return c.caches[len(c.caches)-1].TTL(key)
   120  }
   121  
   122  // Invalidate invalidates cache item from given options
   123  func (c *ChainCache) Invalidate(options store.InvalidateOptions) error {
   124  	for _, cache := range c.caches {
   125  		_ = cache.Invalidate(options)
   126  	}
   127  	return nil
   128  }
   129  
   130  // Clear resets all cache data
   131  func (c *ChainCache) Clear() error {
   132  	c.pool.Release()
   133  	for _, cache := range c.caches {
   134  		_ = cache.Clear()
   135  	}
   136  	c.pool.Reboot()
   137  	return nil
   138  }
   139  
   140  // GetCaches returns all chain caches
   141  func (c *ChainCache) GetCaches() []StorageInterface {
   142  	return c.caches
   143  }
   144  
   145  // GetType returns the cache type
   146  func (c *ChainCache) GetType() string {
   147  	return ChainType
   148  }