极客兔兔Gee-Cache Day2
// ---------------------------------------------------------------------------------------
// ByteView.go 缓存元素的抽象
package gee
// 只读数据结构 表示缓存值,实现了Value接口
type ByteView struct {
b []byte
}
func (v ByteView) Len() int {
return len(v.b)
}
func (v ByteView) ByteSlice() []byte {
return cloneBytes(v.b)
}
func cloneBytes(b []byte) []byte {
c := make([]byte, len(b))
copy(c, b)
return c
}
func (v ByteView) String() string {
return string(v.b)
}
// cache.go 对day1中的lru加上并发控制
package gee
// ---------------------------------------------------------------------------------------
// 实现并发控制
import (
"sync"
)
type cache struct {
mu sync.Mutex
lru *Cache
cacheBytes int64
}
func (c *cache) add(key string, value ByteView) {
c.mu.Lock()
defer c.mu.Unlock()
if c.lru == nil { // 延迟初始化
c.lru = New(c.cacheBytes, nil)
}
c.lru.Add(key, value)
}
func (c *cache) get(key string) (value ByteView, ok bool) {
c.mu.Lock()
defer c.mu.Unlock()
if c.lru == nil {
return
}
if v, ok := c.lru.Get(key); ok {
return v.(ByteView), ok
}
return
}
// ---------------------------------------------------------------------------------------
// geecache.go 与源数据库进行交互
package gee
// 实现与外部交互
import (
"fmt"
"sync"
)
type Getter interface {
Get(key string) ([]byte, error)
}
type GetterFunc func(key string) ([]byte, error)
// 接口型函数
func (f GetterFunc) Get(key string) ([]byte, error) {
return f(key)
}
type Group struct {
name string // 缓存名称
getter Getter // 回调函数
mainCache cache // 缓存
}
var (
mu sync.Mutex
groups = make(map[string]*Group)
)
func NewGroup(name string, cacheBytes int64, getter Getter) *Group {
if getter == nil {
panic("Getter nil")
}
mu.Lock()
defer mu.Unlock()
g := &Group{
name: name,
getter: getter,
mainCache: cache{cacheBytes: cacheBytes},
}
groups[name] = g
return g
}
func GetGroup(name string) *Group {
mu.Lock()
defer mu.Unlock()
g := groups[name]
return g
}
func (g *Group) Get(key string) (ByteView, error) {
if key == "" {
return ByteView{}, fmt.Errorf("key is nil")
}
if v, ok := g.mainCache.get(key); ok {
fmt.Println("Gee Cache hit")
return v, nil
}
return g.load(key)
}
func (g *Group) load(key string) (Value ByteView, err error) {
return g.getLocally(key)
}
// 调用回调函数,去源数据库查找内容
func (g *Group) getLocally(key string) (ByteView, error) {
bytes, err := g.getter.Get(key)
if err != nil {
return ByteView{}, err
}
value := ByteView{b: cloneBytes(bytes)}
g.add(key, value)
return value, nil
}
func (g *Group) add(key string, value ByteView) {
g.mainCache.add(key, value)
}