123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- package gcache
- import (
- "errors"
- "fmt"
- "sync"
- "time"
- )
- const (
- TYPE_SIMPLE = "simple"
- TYPE_LRU = "lru"
- TYPE_LFU = "lfu"
- TYPE_ARC = "arc"
- )
- var KeyNotFoundError = errors.New("Key not found.")
- type Cache interface {
- Set(interface{}, interface{}) error
- SetWithExpire(interface{}, interface{}, time.Duration) error
- Get(interface{}) (interface{}, error)
- GetIFPresent(interface{}) (interface{}, error)
- GetALL() map[interface{}]interface{}
- get(interface{}, bool) (interface{}, error)
- Remove(interface{}) bool
- Purge()
- Keys() []interface{}
- Len() int
- statsAccessor
- }
- type baseCache struct {
- clock Clock
- size int
- loaderExpireFunc LoaderExpireFunc
- evictedFunc EvictedFunc
- purgeVisitorFunc PurgeVisitorFunc
- addedFunc AddedFunc
- deserializeFunc DeserializeFunc
- serializeFunc SerializeFunc
- expiration *time.Duration
- mu sync.RWMutex
- loadGroup Group
- *stats
- }
- type (
- LoaderFunc func(interface{}) (interface{}, error)
- LoaderExpireFunc func(interface{}) (interface{}, *time.Duration, error)
- EvictedFunc func(interface{}, interface{})
- PurgeVisitorFunc func(interface{}, interface{})
- AddedFunc func(interface{}, interface{})
- DeserializeFunc func(interface{}, interface{}) (interface{}, error)
- SerializeFunc func(interface{}, interface{}) (interface{}, error)
- )
- type CacheBuilder struct {
- clock Clock
- tp string
- size int
- loaderExpireFunc LoaderExpireFunc
- evictedFunc EvictedFunc
- purgeVisitorFunc PurgeVisitorFunc
- addedFunc AddedFunc
- expiration *time.Duration
- deserializeFunc DeserializeFunc
- serializeFunc SerializeFunc
- }
- func New(size int) *CacheBuilder {
- return &CacheBuilder{
- clock: NewRealClock(),
- tp: TYPE_SIMPLE,
- size: size,
- }
- }
- func (cb *CacheBuilder) Clock(clock Clock) *CacheBuilder {
- cb.clock = clock
- return cb
- }
- // Set a loader function.
- // loaderFunc: create a new value with this function if cached value is expired.
- func (cb *CacheBuilder) LoaderFunc(loaderFunc LoaderFunc) *CacheBuilder {
- cb.loaderExpireFunc = func(k interface{}) (interface{}, *time.Duration, error) {
- v, err := loaderFunc(k)
- return v, nil, err
- }
- return cb
- }
- // Set a loader function with expiration.
- // loaderExpireFunc: create a new value with this function if cached value is expired.
- // If nil returned instead of time.Duration from loaderExpireFunc than value will never expire.
- func (cb *CacheBuilder) LoaderExpireFunc(loaderExpireFunc LoaderExpireFunc) *CacheBuilder {
- cb.loaderExpireFunc = loaderExpireFunc
- return cb
- }
- func (cb *CacheBuilder) EvictType(tp string) *CacheBuilder {
- cb.tp = tp
- return cb
- }
- func (cb *CacheBuilder) Simple() *CacheBuilder {
- return cb.EvictType(TYPE_SIMPLE)
- }
- func (cb *CacheBuilder) LRU() *CacheBuilder {
- return cb.EvictType(TYPE_LRU)
- }
- func (cb *CacheBuilder) LFU() *CacheBuilder {
- return cb.EvictType(TYPE_LFU)
- }
- func (cb *CacheBuilder) ARC() *CacheBuilder {
- return cb.EvictType(TYPE_ARC)
- }
- func (cb *CacheBuilder) EvictedFunc(evictedFunc EvictedFunc) *CacheBuilder {
- cb.evictedFunc = evictedFunc
- return cb
- }
- func (cb *CacheBuilder) PurgeVisitorFunc(purgeVisitorFunc PurgeVisitorFunc) *CacheBuilder {
- cb.purgeVisitorFunc = purgeVisitorFunc
- return cb
- }
- func (cb *CacheBuilder) AddedFunc(addedFunc AddedFunc) *CacheBuilder {
- cb.addedFunc = addedFunc
- return cb
- }
- func (cb *CacheBuilder) DeserializeFunc(deserializeFunc DeserializeFunc) *CacheBuilder {
- cb.deserializeFunc = deserializeFunc
- return cb
- }
- func (cb *CacheBuilder) SerializeFunc(serializeFunc SerializeFunc) *CacheBuilder {
- cb.serializeFunc = serializeFunc
- return cb
- }
- func (cb *CacheBuilder) Expiration(expiration time.Duration) *CacheBuilder {
- cb.expiration = &expiration
- return cb
- }
- func (cb *CacheBuilder) Build() Cache {
- if cb.size <= 0 && cb.tp != TYPE_SIMPLE {
- panic("gcache: Cache size <= 0")
- }
- return cb.build()
- }
- func (cb *CacheBuilder) build() Cache {
- switch cb.tp {
- case TYPE_SIMPLE:
- return newSimpleCache(cb)
- case TYPE_LRU:
- return newLRUCache(cb)
- case TYPE_LFU:
- return newLFUCache(cb)
- case TYPE_ARC:
- return newARC(cb)
- default:
- panic("gcache: Unknown type " + cb.tp)
- }
- }
- func buildCache(c *baseCache, cb *CacheBuilder) {
- c.clock = cb.clock
- c.size = cb.size
- c.loaderExpireFunc = cb.loaderExpireFunc
- c.expiration = cb.expiration
- c.addedFunc = cb.addedFunc
- c.deserializeFunc = cb.deserializeFunc
- c.serializeFunc = cb.serializeFunc
- c.evictedFunc = cb.evictedFunc
- c.purgeVisitorFunc = cb.purgeVisitorFunc
- c.stats = &stats{}
- }
- // load a new value using by specified key.
- func (c *baseCache) load(key interface{}, cb func(interface{}, *time.Duration, error) (interface{}, error), isWait bool) (interface{}, bool, error) {
- v, called, err := c.loadGroup.Do(key, func() (v interface{}, e error) {
- defer func() {
- if r := recover(); r != nil {
- e = fmt.Errorf("Loader panics: %v", r)
- }
- }()
- return cb(c.loaderExpireFunc(key))
- }, isWait)
- if err != nil {
- return nil, called, err
- }
- return v, called, nil
- }
|