blob: bf4898c9e3f8ea41f7b3b139a22b4a065cfac5bf [file] [log] [blame]
William Kurkianea869482019-04-09 15:16:11 -04001// 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"
Abhilash S.L3b494632019-07-16 15:51:09 +053021 "go.etcd.io/etcd/raft/tracker"
William Kurkianea869482019-04-09 15:16:11 -040022)
23
24type Status struct {
25 ID uint64
26
27 pb.HardState
28 SoftState
29
30 Applied uint64
Abhilash S.L3b494632019-07-16 15:51:09 +053031 Progress map[uint64]tracker.Progress
William Kurkianea869482019-04-09 15:16:11 -040032
33 LeadTransferee uint64
34}
35
Abhilash S.L3b494632019-07-16 15:51:09 +053036func getProgressCopy(r *raft) map[uint64]tracker.Progress {
37 m := make(map[uint64]tracker.Progress)
38 r.prs.Visit(func(id uint64, pr *tracker.Progress) {
39 var p tracker.Progress
40 p, pr = *pr, nil /* avoid accidental reuse below */
William Kurkianea869482019-04-09 15:16:11 -040041
Abhilash S.L3b494632019-07-16 15:51:09 +053042 // The inflight buffer is tricky to copy and besides, it isn't exposed
43 // to the client, so pretend it's nil.
44 p.Inflights = nil
45
46 m[id] = p
47 })
48 return m
William Kurkianea869482019-04-09 15:16:11 -040049}
50
51func getStatusWithoutProgress(r *raft) Status {
52 s := Status{
53 ID: r.id,
54 LeadTransferee: r.leadTransferee,
55 }
56 s.HardState = r.hardState()
57 s.SoftState = *r.softState()
58 s.Applied = r.raftLog.applied
59 return s
60}
61
62// getStatus gets a copy of the current raft status.
63func getStatus(r *raft) Status {
64 s := getStatusWithoutProgress(r)
65 if s.RaftState == StateLeader {
66 s.Progress = getProgressCopy(r)
67 }
68 return s
69}
70
71// MarshalJSON translates the raft status into JSON.
72// TODO: try to simplify this by introducing ID type into raft
73func (s Status) MarshalJSON() ([]byte, error) {
74 j := fmt.Sprintf(`{"id":"%x","term":%d,"vote":"%x","commit":%d,"lead":"%x","raftState":%q,"applied":%d,"progress":{`,
75 s.ID, s.Term, s.Vote, s.Commit, s.Lead, s.RaftState, s.Applied)
76
77 if len(s.Progress) == 0 {
78 j += "},"
79 } else {
80 for k, v := range s.Progress {
81 subj := fmt.Sprintf(`"%x":{"match":%d,"next":%d,"state":%q},`, k, v.Match, v.Next, v.State)
82 j += subj
83 }
84 // remove the trailing ","
85 j = j[:len(j)-1] + "},"
86 }
87
88 j += fmt.Sprintf(`"leadtransferee":"%x"}`, s.LeadTransferee)
89 return []byte(j), nil
90}
91
92func (s Status) String() string {
93 b, err := s.MarshalJSON()
94 if err != nil {
95 raftLogger.Panicf("unexpected error: %v", err)
96 }
97 return string(b)
98}