github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/raft.go (about)

     1  // Copyright 2015 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package kvserver
    12  
    13  import (
    14  	"bytes"
    15  	"context"
    16  	"fmt"
    17  	"sync"
    18  
    19  	"github.com/cockroachdb/cockroach/pkg/kv/kvserver/kvserverbase"
    20  	"github.com/cockroachdb/cockroach/pkg/util/log"
    21  	"go.etcd.io/etcd/raft"
    22  	"go.etcd.io/etcd/raft/raftpb"
    23  )
    24  
    25  // maxRaftMsgType is the maximum value in the raft.MessageType enum.
    26  const maxRaftMsgType = raftpb.MsgPreVoteResp
    27  
    28  func init() {
    29  	for v := range raftpb.MessageType_name {
    30  		typ := raftpb.MessageType(v)
    31  		if typ > maxRaftMsgType {
    32  			panic(fmt.Sprintf("raft.MessageType (%s) with value larger than maxRaftMsgType", typ))
    33  		}
    34  	}
    35  }
    36  
    37  // init installs an adapter to use clog for log messages from raft which
    38  // don't belong to any range.
    39  func init() {
    40  	raft.SetLogger(&raftLogger{ctx: context.Background()})
    41  }
    42  
    43  // *clogLogger implements the raft.Logger interface. Note that all methods
    44  // must be defined on the pointer type rather than the value type because
    45  // (at least in the go 1.4 compiler), methods on a value type called through
    46  // an interface pointer go through an additional layer of indirection that
    47  // appears on the stack, and would make all our stack frame offsets incorrect.
    48  //
    49  // Raft is fairly verbose at the "info" level, so we map "info" messages to
    50  // clog.V(1) and "debug" messages to clog.V(2).
    51  //
    52  // This file is named raft.go instead of something like logger.go because this
    53  // file's name is used to determine the vmodule parameter: --vmodule=raft=1
    54  type raftLogger struct {
    55  	ctx context.Context
    56  }
    57  
    58  func (r *raftLogger) Debug(v ...interface{}) {
    59  	if log.V(3) {
    60  		log.InfofDepth(r.ctx, 1, "", v...)
    61  	}
    62  }
    63  
    64  func (r *raftLogger) Debugf(format string, v ...interface{}) {
    65  	if log.V(3) {
    66  		log.InfofDepth(r.ctx, 1, format, v...)
    67  	}
    68  }
    69  
    70  func (r *raftLogger) Info(v ...interface{}) {
    71  	if log.V(2) {
    72  		log.InfofDepth(r.ctx, 1, "", v...)
    73  	}
    74  }
    75  
    76  func (r *raftLogger) Infof(format string, v ...interface{}) {
    77  	if log.V(2) {
    78  		log.InfofDepth(r.ctx, 1, format, v...)
    79  	}
    80  }
    81  
    82  func (r *raftLogger) Warning(v ...interface{}) {
    83  	log.WarningfDepth(r.ctx, 1, "", v...)
    84  }
    85  
    86  func (r *raftLogger) Warningf(format string, v ...interface{}) {
    87  	log.WarningfDepth(r.ctx, 1, format, v...)
    88  }
    89  
    90  func (r *raftLogger) Error(v ...interface{}) {
    91  	log.ErrorfDepth(r.ctx, 1, "", v...)
    92  }
    93  
    94  func (r *raftLogger) Errorf(format string, v ...interface{}) {
    95  	log.ErrorfDepth(r.ctx, 1, format, v...)
    96  }
    97  
    98  func (r *raftLogger) Fatal(v ...interface{}) {
    99  	wrapNumbersAsSafe(v)
   100  	log.FatalfDepth(r.ctx, 1, "", v...)
   101  }
   102  
   103  func (r *raftLogger) Fatalf(format string, v ...interface{}) {
   104  	wrapNumbersAsSafe(v)
   105  	log.FatalfDepth(r.ctx, 1, format, v...)
   106  }
   107  
   108  func (r *raftLogger) Panic(v ...interface{}) {
   109  	wrapNumbersAsSafe(v)
   110  	log.FatalfDepth(r.ctx, 1, "", v...)
   111  }
   112  
   113  func (r *raftLogger) Panicf(format string, v ...interface{}) {
   114  	wrapNumbersAsSafe(v)
   115  	log.FatalfDepth(r.ctx, 1, format, v...)
   116  }
   117  
   118  func wrapNumbersAsSafe(v ...interface{}) {
   119  	for i := range v {
   120  		switch v[i].(type) {
   121  		case uint:
   122  			v[i] = log.Safe(v[i])
   123  		case uint8:
   124  			v[i] = log.Safe(v[i])
   125  		case uint16:
   126  			v[i] = log.Safe(v[i])
   127  		case uint32:
   128  			v[i] = log.Safe(v[i])
   129  		case uint64:
   130  			v[i] = log.Safe(v[i])
   131  		case int:
   132  			v[i] = log.Safe(v[i])
   133  		case int8:
   134  			v[i] = log.Safe(v[i])
   135  		case int16:
   136  			v[i] = log.Safe(v[i])
   137  		case int32:
   138  			v[i] = log.Safe(v[i])
   139  		case int64:
   140  			v[i] = log.Safe(v[i])
   141  		case float32:
   142  			v[i] = log.Safe(v[i])
   143  		case float64:
   144  			v[i] = log.Safe(v[i])
   145  		default:
   146  		}
   147  	}
   148  }
   149  
   150  func verboseRaftLoggingEnabled() bool {
   151  	return log.V(5)
   152  }
   153  
   154  func logRaftReady(ctx context.Context, ready raft.Ready) {
   155  	if !verboseRaftLoggingEnabled() {
   156  		return
   157  	}
   158  
   159  	var buf bytes.Buffer
   160  	if ready.SoftState != nil {
   161  		fmt.Fprintf(&buf, "  SoftState updated: %+v\n", *ready.SoftState)
   162  	}
   163  	if !raft.IsEmptyHardState(ready.HardState) {
   164  		fmt.Fprintf(&buf, "  HardState updated: %+v\n", ready.HardState)
   165  	}
   166  	for i, e := range ready.Entries {
   167  		fmt.Fprintf(&buf, "  New Entry[%d]: %.200s\n",
   168  			i, raft.DescribeEntry(e, raftEntryFormatter))
   169  	}
   170  	for i, e := range ready.CommittedEntries {
   171  		fmt.Fprintf(&buf, "  Committed Entry[%d]: %.200s\n",
   172  			i, raft.DescribeEntry(e, raftEntryFormatter))
   173  	}
   174  	if !raft.IsEmptySnap(ready.Snapshot) {
   175  		snap := ready.Snapshot
   176  		snap.Data = nil
   177  		fmt.Fprintf(&buf, "  Snapshot updated: %v\n", snap)
   178  	}
   179  	for i, m := range ready.Messages {
   180  		fmt.Fprintf(&buf, "  Outgoing Message[%d]: %.200s\n",
   181  			i, raftDescribeMessage(m, raftEntryFormatter))
   182  	}
   183  	log.Infof(ctx, "raft ready (must-sync=%t)\n%s", ready.MustSync, buf.String())
   184  }
   185  
   186  // This is a fork of raft.DescribeMessage with a tweak to avoid logging
   187  // snapshot data.
   188  func raftDescribeMessage(m raftpb.Message, f raft.EntryFormatter) string {
   189  	var buf bytes.Buffer
   190  	fmt.Fprintf(&buf, "%x->%x %v Term:%d Log:%d/%d", m.From, m.To, m.Type, m.Term, m.LogTerm, m.Index)
   191  	if m.Reject {
   192  		fmt.Fprintf(&buf, " Rejected (Hint: %d)", m.RejectHint)
   193  	}
   194  	if m.Commit != 0 {
   195  		fmt.Fprintf(&buf, " Commit:%d", m.Commit)
   196  	}
   197  	if len(m.Entries) > 0 {
   198  		fmt.Fprintf(&buf, " Entries:[")
   199  		for i, e := range m.Entries {
   200  			if i != 0 {
   201  				buf.WriteString(", ")
   202  			}
   203  			buf.WriteString(raft.DescribeEntry(e, f))
   204  		}
   205  		fmt.Fprintf(&buf, "]")
   206  	}
   207  	if !raft.IsEmptySnap(m.Snapshot) {
   208  		snap := m.Snapshot
   209  		snap.Data = nil
   210  		fmt.Fprintf(&buf, " Snapshot:%v", snap)
   211  	}
   212  	return buf.String()
   213  }
   214  
   215  func raftEntryFormatter(data []byte) string {
   216  	if len(data) == 0 {
   217  		return "[empty]"
   218  	}
   219  	commandID, _ := DecodeRaftCommand(data)
   220  	return fmt.Sprintf("[%x] [%d]", commandID, len(data))
   221  }
   222  
   223  var raftMessageRequestPool = sync.Pool{
   224  	New: func() interface{} {
   225  		return &RaftMessageRequest{}
   226  	},
   227  }
   228  
   229  func newRaftMessageRequest() *RaftMessageRequest {
   230  	return raftMessageRequestPool.Get().(*RaftMessageRequest)
   231  }
   232  
   233  func (m *RaftMessageRequest) release() {
   234  	*m = RaftMessageRequest{}
   235  	raftMessageRequestPool.Put(m)
   236  }
   237  
   238  // IsPreemptive returns whether this is a preemptive snapshot or a Raft
   239  // snapshot.
   240  func (h *SnapshotRequest_Header) IsPreemptive() bool {
   241  	// Preemptive snapshots are addressed to replica ID 0. No other requests to
   242  	// replica ID 0 are allowed.
   243  	return h.RaftMessageRequest.ToReplica.ReplicaID == 0
   244  }
   245  
   246  // traceEntries records the provided event for all proposals corresponding
   247  // to the entries contained in ents. The vmodule level for raft must be at
   248  // least 1.
   249  func (r *Replica) traceEntries(ents []raftpb.Entry, event string) {
   250  	if log.V(1) || r.store.TestingKnobs().TraceAllRaftEvents {
   251  		ids := extractIDs(nil, ents)
   252  		traceProposals(r, ids, event)
   253  	}
   254  }
   255  
   256  // traceMessageSends records the provided event for all proposals contained in
   257  // in entries contained in msgs. The vmodule level for raft must be at
   258  // least 1.
   259  func (r *Replica) traceMessageSends(msgs []raftpb.Message, event string) {
   260  	if log.V(1) || r.store.TestingKnobs().TraceAllRaftEvents {
   261  		var ids []kvserverbase.CmdIDKey
   262  		for _, m := range msgs {
   263  			ids = extractIDs(ids, m.Entries)
   264  		}
   265  		traceProposals(r, ids, event)
   266  	}
   267  }
   268  
   269  // extractIDs decodes and appends each of the ids corresponding to the entries
   270  // in ents to ids and returns the result.
   271  func extractIDs(ids []kvserverbase.CmdIDKey, ents []raftpb.Entry) []kvserverbase.CmdIDKey {
   272  	for _, e := range ents {
   273  		if e.Type == raftpb.EntryNormal && len(e.Data) > 0 {
   274  			id, _ := DecodeRaftCommand(e.Data)
   275  			ids = append(ids, id)
   276  		}
   277  	}
   278  	return ids
   279  }
   280  
   281  // traceLocalProposals logs a trace event with the provided string for each
   282  // locally proposed command which corresponds to an id in ids.
   283  func traceProposals(r *Replica, ids []kvserverbase.CmdIDKey, event string) {
   284  	ctxs := make([]context.Context, 0, len(ids))
   285  	r.mu.RLock()
   286  	for _, id := range ids {
   287  		if prop, ok := r.mu.proposals[id]; ok {
   288  			ctxs = append(ctxs, prop.ctx)
   289  		}
   290  	}
   291  	r.mu.RUnlock()
   292  	for _, ctx := range ctxs {
   293  		log.Eventf(ctx, "%v", event)
   294  	}
   295  }