github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/core/bloombits/scheduler.go (about) 1 2 //此源码被清华学神尹成大魔王专业翻译分析并修改 3 //尹成QQ77025077 4 //尹成微信18510341407 5 //尹成所在QQ群721929980 6 //尹成邮箱 yinc13@mails.tsinghua.edu.cn 7 //尹成毕业于清华大学,微软区块链领域全球最有价值专家 8 //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620 9 //版权所有2017 Go Ethereum作者 10 //此文件是Go以太坊库的一部分。 11 // 12 //Go-Ethereum库是免费软件:您可以重新分发它和/或修改 13 //根据GNU发布的较低通用公共许可证的条款 14 //自由软件基金会,或者许可证的第3版,或者 15 //(由您选择)任何更高版本。 16 // 17 //Go以太坊图书馆的发行目的是希望它会有用, 18 //但没有任何保证;甚至没有 19 //适销性或特定用途的适用性。见 20 //GNU较低的通用公共许可证,了解更多详细信息。 21 // 22 //你应该收到一份GNU较低级别的公共许可证副本 23 //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。 24 25 package bloombits 26 27 import ( 28 "sync" 29 ) 30 31 //请求表示一个Bloom检索任务,以确定优先级并从本地 32 //数据库或从网络远程访问。 33 type request struct { 34 section uint64 //从中检索位向量的节索引 35 bit uint //段内的位索引,用于检索 36 } 37 38 //响应表示通过调度程序请求的位向量的状态。 39 type response struct { 40 cached []byte //用于消除多个请求的缓存位 41 done chan struct{} //允许等待完成的通道 42 } 43 44 //调度程序处理Bloom过滤器检索操作的调度 45 //整段批次属于一个单独的开孔钻头。除了安排 46 //检索操作,此结构还消除重复请求和缓存 47 //即使在复杂的过滤中,也能最大限度地减少网络/数据库开销。 48 //情节。 49 type scheduler struct { 50 bit uint //此计划程序负责的Bloom筛选器中位的索引 51 responses map[uint64]*response //当前挂起的检索请求或已缓存的响应 52 lock sync.Mutex //防止响应并发访问的锁 53 } 54 55 //Newscheduler为特定的 56 //位索引。 57 func newScheduler(idx uint) *scheduler { 58 return &scheduler{ 59 bit: idx, 60 responses: make(map[uint64]*response), 61 } 62 } 63 64 //运行创建检索管道,从节和 65 //通过完成通道以相同顺序返回结果。同时发生的 66 //允许运行同一个调度程序,从而导致检索任务重复数据消除。 67 func (s *scheduler) run(sections chan uint64, dist chan *request, done chan []byte, quit chan struct{}, wg *sync.WaitGroup) { 68 //在与相同大小的请求和响应之间创建转发器通道 69 //分配通道(因为这样会阻塞管道)。 70 pend := make(chan uint64, cap(dist)) 71 72 //启动管道调度程序在用户->分发服务器->用户之间转发 73 wg.Add(2) 74 go s.scheduleRequests(sections, dist, pend, quit, wg) 75 go s.scheduleDeliveries(pend, done, quit, wg) 76 } 77 78 //重置将清除以前运行的所有剩余部分。这是在 79 //重新启动以确保以前没有请求但从未传递的状态将 80 //导致锁定。 81 func (s *scheduler) reset() { 82 s.lock.Lock() 83 defer s.lock.Unlock() 84 85 for section, res := range s.responses { 86 if res.cached == nil { 87 delete(s.responses, section) 88 } 89 } 90 } 91 92 //schedulerequests从输入通道读取段检索请求, 93 //消除流中的重复数据并将唯一的检索任务推送到分发中 94 //数据库或网络层的通道。 95 func (s *scheduler) scheduleRequests(reqs chan uint64, dist chan *request, pend chan uint64, quit chan struct{}, wg *sync.WaitGroup) { 96 //完成后清理Goroutine和管道 97 defer wg.Done() 98 defer close(pend) 99 100 //继续阅读和安排分区请求 101 for { 102 select { 103 case <-quit: 104 return 105 106 case section, ok := <-reqs: 107 //请求新分区检索 108 if !ok { 109 return 110 } 111 //消除重复检索请求 112 unique := false 113 114 s.lock.Lock() 115 if s.responses[section] == nil { 116 s.responses[section] = &response{ 117 done: make(chan struct{}), 118 } 119 unique = true 120 } 121 s.lock.Unlock() 122 123 //安排检索部分的时间,并通知交付者期望此部分 124 if unique { 125 select { 126 case <-quit: 127 return 128 case dist <- &request{bit: s.bit, section: section}: 129 } 130 } 131 select { 132 case <-quit: 133 return 134 case pend <- section: 135 } 136 } 137 } 138 } 139 140 //ScheduledDeliveries读取区段接受通知并等待它们 141 //要传递,将它们推入输出数据缓冲区。 142 func (s *scheduler) scheduleDeliveries(pend chan uint64, done chan []byte, quit chan struct{}, wg *sync.WaitGroup) { 143 //完成后清理Goroutine和管道 144 defer wg.Done() 145 defer close(done) 146 147 //继续阅读通知并安排交货 148 for { 149 select { 150 case <-quit: 151 return 152 153 case idx, ok := <-pend: 154 //新分区检索挂起 155 if !ok { 156 return 157 } 158 //等到请求得到满足为止 159 s.lock.Lock() 160 res := s.responses[idx] 161 s.lock.Unlock() 162 163 select { 164 case <-quit: 165 return 166 case <-res.done: 167 } 168 //交付结果 169 select { 170 case <-quit: 171 return 172 case done <- res.cached: 173 } 174 } 175 } 176 } 177 178 //请求分发服务器在对请求的答复到达时调用传递。 179 func (s *scheduler) deliver(sections []uint64, data [][]byte) { 180 s.lock.Lock() 181 defer s.lock.Unlock() 182 183 for i, section := range sections { 184 if res := s.responses[section]; res != nil && res.cached == nil { //避免非请求和双倍交货 185 res.cached = data[i] 186 close(res.done) 187 } 188 } 189 }