add redisPool
This commit is contained in:
		
							parent
							
								
									3ca8e82637
								
							
						
					
					
						commit
						3888bcb8cd
					
				
							
								
								
									
										148
									
								
								cache.go
									
									
									
									
									
								
							
							
						
						
									
										148
									
								
								cache.go
									
									
									
									
									
								
							@ -28,17 +28,67 @@ type Getter[T any] interface {
 | 
				
			|||||||
type (
 | 
					type (
 | 
				
			||||||
	Option            any
 | 
						Option            any
 | 
				
			||||||
	optWithoutGetter  struct{}                        // for get only
 | 
						optWithoutGetter  struct{}                        // for get only
 | 
				
			||||||
 | 
						optWithRedisConn  struct{ redisconn redis.Conn }  // for set & get
 | 
				
			||||||
	optWithCreateTime struct{ createtime *time.Time } // for set & get
 | 
						optWithCreateTime struct{ createtime *time.Time } // for set & get
 | 
				
			||||||
	Options           struct {
 | 
						Options           struct {
 | 
				
			||||||
		withoutGetter  *optWithoutGetter
 | 
							withoutGetter  *optWithoutGetter
 | 
				
			||||||
		withCreateTime *optWithCreateTime
 | 
							withCreateTime *optWithCreateTime
 | 
				
			||||||
 | 
							withRedisConn  *optWithRedisConn
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func optionParser(options ...Option) (opts Options, err error) {
 | 
					type Config struct {
 | 
				
			||||||
 | 
						UseLocalCache            bool        // use localcache or not
 | 
				
			||||||
 | 
						LocalCacheLifetimeSecond int64       // local cache lifetime(t<0: forever; t=0: default; t>0: seconds)
 | 
				
			||||||
 | 
						UseRedisCache            bool        // use redis or not
 | 
				
			||||||
 | 
						RedisCacheConn           redis.Conn  // redis.Conn
 | 
				
			||||||
 | 
						RedisCacheConnPool       *redis.Pool // redis.Pool
 | 
				
			||||||
 | 
						RedisCacheKeyPrefix      string      // redis key prefix
 | 
				
			||||||
 | 
						RedisCacheLifetimeSecond int64       // redis cache lifetime(t<0: forever; t=0: default; t>0: seconds)
 | 
				
			||||||
 | 
						UseGetter                bool        // not used
 | 
				
			||||||
 | 
						GetterNoWarning          bool        // no warning if no getter
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewCache[T any](getter Getter[T], cfg Config) Cacher[T] {
 | 
				
			||||||
 | 
						var c = new(cacher[T])
 | 
				
			||||||
 | 
						// Getter
 | 
				
			||||||
 | 
						c.cfg = cfg
 | 
				
			||||||
 | 
						c.getter = getter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Local cache
 | 
				
			||||||
 | 
						if cfg.UseLocalCache {
 | 
				
			||||||
 | 
							c.localCache = new(localCacher[T])
 | 
				
			||||||
 | 
							c.localCache.cacheItems = map[string]*cacheItem[T]{}
 | 
				
			||||||
 | 
							c.localCache.cacheDuration = time.Duration(cfg.LocalCacheLifetimeSecond) * time.Second
 | 
				
			||||||
 | 
							if c.localCache.cacheDuration.Nanoseconds() == 0 {
 | 
				
			||||||
 | 
								c.localCache.cacheDuration = 60 * time.Second
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Redis cache
 | 
				
			||||||
 | 
						if cfg.UseRedisCache && (cfg.RedisCacheConn != nil || cfg.RedisCacheConnPool != nil) {
 | 
				
			||||||
 | 
							if cfg.RedisCacheKeyPrefix == "" {
 | 
				
			||||||
 | 
								panic("redis cache's key prefix must not be null")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							c.redisCache = new(redisCacher[T])
 | 
				
			||||||
 | 
							c.redisCache.rds = cfg.RedisCacheConn
 | 
				
			||||||
 | 
							c.redisCache.rdsPool = cfg.RedisCacheConnPool
 | 
				
			||||||
 | 
							c.redisCache.cacheDuration = time.Duration(cfg.RedisCacheLifetimeSecond) * time.Second
 | 
				
			||||||
 | 
							c.redisCache.cachePrefix = fmt.Sprintf("%s-cache-id:", cfg.RedisCacheKeyPrefix)
 | 
				
			||||||
 | 
							if c.redisCache.cacheDuration.Nanoseconds() == 0 {
 | 
				
			||||||
 | 
								c.redisCache.cacheDuration = 180 * time.Second
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else if cfg.UseRedisCache {
 | 
				
			||||||
 | 
							panic("want to user redis cache, but redis.Conn is nil")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return c
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func optionParser(options ...Option) (opts Options) {
 | 
				
			||||||
	var l = len(options)
 | 
						var l = len(options)
 | 
				
			||||||
	if l == 0 {
 | 
						if l == 0 {
 | 
				
			||||||
		return opts, nil
 | 
							return opts
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	//TODO: add i out of range & options[i] type mismatch panic recover
 | 
						//TODO: add i out of range & options[i] type mismatch panic recover
 | 
				
			||||||
	for i := 0; i < l; i++ {
 | 
						for i := 0; i < l; i++ {
 | 
				
			||||||
@ -50,11 +100,15 @@ func optionParser(options ...Option) (opts Options, err error) {
 | 
				
			|||||||
			opts.withCreateTime = new(optWithCreateTime)
 | 
								opts.withCreateTime = new(optWithCreateTime)
 | 
				
			||||||
			i++
 | 
								i++
 | 
				
			||||||
			opts.withCreateTime.createtime = options[i].(*time.Time)
 | 
								opts.withCreateTime.createtime = options[i].(*time.Time)
 | 
				
			||||||
 | 
							case optWithRedisConn:
 | 
				
			||||||
 | 
								opts.withRedisConn = new(optWithRedisConn)
 | 
				
			||||||
 | 
								i++
 | 
				
			||||||
 | 
								opts.withRedisConn.redisconn = options[i].(redis.Conn)
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			panic("unreachable code, maybe miss some code modification")
 | 
								panic("unreachable code, maybe miss some code modification")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return opts, nil
 | 
						return opts
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func isOptWithCreateTimeForSetter(opts Options) bool {
 | 
					func isOptWithCreateTimeForSetter(opts Options) bool {
 | 
				
			||||||
@ -79,52 +133,6 @@ func isOptWithCreateTimeForGetter(opts Options) bool {
 | 
				
			|||||||
	return createtime.IsZero()
 | 
						return createtime.IsZero()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Config struct {
 | 
					 | 
				
			||||||
	UseLocalCache            bool       // use localcache or not
 | 
					 | 
				
			||||||
	LocalCacheLifetimeSecond int64      // local cache lifetime(t<0: forever; t=0: default; t>0: seconds)
 | 
					 | 
				
			||||||
	UseRedisCache            bool       // use redis or not
 | 
					 | 
				
			||||||
	RedisCacheConn           redis.Conn // redis.Conn
 | 
					 | 
				
			||||||
	RedisCacheKeyPrefix      string     // redis key prefix
 | 
					 | 
				
			||||||
	RedisCacheLifetimeSecond int64      // redis cache lifetime(t<0: forever; t=0: default; t>0: seconds)
 | 
					 | 
				
			||||||
	UseGetter                bool       // not used
 | 
					 | 
				
			||||||
	GetterNoWarning          bool       // no warning if no getter
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func NewCache[T any](getter Getter[T], cfg Config) Cacher[T] {
 | 
					 | 
				
			||||||
	var c = new(cacher[T])
 | 
					 | 
				
			||||||
	// Getter
 | 
					 | 
				
			||||||
	c.cfg = cfg
 | 
					 | 
				
			||||||
	c.getter = getter
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Local cache
 | 
					 | 
				
			||||||
	if cfg.UseLocalCache {
 | 
					 | 
				
			||||||
		c.localCache = new(localCacher[T])
 | 
					 | 
				
			||||||
		c.localCache.cacheItems = map[string]*cacheItem[T]{}
 | 
					 | 
				
			||||||
		c.localCache.cacheDuration = time.Duration(cfg.LocalCacheLifetimeSecond) * time.Second
 | 
					 | 
				
			||||||
		if c.localCache.cacheDuration.Nanoseconds() == 0 {
 | 
					 | 
				
			||||||
			c.localCache.cacheDuration = 60 * time.Second
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Redis cache
 | 
					 | 
				
			||||||
	if cfg.UseRedisCache && cfg.RedisCacheConn != nil {
 | 
					 | 
				
			||||||
		if cfg.RedisCacheKeyPrefix == "" {
 | 
					 | 
				
			||||||
			panic("redis cache's key prefix must not be null")
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		c.redisCache = new(redisCacher[T])
 | 
					 | 
				
			||||||
		c.redisCache.rds = cfg.RedisCacheConn
 | 
					 | 
				
			||||||
		c.redisCache.cacheDuration = time.Duration(cfg.RedisCacheLifetimeSecond) * time.Second
 | 
					 | 
				
			||||||
		c.redisCache.cachePrefix = fmt.Sprintf("%s-cache-id:", cfg.RedisCacheKeyPrefix)
 | 
					 | 
				
			||||||
		if c.redisCache.cacheDuration.Nanoseconds() == 0 {
 | 
					 | 
				
			||||||
			c.redisCache.cacheDuration = 180 * time.Second
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else if cfg.UseRedisCache {
 | 
					 | 
				
			||||||
		panic("want to user redis cache, but redis.Conn is nil")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return c
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type cacheItem[T any] struct {
 | 
					type cacheItem[T any] struct {
 | 
				
			||||||
	Data       *T        `json:"d"` //cache data
 | 
						Data       *T        `json:"d"` //cache data
 | 
				
			||||||
	CreateTime time.Time `json:"t"` //cache create time
 | 
						CreateTime time.Time `json:"t"` //cache create time
 | 
				
			||||||
@ -137,6 +145,7 @@ type localCacher[T any] struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
type redisCacher[T any] struct {
 | 
					type redisCacher[T any] struct {
 | 
				
			||||||
	rds           redis.Conn
 | 
						rds           redis.Conn
 | 
				
			||||||
 | 
						rdsPool       *redis.Pool
 | 
				
			||||||
	cachePrefix   string
 | 
						cachePrefix   string
 | 
				
			||||||
	cacheDuration time.Duration
 | 
						cacheDuration time.Duration
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -164,8 +173,8 @@ func (c *localCacher[T]) GetFromCache(id string, options ...Option) (t *T, err e
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	opt, err := optionParser(options...)
 | 
						var opt = optionParser(options...)
 | 
				
			||||||
	if err == nil && isOptWithCreateTimeForGetter(opt) {
 | 
						if isOptWithCreateTimeForGetter(opt) {
 | 
				
			||||||
		*opt.withCreateTime.createtime = a.CreateTime
 | 
							*opt.withCreateTime.createtime = a.CreateTime
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -173,9 +182,9 @@ func (c *localCacher[T]) GetFromCache(id string, options ...Option) (t *T, err e
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *localCacher[T]) SetIntoCache(id string, t *T, options ...Option) (err error) {
 | 
					func (c *localCacher[T]) SetIntoCache(id string, t *T, options ...Option) (err error) {
 | 
				
			||||||
 | 
						var opt = optionParser(options...)
 | 
				
			||||||
	var newitem = &cacheItem[T]{Data: t}
 | 
						var newitem = &cacheItem[T]{Data: t}
 | 
				
			||||||
	opt, err := optionParser(options...)
 | 
						if isOptWithCreateTimeForSetter(opt) {
 | 
				
			||||||
	if err == nil && isOptWithCreateTimeForSetter(opt) {
 | 
					 | 
				
			||||||
		newitem.CreateTime = *opt.withCreateTime.createtime
 | 
							newitem.CreateTime = *opt.withCreateTime.createtime
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		newitem.CreateTime = time.Now()
 | 
							newitem.CreateTime = time.Now()
 | 
				
			||||||
@ -186,11 +195,20 @@ func (c *localCacher[T]) SetIntoCache(id string, t *T, options ...Option) (err e
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (c *redisCacher[T]) GetFromCache(id string, options ...Option) (*T, error) {
 | 
					func (c *redisCacher[T]) GetFromCache(id string, options ...Option) (*T, error) {
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
		rds              = c.rds
 | 
							err        error      = nil
 | 
				
			||||||
 | 
							rds        redis.Conn = nil
 | 
				
			||||||
 | 
							opt                   = optionParser(options...)
 | 
				
			||||||
		redisKey              = c.cachePrefix + id
 | 
							redisKey              = c.cachePrefix + id
 | 
				
			||||||
		redisValue            = ""
 | 
							redisValue            = ""
 | 
				
			||||||
		err        error = nil
 | 
					 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
 | 
						if opt.withRedisConn != nil && opt.withRedisConn.redisconn != nil {
 | 
				
			||||||
 | 
							rds = opt.withRedisConn.redisconn
 | 
				
			||||||
 | 
						} else if c.rdsPool != nil {
 | 
				
			||||||
 | 
							rds = c.rdsPool.Get()
 | 
				
			||||||
 | 
							defer rds.Close()
 | 
				
			||||||
 | 
						} else if c.rds != nil {
 | 
				
			||||||
 | 
							rds = c.rds
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Step 1. read from redis
 | 
						// Step 1. read from redis
 | 
				
			||||||
	if redisValue, err = redis.String(rds.Do("GET", redisKey)); err != nil {
 | 
						if redisValue, err = redis.String(rds.Do("GET", redisKey)); err != nil {
 | 
				
			||||||
@ -215,8 +233,7 @@ func (c *redisCacher[T]) GetFromCache(id string, options ...Option) (*T, error)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Step 4. get cache creattime if need
 | 
						// Step 4. get cache creattime if need
 | 
				
			||||||
	opt, err := optionParser(options...)
 | 
						if isOptWithCreateTimeForGetter(opt) {
 | 
				
			||||||
	if err == nil && isOptWithCreateTimeForGetter(opt) {
 | 
					 | 
				
			||||||
		*opt.withCreateTime.createtime = a.CreateTime
 | 
							*opt.withCreateTime.createtime = a.CreateTime
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -225,16 +242,25 @@ func (c *redisCacher[T]) GetFromCache(id string, options ...Option) (*T, error)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (c *redisCacher[T]) SetIntoCache(id string, t *T, options ...Option) error {
 | 
					func (c *redisCacher[T]) SetIntoCache(id string, t *T, options ...Option) error {
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
		opt, _           = optionParser(options...)
 | 
							opt                   = optionParser(options...)
 | 
				
			||||||
		rds              = c.rds
 | 
							rds        redis.Conn = nil
 | 
				
			||||||
		redisKey              = c.cachePrefix + id
 | 
							redisKey              = c.cachePrefix + id
 | 
				
			||||||
		redisValue            = []byte{}
 | 
							redisValue            = []byte{}
 | 
				
			||||||
		err        error      = nil
 | 
							err        error      = nil
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
 | 
						// Step 0. redis.Conn
 | 
				
			||||||
 | 
						if opt.withRedisConn != nil && opt.withRedisConn.redisconn != nil {
 | 
				
			||||||
 | 
							rds = opt.withRedisConn.redisconn
 | 
				
			||||||
 | 
						} else if c.rdsPool != nil {
 | 
				
			||||||
 | 
							rds = c.rdsPool.Get()
 | 
				
			||||||
 | 
							defer rds.Close()
 | 
				
			||||||
 | 
						} else if c.rds != nil {
 | 
				
			||||||
 | 
							rds = c.rds
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Step 1. encode  to string
 | 
						// Step 1. encode  to string
 | 
				
			||||||
	var a = cacheItem[T]{Data: t}
 | 
						var a = cacheItem[T]{Data: t}
 | 
				
			||||||
	if err == nil && isOptWithCreateTimeForSetter(opt) {
 | 
						if isOptWithCreateTimeForSetter(opt) {
 | 
				
			||||||
		a.CreateTime = *opt.withCreateTime.createtime
 | 
							a.CreateTime = *opt.withCreateTime.createtime
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		a.CreateTime = time.Now()
 | 
							a.CreateTime = time.Now()
 | 
				
			||||||
@ -259,7 +285,7 @@ func (c *cacher[T]) GetFromCache(id string, options ...Option) (dat *T, err erro
 | 
				
			|||||||
		return nil, ErrNotFound
 | 
							return nil, ErrNotFound
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var opt, _ = optionParser(options...)
 | 
						var opt = optionParser(options...)
 | 
				
			||||||
	// Step 2. get from [local]
 | 
						// Step 2. get from [local]
 | 
				
			||||||
	if c.localCache != nil {
 | 
						if c.localCache != nil {
 | 
				
			||||||
		if dat, err := c.localCache.GetFromCache(id, options...); err == nil {
 | 
							if dat, err := c.localCache.GetFromCache(id, options...); err == nil {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user