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

     1  // Copyright 2018 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  	"fmt"
    16  	"strconv"
    17  	"strings"
    18  
    19  	"github.com/cockroachdb/cockroach/pkg/keys"
    20  	"github.com/cockroachdb/cockroach/pkg/kv/kvserver/kvserverpb"
    21  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    22  	"github.com/cockroachdb/cockroach/pkg/storage"
    23  	"github.com/cockroachdb/cockroach/pkg/storage/enginepb"
    24  	"github.com/cockroachdb/cockroach/pkg/util/hlc"
    25  	"github.com/cockroachdb/cockroach/pkg/util/protoutil"
    26  	"github.com/cockroachdb/errors"
    27  	"go.etcd.io/etcd/raft/raftpb"
    28  )
    29  
    30  // PrintKeyValue attempts to pretty-print the specified MVCCKeyValue to
    31  // os.Stdout, falling back to '%q' formatting.
    32  func PrintKeyValue(kv storage.MVCCKeyValue) {
    33  	fmt.Println(SprintKeyValue(kv, true /* printKey */))
    34  }
    35  
    36  // SprintKey pretty-prings the specified MVCCKey.
    37  func SprintKey(key storage.MVCCKey) string {
    38  	return fmt.Sprintf("%s %s (%#x): ", key.Timestamp, key.Key, storage.EncodeKey(key))
    39  }
    40  
    41  // SprintKeyValue is like PrintKeyValue, but returns a string. If
    42  // printKey is true, prints the key and the value together; otherwise,
    43  // prints just the value.
    44  func SprintKeyValue(kv storage.MVCCKeyValue, printKey bool) string {
    45  	var sb strings.Builder
    46  	if printKey {
    47  		sb.WriteString(SprintKey(kv.Key))
    48  	}
    49  	decoders := []func(kv storage.MVCCKeyValue) (string, error){
    50  		tryRaftLogEntry,
    51  		tryRangeDescriptor,
    52  		tryMeta,
    53  		tryTxn,
    54  		tryRangeIDKey,
    55  		tryTimeSeries,
    56  		tryIntent,
    57  		func(kv storage.MVCCKeyValue) (string, error) {
    58  			// No better idea, just print raw bytes and hope that folks use `less -S`.
    59  			return fmt.Sprintf("%q", kv.Value), nil
    60  		},
    61  	}
    62  	for _, decoder := range decoders {
    63  		out, err := decoder(kv)
    64  		if err != nil {
    65  			continue
    66  		}
    67  		sb.WriteString(out)
    68  		return sb.String()
    69  	}
    70  	panic("unreachable")
    71  }
    72  
    73  func tryRangeDescriptor(kv storage.MVCCKeyValue) (string, error) {
    74  	if err := IsRangeDescriptorKey(kv.Key); err != nil {
    75  		return "", err
    76  	}
    77  	var desc roachpb.RangeDescriptor
    78  	if err := getProtoValue(kv.Value, &desc); err != nil {
    79  		return "", err
    80  	}
    81  	return descStr(desc), nil
    82  }
    83  
    84  func tryIntent(kv storage.MVCCKeyValue) (string, error) {
    85  	if len(kv.Value) == 0 {
    86  		return "", errors.New("empty")
    87  	}
    88  	var meta enginepb.MVCCMetadata
    89  	if err := protoutil.Unmarshal(kv.Value, &meta); err != nil {
    90  		return "", err
    91  	}
    92  	s := fmt.Sprintf("%+v", meta)
    93  	if meta.Txn != nil {
    94  		s = meta.Txn.WriteTimestamp.String() + " " + s
    95  	}
    96  	return s, nil
    97  }
    98  
    99  func decodeWriteBatch(writeBatch *kvserverpb.WriteBatch) (string, error) {
   100  	if writeBatch == nil {
   101  		return "<nil>\n", nil
   102  	}
   103  
   104  	r, err := storage.NewRocksDBBatchReader(writeBatch.Data)
   105  	if err != nil {
   106  		return "", err
   107  	}
   108  
   109  	// NB: always return sb.String() as the first arg, even on error, to give
   110  	// the caller all the info we have (in case the writebatch is corrupted).
   111  	var sb strings.Builder
   112  	for r.Next() {
   113  		switch r.BatchType() {
   114  		case storage.BatchTypeDeletion:
   115  			mvccKey, err := r.MVCCKey()
   116  			if err != nil {
   117  				return sb.String(), err
   118  			}
   119  			sb.WriteString(fmt.Sprintf("Delete: %s\n", SprintKey(mvccKey)))
   120  		case storage.BatchTypeValue:
   121  			mvccKey, err := r.MVCCKey()
   122  			if err != nil {
   123  				return sb.String(), err
   124  			}
   125  			sb.WriteString(fmt.Sprintf("Put: %s\n", SprintKeyValue(storage.MVCCKeyValue{
   126  				Key:   mvccKey,
   127  				Value: r.Value(),
   128  			}, true /* printKey */)))
   129  		case storage.BatchTypeMerge:
   130  			mvccKey, err := r.MVCCKey()
   131  			if err != nil {
   132  				return sb.String(), err
   133  			}
   134  			sb.WriteString(fmt.Sprintf("Merge: %s\n", SprintKeyValue(storage.MVCCKeyValue{
   135  				Key:   mvccKey,
   136  				Value: r.Value(),
   137  			}, true /* printKey */)))
   138  		case storage.BatchTypeSingleDeletion:
   139  			mvccKey, err := r.MVCCKey()
   140  			if err != nil {
   141  				return sb.String(), err
   142  			}
   143  			sb.WriteString(fmt.Sprintf("Single Delete: %s\n", SprintKey(mvccKey)))
   144  		case storage.BatchTypeRangeDeletion:
   145  			mvccStartKey, err := r.MVCCKey()
   146  			if err != nil {
   147  				return sb.String(), err
   148  			}
   149  			mvccEndKey, err := r.MVCCEndKey()
   150  			if err != nil {
   151  				return sb.String(), err
   152  			}
   153  			sb.WriteString(fmt.Sprintf(
   154  				"Delete Range: [%s, %s)\n", SprintKey(mvccStartKey), SprintKey(mvccEndKey),
   155  			))
   156  		default:
   157  			sb.WriteString(fmt.Sprintf("unsupported batch type: %d\n", r.BatchType()))
   158  		}
   159  	}
   160  	return sb.String(), r.Error()
   161  }
   162  
   163  func tryRaftLogEntry(kv storage.MVCCKeyValue) (string, error) {
   164  	var ent raftpb.Entry
   165  	if err := maybeUnmarshalInline(kv.Value, &ent); err != nil {
   166  		return "", err
   167  	}
   168  
   169  	var cmd kvserverpb.RaftCommand
   170  	switch ent.Type {
   171  	case raftpb.EntryNormal:
   172  		if len(ent.Data) == 0 {
   173  			return fmt.Sprintf("%s: EMPTY\n", &ent), nil
   174  		}
   175  		_, cmdData := DecodeRaftCommand(ent.Data)
   176  		if err := protoutil.Unmarshal(cmdData, &cmd); err != nil {
   177  			return "", err
   178  		}
   179  	case raftpb.EntryConfChange, raftpb.EntryConfChangeV2:
   180  		var c raftpb.ConfChangeI
   181  		if ent.Type == raftpb.EntryConfChange {
   182  			var cc raftpb.ConfChange
   183  			if err := protoutil.Unmarshal(ent.Data, &cc); err != nil {
   184  				return "", err
   185  			}
   186  			c = cc
   187  		} else {
   188  			var cc raftpb.ConfChangeV2
   189  			if err := protoutil.Unmarshal(ent.Data, &cc); err != nil {
   190  				return "", err
   191  			}
   192  			c = cc
   193  		}
   194  
   195  		var ctx ConfChangeContext
   196  		if err := protoutil.Unmarshal(c.AsV2().Context, &ctx); err != nil {
   197  			return "", err
   198  		}
   199  		if err := protoutil.Unmarshal(ctx.Payload, &cmd); err != nil {
   200  			return "", err
   201  		}
   202  	default:
   203  		return "", fmt.Errorf("unknown log entry type: %s", &ent)
   204  	}
   205  	ent.Data = nil
   206  
   207  	var leaseStr string
   208  	if l := cmd.DeprecatedProposerLease; l != nil {
   209  		leaseStr = l.String() // use full lease, if available
   210  	} else {
   211  		leaseStr = fmt.Sprintf("lease #%d", cmd.ProposerLeaseSequence)
   212  	}
   213  
   214  	wbStr, err := decodeWriteBatch(cmd.WriteBatch)
   215  	if err != nil {
   216  		wbStr = "failed to decode: " + err.Error() + "\nafter:\n" + wbStr
   217  	}
   218  	cmd.WriteBatch = nil
   219  
   220  	return fmt.Sprintf("%s by %s\n%s\nwrite batch:\n%s", &ent, leaseStr, &cmd, wbStr), nil
   221  }
   222  
   223  func tryTxn(kv storage.MVCCKeyValue) (string, error) {
   224  	var txn roachpb.Transaction
   225  	if err := maybeUnmarshalInline(kv.Value, &txn); err != nil {
   226  		return "", err
   227  	}
   228  	return txn.String() + "\n", nil
   229  }
   230  
   231  func tryRangeIDKey(kv storage.MVCCKeyValue) (string, error) {
   232  	if kv.Key.Timestamp != (hlc.Timestamp{}) {
   233  		return "", fmt.Errorf("range ID keys shouldn't have timestamps: %s", kv.Key)
   234  	}
   235  	_, _, suffix, _, err := keys.DecodeRangeIDKey(kv.Key.Key)
   236  	if err != nil {
   237  		return "", err
   238  	}
   239  
   240  	// All range ID keys are stored inline on the metadata.
   241  	var meta enginepb.MVCCMetadata
   242  	if err := protoutil.Unmarshal(kv.Value, &meta); err != nil {
   243  		return "", err
   244  	}
   245  	value := roachpb.Value{RawBytes: meta.RawBytes}
   246  
   247  	// Values encoded as protobufs set msg and continue outside the
   248  	// switch. Other types are handled inside the switch and return.
   249  	var msg protoutil.Message
   250  	switch {
   251  	case bytes.Equal(suffix, keys.LocalLeaseAppliedIndexLegacySuffix):
   252  		fallthrough
   253  	case bytes.Equal(suffix, keys.LocalRaftAppliedIndexLegacySuffix):
   254  		i, err := value.GetInt()
   255  		if err != nil {
   256  			return "", err
   257  		}
   258  		return strconv.FormatInt(i, 10), nil
   259  
   260  	case bytes.Equal(suffix, keys.LocalAbortSpanSuffix):
   261  		msg = &roachpb.AbortSpanEntry{}
   262  
   263  	case bytes.Equal(suffix, keys.LocalRangeLastGCSuffix):
   264  		msg = &hlc.Timestamp{}
   265  
   266  	case bytes.Equal(suffix, keys.LocalRangeTombstoneSuffix):
   267  		msg = &roachpb.RangeTombstone{}
   268  
   269  	case bytes.Equal(suffix, keys.LocalRaftTruncatedStateLegacySuffix):
   270  		msg = &roachpb.RaftTruncatedState{}
   271  
   272  	case bytes.Equal(suffix, keys.LocalRangeLeaseSuffix):
   273  		msg = &roachpb.Lease{}
   274  
   275  	case bytes.Equal(suffix, keys.LocalRangeAppliedStateSuffix):
   276  		msg = &enginepb.RangeAppliedState{}
   277  
   278  	case bytes.Equal(suffix, keys.LocalRangeStatsLegacySuffix):
   279  		msg = &enginepb.MVCCStats{}
   280  
   281  	case bytes.Equal(suffix, keys.LocalRaftHardStateSuffix):
   282  		msg = &raftpb.HardState{}
   283  
   284  	case bytes.Equal(suffix, keys.LocalRangeLastReplicaGCTimestampSuffix):
   285  		msg = &hlc.Timestamp{}
   286  
   287  	default:
   288  		return "", fmt.Errorf("unknown raft id key %s", suffix)
   289  	}
   290  
   291  	if err := value.GetProto(msg); err != nil {
   292  		return "", err
   293  	}
   294  	return msg.String(), nil
   295  }
   296  
   297  func tryMeta(kv storage.MVCCKeyValue) (string, error) {
   298  	if !bytes.HasPrefix(kv.Key.Key, keys.Meta1Prefix) && !bytes.HasPrefix(kv.Key.Key, keys.Meta2Prefix) {
   299  		return "", errors.New("not a meta key")
   300  	}
   301  	value := roachpb.Value{
   302  		Timestamp: kv.Key.Timestamp,
   303  		RawBytes:  kv.Value,
   304  	}
   305  	var desc roachpb.RangeDescriptor
   306  	if err := value.GetProto(&desc); err != nil {
   307  		return "", err
   308  	}
   309  	return descStr(desc), nil
   310  }
   311  
   312  func tryTimeSeries(kv storage.MVCCKeyValue) (string, error) {
   313  	if len(kv.Value) == 0 || !bytes.HasPrefix(kv.Key.Key, keys.TimeseriesPrefix) {
   314  		return "", errors.New("empty or not TS")
   315  	}
   316  	var meta enginepb.MVCCMetadata
   317  	if err := protoutil.Unmarshal(kv.Value, &meta); err != nil {
   318  		return "", err
   319  	}
   320  	v := roachpb.Value{RawBytes: meta.RawBytes}
   321  	var ts roachpb.InternalTimeSeriesData
   322  	if err := v.GetProto(&ts); err != nil {
   323  		return "", err
   324  	}
   325  	return fmt.Sprintf("%+v [mergeTS=%s]", &ts, meta.MergeTimestamp), nil
   326  }
   327  
   328  // IsRangeDescriptorKey returns nil if the key decodes as a RangeDescriptor.
   329  func IsRangeDescriptorKey(key storage.MVCCKey) error {
   330  	_, suffix, _, err := keys.DecodeRangeKey(key.Key)
   331  	if err != nil {
   332  		return err
   333  	}
   334  	if !bytes.Equal(suffix, keys.LocalRangeDescriptorSuffix) {
   335  		return fmt.Errorf("wrong suffix: %s", suffix)
   336  	}
   337  	return nil
   338  }
   339  
   340  func getProtoValue(data []byte, msg protoutil.Message) error {
   341  	value := roachpb.Value{
   342  		RawBytes: data,
   343  	}
   344  	return value.GetProto(msg)
   345  }
   346  
   347  func descStr(desc roachpb.RangeDescriptor) string {
   348  	return fmt.Sprintf("[%s, %s)\n\tRaw:%s\n",
   349  		desc.StartKey, desc.EndKey, &desc)
   350  }
   351  
   352  func maybeUnmarshalInline(v []byte, dest protoutil.Message) error {
   353  	var meta enginepb.MVCCMetadata
   354  	if err := protoutil.Unmarshal(v, &meta); err != nil {
   355  		return err
   356  	}
   357  	value := roachpb.Value{
   358  		RawBytes: meta.RawBytes,
   359  	}
   360  	return value.GetProto(dest)
   361  }
   362  
   363  type stringifyWriteBatch kvserverpb.WriteBatch
   364  
   365  func (s *stringifyWriteBatch) String() string {
   366  	wbStr, err := decodeWriteBatch((*kvserverpb.WriteBatch)(s))
   367  	if err == nil {
   368  		return wbStr
   369  	}
   370  	return fmt.Sprintf("failed to stringify write batch (%x): %s", s.Data, err)
   371  }