Initial commit
This commit is contained in:
122
cache/cache.go
vendored
Normal file
122
cache/cache.go
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/creachadair/cityhash"
|
||||
"globalfintech/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)))
|
||||
}
|
||||
88
cache/cache_test.go
vendored
Normal file
88
cache/cache_test.go
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type T struct {
|
||||
A int
|
||||
B string
|
||||
}
|
||||
|
||||
func TestSet(t *testing.T) {
|
||||
err := Set("test", "test")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
value, err := Get("test")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Println(value.(string))
|
||||
}
|
||||
|
||||
func TestStruct(t *testing.T) {
|
||||
err := Set("struct", T{A: 1, B: "testtest"})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
value1, err := Get("struct")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("%+v\n", value1.(T))
|
||||
}
|
||||
|
||||
func TestStruct1(t *testing.T) {
|
||||
err := Set("struct", &T{A: 1, B: "testtest"})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
value1, err := Get("struct")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("%+v\n", value1.(*T))
|
||||
}
|
||||
|
||||
func TestDel(t *testing.T) {
|
||||
err := Del("test")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
value, err := Get("test")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Println(value.(string))
|
||||
}
|
||||
|
||||
func TestSetEx(t *testing.T) {
|
||||
err := SetEx("testex", []byte("testex"), 2)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
valueEx, err := Get("testex")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Println(valueEx.([]byte))
|
||||
time.Sleep(3 * time.Second)
|
||||
valueEx, err = Get("testex")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Println(valueEx.([]byte))
|
||||
}
|
||||
Reference in New Issue
Block a user