github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/core/bloombits/matcher.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 "bytes" 29 "context" 30 "errors" 31 "math" 32 "sort" 33 "sync" 34 "sync/atomic" 35 "time" 36 37 "github.com/ethereum/go-ethereum/common/bitutil" 38 "github.com/ethereum/go-ethereum/crypto" 39 ) 40 41 //bloom indexes表示bloom过滤器中属于 42 //一些关键。 43 type bloomIndexes [3]uint 44 45 //calcBloomIndexes返回属于给定键的BloomFilter位索引。 46 func calcBloomIndexes(b []byte) bloomIndexes { 47 b = crypto.Keccak256(b) 48 49 var idxs bloomIndexes 50 for i := 0; i < len(idxs); i++ { 51 idxs[i] = (uint(b[2*i])<<8)&2047 + uint(b[2*i+1]) 52 } 53 return idxs 54 } 55 56 //带有非零矢量的粒子图表示一个部分,其中一些子- 57 //匹配者已经找到了可能的匹配项。后续的子匹配者将 58 //二进制及其与该向量的匹配。如果矢量为零,则表示 59 //由第一个子匹配器处理的部分。 60 type partialMatches struct { 61 section uint64 62 bitset []byte 63 } 64 65 //检索表示对给定任务的检索任务分配的请求 66 //具有给定数量的提取元素的位,或对这种请求的响应。 67 //它还可以将实际结果集用作传递数据结构。 68 // 69 //“竞赛”和“错误”字段由轻型客户端用于终止匹配 70 //如果在管道的某个路径上遇到错误,则为早期。 71 type Retrieval struct { 72 Bit uint 73 Sections []uint64 74 Bitsets [][]byte 75 76 Context context.Context 77 Error error 78 } 79 80 //Matcher是一个由调度程序和逻辑匹配程序组成的流水线系统,执行 81 //位流上的二进制和/或操作,创建一个潜在的流 82 //要检查数据内容的块。 83 type Matcher struct { 84 sectionSize uint64 //要筛选的数据批的大小 85 86 filters [][]bloomIndexes //系统匹配的筛选器 87 schedulers map[uint]*scheduler //用于装载钻头的检索调度程序 88 89 retrievers chan chan uint //检索器处理等待位分配 90 counters chan chan uint //检索器进程正在等待任务计数报告 91 retrievals chan chan *Retrieval //检索器进程正在等待任务分配 92 deliveries chan *Retrieval //检索器进程正在等待任务响应传递 93 94 running uint32 //原子标记会话是否处于活动状态 95 } 96 97 //NewMatcher创建了一个新的管道,用于检索Bloom位流并执行 98 //地址和主题过滤。将筛选器组件设置为“nil”是 99 //允许并将导致跳过该筛选规则(或0x11…1)。 100 func NewMatcher(sectionSize uint64, filters [][][]byte) *Matcher { 101 //创建Matcher实例 102 m := &Matcher{ 103 sectionSize: sectionSize, 104 schedulers: make(map[uint]*scheduler), 105 retrievers: make(chan chan uint), 106 counters: make(chan chan uint), 107 retrievals: make(chan chan *Retrieval), 108 deliveries: make(chan *Retrieval), 109 } 110 //计算我们感兴趣的组的bloom位索引 111 m.filters = nil 112 113 for _, filter := range filters { 114 //采集滤波规则的位指标,专用套管零滤波器 115 if len(filter) == 0 { 116 continue 117 } 118 bloomBits := make([]bloomIndexes, len(filter)) 119 for i, clause := range filter { 120 if clause == nil { 121 bloomBits = nil 122 break 123 } 124 bloomBits[i] = calcBloomIndexes(clause) 125 } 126 //如果不包含nil规则,则累积筛选规则 127 if bloomBits != nil { 128 m.filters = append(m.filters, bloomBits) 129 } 130 } 131 //对于每个位,创建一个调度程序来加载/下载位向量 132 for _, bloomIndexLists := range m.filters { 133 for _, bloomIndexList := range bloomIndexLists { 134 for _, bloomIndex := range bloomIndexList { 135 m.addScheduler(bloomIndex) 136 } 137 } 138 } 139 return m 140 } 141 142 //addscheduler为给定的位索引添加位流检索计划程序,如果 143 //它以前不存在。如果已选择位进行过滤,则 144 //可以使用现有的计划程序。 145 func (m *Matcher) addScheduler(idx uint) { 146 if _, ok := m.schedulers[idx]; ok { 147 return 148 } 149 m.schedulers[idx] = newScheduler(idx) 150 } 151 152 //Start启动匹配过程并返回一个bloom匹配流 153 //给定的块范围。如果范围内没有更多匹配项,则返回结果 154 //通道关闭。 155 func (m *Matcher) Start(ctx context.Context, begin, end uint64, results chan uint64) (*MatcherSession, error) { 156 //确保我们没有创建并发会话 157 if atomic.SwapUint32(&m.running, 1) == 1 { 158 return nil, errors.New("matcher already running") 159 } 160 defer atomic.StoreUint32(&m.running, 0) 161 162 //启动新的匹配轮 163 session := &MatcherSession{ 164 matcher: m, 165 quit: make(chan struct{}), 166 kill: make(chan struct{}), 167 ctx: ctx, 168 } 169 for _, scheduler := range m.schedulers { 170 scheduler.reset() 171 } 172 sink := m.run(begin, end, cap(results), session) 173 174 //从结果接收器读取输出并传递给用户 175 session.pend.Add(1) 176 go func() { 177 defer session.pend.Done() 178 defer close(results) 179 180 for { 181 select { 182 case <-session.quit: 183 return 184 185 case res, ok := <-sink: 186 //找到新的匹配结果 187 if !ok { 188 return 189 } 190 //计算该节的第一个和最后一个块 191 sectionStart := res.section * m.sectionSize 192 193 first := sectionStart 194 if begin > first { 195 first = begin 196 } 197 last := sectionStart + m.sectionSize - 1 198 if end < last { 199 last = end 200 } 201 //遍历该节中的所有块并返回匹配的块 202 for i := first; i <= last; i++ { 203 //如果在内部没有找到匹配项,则跳过整个字节(我们正在处理整个字节!) 204 next := res.bitset[(i-sectionStart)/8] 205 if next == 0 { 206 if i%8 == 0 { 207 i += 7 208 } 209 continue 210 } 211 //设置一些位,做实际的子匹配 212 if bit := 7 - i%8; next&(1<<bit) != 0 { 213 select { 214 case <-session.quit: 215 return 216 case results <- i: 217 } 218 } 219 } 220 } 221 } 222 }() 223 return session, nil 224 } 225 226 //运行创建子匹配器的菊花链,一个用于地址集,另一个用于 227 //对于每个主题集,每个子匹配器仅在上一个主题集 228 //所有人都在该路段的一个街区找到了一个潜在的匹配点, 229 //然后二进制和ing自己匹配并将结果转发到下一个结果。 230 // 231 //该方法开始向上的第一个子匹配器提供节索引。 232 //并返回接收结果的接收通道。 233 func (m *Matcher) run(begin, end uint64, buffer int, session *MatcherSession) chan *partialMatches { 234 //创建源通道并将节索引馈送到 235 source := make(chan *partialMatches, buffer) 236 237 session.pend.Add(1) 238 go func() { 239 defer session.pend.Done() 240 defer close(source) 241 242 for i := begin / m.sectionSize; i <= end/m.sectionSize; i++ { 243 select { 244 case <-session.quit: 245 return 246 case source <- &partialMatches{i, bytes.Repeat([]byte{0xff}, int(m.sectionSize/8))}: 247 } 248 } 249 }() 250 //组装菊花链过滤管道 251 next := source 252 dist := make(chan *request, buffer) 253 254 for _, bloom := range m.filters { 255 next = m.subMatch(next, dist, bloom, session) 256 } 257 //启动请求分发 258 session.pend.Add(1) 259 go m.distributor(dist, session) 260 261 return next 262 } 263 264 //Submatch创建一个子匹配器,该匹配器过滤一组地址或主题(二进制或-s),然后 265 //二进制和-s将结果发送到菊花链输入(源),并将其转发到菊花链输出。 266 //每个地址/主题的匹配是通过获取属于 267 //这个地址/主题,二进制和将这些向量组合在一起。 268 func (m *Matcher) subMatch(source chan *partialMatches, dist chan *request, bloom []bloomIndexes, session *MatcherSession) chan *partialMatches { 269 //为Bloom过滤器所需的每个位启动并发调度程序 270 sectionSources := make([][3]chan uint64, len(bloom)) 271 sectionSinks := make([][3]chan []byte, len(bloom)) 272 for i, bits := range bloom { 273 for j, bit := range bits { 274 sectionSources[i][j] = make(chan uint64, cap(source)) 275 sectionSinks[i][j] = make(chan []byte, cap(source)) 276 277 m.schedulers[bit].run(sectionSources[i][j], dist, sectionSinks[i][j], session.quit, &session.pend) 278 } 279 } 280 281 process := make(chan *partialMatches, cap(source)) //在初始化提取之后,源中的条目将在此处转发。 282 results := make(chan *partialMatches, cap(source)) 283 284 session.pend.Add(2) 285 go func() { 286 //关闭Goroutine并终止所有源通道 287 defer session.pend.Done() 288 defer close(process) 289 290 defer func() { 291 for _, bloomSources := range sectionSources { 292 for _, bitSource := range bloomSources { 293 close(bitSource) 294 } 295 } 296 }() 297 //从源信道中读取段,并多路复用到所有位调度程序中。 298 for { 299 select { 300 case <-session.quit: 301 return 302 303 case subres, ok := <-source: 304 //从上一链接新建子结果 305 if !ok { 306 return 307 } 308 //将区段索引多路复用到所有位调度程序 309 for _, bloomSources := range sectionSources { 310 for _, bitSource := range bloomSources { 311 select { 312 case <-session.quit: 313 return 314 case bitSource <- subres.section: 315 } 316 } 317 } 318 //通知处理器此部分将可用 319 select { 320 case <-session.quit: 321 return 322 case process <- subres: 323 } 324 } 325 } 326 }() 327 328 go func() { 329 //拆除Goroutine并终止最终水槽通道 330 defer session.pend.Done() 331 defer close(results) 332 333 //读取源通知并收集传递的结果 334 for { 335 select { 336 case <-session.quit: 337 return 338 339 case subres, ok := <-process: 340 //已通知正在检索的节 341 if !ok { 342 return 343 } 344 //收集所有子结果并将它们合并在一起 345 var orVector []byte 346 for _, bloomSinks := range sectionSinks { 347 var andVector []byte 348 for _, bitSink := range bloomSinks { 349 var data []byte 350 select { 351 case <-session.quit: 352 return 353 case data = <-bitSink: 354 } 355 if andVector == nil { 356 andVector = make([]byte, int(m.sectionSize/8)) 357 copy(andVector, data) 358 } else { 359 bitutil.ANDBytes(andVector, andVector, data) 360 } 361 } 362 if orVector == nil { 363 orVector = andVector 364 } else { 365 bitutil.ORBytes(orVector, orVector, andVector) 366 } 367 } 368 369 if orVector == nil { 370 orVector = make([]byte, int(m.sectionSize/8)) 371 } 372 if subres.bitset != nil { 373 bitutil.ANDBytes(orVector, orVector, subres.bitset) 374 } 375 if bitutil.TestBytes(orVector) { 376 select { 377 case <-session.quit: 378 return 379 case results <- &partialMatches{subres.section, orVector}: 380 } 381 } 382 } 383 } 384 }() 385 return results 386 } 387 388 //分发服务器接收来自调度程序的请求并将它们排队到一个集合中 389 //待处理的请求,这些请求被分配给想要完成它们的检索器。 390 func (m *Matcher) distributor(dist chan *request, session *MatcherSession) { 391 defer session.pend.Done() 392 393 var ( 394 requests = make(map[uint][]uint64) //按节号排序的节请求的逐位列表 395 unallocs = make(map[uint]struct{}) //具有挂起请求但未分配给任何检索器的位 396 retrievers chan chan uint //等待检索器(如果unallocs为空,则切换为nil) 397 ) 398 var ( 399 allocs int //处理正常关闭请求的活动分配数 400 shutdown = session.quit //关闭请求通道,将优雅地等待挂起的请求 401 ) 402 403 //assign是一个帮助方法,用于尝试将挂起的位 404 //监听服务,或者在有人到达后安排它。 405 assign := func(bit uint) { 406 select { 407 case fetcher := <-m.retrievers: 408 allocs++ 409 fetcher <- bit 410 default: 411 //没有激活的检索器,开始监听新的检索器 412 retrievers = m.retrievers 413 unallocs[bit] = struct{}{} 414 } 415 } 416 417 for { 418 select { 419 case <-shutdown: 420 //请求正常关闭,等待所有挂起的请求得到满足。 421 if allocs == 0 { 422 return 423 } 424 shutdown = nil 425 426 case <-session.kill: 427 //未及时处理的未决请求,硬终止 428 return 429 430 case req := <-dist: 431 //到达新的检索请求,将其分发到某个提取进程 432 queue := requests[req.bit] 433 index := sort.Search(len(queue), func(i int) bool { return queue[i] >= req.section }) 434 requests[req.bit] = append(queue[:index], append([]uint64{req.section}, queue[index:]...)...) 435 436 //如果是一个新的位,我们有等待取数器,分配给他们 437 if len(queue) == 0 { 438 assign(req.bit) 439 } 440 441 case fetcher := <-retrievers: 442 //新的检索器到达,找到要分配的最下面的ed位。 443 bit, best := uint(0), uint64(math.MaxUint64) 444 for idx := range unallocs { 445 if requests[idx][0] < best { 446 bit, best = idx, requests[idx][0] 447 } 448 } 449 //停止跟踪此位(如果没有更多工作可用,则停止分配通知) 450 delete(unallocs, bit) 451 if len(unallocs) == 0 { 452 retrievers = nil 453 } 454 allocs++ 455 fetcher <- bit 456 457 case fetcher := <-m.counters: 458 //新任务计数请求已到达,返回项目数 459 fetcher <- uint(len(requests[<-fetcher])) 460 461 case fetcher := <-m.retrievals: 462 //等待任务检索、分配的新提取程序 463 task := <-fetcher 464 if want := len(task.Sections); want >= len(requests[task.Bit]) { 465 task.Sections = requests[task.Bit] 466 delete(requests, task.Bit) 467 } else { 468 task.Sections = append(task.Sections[:0], requests[task.Bit][:want]...) 469 requests[task.Bit] = append(requests[task.Bit][:0], requests[task.Bit][want:]...) 470 } 471 fetcher <- task 472 473 //如果有未分配的内容,请尝试分配给其他人 474 if len(requests[task.Bit]) > 0 { 475 assign(task.Bit) 476 } 477 478 case result := <-m.deliveries: 479 //从获取器中新建检索任务响应,拆分缺少的部分和 480 //交付完整的 481 var ( 482 sections = make([]uint64, 0, len(result.Sections)) 483 bitsets = make([][]byte, 0, len(result.Bitsets)) 484 missing = make([]uint64, 0, len(result.Sections)) 485 ) 486 for i, bitset := range result.Bitsets { 487 if len(bitset) == 0 { 488 missing = append(missing, result.Sections[i]) 489 continue 490 } 491 sections = append(sections, result.Sections[i]) 492 bitsets = append(bitsets, bitset) 493 } 494 m.schedulers[result.Bit].deliver(sections, bitsets) 495 allocs-- 496 497 //重新安排缺少的部分,如果新的部分可用,则分配位 498 if len(missing) > 0 { 499 queue := requests[result.Bit] 500 for _, section := range missing { 501 index := sort.Search(len(queue), func(i int) bool { return queue[i] >= section }) 502 queue = append(queue[:index], append([]uint64{section}, queue[index:]...)...) 503 } 504 requests[result.Bit] = queue 505 506 if len(queue) == len(missing) { 507 assign(result.Bit) 508 } 509 } 510 //如果我们正在关闭,请终止 511 if allocs == 0 && shutdown == nil { 512 return 513 } 514 } 515 } 516 } 517 518 //MatcherSession由已启动的Matcher返回,用作终止符 519 //对于正在运行的匹配操作。 520 type MatcherSession struct { 521 matcher *Matcher 522 523 closer sync.Once //同步对象以确保只关闭一次 524 quit chan struct{} //退出通道以请求管道终止 525 kill chan struct{} //表示非正常强制停机的通道 526 527 ctx context.Context //轻型客户端用于中止筛选的上下文 528 err atomic.Value //跟踪链深处检索失败的全局错误 529 530 pend sync.WaitGroup 531 } 532 533 //关闭停止匹配进程并等待所有子进程终止 534 //返回前。超时可用于正常关机,允许 535 //当前正在运行要在此时间之前完成的检索。 536 func (s *MatcherSession) Close() { 537 s.closer.Do(func() { 538 //信号终止并等待所有Goroutine关闭 539 close(s.quit) 540 time.AfterFunc(time.Second, func() { close(s.kill) }) 541 s.pend.Wait() 542 }) 543 } 544 545 //错误返回匹配会话期间遇到的任何失败。 546 func (s *MatcherSession) Error() error { 547 if err := s.err.Load(); err != nil { 548 return err.(error) 549 } 550 return nil 551 } 552 553 //allocateretrieval将一个bloom位索引分配给一个客户端进程,该进程可以 554 //立即请求并获取分配给该位的节内容或等待 555 //有一段时间需要更多的部分。 556 func (s *MatcherSession) AllocateRetrieval() (uint, bool) { 557 fetcher := make(chan uint) 558 559 select { 560 case <-s.quit: 561 return 0, false 562 case s.matcher.retrievers <- fetcher: 563 bit, ok := <-fetcher 564 return bit, ok 565 } 566 } 567 568 //PendingSections返回属于 569 //给定的牙轮钻头指数。 570 func (s *MatcherSession) PendingSections(bit uint) int { 571 fetcher := make(chan uint) 572 573 select { 574 case <-s.quit: 575 return 0 576 case s.matcher.counters <- fetcher: 577 fetcher <- bit 578 return int(<-fetcher) 579 } 580 } 581 582 //分配操作分配已分配的位任务队列的全部或部分 583 //到请求过程。 584 func (s *MatcherSession) AllocateSections(bit uint, count int) []uint64 { 585 fetcher := make(chan *Retrieval) 586 587 select { 588 case <-s.quit: 589 return nil 590 case s.matcher.retrievals <- fetcher: 591 task := &Retrieval{ 592 Bit: bit, 593 Sections: make([]uint64, count), 594 } 595 fetcher <- task 596 return (<-fetcher).Sections 597 } 598 } 599 600 //deliversections为特定的bloom提供一批区段位向量 601 //要注入处理管道的位索引。 602 func (s *MatcherSession) DeliverSections(bit uint, sections []uint64, bitsets [][]byte) { 603 select { 604 case <-s.kill: 605 return 606 case s.matcher.deliveries <- &Retrieval{Bit: bit, Sections: sections, Bitsets: bitsets}: 607 } 608 } 609 610 //多路复用轮询匹配器会话以执行检索任务,并将其多路复用到 611 //请求的检索队列将与其他会话一起提供服务。 612 // 613 //此方法将在会话的生存期内阻塞。即使在终止之后 614 //在会议期间,任何在飞行中的请求都需要得到响应!空响应 615 //不过在那种情况下还是可以的。 616 func (s *MatcherSession) Multiplex(batch int, wait time.Duration, mux chan chan *Retrieval) { 617 for { 618 //分配新的Bloom位索引以检索数据,完成后停止 619 bit, ok := s.AllocateRetrieval() 620 if !ok { 621 return 622 } 623 //位分配,如果低于批处理限制,则限制一点 624 if s.PendingSections(bit) < batch { 625 select { 626 case <-s.quit: 627 //会话终止,我们无法有意义地服务,中止 628 s.AllocateSections(bit, 0) 629 s.DeliverSections(bit, []uint64{}, [][]byte{}) 630 return 631 632 case <-time.After(wait): 633 //节流,获取任何可用的 634 } 635 } 636 //尽可能多地分配和请求服务 637 sections := s.AllocateSections(bit, batch) 638 request := make(chan *Retrieval) 639 640 select { 641 case <-s.quit: 642 //会话终止,我们无法有意义地服务,中止 643 s.DeliverSections(bit, sections, make([][]byte, len(sections))) 644 return 645 646 case mux <- request: 647 //接受检索,必须在中止之前到达 648 request <- &Retrieval{Bit: bit, Sections: sections, Context: s.ctx} 649 650 result := <-request 651 if result.Error != nil { 652 s.err.Store(result.Error) 653 s.Close() 654 } 655 s.DeliverSections(result.Bit, result.Sections, result.Bitsets) 656 } 657 } 658 }