-
Notifications
You must be signed in to change notification settings - Fork 16
/
gache.go
161 lines (135 loc) · 2.76 KB
/
gache.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package Gache
import (
"fmt"
"log"
"sync"
)
/*
负责与外部交互
控制缓存存储和获取的主流程
*/
//回调函数
//当缓存不存在,从其他数据源获取,并添加到缓存
type Getter interface {
Get(key string)([]byte,error)
}
/*
定义一个函数类型 F,并且实现接口 A 的方法,
然后在这个方法中调用自己。
这是 Go 语言中将其他函数转换为接口 A 的常用技巧
(参数返回值定义与 F 一致)
*/
type GetterFunc func(key string)([]byte,error)
//
func (f GetterFunc) Get(key string)([]byte,error){
return f(key)
}
/*
Groups
缓存的集合
Groups =Group的集合= n个缓存表
注意区分Groups和Group
*/
type Group struct {
name string
getter Getter
mainCache cache
/*
后续添加
*/
/*
一致性哈希算法的节点表
*/
peers PeerPicker
}
/*
注册节点
*/
func(g *Group) RegisterPeers(peers PeerPicker){
if g.peers != nil{
panic("注册器已被调用过")
}
g.peers = peers
}
/*
load方法
如果是远程节点,使用PickPeer()方法选择节点
本地节点则使用getLocally()
*/
func (g *Group) load(key string) (value ByteView, err error) {
if g.peers != nil {
//选择节点
if peer, ok := g.peers.PickPeer(key); ok {
//远程节点-取值
if value, err = g.getFromPeer(peer, key); err == nil {
return value, nil
}
log.Println("[Gache] Failed to get from peer", err)
}
}
return g.getLocally(key)
}
/*
远程节点取值实现
*/
func (g *Group) getFromPeer(peer PeerGetter, key string) (ByteView, error) {
/*
这里的peer类型其实是http.go中的httpGetter
*/
bytes, err := peer.Get(g.name, key)
if err != nil {
return ByteView{}, err
}
return ByteView{b: bytes}, nil
}
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.popularCache(key,value)
return value,nil
}
func (g *Group) popularCache(key string,value ByteView) {
g.mainCache.add(key,value)
}
var (
mu sync.RWMutex
groups = make(map[string]*Group)
)
func NewGroup(name string,cacheBytes int64, getter Getter) *Group{
//getter是一个函数类型的参数
if getter == nil{
panic("nil Getter")
}
mu.Lock()
defer mu.Unlock()
g:= &Group{
name: name,
getter: getter,
mainCache:cache{cacheBytes:cacheBytes},
}
groups[name] = g
return g
}
//返回相应的group
func GetGroup(name string) *Group{
mu.RLock()
g:=groups[name]
mu.RUnlock()
return g
}
//get
func (g *Group)Get(key string) (ByteView,error){
if key==""{
return ByteView{},fmt.Errorf("key is required")
}
if v,ok:=g.mainCache.get(key);ok{
log.Println("[Gache] hit")
return v,nil;
}
//从其他数据源获取
return g.load(key)
}