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