74 lines
2.6 KiB
Go
74 lines
2.6 KiB
Go
// 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)
|
|
}
|