go-libp 2 p-kad-dht bootstrapソースコード分析

4814 ワード

Bootstrapロジック


エントリコード:go-libp 2 p-kad-dht/dht_bootstrap.go
入口方法:func(dht*IpfsDHT)Bootstrap(ctx context.context)error{最終的にこの方法はrunBootstrap方法を実行し、本当の操作はここから始まる
  • func (dht *IpfsDHT) runBootstrap(ctx context.Context, cfg BootstrapConfig) error

  • 原理は多分、ランダムなターゲットrandomIDを生成して、ネットの中でfindというpeerを生成して、きっと見つからないので、各peerはあなたにこのrandomIDに最も近いpeers、つまりCloserPeersに戻ってあなたの地元のkバケツを充填して、このような動作は5分に1回実行されていることを黙認して、だからkバケツはすぐに埋められます.
  • func (dht *IpfsDHT) FindPeer(ctx context.Context, id peer.ID) (_ pstore.PeerInfo, err error)

  • この方法は今現地で探します:dht.FindLocal(id)ローカルはルーティングテーブルで探していません
    peers := dht.routingTable.NearestPeers(kb.ConvertPeerID(id)、AlphaValue)という方法の論理は、AlphaValue=3で、最低でも3つのpeersに送信するターゲットidがxorに1つのバケツを出されることを確保しなければならないことを示しています.このバケツが空いているか、バケツに3つ未満のpeerが近いバケツからpeerに戻り、バケツにpeerがAlphaValueを超えるとバケツの総数で不思議なことに、最後に3つの距離が最も近いpeerしか選ばれません.どうしてですか.
    func (rt *RoutingTable) NearestPeers(id ID, count int) []peer.ID {
        cpl := commonPrefixLen(id, rt.local)
    
        rt.tabLock.RLock()
    
        // Get bucket at cpl index or last bucket
        var bucket *Bucket
        if cpl >= len(rt.Buckets) {
            cpl = len(rt.Buckets) - 1
        }
        bucket = rt.Buckets[cpl]
    
        peerArr := make(peerSorterArr, 0, count)
        //TODO   peerArr  ,  make peerArr
        peerArr = copyPeersFromList(id, peerArr, bucket.list)
        if len(peerArr) < count {
            // In the case of an unusual split, one bucket may be short or empty.
            // if this happens, search both surrounding buckets for nearby peers
            if cpl > 0 {
                plist := rt.Buckets[cpl-1].list
                peerArr = copyPeersFromList(id, peerArr, plist)
            }
    
            if cpl < len(rt.Buckets)-1 {
                plist := rt.Buckets[cpl+1].list
                peerArr = copyPeersFromList(id, peerArr, plist)
            }
        }
        rt.tabLock.RUnlock()
    
        // Sort by distance to local peer
        sort.Sort(peerArr)
        // TODO  ? 3 , ?
        if count < len(peerArr) {
            peerArr = peerArr[:count]
        }
    
        out := make([]peer.ID, 0, len(peerArr))
        for _, p := range peerArr {
            out = append(out, p.p)
        }
    
        return out
    }
    

    応答するpeerごとのttlはqueryと同時にリフレッシュされますが、queryリクエストは最大3つのpeerにのみ送信されます.

    リクエストの返されたcloserは処理されていないようですが、なぜですか?


    辛抱強く探す必要があるので、一回り見てやっとfunc(r*dhtQueryRunner)queryPeer(proc process.Process,p peer.ID)の中で答えを見つけた.これはあまりにも隠蔽的で、コードの作者を非難した.
    次はFindPeerのコードクリップです.
        parent := ctx
        query := dht.newQuery(string(id), func(ctx context.Context, p peer.ID) (*dhtQueryResult, error) {
            notif.PublishQueryEvent(parent, &notif.QueryEvent{
                Type: notif.SendingQuery,
                ID:   p,
            })
    
            pmes, err := dht.findPeerSingle(ctx, p, id)
            if err != nil {
                return nil, err
            }
    
            closer := pmes.GetCloserPeers()
            clpeerInfos := pb.PBPeersToPeerInfos(closer)
    
            // see if we got the peer here
            for _, npi := range clpeerInfos {
                if npi.ID == id {
                    // add by liangc ---->
                    notif.PublishQueryEvent(parent, &notif.QueryEvent{
                        Type: notif.PeerFindby,
                        ID:   p,
                    })
                    // add by liangc 

    上の最後の一言Runには、次のような呼び出しトラックが含まれています.
  • func (q dhtQuery) Run(ctx context.Context, peers []peer.ID) (dhtQueryResult, error)
  • func (r dhtQueryRunner) Run(ctx context.Context, peers []peer.ID) (dhtQueryResult, error)
  • func (r *dhtQueryRunner) spawnWorkers(proc process.Process)
  • func (r *dhtQueryRunner) queryPeer(proc process.Process, p peer.ID)




  • dhtQueryRunnerで义齿
        } else if len(res.closerPeers) > 0 {
            log.Debugf("PEERS CLOSER -- worker for: %v (%d closer peers)", p, len(res.closerPeers))
            for _, next := range res.closerPeers {
                if next.ID == r.query.dht.self { // don't add self.
                    log.Debugf("PEERS CLOSER -- worker for: %v found self", p)
                    continue
                }
    
                // add their addresses to the dialer's peerstore
                r.query.dht.peerstore.AddAddrs(next.ID, next.Addrs, pstore.TempAddrTTL)
                r.addPeerToQuery(next.ID)
                log.Debugf("PEERS CLOSER -- worker for: %v added %v (%v)", p, next.ID, next.Addrs)
            }
        } else {
            log.Debugf("QUERY worker for: %v - not found, and no closer peers.", p)
        }
    

    各closerはpeerstoreに配置され、peersseenにも配置されていることがわかります.実際には、ここではpeersseenを反復してrunメソッドを実行します.peersseenはスレッドの安全なsetタイプです.これにより、すべてのrunがスレッドで実行されているにもかかわらず、メインプログラムのローテーションでsetの新しいメンバーを逃さないことを保証します.また、setは重複するpeerが重複しないことを保証します.これによりsetは絶え間なく増加しないと断定できる
    実はbootstrapはここまでで何も見ることはありません