2020-04-06 19:57:19 +08:00
|
|
|
package lrucache
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"errors"
|
|
|
|
|
"github.com/creachadair/cityhash"
|
|
|
|
|
"github.com/hashicorp/golang-lru"
|
2020-04-16 00:49:26 +08:00
|
|
|
"unitech/golib/tlog"
|
2020-04-06 19:57:19 +08:00
|
|
|
"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)
|
|
|
|
|
}
|