package lrucache import ( "errors" "github.com/creachadair/cityhash" "github.com/hashicorp/golang-lru" "globalfintech/golib/tlog" "time" ) // API var ( Nil error = errors.New("cache: nil") ErrExpTime error = errors.New("args error, expTime must be > 0") dbs map[int]*lru.Cache ) func Set(key string, value interface{}) error { return SetEx(key, value, 86400) } func SetEx(key string, value interface{}, exp int) error { return setEx(key, value, exp) } func Get(key string) (interface{}, error) { return get(key) } func Del(key string) error { return del(key) } // internal func init() { if dbs == nil { dbs = make(map[int]*lru.Cache, 1024) for i := 0; i < 1024; i++ { dbs[i], _ = lru.New(3000) } } go flush() } func flush() { i := 0 for range time.NewTicker(time.Minute).C { start := time.Now() shard := i % 1024 db, _ := dbs[shard] keys := db.Keys() for _, key := range keys { if keyS, ok := key.(string); ok { getByDb(keyS, db) } } i++ tlog.Infof("FlushKey||time=%s||shard=%d||old=%d||new=%d", time.Since(start), shard, len(keys), db.Len()) } } type item struct { d interface{} t int } func setEx(key string, value interface{}, exp int) error { if exp < 1 { return ErrExpTime } db, _ := dbs[hash(key)] db.Add(key, &item{d: value, t: int(time.Now().Unix()) + exp}) return nil } func get(key string) (interface{}, error) { db, _ := dbs[hash(key)] return getByDb(key, db) } func getByDb(key string, db *lru.Cache) (interface{}, error) { if value, ok := db.Get(key); ok { if item, ok := value.(*item); ok { if item.t >= int(time.Now().Unix()) { return item.d, nil } else { delByDb(key, db) } } } return nil, Nil } func del(key string) error { db, _ := dbs[hash(key)] return delByDb(key, db) } func delByDb(key string, db *lru.Cache) error { db.Remove(key) return nil } func hash(key string) int { return int(cityhash.Hash32([]byte(key)) % 1024) }