util.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  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. package raft
  15. import (
  16. "bytes"
  17. "fmt"
  18. "strings"
  19. pb "go.etcd.io/etcd/raft/raftpb"
  20. )
  21. func (st StateType) MarshalJSON() ([]byte, error) {
  22. return []byte(fmt.Sprintf("%q", st.String())), nil
  23. }
  24. func min(a, b uint64) uint64 {
  25. if a > b {
  26. return b
  27. }
  28. return a
  29. }
  30. func max(a, b uint64) uint64 {
  31. if a > b {
  32. return a
  33. }
  34. return b
  35. }
  36. func IsLocalMsg(msgt pb.MessageType) bool {
  37. return msgt == pb.MsgHup || msgt == pb.MsgBeat || msgt == pb.MsgUnreachable ||
  38. msgt == pb.MsgSnapStatus || msgt == pb.MsgCheckQuorum
  39. }
  40. func IsResponseMsg(msgt pb.MessageType) bool {
  41. return msgt == pb.MsgAppResp || msgt == pb.MsgVoteResp || msgt == pb.MsgHeartbeatResp || msgt == pb.MsgUnreachable || msgt == pb.MsgPreVoteResp
  42. }
  43. // voteResponseType maps vote and prevote message types to their corresponding responses.
  44. func voteRespMsgType(msgt pb.MessageType) pb.MessageType {
  45. switch msgt {
  46. case pb.MsgVote:
  47. return pb.MsgVoteResp
  48. case pb.MsgPreVote:
  49. return pb.MsgPreVoteResp
  50. default:
  51. panic(fmt.Sprintf("not a vote message: %s", msgt))
  52. }
  53. }
  54. func DescribeHardState(hs pb.HardState) string {
  55. var buf strings.Builder
  56. fmt.Fprintf(&buf, "Term:%d", hs.Term)
  57. if hs.Vote != 0 {
  58. fmt.Fprintf(&buf, " Vote:%d", hs.Vote)
  59. }
  60. fmt.Fprintf(&buf, " Commit:%d", hs.Commit)
  61. return buf.String()
  62. }
  63. func DescribeSoftState(ss SoftState) string {
  64. return fmt.Sprintf("Lead:%d State:%s", ss.Lead, ss.RaftState)
  65. }
  66. func DescribeConfState(state pb.ConfState) string {
  67. return fmt.Sprintf(
  68. "Voters:%v VotersOutgoing:%v Learners:%v LearnersNext:%v AutoLeave:%v",
  69. state.Voters, state.VotersOutgoing, state.Learners, state.LearnersNext, state.AutoLeave,
  70. )
  71. }
  72. func DescribeSnapshot(snap pb.Snapshot) string {
  73. m := snap.Metadata
  74. return fmt.Sprintf("Index:%d Term:%d ConfState:%s", m.Index, m.Term, DescribeConfState(m.ConfState))
  75. }
  76. func DescribeReady(rd Ready, f EntryFormatter) string {
  77. var buf strings.Builder
  78. if rd.SoftState != nil {
  79. fmt.Fprint(&buf, DescribeSoftState(*rd.SoftState))
  80. buf.WriteByte('\n')
  81. }
  82. if !IsEmptyHardState(rd.HardState) {
  83. fmt.Fprintf(&buf, "HardState %s", DescribeHardState(rd.HardState))
  84. buf.WriteByte('\n')
  85. }
  86. if len(rd.ReadStates) > 0 {
  87. fmt.Fprintf(&buf, "ReadStates %v\n", rd.ReadStates)
  88. }
  89. if len(rd.Entries) > 0 {
  90. buf.WriteString("Entries:\n")
  91. fmt.Fprint(&buf, DescribeEntries(rd.Entries, f))
  92. }
  93. if !IsEmptySnap(rd.Snapshot) {
  94. fmt.Fprintf(&buf, "Snapshot %s\n", DescribeSnapshot(rd.Snapshot))
  95. }
  96. if len(rd.CommittedEntries) > 0 {
  97. buf.WriteString("CommittedEntries:\n")
  98. fmt.Fprint(&buf, DescribeEntries(rd.CommittedEntries, f))
  99. }
  100. if len(rd.Messages) > 0 {
  101. buf.WriteString("Messages:\n")
  102. for _, msg := range rd.Messages {
  103. fmt.Fprint(&buf, DescribeMessage(msg, f))
  104. buf.WriteByte('\n')
  105. }
  106. }
  107. if buf.Len() > 0 {
  108. return fmt.Sprintf("Ready MustSync=%t:\n%s", rd.MustSync, buf.String())
  109. }
  110. return "<empty Ready>"
  111. }
  112. // EntryFormatter can be implemented by the application to provide human-readable formatting
  113. // of entry data. Nil is a valid EntryFormatter and will use a default format.
  114. type EntryFormatter func([]byte) string
  115. // DescribeMessage returns a concise human-readable description of a
  116. // Message for debugging.
  117. func DescribeMessage(m pb.Message, f EntryFormatter) string {
  118. var buf bytes.Buffer
  119. fmt.Fprintf(&buf, "%x->%x %v Term:%d Log:%d/%d", m.From, m.To, m.Type, m.Term, m.LogTerm, m.Index)
  120. if m.Reject {
  121. fmt.Fprintf(&buf, " Rejected (Hint: %d)", m.RejectHint)
  122. }
  123. if m.Commit != 0 {
  124. fmt.Fprintf(&buf, " Commit:%d", m.Commit)
  125. }
  126. if len(m.Entries) > 0 {
  127. fmt.Fprintf(&buf, " Entries:[")
  128. for i, e := range m.Entries {
  129. if i != 0 {
  130. buf.WriteString(", ")
  131. }
  132. buf.WriteString(DescribeEntry(e, f))
  133. }
  134. fmt.Fprintf(&buf, "]")
  135. }
  136. if !IsEmptySnap(m.Snapshot) {
  137. fmt.Fprintf(&buf, " Snapshot: %s", DescribeSnapshot(m.Snapshot))
  138. }
  139. return buf.String()
  140. }
  141. // PayloadSize is the size of the payload of this Entry. Notably, it does not
  142. // depend on its Index or Term.
  143. func PayloadSize(e pb.Entry) int {
  144. return len(e.Data)
  145. }
  146. // DescribeEntry returns a concise human-readable description of an
  147. // Entry for debugging.
  148. func DescribeEntry(e pb.Entry, f EntryFormatter) string {
  149. if f == nil {
  150. f = func(data []byte) string { return fmt.Sprintf("%q", data) }
  151. }
  152. formatConfChange := func(cc pb.ConfChangeI) string {
  153. // TODO(tbg): give the EntryFormatter a type argument so that it gets
  154. // a chance to expose the Context.
  155. return pb.ConfChangesToString(cc.AsV2().Changes)
  156. }
  157. var formatted string
  158. switch e.Type {
  159. case pb.EntryNormal:
  160. formatted = f(e.Data)
  161. case pb.EntryConfChange:
  162. var cc pb.ConfChange
  163. if err := cc.Unmarshal(e.Data); err != nil {
  164. formatted = err.Error()
  165. } else {
  166. formatted = formatConfChange(cc)
  167. }
  168. case pb.EntryConfChangeV2:
  169. var cc pb.ConfChangeV2
  170. if err := cc.Unmarshal(e.Data); err != nil {
  171. formatted = err.Error()
  172. } else {
  173. formatted = formatConfChange(cc)
  174. }
  175. }
  176. if formatted != "" {
  177. formatted = " " + formatted
  178. }
  179. return fmt.Sprintf("%d/%d %s%s", e.Term, e.Index, e.Type, formatted)
  180. }
  181. // DescribeEntries calls DescribeEntry for each Entry, adding a newline to
  182. // each.
  183. func DescribeEntries(ents []pb.Entry, f EntryFormatter) string {
  184. var buf bytes.Buffer
  185. for _, e := range ents {
  186. _, _ = buf.WriteString(DescribeEntry(e, f) + "\n")
  187. }
  188. return buf.String()
  189. }
  190. func limitSize(ents []pb.Entry, maxSize uint64) []pb.Entry {
  191. if len(ents) == 0 {
  192. return ents
  193. }
  194. size := ents[0].Size()
  195. var limit int
  196. for limit = 1; limit < len(ents); limit++ {
  197. size += ents[limit].Size()
  198. if uint64(size) > maxSize {
  199. break
  200. }
  201. }
  202. return ents[:limit]
  203. }
  204. func assertConfStatesEquivalent(l Logger, cs1, cs2 pb.ConfState) {
  205. err := cs1.Equivalent(cs2)
  206. if err == nil {
  207. return
  208. }
  209. l.Panic(err)
  210. }