github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/les/distributor.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:38</date> 10 //</624450093361139712> 11 12 13 //package light实现可按需检索的状态和链对象 14 //对于以太坊Light客户端。 15 package les 16 17 import ( 18 "container/list" 19 "sync" 20 "time" 21 ) 22 23 //requestdistributor实现一种机制,将请求分发到 24 //合适的同行,遵守流程控制规则,并在创建过程中对其进行优先级排序。 25 //订购(即使需要重新发送)。 26 type requestDistributor struct { 27 reqQueue *list.List 28 lastReqOrder uint64 29 peers map[distPeer]struct{} 30 peerLock sync.RWMutex 31 stopChn, loopChn chan struct{} 32 loopNextSent bool 33 lock sync.Mutex 34 } 35 36 //distpeer是请求分发服务器的LES服务器对等接口。 37 //waitbefore返回发送请求前所需的等待时间 38 //具有给定的较高估计成本或估计的剩余相对缓冲 39 //发送此类请求后的值(在这种情况下,可以发送请求 40 //立即)。这些值中至少有一个始终为零。 41 type distPeer interface { 42 waitBefore(uint64) (time.Duration, float64) 43 canQueue() bool 44 queueSend(f func()) 45 } 46 47 //Distreq是分发服务器使用的请求抽象。它是建立在 48 //三个回调函数: 49 //- getCost returns the upper estimate of the cost of sending the request to a given peer 50 //-cansend告诉服务器对等端是否适合服务请求 51 //-请求准备将请求发送给给定的对等方,并返回一个函数, 52 //does the actual sending. Request order should be preserved but the callback itself should not 53 //在发送之前阻止,因为其他对等方可能仍然能够在 54 //其中一个正在阻塞。相反,返回的函数被放入对等方的发送队列中。 55 type distReq struct { 56 getCost func(distPeer) uint64 57 canSend func(distPeer) bool 58 request func(distPeer) func() 59 60 reqOrder uint64 61 sentChn chan distPeer 62 element *list.Element 63 } 64 65 //new request distributor创建新的请求分发服务器 66 func newRequestDistributor(peers *peerSet, stopChn chan struct{}) *requestDistributor { 67 d := &requestDistributor{ 68 reqQueue: list.New(), 69 loopChn: make(chan struct{}, 2), 70 stopChn: stopChn, 71 peers: make(map[distPeer]struct{}), 72 } 73 if peers != nil { 74 peers.notify(d) 75 } 76 go d.loop() 77 return d 78 } 79 80 //registerpeer实现peersetnotify 81 func (d *requestDistributor) registerPeer(p *peer) { 82 d.peerLock.Lock() 83 d.peers[p] = struct{}{} 84 d.peerLock.Unlock() 85 } 86 87 //UnregisterPeer实现PeerSetNotify 88 func (d *requestDistributor) unregisterPeer(p *peer) { 89 d.peerLock.Lock() 90 delete(d.peers, p) 91 d.peerLock.Unlock() 92 } 93 94 //RegisterTestPeer添加新的测试对等 95 func (d *requestDistributor) registerTestPeer(p distPeer) { 96 d.peerLock.Lock() 97 d.peers[p] = struct{}{} 98 d.peerLock.Unlock() 99 } 100 101 //distmaxwait是最长的等待时间,在此之后需要进一步等待。 102 //根据服务器的新反馈重新计算时间 103 const distMaxWait = time.Millisecond * 10 104 105 //主事件循环 106 func (d *requestDistributor) loop() { 107 for { 108 select { 109 case <-d.stopChn: 110 d.lock.Lock() 111 elem := d.reqQueue.Front() 112 for elem != nil { 113 req := elem.Value.(*distReq) 114 close(req.sentChn) 115 req.sentChn = nil 116 elem = elem.Next() 117 } 118 d.lock.Unlock() 119 return 120 case <-d.loopChn: 121 d.lock.Lock() 122 d.loopNextSent = false 123 loop: 124 for { 125 peer, req, wait := d.nextRequest() 126 if req != nil && wait == 0 { 127 chn := req.sentChn //保存sentchn,因为remove将其设置为nil 128 d.remove(req) 129 send := req.request(peer) 130 if send != nil { 131 peer.queueSend(send) 132 } 133 chn <- peer 134 close(chn) 135 } else { 136 if wait == 0 { 137 //没有发送请求,没有等待;下一个 138 //排队的请求将唤醒循环 139 break loop 140 } 141 d.loopNextSent = true //已发送“下一个”信号,在收到该信号之前不要再发送另一个信号。 142 if wait > distMaxWait { 143 //传入的请求答复可能会缩短等待时间,如果时间太长,请定期重新计算 144 wait = distMaxWait 145 } 146 go func() { 147 time.Sleep(wait) 148 d.loopChn <- struct{}{} 149 }() 150 break loop 151 } 152 } 153 d.lock.Unlock() 154 } 155 } 156 } 157 158 //SelectePeerItem表示要按WeightedRandomSelect为请求选择的对等机 159 type selectPeerItem struct { 160 peer distPeer 161 req *distReq 162 weight int64 163 } 164 165 //权重实现WRSitem接口 166 func (sp selectPeerItem) Weight() int64 { 167 return sp.weight 168 } 169 170 //NextRequest返回来自任何对等机的下一个可能的请求,以及 171 //关联的对等机和必要的等待时间 172 func (d *requestDistributor) nextRequest() (distPeer, *distReq, time.Duration) { 173 checkedPeers := make(map[distPeer]struct{}) 174 elem := d.reqQueue.Front() 175 var ( 176 bestPeer distPeer 177 bestReq *distReq 178 bestWait time.Duration 179 sel *weightedRandomSelect 180 ) 181 182 d.peerLock.RLock() 183 defer d.peerLock.RUnlock() 184 185 for (len(d.peers) > 0 || elem == d.reqQueue.Front()) && elem != nil { 186 req := elem.Value.(*distReq) 187 canSend := false 188 for peer := range d.peers { 189 if _, ok := checkedPeers[peer]; !ok && peer.canQueue() && req.canSend(peer) { 190 canSend = true 191 cost := req.getCost(peer) 192 wait, bufRemain := peer.waitBefore(cost) 193 if wait == 0 { 194 if sel == nil { 195 sel = newWeightedRandomSelect() 196 } 197 sel.update(selectPeerItem{peer: peer, req: req, weight: int64(bufRemain*1000000) + 1}) 198 } else { 199 if bestReq == nil || wait < bestWait { 200 bestPeer = peer 201 bestReq = req 202 bestWait = wait 203 } 204 } 205 checkedPeers[peer] = struct{}{} 206 } 207 } 208 next := elem.Next() 209 if !canSend && elem == d.reqQueue.Front() { 210 close(req.sentChn) 211 d.remove(req) 212 } 213 elem = next 214 } 215 216 if sel != nil { 217 c := sel.choose().(selectPeerItem) 218 return c.peer, c.req, 0 219 } 220 return bestPeer, bestReq, bestWait 221 } 222 223 //队列向分发队列添加请求,返回一个通道,其中 224 //发送请求后即发送接收对等(返回请求回调)。 225 //如果请求被取消或在没有合适的对等方的情况下超时,则通道为 226 //关闭而不向其发送任何对等引用。 227 func (d *requestDistributor) queue(r *distReq) chan distPeer { 228 d.lock.Lock() 229 defer d.lock.Unlock() 230 231 if r.reqOrder == 0 { 232 d.lastReqOrder++ 233 r.reqOrder = d.lastReqOrder 234 } 235 236 back := d.reqQueue.Back() 237 if back == nil || r.reqOrder > back.Value.(*distReq).reqOrder { 238 r.element = d.reqQueue.PushBack(r) 239 } else { 240 before := d.reqQueue.Front() 241 for before.Value.(*distReq).reqOrder < r.reqOrder { 242 before = before.Next() 243 } 244 r.element = d.reqQueue.InsertBefore(r, before) 245 } 246 247 if !d.loopNextSent { 248 d.loopNextSent = true 249 d.loopChn <- struct{}{} 250 } 251 252 r.sentChn = make(chan distPeer, 1) 253 return r.sentChn 254 } 255 256 //如果尚未发送请求,则取消将其从队列中删除(返回 257 //如果已发送,则为false)。保证回调函数 258 //取消返回后将不调用。 259 func (d *requestDistributor) cancel(r *distReq) bool { 260 d.lock.Lock() 261 defer d.lock.Unlock() 262 263 if r.sentChn == nil { 264 return false 265 } 266 267 close(r.sentChn) 268 d.remove(r) 269 return true 270 } 271 272 //删除从队列中删除请求 273 func (d *requestDistributor) remove(r *distReq) { 274 r.sentChn = nil 275 if r.element != nil { 276 d.reqQueue.Remove(r.element) 277 r.element = nil 278 } 279 } 280