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