美文网首页区块链研习社区块链研究
btcd 源码分析系列:2 - addrmanager

btcd 源码分析系列:2 - addrmanager

作者: tpkeeper | 来源:发表于2019-09-28 08:43 被阅读0次

    参考:btcd

    • addrmanager 主要提供了peer地址的管理功能,包括地址的增删查改
    • 通过存储json序列化后的数据到本地文件实现持久化
    • btc启动的时候,会读取该json文件,将保存的节点信息读取到内存中
    • btc运行的过程中,每过一段时间(十分钟)就持久化一次,以备下次启动时使用
    • btc退出时,会再次持久化一次

    一、创建addrmanager对象

    // New returns a new bitcoin address manager.
    // Use Start to begin processing asynchronous address updates.
    func New(dataDir string, lookupFunc func(string) ([]net.IP, error)) *AddrManager {
        am := AddrManager{
            peersFile:      filepath.Join(dataDir, "peers.json"),
            lookupFunc:     lookupFunc,
            rand:           rand.New(rand.NewSource(time.Now().UnixNano())),
            quit:           make(chan struct{}),
            localAddresses: make(map[string]*localAddress),
            version:        serialisationVersion,
        }
        am.reset()
        return &am
    }
    

    二、启动

    • 通过started字段保证一个addrManager只能start一次

    • loadPeers()就是读取硬盘上保存的peer信息到内存中

    • addressHander 启动一个协程处理周期性的持久化和

      // Start begins the core address handler which manages a pool of known
      // addresses, timeouts, and interval based writes.
      func (a *AddrManager) Start() {
          // Already started?
          if atomic.AddInt32(&a.started, 1) != 1 {
              return
          }
      
          log.Trace("Starting address manager")
      
          // Load peers we already know about from file.
          a.loadPeers()
      
          // Start the address ticker to save addresses periodically.
          a.wg.Add(1)
          go a.addressHandler()
      }
      

    三、停止

    • stop的时候通过close channel 通知并等待子协程(处理持久化任务)的退出

      // Stop gracefully shuts down the address manager by stopping the main handler.
      func (a *AddrManager) Stop() error {
          if atomic.AddInt32(&a.shutdown, 1) != 1 {
              log.Warnf("Address manager is already in the process of " +
                  "shutting down")
              return nil
          }
      
          log.Infof("Address manager shutting down")
          close(a.quit)
          a.wg.Wait()
          return nil
      }
      
      // addressHandler is the main handler for the address manager.  It must be run
      // as a goroutine.
      func (a *AddrManager) addressHandler() {
          dumpAddressTicker := time.NewTicker(dumpAddressInterval)
          defer dumpAddressTicker.Stop()
      out:
          for {
              select {
              case <-dumpAddressTicker.C:
                  a.savePeers()
      
              case <-a.quit:
                  break out
              }
          }
          a.savePeers()
          a.wg.Done()
          log.Trace("Address handler done")
      }
      

    四、获取地址

    • 用了自己的随机算法选取部分地址返回

    • 这个随机算法简单的说就是,先根据百分比确定返回的数量max,然后选中第i个,并与i-n之间的随机一个交换,i从0依次递增到max-1,这样一共选出来max个

      // AddressCache returns the current address cache.  It must be treated as
      // read-only (but since it is a copy now, this is not as dangerous).
      func (a *AddrManager) AddressCache() []*wire.NetAddress {
          allAddr := a.getAddresses()
      
          numAddresses := len(allAddr) * getAddrPercent / 100
          if numAddresses > getAddrMax {
              numAddresses = getAddrMax
          }
      
          // Fisher-Yates shuffle the array. We only need to do the first
          // `numAddresses' since we are throwing the rest.
          for i := 0; i < numAddresses; i++ {
              // pick a number between current index and the end
              j := rand.Intn(len(allAddr)-i) + i
              allAddr[i], allAddr[j] = allAddr[j], allAddr[i]
          }
      
          // slice off the limit we are willing to share.
          return allAddr[0:numAddresses]
      }
      
      

    相关文章

      网友评论

        本文标题:btcd 源码分析系列:2 - addrmanager

        本文链接:https://www.haomeiwen.com/subject/ifuhyctx.html