etcd中raft协议的消息(六)——客户端的写请求相关的消息(MsgProp消息)

        在etcd-raft模块中,客户端发往集群中的写请求是通过MsgProp消息表示的。Raft集群中只有Leader节点能够响应客户端的写入请求。

        客户端请求的写操作,会通过调用Node接口的Propose函数请求到raft模块中,当Follower接收到MsgProp类型的消息会转发到Leader节点,所以MsgProp消息的主要处理是在raft.stepLeader()方法中实现。主要流程如下:

   etcd中raft协议的消息(六)——客户端的写请求相关的消息(MsgProp消息)

   1.判断MsgProp是否携带Entry记录,如果未携带则输出异常日志并终止程序

   2.检测当前节点是否被移除集群,如果当前节点以Leader状态被移除集群,则不再处理MsgProp消息

   3.判断当前是否正在进行Leader节点转移,如果正在转移则返回错误

   4.遍历MsgProp消息携带的全部Entry,如果pendingConfIndex大于已提交的位置,则该Entry的类型设置为EntryNormal,否则更新pendingConfIndex值

   5.将上述Entries记录追加到当前节点的raftLog中

  6.向集群中的其他节点发送MspApp消息复制日志

func stepLeader(r *raft, m pb.Message) error {
    switch m.Type {
    //其他消息省略.....
    case pb.MsgProp:
    if len(m.Entries) == 0 {  //判断MsgProp是否携带Entry记录,如果未携带则输出异常日志并终止程序
        r.logger.Panicf("%x stepped empty MsgProp", r.id)
    }
    if _, ok := r.prs[r.id]; !ok {  //检测当前节点是否被移除集群,如果当前节点以Leader状态被移除集群,则不再处理MsgProp消息
       // If we are not currently a member of the range (i.e. this node
       // was removed from the configuration while serving as leader),
       // drop any new proposals.
       return ErrProposalDropped
    }
    if r.leadTransferee != None {   //判断当前是否正在进行Leader节点转移
       r.logger.Debugf("%x [term %d] transfer leadership to %x is in progress; dropping proposal", r.id, r.Term, r.leadTransferee)
       return ErrProposalDropped
    }

    for i, e := range m.Entries {  //遍历MsgProp消息携带的全部Entry
       if e.Type == pb.EntryConfChange {
          if r.pendingConfIndex > r.raftLog.applied {
             r.logger.Infof("propose conf %s ignored since pending unapplied configuration [index %d, applied %d]",
            e.String(), r.pendingConfIndex, r.raftLog.applied)
             m.Entries[i] = pb.Entry{Type: pb.EntryNormal}
          } else {
             r.pendingConfIndex = r.raftLog.lastIndex() + uint64(i) + 1
          }
       }
    }
    r.appendEntry(m.Entries...)  //将上述Entry记录追加到当前节点的raftLog中
    r.bcastAppend()  //向集群中的其他节点发送MspApp消息复制日志
    return nil
    }
}