// createMergedSnapshotMessage creates a snapshot message that contains: raft status (term, conf), // a snapshot of v2 store inside raft.Snapshot as []byte, a snapshot of v3 KV in the top level message // as ReadCloser. func (s *EtcdServer) createMergedSnapshotMessage(m raftpb.Message, snapi uint64, confState raftpb.ConfState) snap.Message { snapt, err := s.r.raftStorage.Term(snapi) if err != nil { log.Panicf("get term should never fail: %v", err) } // get a snapshot of v2 store as []byte clone := s.store.Clone() d, err := clone.SaveNoCopy() if err != nil { plog.Panicf("store save should never fail: %v", err) } // get a snapshot of v3 KV as readCloser rc := newSnapshotReaderCloser(s.kv.Snapshot()) // put the []byte snapshot of store into raft snapshot and return the merged snapshot with // KV readCloser snapshot. snapshot := raftpb.Snapshot{ Metadata: raftpb.SnapshotMetadata{ Index: snapi, Term: snapt, ConfState: confState, }, Data: d, } m.Snapshot = snapshot return snap.Message{ Message: m, ReadCloser: rc, } }
// sendAppend sends RRPC, with entries to the given peer. func (r *raft) sendAppend(to uint64) { pr := r.prs[to] m := pb.Message{} m.To = to if r.needSnapshot(pr.next) { m.Type = pb.MsgSnap snapshot, err := r.raftLog.snapshot() if err != nil { panic(err) // TODO(bdarnell) } if IsEmptySnap(snapshot) { panic("need non-empty snapshot") } m.Snapshot = snapshot sindex, sterm := snapshot.Metadata.Index, snapshot.Metadata.Term log.Printf("raft: %x [firstindex: %d, commit: %d] sent snapshot[index: %d, term: %d] to %x [%s]", r.id, r.raftLog.firstIndex(), r.Commit, sindex, sterm, to, pr) } else { m.Type = pb.MsgApp m.Index = pr.next - 1 m.LogTerm = r.raftLog.term(pr.next - 1) m.Entries = r.raftLog.entries(pr.next) m.Commit = r.raftLog.committed // optimistically increase the next if the follower // has been matched. if n := len(m.Entries); pr.match != 0 && n != 0 { pr.optimisticUpdate(m.Entries[n-1].Index) } } r.send(m) }
// sendAppend sends RRPC, with entries to the given peer. func (r *raft) sendAppend(to uint64) { pr := r.prs[to] m := pb.Message{} m.To = to if r.needSnapshot(pr.next) { m.Type = pb.MsgSnap snapshot, err := r.raftLog.snapshot() if err != nil { panic(err) // TODO(bdarnell) } if IsEmptySnap(snapshot) { panic("need non-empty snapshot") } m.Snapshot = snapshot } else { m.Type = pb.MsgApp m.Index = pr.next - 1 m.LogTerm = r.raftLog.term(pr.next - 1) m.Entries = r.raftLog.entries(pr.next) m.Commit = r.raftLog.committed // optimistically increase the next if the follower // has been matched. if n := len(m.Entries); pr.match != 0 && n != 0 { pr.optimisticUpdate(m.Entries[n-1].Index) } } r.send(m) }
// createMergedSnapshotMessage creates a snapshot message that contains: raft status (term, conf), // a snapshot of v2 store inside raft.Snapshot as []byte, a snapshot of v3 KV in the top level message // as ReadCloser. func (s *EtcdServer) createMergedSnapshotMessage(m raftpb.Message, snapi uint64, confState raftpb.ConfState) snap.Message { snapt, err := s.r.raftStorage.Term(snapi) if err != nil { log.Panicf("get term should never fail: %v", err) } // get a snapshot of v2 store as []byte clone := s.store.Clone() d, err := clone.SaveNoCopy() if err != nil { plog.Panicf("store save should never fail: %v", err) } // commit kv to write metadata(for example: consistent index). s.KV().Commit() dbsnap := s.be.Snapshot() // get a snapshot of v3 KV as readCloser rc := newSnapshotReaderCloser(dbsnap) // put the []byte snapshot of store into raft snapshot and return the merged snapshot with // KV readCloser snapshot. snapshot := raftpb.Snapshot{ Metadata: raftpb.SnapshotMetadata{ Index: snapi, Term: snapt, ConfState: confState, }, Data: d, } m.Snapshot = snapshot return *snap.NewMessage(m, rc, dbsnap.Size()) }
// sendAppend sends RPC, with entries to the given peer. func (r *raft) sendAppend(to uint64) { pr := r.prs[to] if pr.isPaused() { return } m := pb.Message{} m.To = to term, errt := r.raftLog.term(pr.Next - 1) ents, erre := r.raftLog.entries(pr.Next, r.maxMsgSize) if errt != nil || erre != nil { // send snapshot if we failed to get term or entries if !pr.RecentActive { r.logger.Debugf("ignore sending snapshot to %x since it is not recently active", to) return } m.Type = pb.MsgSnap snapshot, err := r.raftLog.snapshot() if err != nil { if err == ErrSnapshotTemporarilyUnavailable { r.logger.Debugf("%x failed to send snapshot to %x because snapshot is temporarily unavailable", r.id, to) return } panic(err) // TODO(bdarnell) } if IsEmptySnap(snapshot) { panic("need non-empty snapshot") } m.Snapshot = snapshot sindex, sterm := snapshot.Metadata.Index, snapshot.Metadata.Term r.logger.Debugf("%x [firstindex: %d, commit: %d] sent snapshot[index: %d, term: %d] to %x [%s]", r.id, r.raftLog.firstIndex(), r.raftLog.committed, sindex, sterm, to, pr) pr.becomeSnapshot(sindex) r.logger.Debugf("%x paused sending replication messages to %x [%s]", r.id, to, pr) } else { m.Type = pb.MsgApp m.Index = pr.Next - 1 m.LogTerm = term m.Entries = ents m.Commit = r.raftLog.committed if n := len(m.Entries); n != 0 { switch pr.State { // optimistically increase the next when in ProgressStateReplicate case ProgressStateReplicate: last := m.Entries[n-1].Index pr.optimisticUpdate(last) pr.ins.add(last) case ProgressStateProbe: pr.pause() default: r.logger.Panicf("%x is sending append in unhandled state %s", r.id, pr.State) } } } r.send(m) }
// sendAppend sends RRPC, with entries to the given peer. func (r *raft) sendAppend(to int64) { pr := r.prs[to] m := pb.Message{} m.To = to m.Index = pr.next - 1 if r.needSnapshot(m.Index) { m.Type = msgSnap m.Snapshot = r.raftLog.snapshot } else { m.Type = msgApp m.LogTerm = r.raftLog.term(pr.next - 1) m.Entries = r.raftLog.entries(pr.next) m.Commit = r.raftLog.committed } r.send(m) }
// sendAppend sends RRPC, with entries to the given peer. func (r *raft) sendAppend(to uint64) { pr := r.prs[to] if pr.isPaused() { return } m := pb.Message{} m.To = to if r.needSnapshot(pr.Next) { m.Type = pb.MsgSnap snapshot, err := r.raftLog.snapshot() if err != nil { panic(err) // TODO(bdarnell) } if IsEmptySnap(snapshot) { panic("need non-empty snapshot") } m.Snapshot = snapshot sindex, sterm := snapshot.Metadata.Index, snapshot.Metadata.Term raftLogger.Infof("%x [firstindex: %d, commit: %d] sent snapshot[index: %d, term: %d] to %x [%s]", r.id, r.raftLog.firstIndex(), r.Commit, sindex, sterm, to, pr) pr.becomeSnapshot(sindex) raftLogger.Infof("%x paused sending replication messages to %x [%s]", r.id, to, pr) } else { m.Type = pb.MsgApp m.Index = pr.Next - 1 m.LogTerm = r.raftLog.term(pr.Next - 1) m.Entries = r.raftLog.entries(pr.Next, r.maxMsgSize) m.Commit = r.raftLog.committed if n := len(m.Entries); n != 0 { switch pr.State { // optimistically increase the next when in ProgressStateReplicate case ProgressStateReplicate: last := m.Entries[n-1].Index pr.optimisticUpdate(last) pr.ins.add(last) case ProgressStateProbe: pr.pause() default: raftLogger.Panicf("%x is sending append in unhandled state %s", r.id, pr.State) } } } r.send(m) }
// sendAppend sends RRPC, with entries to the given peer. func (r *raft) sendAppend(to uint64) { pr := r.prs[to] if pr.shouldWait() { log.Printf("raft: %x ignored sending %s to %x [%s]", r.id, pb.MsgApp, to, pr) return } m := pb.Message{} m.To = to if r.needSnapshot(pr.next) { m.Type = pb.MsgSnap snapshot, err := r.raftLog.snapshot() if err != nil { panic(err) // TODO(bdarnell) } if IsEmptySnap(snapshot) { panic("need non-empty snapshot") } m.Snapshot = snapshot sindex, sterm := snapshot.Metadata.Index, snapshot.Metadata.Term log.Printf("raft: %x [firstindex: %d, commit: %d] sent snapshot[index: %d, term: %d] to %x [%s]", r.id, r.raftLog.firstIndex(), r.Commit, sindex, sterm, to, pr) pr.waitSet(r.electionTimeout) } else { m.Type = pb.MsgApp m.Index = pr.next - 1 m.LogTerm = r.raftLog.term(pr.next - 1) m.Entries = r.raftLog.entries(pr.next) m.Commit = r.raftLog.committed // optimistically increase the next if the follower // has been matched. if n := len(m.Entries); pr.match != 0 && n != 0 { pr.optimisticUpdate(m.Entries[n-1].Index) } else if pr.match == 0 { // TODO (xiangli): better way to find out if the follower is in good path or not // a follower might be in bad path even if match != 0, since we optimistically // increase the next. pr.waitSet(r.heartbeatTimeout) } } r.send(m) }