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 }