// Copyright 2024 PingCAP, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package util import "encoding/binary" // GetValuesList is used to get `num` values between lower and upper value. // To Simplify the explain, suppose lower and upper value type is int64, and lower=0, upper=100, num=10, // then calculate the step=(upper-lower)/num=10, then the function should return 0+10, 10+10, 20+10... all together 9 (num-1) values. // Then the function will return [10,20,30,40,50,60,70,80,90]. // The difference is the value type of upper, lower is []byte, So I use getUint64FromBytes to convert []byte to uint64. func GetValuesList(lower, upper []byte, num int, valuesList [][]byte) [][]byte { commonPrefixIdx := longestCommonPrefixLen(lower, upper) step := getStepValue(lower[commonPrefixIdx:], upper[commonPrefixIdx:], num) startV := getUint64FromBytes(lower[commonPrefixIdx:], 0) // To get `num` regions, only need to split `num-1` idx keys. buf := make([]byte, 8) for range num - 1 { value := make([]byte, 0, commonPrefixIdx+8) value = append(value, lower[:commonPrefixIdx]...) startV += step binary.BigEndian.PutUint64(buf, startV) value = append(value, buf...) valuesList = append(valuesList, value) } return valuesList } // longestCommonPrefixLen gets the longest common prefix byte length. func longestCommonPrefixLen(s1, s2 []byte) int { l := min(len(s1), len(s2)) i := 0 for ; i < l; i++ { if s1[i] != s2[i] { break } } return i } // getStepValue gets the step of between the lower and upper value. step = (upper-lower)/num. // Convert byte slice to uint64 first. func getStepValue(lower, upper []byte, num int) uint64 { lowerUint := getUint64FromBytes(lower, 0) upperUint := getUint64FromBytes(upper, 0xff) return (upperUint - lowerUint) / uint64(num) } // getUint64FromBytes gets a uint64 from the `bs` byte slice. // If len(bs) < 8, then padding with `pad`. func getUint64FromBytes(bs []byte, pad byte) uint64 { buf := bs if len(buf) < 8 { buf = make([]byte, 0, 8) buf = append(buf, bs...) for i := len(buf); i < 8; i++ { buf = append(buf, pad) } } return binary.BigEndian.Uint64(buf) }