From 8aca1698aebb14c1110b9889313f6d428e6b178e Mon Sep 17 00:00:00 2001 From: Tobias Schottdorf Date: Thu, 30 Aug 2018 12:08:01 +0200 Subject: [PATCH] cli: add hex option to debug keys This was used in #29252 and I imagine I'll want to use it again whenever we see the consistency checker fail in the future. Release note: None --- pkg/cli/cli_debug_test.go | 45 +++++++++++++++++++++++++++++++++++++++ pkg/cli/cliflags/flags.go | 8 +++---- pkg/cli/debug.go | 6 +++--- pkg/cli/flags_util.go | 15 +++++++++++++ pkg/cli/keytype_string.go | 4 ++-- 5 files changed, 69 insertions(+), 9 deletions(-) diff --git a/pkg/cli/cli_debug_test.go b/pkg/cli/cli_debug_test.go index c04c0fbb8d47..857c1ab4b926 100644 --- a/pkg/cli/cli_debug_test.go +++ b/pkg/cli/cli_debug_test.go @@ -14,6 +14,15 @@ package cli +import ( + "path/filepath" + "strings" + "testing" + + "github.com/cockroachdb/cockroach/pkg/testutils" + "github.com/cockroachdb/cockroach/pkg/util/leaktest" +) + func Example_debug_decode_key_value() { cliTest{}.RunWithArgs([]string{"debug", "decode-value", "016b12bd8980c0b6c2e211ba5182000172647363", "884d186d03089b09120bbd8980c0b6c2e211ba51821a0bbd8980c0b9e7c5c610e99622060801100118012206080410041802220608021002180428053004"}) @@ -25,3 +34,39 @@ func Example_debug_decode_key_value() { // 0.987654321,0 /Local/Range/Table/53/1/-4560243296450227838/RangeDescriptor: [/Table/53/1/-4560243296450227838, /Table/53/1/-4559358311118345834) // Raw:r1179:/Table/53/1/-45{60243296450227838-59358311118345834} [(n1,s1):1, (n4,s4):2, (n2,s2):4, next=5, gen=4] } + +func TestDebugKeysHex(t *testing.T) { + defer leaktest.AfterTest(t)() + + baseDir, dirCleanupFn := testutils.TempDir(t) + defer dirCleanupFn() + + storePath := filepath.Join(baseDir, "store") + createStore(t, storePath) + + { + out, err := cliTest{}.RunWithCapture("debug keys " + storePath + + " --from hex:016b12bd898090d79e52e79b0144000174786e2d733fb094e9aa4d67974c71486b9823b900" + + " --to hex:016b12bd898090d79e52e79b0144000174786e2d733fb094e9aa4d67974c71486b9823b900") + if err != nil { + t.Fatal(err) + } + // Should just output the command invocation and no results. + if !strings.HasSuffix(strings.TrimSpace(out), "b900") { + t.Fatalf("%q", out) + } + } + + // Test invalid key, verify we get a good suggestion back. + out, err := cliTest{}.RunWithCapture("debug keys " + storePath + + " --to hex:01") + if err != nil { + t.Fatal(err) + } + expOut := `invalid argument "hex:01" for "--to" flag: perhaps this is just a hex-encoded key; ` + + `you need an encoded MVCCKey (i.e. with a timestamp component); here's one with a zero timestamp: ` + + `0100: invalid encoded mvcc key: 01` + if !strings.Contains(out, expOut) { + t.Fatalf("%q", out) + } +} diff --git a/pkg/cli/cliflags/flags.go b/pkg/cli/cliflags/flags.go index a7b509459173..41a9cdd92783 100644 --- a/pkg/cli/cliflags/flags.go +++ b/pkg/cli/cliflags/flags.go @@ -678,17 +678,17 @@ database, insecure, certs).`, From = FlagInfo{ Name: "from", Description: ` -Start key and format as [:]. Supported formats: raw, human, +Start key and format as [:]. Supported formats: raw, hex, human, rangeID. The raw format supports escaped text. For example, "raw:\x01k" is the -prefix for range local keys.`, +prefix for range local keys. The hex format takes an encoded MVCCKey.`, } To = FlagInfo{ Name: "to", Description: ` -Exclusive end key and format as [:]. Supported formats: raw, +Exclusive end key and format as [:]. Supported formats: raw, hex, human, rangeID. The raw format supports escaped text. For example, "raw:\x01k" -is the prefix for range local keys.`} +is the prefix for range local keys. The hex format takes an encoded MVCCKey.`} Values = FlagInfo{ Name: "values", diff --git a/pkg/cli/debug.go b/pkg/cli/debug.go index 56c30d037912..bc6a2839a307 100644 --- a/pkg/cli/debug.go +++ b/pkg/cli/debug.go @@ -19,7 +19,7 @@ import ( "bufio" "bytes" "context" - "encoding/hex" + gohex "encoding/hex" "fmt" "io" "math" @@ -337,7 +337,7 @@ Decode a hexadecimal-encoded key and pretty-print it. For example: Args: cobra.ArbitraryArgs, RunE: func(cmd *cobra.Command, args []string) error { for _, arg := range args { - b, err := hex.DecodeString(arg) + b, err := gohex.DecodeString(arg) if err != nil { return err } @@ -364,7 +364,7 @@ Decode and print a hexadecimal-encoded key-value pair. RunE: func(cmd *cobra.Command, args []string) error { var bs [][]byte for _, arg := range args { - b, err := hex.DecodeString(arg) + b, err := gohex.DecodeString(arg) if err != nil { return err } diff --git a/pkg/cli/flags_util.go b/pkg/cli/flags_util.go index 54bf825239dd..a5966e53e6f2 100644 --- a/pkg/cli/flags_util.go +++ b/pkg/cli/flags_util.go @@ -16,6 +16,7 @@ package cli import ( "context" + gohex "encoding/hex" "fmt" "math" "regexp" @@ -166,6 +167,19 @@ func (k *mvccKey) Set(value string) error { } switch typ { + case hex: + b, err := gohex.DecodeString(keyStr) + if err != nil { + return err + } + newK, err := engine.DecodeKey(b) + if err != nil { + encoded := gohex.EncodeToString(engine.EncodeKey(engine.MakeMVCCMetadataKey(roachpb.Key(b)))) + return errors.Wrapf(err, "perhaps this is just a hex-encoded key; you need an "+ + "encoded MVCCKey (i.e. with a timestamp component); here's one with a zero timestamp: %s", + encoded) + } + *k = mvccKey(newK) case raw: unquoted, err := unquoteArg(keyStr) if err != nil { @@ -208,6 +222,7 @@ const ( raw keyType = iota human rangeID + hex ) // _keyTypes stores the names of all the possible key types. diff --git a/pkg/cli/keytype_string.go b/pkg/cli/keytype_string.go index d6d3827c61b2..0c7e5a1d34da 100644 --- a/pkg/cli/keytype_string.go +++ b/pkg/cli/keytype_string.go @@ -4,9 +4,9 @@ package cli import "strconv" -const _keyType_name = "rawhumanrangeID" +const _keyType_name = "rawhumanrangeIDhex" -var _keyType_index = [...]uint8{0, 3, 8, 15} +var _keyType_index = [...]uint8{0, 3, 8, 15, 18} func (i keyType) String() string { if i < 0 || i >= keyType(len(_keyType_index)-1) {