HyperLedgerFabric源码解读(4)-pull

关于gossip pull机制的相关操作

/*
 PullEngine是一个执行pull的gossip对象; 维护一个内部状态关于item 通过字符串编号来识别;
 协议如下
 1、发送者发送一个携带特殊NONCE的Hello消息给其他远程对等节点peer
 2、每个远程对等节点peer响应消息的摘要及对应的NONCE
 3、发送者检验接收的NONCE的有效性,聚集这些摘要;创建一个request包含想从指定每个远程对等节点peer item的id 并发送每个request到对应的对等节点peer
 4、若是每个对等点保存了item request和NONCE,那对应的对等节点peer将返回包含请求项的响应
 远程对等节点peer                                          发送者
     O  <-------- Hello  -------------------------       O  (hello请求)
    /|\ --------- Digest <[3,5,8, 10...], NONCE> -------->     /|\ (摘要响应)
     |  <-------- Request <[3,8], NONCE> -----------------      |  (验证摘要请求)
    / \ --------- Response <[item3, item8], NONCE>------->     / \ (请求响应)
*/

const (
    defDigestWaitTime   = time.Duration(1000) * time.Millisecond                 // 摘要等待周期
    defRequestWaitTime  = time.Duration(1500) * time.Millisecond                 // 请求等待周期
    defResponseWaitTime = time.Duration(2000) * time.Millisecond                 // 响应等待周期
)

// 设置摘要等待时间
// SetDigestWaitTime sets the digest wait time
func SetDigestWaitTime(time time.Duration) {
    viper.Set("peer.gossip.digestWaitTime", time)
}

// 设置请求等待时间
// SetRequestWaitTime sets the request wait time
func SetRequestWaitTime(time time.Duration) {
    viper.Set("peer.gossip.requestWaitTime", time)
}

