1// Copyright 2015 The etcd Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package raft 16 17import ( 18 "fmt" 19 20 pb "go.etcd.io/etcd/raft/raftpb" 21 "go.etcd.io/etcd/raft/tracker" 22) 23 24// Status contains information about this Raft peer and its view of the system. 25// The Progress is only populated on the leader. 26type Status struct { 27 BasicStatus 28 Config tracker.Config 29 Progress map[uint64]tracker.Progress 30} 31 32// BasicStatus contains basic information about the Raft peer. It does not allocate. 33type BasicStatus struct { 34 ID uint64 35 36 pb.HardState 37 SoftState 38 39 Applied uint64 40 41 LeadTransferee uint64 42} 43 44func getProgressCopy(r *raft) map[uint64]tracker.Progress { 45 m := make(map[uint64]tracker.Progress) 46 r.prs.Visit(func(id uint64, pr *tracker.Progress) { 47 var p tracker.Progress 48 p = *pr 49 p.Inflights = pr.Inflights.Clone() 50 pr = nil 51 52 m[id] = p 53 }) 54 return m 55} 56 57func getBasicStatus(r *raft) BasicStatus { 58 s := BasicStatus{ 59 ID: r.id, 60 LeadTransferee: r.leadTransferee, 61 } 62 s.HardState = r.hardState() 63 s.SoftState = *r.softState() 64 s.Applied = r.raftLog.applied 65 return s 66} 67 68// getStatus gets a copy of the current raft status. 69func getStatus(r *raft) Status { 70 var s Status 71 s.BasicStatus = getBasicStatus(r) 72 if s.RaftState == StateLeader { 73 s.Progress = getProgressCopy(r) 74 } 75 s.Config = r.prs.Config.Clone() 76 return s 77} 78 79// MarshalJSON translates the raft status into JSON. 80// TODO: try to simplify this by introducing ID type into raft 81func (s Status) MarshalJSON() ([]byte, error) { 82 j := fmt.Sprintf(`{"id":"%x","term":%d,"vote":"%x","commit":%d,"lead":"%x","raftState":%q,"applied":%d,"progress":{`, 83 s.ID, s.Term, s.Vote, s.Commit, s.Lead, s.RaftState, s.Applied) 84 85 if len(s.Progress) == 0 { 86 j += "}," 87 } else { 88 for k, v := range s.Progress { 89 subj := fmt.Sprintf(`"%x":{"match":%d,"next":%d,"state":%q},`, k, v.Match, v.Next, v.State) 90 j += subj 91 } 92 // remove the trailing "," 93 j = j[:len(j)-1] + "}," 94 } 95 96 j += fmt.Sprintf(`"leadtransferee":"%x"}`, s.LeadTransferee) 97 return []byte(j), nil 98} 99 100func (s Status) String() string { 101 b, err := s.MarshalJSON() 102 if err != nil { 103 raftLogger.Panicf("unexpected error: %v", err) 104 } 105 return string(b) 106} 107