groupcache源码走读

->func (g *Group) Get(ctx Context, key string, dest Sink)
	->value, cacheHit := g.lookupCache(key)
		->value, ok = g.mainCache.get(key)
			->vi, ok := c.lru.Get(key)
				->"lru cache 是如何实现的 -> hashMap + 双向链表"
				->"hashMap : [k:key,v:元素在链表的地址]"
				->"每次Get则把链表的元素移动到链表头部,链表的插入操作。"
		->value, ok = g.hotCache.get(key)
			->vi, ok := c.lru.Get(key)
	->if cacheHit
		->setSinkView(dest, value)
	->value, destPopulated, err := g.load(ctx, key, dest)
		->g.loadGroup.Do(key, func() (interface{}, error))
			->value, cacheHit := g.lookupCache(key)
				->"理解这个地方为什么还是要读一次cahce,我想了很久,什么情况下会读到这里面的cache"
				->"singleflight只能解决并行情况下多次load()"
				->"当两个串行的请求g1,g2都没有在cache中读到,g1执行完load并且已经置cache,g2才开始执行load"
				->"这样解释比较牵强"
			->"当有两个并行的请求g1,g2,这两个请求都没有在cache中找到key,那么都要去调用load()(两次)。"
			->"有了去重之后,假设g1先调用load(),那么g2会直接等待g1的load()结果,而不会去真正调用load"
			->"load()由2次变为1次。"
			->peer, ok := g.peers.PickPeer(key)
				->"key一直固定在某一台机器上面"
				->if ok : 这个key应该在远地peer上
					->value, err = g.getFromPeer(ctx, peer, key)
						->构造pb.GetRequest
						->构造pb.GetResponse
						->peer.Get(ctx, req, res)
						->value := ByteView{b: res.Value}
						->if rand.Intn(10) == 0 : 
							->"main cache 主要缓存本机负责的key,这个百分百要缓存"
							->"hot cache 主要缓存远端负责的key,这个百分之十缓存"
							-> g.populateCache(key, value, &g.hotCache)
								->"cache容量已满,则不直接return"
								->"加锁"
									->"非线程安全"
									->"如果第一次,则new一个lru,并且给被清除的key注册回调函数"
										->c.nbytes -= int64(len(key.(string))) + int64(val.Len())
										->c.nevict++
									->c.lru.Add(key, value)
										->c.nbytes += int64(len(key)) + int64(value.Len())
								->"解锁"

				->not ok : 这个key应该在本地peer上
					->value, err = g.getLocally(ctx, key, dest)
						->err := g.getter.Get(ctx, key, dest)
							->"定制的getter方法去load数据,这个数据起初不在cache中,最终存在dest中"
						->return dest.view()
					->destPopulated = true
						->"已经将load的数据放到dest里面了,就不需要再放一遍dest里面了。"
					->g.populateCache(key, value, &g.mainCache)
						->cache.add(key, value)
						->mainBytes := g.mainCache.bytes()
						->hotBytes := g.hotCache.bytes()
						->if mainBytes+hotBytes <= g.cacheBytes : return 
							->"没有满,则不驱逐"
						->if hotBytes > mainBytes/8 : victim = &g.hotCache else victim := &g.mainCache
							->"如果远端cache比本地cahce的1/8还要大,则删掉尾部"
						->victim.removeOldest()
							->"清除链表尾部的元素"
							->"清除map"
	->setSinkView(dest, value)
		->"minimize copies"
		->"如果dest Sink不仅实现了Sink interface所需要的所有方法,并且还实现了setView(v ByteView) error方法,则"
			->vs.setView(v)
		->if v.b != nil
			->"dest Sink必须实现Sink interface所需要的SetBytes()方法"
			->s.SetBytes(v.b) 
		->"dest Sink必须实现Sink interface所需要的SetString()方法"
		->s.SetString(v.s)


"an HTTP pool of peers"
->func NewHTTPPool(self string) *HTTPPool
	->p := NewHTTPPoolOpts(self, nil)
		->p.opts.BasePath = "/_groupcache/"
		->p.opts.Replicas = 50
			->"一致性哈希,为了使哈希环上的节点分布均匀,需要给一个实际节点虚拟出N个虚拟节点"
		->p.peers = consistenthash.New(p.opts.Replicas, p.opts.HashFn)
			->m.hash = crc32.ChecksumIEEE
		->RegisterPeerPicker(func() PeerPicker { return p })
			->"这个对象必须要实现了PeerPicker接口所必须要的PickPeer方法"
			->"即根据key找到对应的机器"
			->func (p *HTTPPool) PickPeer(key string) (ProtoGetter, bool)
				->if peer := p.peers.Get(key); peer != p.self 
					return p.httpGetters[peer], true
					->func (m *Map) Get(key string) string
						->"找到hash环中(顺时针)离这个key最近的一个节点"
						->hash := int(m.hash([]byte(key)))
							->"crc32.ChecksumIEEE"
						->idx := sort.Search(len(m.keys), func(i int) bool { return m.keys[i] >= hash })
							->"二分查找"
							->"满足fn(),则在左半侧;不满足fn(),则在右半侧"
							->"将所有节点的hash值,从左到右,从小到大排序好"
						->if idx == len(m.keys) : idx = 0 
						->return m.hashMap[m.keys[idx]]
							->"根据key找对应的机器节点idx,然后找到对应节点的hash值,根据hash值最后反查节点的地址(ip,port,url,replica)"
							-> e.g. "https://example.net:8000"

->func (p *HTTPPool) ServeHTTP(w http.ResponseWriter, r *http.Request)
	->groupName := parts[0]
	->key := parts[1]
	->group := GetGroup(groupName)
	->var value []byte
	->err := group.Get(ctx, key, AllocatingByteSliceSink(&value))
		->"从外部定义一个[]byte,然后Get()函数内部(通过指针)往这个里面填数值"
			->func (s *allocBytesSink) setView(v ByteView) error
				->*s.dst = cloneBytes(v.b)
					->c := make([]byte, len(b))
					->copy(c, b)
				->*s.dst = []byte(v.s)
		->"深拷贝"
		->"因为整个groupcache里面存储的value是[]byte,所以如果不深拷贝,则会共用一段内存"
	

 

你可能感兴趣的:(Go开源框架源码走读)