// 设置响应等待时间
// SetResponseWaitTime sets the response wait time
func SetResponseWaitTime(time time.Duration) {
    viper.Set("peer.gossip.responseWaitTime", time)
}
// DigestFilter 摘要过滤策略器
// 根据消息的上下文将发送hello或请求的远程对等点,将应用摘要过滤策略器
// DigestFilter filters digests to be sent to a remote peer that
// sent a hello or a request, based on its messages's context
type DigestFilter func(context interface{}) func(digestItem string) bool
// PullAdapter: PullEngine的适配器接口
// 为了向远程的PullEngine实例发送消息,PullEngine是需要的
// 当相应的消息从远程对等节点peer达到时,PullEngine将按照预期调用OnHello、OnDigest、OnReq、OnRes
// PullAdapter is needed by the PullEngine in order to
// send messages to the remote PullEngine instances.
// The PullEngine expects to be invoked with
// OnHello, OnDigest, OnReq, OnRes when the respective message arrives
// from a remote PullEngine
type PullAdapter interface {
    // pullEngine启动协议时需要的对等节点列表peers
    // SelectPeers returns a slice of peers which the engine will initiate the protocol with
    SelectPeers() []string

    // 启动协议时发送hello消息并返回一个预期摘要信息以及NONCE
    // Hello sends a hello message to initiate the protocol
    // and returns an NONCE that is expected to be returned
    // in the digest message.
    Hello(dest string, nonce uint64)

    // 发送一个摘要消息给远程的PullEngine,其中context参数指定目的PullEngine
    // SendDigest sends a digest to a remote PullEngine.
    // The context parameter specifies the remote engine to send to.
    SendDigest(digest []string, nonce uint64, context interface{})

    // 发送item数组到dest指定远程PullEngine(request消息)
    // SendReq sends an array of items to a certain remote PullEngine identified
    // by a string
    SendReq(dest string, items []string, nonce uint64)

    // 发送item数组到context指定远程PullEngine(response消息)
    // SendRes sends an array of items to a remote PullEngine identified by a context.
    SendRes(items []string, context interface{}, nonce uint64)
}
// PullEnine是个在PullAdapter帮助下实际调用pull算法的组件
// PullEngine is the component that actually invokes the pull algorithm
// with the help of the PullAdapter
type PullEngine struct {
    PullAdapter
    stopFlag           int32                   // 是否可用
    state              *util.Set               // 状态集
    item2owners        map[string][]string     // items所有者集
    peers2nonces       map[string]uint64       // 对等节点peer的nonces集(peer:nonce)
    nonces2peers       map[uint64]string       // (nonce:peer)
    acceptingDigests   int32                   // 接收的摘要
    acceptingResponses int32                   // 接收的响应
    lock               sync.Mutex
    outgoingNONCES     *util.Set               // 发出的nonces
    incomingNONCES     *util.Set               // 接收的nonces
    digFilter          DigestFilter            // 摘要过滤策略

    digestWaitTime   time.Duration             // 摘要等待周期
    requestWaitTime  time.Duration             // 请求等待周期
    responseWaitTime time.Duration             // 响应等待周期
}
// 创建一个带有确定休眠时间的PullEngine实例在pull启动时,当发送摘要和响应消息时能使用给定的过滤策略
// NewPullEngineWithFilter creates an instance of a PullEngine with a certain sleep time
// between pull initiations, and uses the given filters when sending digests and responses
func NewPullEngineWithFilter(participant PullAdapter,  // Pull适配器
    sleepTime time.Duration,                           // 休眠时长
    df DigestFilter) *PullEngine {                     // 摘要过滤器
    engine := &PullEngine{
        PullAdapter:        participant,               // pull参与者
        stopFlag:           int32(0),                  // 停止标记
        state:              util.NewSet(),             // 状态集
        item2owners:        make(map[string][]string),
        peers2nonces:       make(map[string]uint64),
        nonces2peers:       make(map[uint64]string),
        acceptingDigests:   int32(0),
        acceptingResponses: int32(0),
        incomingNONCES:     util.NewSet(),
        outgoingNONCES:     util.NewSet(),
        digFilter:          df,
        digestWaitTime:     util.GetDurationOrDefault("peer.gossip.digestWaitTime", defDigestWaitTime),
        requestWaitTime:    util.GetDurationOrDefault("peer.gossip.requestWaitTime", defRequestWaitTime),
        responseWaitTime:   util.GetDurationOrDefault("peer.gossip.responseWaitTime", defResponseWaitTime),
    }

    go func() {           // 开启goroutine执行pullEngine初始化
        for !engine.toDie() {     // pullEngine可用
            time.Sleep(sleepTime)  // 双重检查pullEngine是否可用
            if engine.toDie() {
                return
            }
            engine.initiatePull()  // 初始化pullEngine
        }
    }()

    return engine
}
// 新建PullEngine实例并指定初始化的休眠时长
// NewPullEngine creates an instance of a PullEngine with a certain sleep time
// between pull initiations
func NewPullEngine(participant PullAdapter,  // Pull适配器
    sleepTime time.Duration) *PullEngine {   // 休眠时长
    acceptAllFilter := func(_ interface{}) func(string) bool {  // 过滤策略:接收所有的内容
        return func(_ string) bool {
            return true
        }
    }
    return NewPullEngineWithFilter(participant, sleepTime, acceptAllFilter)
}
// PullEngine是否可用
func (engine *PullEngine) toDie() bool {
    return atomic.LoadInt32(&(engine.stopFlag)) == int32(1)
}
// 接收响应内容
func (engine *PullEngine) acceptResponses() {
    atomic.StoreInt32(&(engine.acceptingResponses), int32(1))
}
// 是否为响应内容
func (engine *PullEngine) isAcceptingResponses() bool {
    return atomic.LoadInt32(&(engine.acceptingResponses)) == int32(1)
}
// 接收摘要
func (engine *PullEngine) acceptDigests() {
    atomic.StoreInt32(&(engine.acceptingDigests), int32(1))
}
// 是否为摘要
func (engine *PullEngine) isAcceptingDigests() bool {
    return atomic.LoadInt32(&(engine.acceptingDigests)) == int32(1)
}
// 忽略摘要
func (engine *PullEngine) ignoreDigests() {
    atomic.StoreInt32(&(engine.acceptingDigests), int32(0))
}
// 停止PullEngine
// Stop stops the engine
func (engine *PullEngine) Stop() {
    atomic.StoreInt32(&(engine.stopFlag), int32(1))
}
// 初始化PullEngine
// 发送hello消息 并完成返回摘要处理
func (engine *PullEngine) initiatePull() {
    engine.lock.Lock()
    defer engine.lock.Unlock()

    // 接收摘要
    engine.acceptDigests()
    for _, peer := range engine.SelectPeers() { // 遍历远程对等节点peer
        nonce := engine.newNONCE()               // 新建NONCE
        engine.outgoingNONCES.Add(nonce)         // 对外输出NONCE
        engine.nonces2peers[nonce] = peer        // (nonce, peer)映射表
        engine.peers2nonces[peer] = nonce        // (peer, nonce)映射表
        engine.Hello(peer, nonce)                // 发送hello信息给各自远程对等节点peer
    }

    time.AfterFunc(engine.digestWaitTime, func() {   // 等待摘要时长  处理返回的摘要
        engine.processIncomingDigests()
    })
}
// 处理摘要
func (engine *PullEngine) processIncomingDigests() {
    engine.ignoreDigests()         // 忽略摘要

    engine.lock.Lock()
    defer engine.lock.Unlock()

    requestMapping := make(map[string][]string)  // 构建请求映射表  (目的dest , items's ids)
    for n, sources := range engine.item2owners {  // item2owners: 
        // select a random source
        source := sources[util.RandomInt(len(sources))]
        if _, exists := requestMapping[source]; !exists {
            requestMapping[source] = make([]string, 0)
        }
        // append the number to that source
        requestMapping[source] = append(requestMapping[source], n)
    }

    engine.acceptResponses()

    for dest, seqsToReq := range requestMapping {   // 遍历对各个peer执行request消息
        engine.SendReq(dest, seqsToReq, engine.peers2nonces[dest])
    }

    time.AfterFunc(engine.responseWaitTime, engine.endPull)  // 等待响应时长 执行结束pull
}
// 结束pull
func (engine *PullEngine) endPull() {
    engine.lock.Lock()
    defer engine.lock.Unlock()

    atomic.StoreInt32(&(engine.acceptingResponses), int32(0))  // acceptingResponses 置 为0
    engine.outgoingNONCES.Clear()                                    // 输出的nonce清空

    engine.item2owners = make(map[string][]string)                   // 置空映射表
    engine.peers2nonces = make(map[string]uint64)
    engine.nonces2peers = make(map[uint64]string)
}
// 当摘要到达时通知PullEngine
// OnDigest notifies the engine that a digest has arrived
func (engine *PullEngine) OnDigest(digest []string, nonce uint64, context interface{}) {
    if !engine.isAcceptingDigests() || !engine.outgoingNONCES.Exists(nonce) {   // 摘要和nonce检查
        return
    }

    engine.lock.Lock()
    defer engine.lock.Unlock()

    for _, n := range digest {  // 遍历接收到的摘要
        if engine.state.Exists(n) { // 状态集已存在则不做处理
            continue
        }

        if _, exists := engine.item2owners[n]; !exists {  // 不存在 新建内容便于后续添加新内容; 若存在则增加peer到item2owners映射表
            engine.item2owners[n] = make([]string, 0)
        }
        // 存在则新增
        engine.item2owners[n] = append(engine.item2owners[n], engine.nonces2peers[nonce])
    }
}
// 将item添加到状态集中
// Add adds items to the state
func (engine *PullEngine) Add(seqs ...string) {
    for _, seq := range seqs {
        engine.state.Add(seq)
    }
}
// 移除状态集中的item
// Remove removes items from the state
func (engine *PullEngine) Remove(seqs ...string) {
    for _, seq := range seqs {
        engine.state.Remove(seq)
    }
}
// 当hello消息到达时通知PullEngine
// OnHello notifies the engine a hello has arrived
func (engine *PullEngine) OnHello(nonce uint64, context interface{}) {
    engine.incomingNONCES.Add(nonce)                          // 新增nonce

    time.AfterFunc(engine.requestWaitTime, func() {          // 执行request等待时长后的操作
        engine.incomingNONCES.Remove(nonce)                   // 移除nonce
    })

    a := engine.state.ToArray()                
    var digest []string
    filter := engine.digFilter(context)           // 获取PullEngine的摘要过滤器
    for _, item := range a {                     // 遍历状态内容 通过filter的摘要则追加到本地digest数组中
        dig := item.(string)
        if !filter(dig) {
            continue
        }
        digest = append(digest, dig)
    }
    if len(digest) == 0 {
        return
    }
    engine.SendDigest(digest, nonce, context)   // 发送摘要请求
}
// 当request消息到达时通知PullEngine
// OnReq notifies the engine a request has arrived
func (engine *PullEngine) OnReq(items []string, nonce uint64, context interface{}) {
    if !engine.incomingNONCES.Exists(nonce) {                      // 不存在nonce 则忽略
        return
    }
    engine.lock.Lock()
    defer engine.lock.Unlock()

    filter := engine.digFilter(context)         // 获取过滤器
    var items2Send []string
    for _, item := range items {               // 遍历item 满足过滤器 并且engine状态集已存在 便追加到本地item2Seed中
        if engine.state.Exists(item) && filter(item) {
            items2Send = append(items2Send, item)
        }
    }

    if len(items2Send) == 0 {
        return
    }

    go engine.SendRes(items2Send, context, nonce)    // 执行发送response消息
}
// 当response消息到达 则通知PullEngine
// OnRes notifies the engine a response has arrived
func (engine *PullEngine) OnRes(items []string, nonce uint64) {
    if !engine.outgoingNONCES.Exists(nonce) || !engine.isAcceptingResponses() {  // nonce不存在engine的outgoingNONCES中或非响应消息 则忽略
        return
    }

    engine.Add(items...)  // 添加item
}
// 新建NONCE
func (engine *PullEngine) newNONCE() uint64 {
    n := uint64(0)                          // 定义一个uint64的变量
    for {                                   // 循环执行 通过随机函数生产一个随机数 并且该随机数不存在outgoingNONCES中  则接受该NONCE
        n = util.RandomUInt64()
        if !engine.outgoingNONCES.Exists(n) {
            return n
        }
    }
}

你可能感兴趣的:(HyperLedgerFabric源码解读(4)-pull)