github.com/pingcap/br@v5.3.0-alpha.0.20220125034240-ec59c7b6ce30+incompatible/tests/br_rawkv/client.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/hex"
     7  	"flag"
     8  	"fmt"
     9  	"hash/crc64"
    10  	"math/rand"
    11  	"strings"
    12  	"time"
    13  
    14  	"github.com/pingcap/errors"
    15  	"github.com/pingcap/log"
    16  	"github.com/tikv/client-go/v2/config"
    17  	"github.com/tikv/client-go/v2/rawkv"
    18  	"go.uber.org/zap"
    19  )
    20  
    21  var (
    22  	ca          = flag.String("ca", "", "CA certificate path for TLS connection")
    23  	cert        = flag.String("cert", "", "certificate path for TLS connection")
    24  	key         = flag.String("key", "", "private key path for TLS connection")
    25  	pdAddr      = flag.String("pd", "127.0.0.1:2379", "Address of PD")
    26  	runMode     = flag.String("mode", "", "Mode. One of 'rand-gen', 'checksum', 'scan', 'diff', 'delete' and 'put'")
    27  	startKeyStr = flag.String("start-key", "", "Start key in hex")
    28  	endKeyStr   = flag.String("end-key", "", "End key in hex")
    29  	keyMaxLen   = flag.Int("key-max-len", 32, "Max length of keys for rand-gen mode")
    30  	concurrency = flag.Int("concurrency", 32, "Concurrency to run rand-gen")
    31  	duration    = flag.Int("duration", 10, "duration(second) of rand-gen")
    32  	putDataStr  = flag.String("put-data", "", "Kv pairs to put to the cluster in hex. "+
    33  		"kv pairs are separated by commas, key and value in a pair are separated by a colon")
    34  )
    35  
    36  func createClient(addr string) (*rawkv.Client, error) {
    37  	cli, err := rawkv.NewClient(context.TODO(), []string{addr}, config.Security{
    38  		ClusterSSLCA:   *ca,
    39  		ClusterSSLCert: *cert,
    40  		ClusterSSLKey:  *key,
    41  	})
    42  	return cli, errors.Trace(err)
    43  }
    44  
    45  func main() {
    46  	flag.Parse()
    47  
    48  	startKey, err := hex.DecodeString(*startKeyStr)
    49  	if err != nil {
    50  		log.Panic("Invalid startKey", zap.String("starkey", *startKeyStr), zap.Error(err))
    51  	}
    52  	endKey, err := hex.DecodeString(*endKeyStr)
    53  	if err != nil {
    54  		log.Panic("Invalid endKey: %v, err: %+v", zap.String("endkey", *endKeyStr), zap.Error(err))
    55  	}
    56  	// For "put" mode, the key range is not used. So no need to throw error here.
    57  	if len(endKey) == 0 && *runMode != "put" {
    58  		log.Panic("Empty endKey is not supported yet")
    59  	}
    60  
    61  	if *runMode == "test-rand-key" {
    62  		testRandKey(startKey, endKey, *keyMaxLen)
    63  		return
    64  	}
    65  
    66  	client, err := createClient(*pdAddr)
    67  	if err != nil {
    68  		log.Panic("Failed to create client", zap.String("pd", *pdAddr), zap.Error(err))
    69  	}
    70  
    71  	switch *runMode {
    72  	case "rand-gen":
    73  		err = randGenWithDuration(client, startKey, endKey, *keyMaxLen, *concurrency, *duration)
    74  	case "checksum":
    75  		err = checksum(client, startKey, endKey)
    76  	case "scan":
    77  		err = scan(client, startKey, endKey)
    78  	case "delete":
    79  		err = deleteRange(client, startKey, endKey)
    80  	case "put":
    81  		err = put(client, *putDataStr)
    82  	}
    83  
    84  	if err != nil {
    85  		log.Panic("Error", zap.Error(err))
    86  	}
    87  }
    88  
    89  func randGenWithDuration(client *rawkv.Client, startKey, endKey []byte,
    90  	maxLen int, concurrency int, duration int) error {
    91  	var err error
    92  	ok := make(chan struct{})
    93  	go func() {
    94  		err = randGen(client, startKey, endKey, maxLen, concurrency)
    95  		ok <- struct{}{}
    96  	}()
    97  	select {
    98  	case <-time.After(time.Second * time.Duration(duration)):
    99  	case <-ok:
   100  	}
   101  	return errors.Trace(err)
   102  }
   103  
   104  func randGen(client *rawkv.Client, startKey, endKey []byte, maxLen int, concurrency int) error {
   105  	log.Info("Start rand-gen", zap.Int("maxlen", maxLen),
   106  		zap.String("startkey", hex.EncodeToString(startKey)), zap.String("endkey", hex.EncodeToString(endKey)))
   107  	log.Info("Rand-gen will keep running. Please Ctrl+C to stop manually.")
   108  
   109  	// Cannot generate shorter key than commonPrefix
   110  	commonPrefixLen := 0
   111  	for ; commonPrefixLen < len(startKey) && commonPrefixLen < len(endKey) &&
   112  		startKey[commonPrefixLen] == endKey[commonPrefixLen]; commonPrefixLen++ {
   113  		continue
   114  	}
   115  
   116  	if maxLen < commonPrefixLen {
   117  		return errors.Errorf("maxLen (%v) < commonPrefixLen (%v)", maxLen, commonPrefixLen)
   118  	}
   119  
   120  	const batchSize = 32
   121  
   122  	errCh := make(chan error, concurrency)
   123  	for i := 0; i < concurrency; i++ {
   124  		go func() {
   125  			for {
   126  				keys := make([][]byte, 0, batchSize)
   127  				values := make([][]byte, 0, batchSize)
   128  
   129  				for i := 0; i < batchSize; i++ {
   130  					key := randKey(startKey, endKey, maxLen)
   131  					keys = append(keys, key)
   132  					value := randValue()
   133  					values = append(values, value)
   134  				}
   135  
   136  				err := client.BatchPut(context.TODO(), keys, values)
   137  				if err != nil {
   138  					errCh <- errors.Trace(err)
   139  				}
   140  			}
   141  		}()
   142  	}
   143  
   144  	err := <-errCh
   145  	if err != nil {
   146  		return errors.Trace(err)
   147  	}
   148  
   149  	return nil
   150  }
   151  
   152  func testRandKey(startKey, endKey []byte, maxLen int) {
   153  	for {
   154  		k := randKey(startKey, endKey, maxLen)
   155  		if bytes.Compare(k, startKey) < 0 || bytes.Compare(k, endKey) >= 0 {
   156  			panic(hex.EncodeToString(k))
   157  		}
   158  	}
   159  }
   160  
   161  func randKey(startKey, endKey []byte, maxLen int) []byte {
   162  Retry:
   163  	for { // Regenerate on fail
   164  		result := make([]byte, 0, maxLen)
   165  
   166  		upperUnbounded := false
   167  		lowerUnbounded := false
   168  
   169  		for i := 0; i < maxLen; i++ {
   170  			upperBound := 256
   171  			if !upperUnbounded {
   172  				if i >= len(endKey) {
   173  					// The generated key is the same as endKey which is invalid. Regenerate it.
   174  					continue Retry
   175  				}
   176  				upperBound = int(endKey[i]) + 1
   177  			}
   178  
   179  			lowerBound := 0
   180  			if !lowerUnbounded {
   181  				if i >= len(startKey) {
   182  					lowerUnbounded = true
   183  				} else {
   184  					lowerBound = int(startKey[i])
   185  				}
   186  			}
   187  
   188  			if lowerUnbounded {
   189  				if rand.Intn(257) == 0 {
   190  					return result
   191  				}
   192  			}
   193  
   194  			value := rand.Intn(upperBound - lowerBound)
   195  			value += lowerBound
   196  
   197  			if value < upperBound-1 {
   198  				upperUnbounded = true
   199  			}
   200  			if value > lowerBound {
   201  				lowerUnbounded = true
   202  			}
   203  
   204  			result = append(result, uint8(value))
   205  		}
   206  
   207  		return result
   208  	}
   209  }
   210  
   211  func randValue() []byte {
   212  	result := make([]byte, 0, 512)
   213  	for i := 0; i < 512; i++ {
   214  		value := rand.Intn(257)
   215  		if value == 256 {
   216  			if i > 0 {
   217  				return result
   218  			}
   219  			value--
   220  		}
   221  		result = append(result, uint8(value))
   222  	}
   223  	return result
   224  }
   225  
   226  func checksum(client *rawkv.Client, startKey, endKey []byte) error {
   227  	log.Info("Start checkcum on range",
   228  		zap.String("startkey", hex.EncodeToString(startKey)), zap.String("endkey", hex.EncodeToString(endKey)))
   229  
   230  	scanner := newRawKVScanner(client, startKey, endKey)
   231  	digest := crc64.New(crc64.MakeTable(crc64.ECMA))
   232  
   233  	var res uint64
   234  
   235  	for {
   236  		k, v, err := scanner.Next()
   237  		if err != nil {
   238  			return errors.Trace(err)
   239  		}
   240  		if len(k) == 0 {
   241  			break
   242  		}
   243  		_, _ = digest.Write(k)
   244  		_, _ = digest.Write(v)
   245  		res ^= digest.Sum64()
   246  	}
   247  
   248  	log.Info("Checksum result", zap.Uint64("checksum", res))
   249  	fmt.Printf("Checksum result: %016x\n", res)
   250  	return nil
   251  }
   252  
   253  func deleteRange(client *rawkv.Client, startKey, endKey []byte) error {
   254  	log.Info("Start delete data in range",
   255  		zap.String("startkey", hex.EncodeToString(startKey)), zap.String("endkey", hex.EncodeToString(endKey)))
   256  	return client.DeleteRange(context.TODO(), startKey, endKey)
   257  }
   258  
   259  func scan(client *rawkv.Client, startKey, endKey []byte) error {
   260  	log.Info("Start scanning data in range",
   261  		zap.String("startkey", hex.EncodeToString(startKey)), zap.String("endkey", hex.EncodeToString(endKey)))
   262  
   263  	scanner := newRawKVScanner(client, startKey, endKey)
   264  
   265  	var key []byte
   266  	for {
   267  		k, v, err := scanner.Next()
   268  		if err != nil {
   269  			return errors.Trace(err)
   270  		}
   271  		if len(k) == 0 {
   272  			break
   273  		}
   274  		fmt.Printf("key: %v, value: %v\n", hex.EncodeToString(k), hex.EncodeToString(v))
   275  		if bytes.Compare(key, k) >= 0 {
   276  			log.Error("Scan result is not in order",
   277  				zap.String("Previous key", hex.EncodeToString(key)), zap.String("Current key", hex.EncodeToString(k)))
   278  		}
   279  	}
   280  
   281  	log.Info("Finished Scanning.")
   282  	return nil
   283  }
   284  
   285  func put(client *rawkv.Client, dataStr string) error {
   286  	keys := make([][]byte, 0)
   287  	values := make([][]byte, 0)
   288  
   289  	for _, pairStr := range strings.Split(dataStr, ",") {
   290  		pair := strings.Split(pairStr, ":")
   291  		if len(pair) != 2 {
   292  			return errors.Errorf("invalid kv pair string %q", pairStr)
   293  		}
   294  
   295  		key, err := hex.DecodeString(strings.Trim(pair[0], " "))
   296  		if err != nil {
   297  			return errors.Annotatef(err, "invalid kv pair string %q", pairStr)
   298  		}
   299  		value, err := hex.DecodeString(strings.Trim(pair[1], " "))
   300  		if err != nil {
   301  			return errors.Annotatef(err, "invalid kv pair string %q", pairStr)
   302  		}
   303  
   304  		keys = append(keys, key)
   305  		values = append(values, value)
   306  	}
   307  
   308  	log.Info("Put rawkv data", zap.ByteStrings("keys", keys), zap.ByteStrings("values", values))
   309  
   310  	err := client.BatchPut(context.TODO(), keys, values)
   311  	return errors.Trace(err)
   312  }
   313  
   314  const defaultScanBatchSize = 128
   315  
   316  type rawKVScanner struct {
   317  	client    *rawkv.Client
   318  	batchSize int
   319  
   320  	currentKey []byte
   321  	endKey     []byte
   322  
   323  	bufferKeys   [][]byte
   324  	bufferValues [][]byte
   325  	bufferCursor int
   326  	noMore       bool
   327  }
   328  
   329  func newRawKVScanner(client *rawkv.Client, startKey, endKey []byte) *rawKVScanner {
   330  	return &rawKVScanner{
   331  		client:    client,
   332  		batchSize: defaultScanBatchSize,
   333  
   334  		currentKey: startKey,
   335  		endKey:     endKey,
   336  
   337  		noMore: false,
   338  	}
   339  }
   340  
   341  func (s *rawKVScanner) Next() ([]byte, []byte, error) {
   342  	if s.bufferCursor >= len(s.bufferKeys) {
   343  		if s.noMore {
   344  			return nil, nil, nil
   345  		}
   346  
   347  		s.bufferCursor = 0
   348  
   349  		batchSize := s.batchSize
   350  		var err error
   351  		s.bufferKeys, s.bufferValues, err = s.client.Scan(context.TODO(), s.currentKey, s.endKey, batchSize)
   352  		if err != nil {
   353  			return nil, nil, errors.Trace(err)
   354  		}
   355  
   356  		if len(s.bufferKeys) < batchSize {
   357  			s.noMore = true
   358  		}
   359  
   360  		if len(s.bufferKeys) == 0 {
   361  			return nil, nil, nil
   362  		}
   363  
   364  		bufferKey := s.bufferKeys[len(s.bufferKeys)-1]
   365  		bufferKey = append(bufferKey, 0)
   366  		s.currentKey = bufferKey
   367  	}
   368  
   369  	key := s.bufferKeys[s.bufferCursor]
   370  	value := s.bufferValues[s.bufferCursor]
   371  	s.bufferCursor++
   372  	return key, value, nil
   373  }