package cache import ( "errors" "github.com/creachadair/cityhash" "gitlab.com/unitechdev/golib/tlog" "sync" "time" ) //API var Nil error = errors.New("cache: nil") 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 var dbs map[byte]*db type db struct { m map[string]*item t time.Duration sync.RWMutex } type item struct { t int d interface{} } func init() { if dbs == nil { dbs = make(map[byte]*db, 256) for i := 0; i <= 255; i++ { dbs[byte(i)] = newdb(time.Duration(3600+i) * time.Second) } } } func newdb(t time.Duration) *db { ret := &db{ t: t, m: make(map[string]*item), } go ret.flush() return ret } //定期扫描过期的key func (this *db) flush() { for range time.NewTicker(this.t).C { this.doflush() } } func (this *db) doflush() { start := time.Now() tt := int(start.Unix()) var i, j int this.Lock() for key, item := range this.m { i++ if item.t != 0 && item.t < tt { j++ delete(this.m, key) } } this.Unlock() tlog.Infof("FlushCacheKey||Totoal=%d||Expired=%d||t=%s", i, j, time.Since(start)) } func setEx(key string, value interface{}, exp int) error { if exp <= 0 { return errors.New("args error, expTime must be > 0") } db, _ := dbs[hash(key)] db.Lock() db.m[key] = &item{ d: value, t: int(time.Now().Unix()) + exp} db.Unlock() return nil } func get(key string) (interface{}, error) { db, _ := dbs[hash(key)] db.RLock() item, ok := db.m[key] db.RUnlock() if ok { if item.t >= int(time.Now().Unix()) { return item.d, nil } del(key) } return nil, Nil } func del(key string) error { db, _ := dbs[hash(key)] db.Lock() delete(db.m, key) db.Unlock() return nil } func hash(key string) byte { return byte(cityhash.Hash32([]byte(key))) }