Create your Gitee Account
Explore and code with more than 12 million developers,Free private repositories !:)
Sign up
文件
This repository doesn't specify license. Please pay attention to the specific project description and its upstream code dependency when using it.
Clone or Download
gogocache.go 2.94 KB
Copy Edit Raw Blame History
Gogo authored 2021-10-09 18:55 . feat: 实现持久化
package gogocache
import (
"bufio"
"fmt"
"gitee.com/Gogo-gitee/gogo-cache/log"
"gitee.com/Gogo-gitee/gogo-cache/persistence"
"gitee.com/Gogo-gitee/gogo-cache/singleflight"
"hash/crc32"
"os"
)
// Hash 哈希函数
type Hash func(data []byte) uint32
// CacheGroup 统一管理多个cache
type CacheGroup struct {
cacheNum int
getter Getter
mainCache []cache
hash Hash
// use singleflight.Group to make sure that
// each key is only fetched once
loader *singleflight.Group
}
//Getter 定义获取数据源的接口
type Getter interface {
Get(key string) ([]byte, error)
}
//GetterFunc 实现Getter接口的一个函数
type GetterFunc func(key string) ([]byte, error)
//GetterFunc 实现了getter的接口
func (f GetterFunc) Get(key string) ([]byte, error) {
return f(key)
}
// NewGroup 新建group的实例
func NewGroup(cacheBytes int64, getter Getter, cacheNum int, fn Hash) *CacheGroup {
caches := make([]cache, cacheNum)
for i, _ := range caches {
caches[i] = cache{cacheBytes: cacheBytes}
}
g := &CacheGroup{
cacheNum: cacheNum,
getter: getter,
hash: fn,
mainCache: caches,
loader: &singleflight.Group{},
}
if g.hash == nil {
g.hash = crc32.ChecksumIEEE
}
//恢复原来的键值对
file, err := os.OpenFile("./persistence.txt", os.O_CREATE|os.O_RDONLY, 0666)
if err != nil {
log.Error(err)
}
scanner := bufio.NewScanner(file)
for scanner.Scan() {
key := scanner.Text()
// do anything with strLine
if scanner.Scan() {
value := scanner.Bytes()
g.recover(key, ByteView{Bytes: value})
}
}
return g
}
//getCacheNo 获取key对应的cache下标
func (g *CacheGroup) getCacheNo(key string) int {
hash := int(g.hash([]byte(key))) % g.cacheNum
return hash
}
// Get 从cache里面查找key
func (g *CacheGroup) Get(key string) (ByteView, error) {
if key == "" {
return ByteView{}, fmt.Errorf("key is required")
}
cacheNo := g.getCacheNo(key)
log.Debugf("searching %s from %d", key, cacheNo)
if v, ok := g.mainCache[cacheNo].get(key); ok {
log.Debugf("[GogoCache] hit")
return v, nil
} else {
if g.getter == nil {
return ByteView{}, fmt.Errorf("[GogoCache] not hit")
} else {
return g.getLocally(key)
}
}
}
//getLocally 从数据源中获取数据
func (g *CacheGroup) getLocally(key string) (ByteView, error) {
bytes, err := g.getter.Get(key)
if err != nil || len(bytes) == 0 {
return ByteView{}, err
}
log.Debugf("got from local %v", bytes)
value := ByteView{Bytes: cloneBytes(bytes)}
//回源以后,异步写入数据
g.Set(key, value)
return value, nil
}
//recover 恢复键值对
func (g *CacheGroup) recover(key string, value ByteView) {
cacheNo := g.getCacheNo(key)
g.mainCache[cacheNo].add(key, value)
}
//Set set加入键值对
func (g *CacheGroup) Set(key string, value ByteView) {
persistence.Record(key, value.Bytes)
cacheNo := g.getCacheNo(key)
log.Debugf("write key: %s value: %v to cache no: %d\n", key, value, cacheNo)
g.mainCache[cacheNo].add(key, value)
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化