92 lines
2.0 KiB
Go
92 lines
2.0 KiB
Go
// Copyright 2020 PingCAP, Inc. Licensed under Apache-2.0.
|
|
|
|
package utils
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
|
|
"github.com/pingcap/errors"
|
|
berrors "github.com/pingcap/tidb/br/pkg/errors"
|
|
)
|
|
|
|
// ParseKey parse key by given format.
|
|
func ParseKey(format, key string) ([]byte, error) {
|
|
switch format {
|
|
case "raw":
|
|
return []byte(key), nil
|
|
case "escaped":
|
|
return unescapedKey(key)
|
|
case "hex":
|
|
key, err := hex.DecodeString(key)
|
|
if err != nil {
|
|
return nil, errors.Trace(err)
|
|
}
|
|
return key, nil
|
|
}
|
|
return nil, errors.Annotate(berrors.ErrInvalidArgument, "unknown format")
|
|
}
|
|
|
|
// Ref PD: https://github.com/pingcap/pd/blob/master/tools/pd-ctl/pdctl/command/region_command.go#L334
|
|
func unescapedKey(text string) ([]byte, error) {
|
|
var buf []byte
|
|
r := bytes.NewBuffer([]byte(text))
|
|
for {
|
|
c, err := r.ReadByte()
|
|
if err != nil {
|
|
if errors.Cause(err) != io.EOF { // nolint:errorlint
|
|
return nil, errors.Trace(err)
|
|
}
|
|
break
|
|
}
|
|
if c != '\\' {
|
|
buf = append(buf, c)
|
|
continue
|
|
}
|
|
n := r.Next(1)
|
|
if len(n) == 0 {
|
|
return nil, io.EOF
|
|
}
|
|
// See: https://golang.org/ref/spec#Rune_literals
|
|
if idx := strings.IndexByte(`abfnrtv\'"`, n[0]); idx != -1 {
|
|
buf = append(buf, []byte("\a\b\f\n\r\t\v\\'\"")[idx])
|
|
continue
|
|
}
|
|
|
|
switch n[0] {
|
|
case 'x':
|
|
fmt.Sscanf(string(r.Next(2)), "%02x", &c)
|
|
buf = append(buf, c)
|
|
default:
|
|
n = append(n, r.Next(2)...)
|
|
_, err := fmt.Sscanf(string(n), "%03o", &c)
|
|
if err != nil {
|
|
return nil, errors.Trace(err)
|
|
}
|
|
buf = append(buf, c)
|
|
}
|
|
}
|
|
return buf, nil
|
|
}
|
|
|
|
// CompareEndKey compared two keys that BOTH represent the EXCLUSIVE ending of some range. An empty end key is the very
|
|
// end, so an empty key is greater than any other keys.
|
|
// Please note that this function is not applicable if any one argument is not an EXCLUSIVE ending of a range.
|
|
func CompareEndKey(a, b []byte) int {
|
|
if len(a) == 0 {
|
|
if len(b) == 0 {
|
|
return 0
|
|
}
|
|
return 1
|
|
}
|
|
|
|
if len(b) == 0 {
|
|
return -1
|
|
}
|
|
|
|
return bytes.Compare(a, b)
|
|
}
|