소스 검색

添加缓存接口 待测试

yjp 2 주 전
부모
커밋
75bd72387c

+ 9 - 0
framework/core/infrastructure/cache/cache.go

@@ -30,6 +30,15 @@ type Cache interface {
 
 	// Clear 清除缓存
 	Clear() error
+
+	// Expire 使用秒数设置key的过期时间
+	Expire(key string, expireSec int64) error
+
+	// ExpireTime 获取过期秒数
+	ExpireTime(key string) (int64, error)
+
+	// TTL 获取过期剩余秒数
+	TTL(key string) (int64, error)
 }
 
 // Set 设置缓存值

+ 85 - 20
framework/core/infrastructure/cache/local/local.go

@@ -1,16 +1,23 @@
 package local
 
 import (
+	"github.com/pkg/errors"
 	"strings"
 	"sync"
 	"time"
 )
 
+type valueItem struct {
+	value           string
+	expireStartTime time.Time
+	expireSec       int64
+}
+
 type Cache struct {
 	namespace                      string
 	syncMap                        *sync.Map
 	expireRoutineDoneChannelsMutex *sync.Mutex
-	expireRoutineDoneChannels      []chan any
+	expireRoutineDoneChannels      map[string]chan any
 }
 
 func New(namespace string) *Cache {
@@ -18,7 +25,7 @@ func New(namespace string) *Cache {
 		namespace:                      namespace,
 		syncMap:                        new(sync.Map),
 		expireRoutineDoneChannelsMutex: new(sync.Mutex),
-		expireRoutineDoneChannels:      make([]chan any, 0),
+		expireRoutineDoneChannels:      make(map[string]chan any),
 	}
 }
 
@@ -43,43 +50,42 @@ func Destroy(cache *Cache) {
 }
 
 func (cache *Cache) Set(key string, value string, expireSec int64) error {
-	cache.syncMap.Store(cache.key2CacheKey(key), value)
+	item := &valueItem{
+		value:           value,
+		expireStartTime: time.Now(),
+		expireSec:       expireSec,
+	}
 
-	if expireSec != 0 {
+	cache.syncMap.Store(cache.key2CacheKey(key), item)
+
+	if item.expireSec != 0 {
 		doneChan := make(chan any)
 
 		cache.expireRoutineDoneChannelsMutex.Lock()
 
 		if cache.expireRoutineDoneChannels != nil {
-			cache.expireRoutineDoneChannels = append(cache.expireRoutineDoneChannels, doneChan)
+			cache.expireRoutineDoneChannels[cache.key2CacheKey(key)] = doneChan
 		}
 
 		cache.expireRoutineDoneChannelsMutex.Unlock()
 
 		go func() {
-			timer := time.NewTimer(time.Second * time.Duration(expireSec))
+			timer := time.NewTimer(time.Second * time.Duration(item.expireSec))
 
 			defer func() {
 				timer.Stop()
 
 				cache.expireRoutineDoneChannelsMutex.Lock()
 
-				if cache.expireRoutineDoneChannels != nil {
-					findIndex := -1
-
-					for i, savedDoneChan := range cache.expireRoutineDoneChannels {
-						if savedDoneChan == doneChan {
-							findIndex = i
-							close(savedDoneChan)
-							savedDoneChan = nil
-							break
-						}
+				if cache.expireRoutineDoneChannels != nil && len(cache.expireRoutineDoneChannels) > 0 {
+					savedDoneChan, ok := cache.expireRoutineDoneChannels[cache.key2CacheKey(key)]
+					if !ok {
+						return
 					}
 
-					if findIndex != -1 {
-						cache.expireRoutineDoneChannels =
-							append(cache.expireRoutineDoneChannels[:findIndex], cache.expireRoutineDoneChannels[findIndex+1:]...)
-					}
+					close(savedDoneChan)
+					savedDoneChan = nil
+					delete(cache.expireRoutineDoneChannels, cache.key2CacheKey(key))
 				}
 
 				cache.expireRoutineDoneChannelsMutex.Unlock()
@@ -145,6 +151,65 @@ func (cache *Cache) Clear() error {
 	return nil
 }
 
+func (cache *Cache) Expire(key string, expireSec int64) error {
+	value, loaded := cache.syncMap.Load(cache.key2CacheKey(key))
+	if !loaded {
+		return errors.New("对应的键不存在")
+	}
+
+	oldItem := value.(*valueItem)
+
+	// 超时时间修改为0,停止协程
+	if expireSec == 0 {
+		cache.expireRoutineDoneChannelsMutex.Lock()
+
+		doneChan, ok := cache.expireRoutineDoneChannels[cache.key2CacheKey(key)]
+		if ok {
+			doneChan <- nil
+			close(doneChan)
+			doneChan = nil
+		}
+
+		delete(cache.expireRoutineDoneChannels, cache.key2CacheKey(key))
+
+		cache.expireRoutineDoneChannelsMutex.Unlock()
+	}
+
+	cache.syncMap.Store(cache.key2CacheKey(key), &valueItem{
+		value:           oldItem.value,
+		expireStartTime: time.Now(),
+		expireSec:       expireSec,
+	})
+
+	return nil
+}
+
+func (cache *Cache) ExpireTime(key string) (int64, error) {
+	value, loaded := cache.syncMap.Load(cache.key2CacheKey(key))
+	if !loaded {
+		return 0, nil
+	}
+
+	oldItem := value.(*valueItem)
+
+	return oldItem.expireSec, nil
+}
+
+func (cache *Cache) TTL(key string) (int64, error) {
+	value, loaded := cache.syncMap.Load(cache.key2CacheKey(key))
+	if !loaded {
+		return 0, nil
+	}
+
+	oldItem := value.(*valueItem)
+	remainSec := int64(oldItem.expireStartTime.Add(time.Duration(oldItem.expireSec) * time.Second).Sub(time.Now()).Seconds())
+	if remainSec <= 0 {
+		return 0, nil
+	}
+
+	return remainSec, nil
+}
+
 func (cache *Cache) key2CacheKey(key string) string {
 	return cache.namespace + "::" + key
 }

+ 35 - 0
framework/core/infrastructure/cache/redis/redis.go

@@ -141,6 +141,41 @@ func (cache *Cache) Clear() error {
 	return nil
 }
 
+func (cache *Cache) Expire(key string, expireSec int64) error {
+	cmd := cache.redisClient.Expire(context.Background(), cache.key2CacheKey(key), time.Duration(expireSec)*time.Second)
+	if cmd.Err() != nil {
+		return errors.New(cmd.Err().Error())
+	}
+
+	return nil
+}
+
+func (cache *Cache) ExpireTime(key string) (int64, error) {
+	cmd := cache.redisClient.ExpireTime(context.Background(), cache.key2CacheKey(key))
+	if cmd.Err() != nil {
+		if cmd.Err().Error() == redis.Nil.Error() {
+			return 0, nil
+		}
+
+		return 0, errors.New(cmd.Err().Error())
+	}
+
+	return int64(cmd.Val().Seconds()), nil
+}
+
+func (cache *Cache) TTL(key string) (int64, error) {
+	cmd := cache.redisClient.TTL(context.Background(), cache.key2CacheKey(key))
+	if cmd.Err() != nil {
+		if cmd.Err().Error() == redis.Nil.Error() {
+			return 0, nil
+		}
+
+		return 0, errors.New(cmd.Err().Error())
+	}
+
+	return int64(cmd.Val().Seconds()), nil
+}
+
 func (cache *Cache) key2CacheKey(key string) string {
 	return keyPrefix + cache.namespace + "::" + key
 }