github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/core/bloombits/scheduler.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:35</date>
    10  //</624450078299394048>
    11  
    12  
    13  package bloombits
    14  
    15  import (
    16  	"sync"
    17  )
    18  
    19  //请求表示一个Bloom检索任务,以确定优先级并从本地
    20  //数据库或从网络远程访问。
    21  type request struct {
    22  section uint64 //从中检索位向量的节索引
    23  bit     uint   //段内的位索引,用于检索
    24  }
    25  
    26  //响应表示通过调度程序请求的位向量的状态。
    27  type response struct {
    28  cached []byte        //用于消除多个请求的缓存位
    29  done   chan struct{} //允许等待完成的通道
    30  }
    31  
    32  //调度程序处理Bloom过滤器检索操作的调度
    33  //整段批次属于一个单独的开孔钻头。除了安排
    34  //retrieval operations, this struct also deduplicates the requests and caches
    35  //即使在复杂的过滤中,也能最大限度地减少网络/数据库开销。
    36  //情节。
    37  type scheduler struct {
    38  bit       uint                 //此计划程序负责的Bloom筛选器中位的索引
    39  responses map[uint64]*response //当前挂起的检索请求或已缓存的响应
    40  lock      sync.Mutex           //防止响应并发访问的锁
    41  }
    42  
    43  //Newscheduler为特定的
    44  //位索引。
    45  func newScheduler(idx uint) *scheduler {
    46  	return &scheduler{
    47  		bit:       idx,
    48  		responses: make(map[uint64]*response),
    49  	}
    50  }
    51  
    52  //运行创建检索管道,从节和
    53  //通过完成通道以相同顺序返回结果。同时发生的
    54  //允许运行同一个调度程序,从而导致检索任务重复数据消除。
    55  func (s *scheduler) run(sections chan uint64, dist chan *request, done chan []byte, quit chan struct{}, wg *sync.WaitGroup) {
    56  //在与相同大小的请求和响应之间创建转发器通道
    57  //分配通道(因为这样会阻塞管道)。
    58  	pend := make(chan uint64, cap(dist))
    59  
    60  //启动管道调度程序在用户->分发服务器->用户之间转发
    61  	wg.Add(2)
    62  	go s.scheduleRequests(sections, dist, pend, quit, wg)
    63  	go s.scheduleDeliveries(pend, done, quit, wg)
    64  }
    65  
    66  //重置将清除以前运行的所有剩余部分。这是在
    67  //重新启动以确保以前没有请求但从未传递的状态将
    68  //导致锁定。
    69  func (s *scheduler) reset() {
    70  	s.lock.Lock()
    71  	defer s.lock.Unlock()
    72  
    73  	for section, res := range s.responses {
    74  		if res.cached == nil {
    75  			delete(s.responses, section)
    76  		}
    77  	}
    78  }
    79  
    80  //schedulerequests从输入通道读取段检索请求,
    81  //消除流中的重复数据并将唯一的检索任务推送到分发中
    82  //数据库或网络层的通道。
    83  func (s *scheduler) scheduleRequests(reqs chan uint64, dist chan *request, pend chan uint64, quit chan struct{}, wg *sync.WaitGroup) {
    84  //完成后清理Goroutine和管道
    85  	defer wg.Done()
    86  	defer close(pend)
    87  
    88  //继续阅读和安排分区请求
    89  	for {
    90  		select {
    91  		case <-quit:
    92  			return
    93  
    94  		case section, ok := <-reqs:
    95  //请求新分区检索
    96  			if !ok {
    97  				return
    98  			}
    99  //消除重复检索请求
   100  			unique := false
   101  
   102  			s.lock.Lock()
   103  			if s.responses[section] == nil {
   104  				s.responses[section] = &response{
   105  					done: make(chan struct{}),
   106  				}
   107  				unique = true
   108  			}
   109  			s.lock.Unlock()
   110  
   111  //安排检索部分的时间,并通知交付者期望此部分
   112  			if unique {
   113  				select {
   114  				case <-quit:
   115  					return
   116  				case dist <- &request{bit: s.bit, section: section}:
   117  				}
   118  			}
   119  			select {
   120  			case <-quit:
   121  				return
   122  			case pend <- section:
   123  			}
   124  		}
   125  	}
   126  }
   127  
   128  //ScheduledDeliveries读取区段接受通知并等待它们
   129  //要传递,将它们推入输出数据缓冲区。
   130  func (s *scheduler) scheduleDeliveries(pend chan uint64, done chan []byte, quit chan struct{}, wg *sync.WaitGroup) {
   131  //完成后清理Goroutine和管道
   132  	defer wg.Done()
   133  	defer close(done)
   134  
   135  //继续阅读通知并安排交货
   136  	for {
   137  		select {
   138  		case <-quit:
   139  			return
   140  
   141  		case idx, ok := <-pend:
   142  //新分区检索挂起
   143  			if !ok {
   144  				return
   145  			}
   146  //等到请求得到满足为止
   147  			s.lock.Lock()
   148  			res := s.responses[idx]
   149  			s.lock.Unlock()
   150  
   151  			select {
   152  			case <-quit:
   153  				return
   154  			case <-res.done:
   155  			}
   156  //交付结果
   157  			select {
   158  			case <-quit:
   159  				return
   160  			case done <- res.cached:
   161  			}
   162  		}
   163  	}
   164  }
   165  
   166  //请求分发服务器在对请求的答复到达时调用传递。
   167  func (s *scheduler) deliver(sections []uint64, data [][]byte) {
   168  	s.lock.Lock()
   169  	defer s.lock.Unlock()
   170  
   171  	for i, section := range sections {
   172  if res := s.responses[section]; res != nil && res.cached == nil { //避免非请求和双倍交货
   173  			res.cached = data[i]
   174  			close(res.done)
   175  		}
   176  	}
   177  }
   178