Skip to content

Commit

Permalink
kv,store/copr: make kv.KeyRange the same with coprocessor.KeyRange, s…
Browse files Browse the repository at this point in the history
…o we can use unsafe optimization (#37288)

close #37286
  • Loading branch information
tiancaiamao authored Aug 23, 2022
1 parent 11dbd0b commit fe4e6ba
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 7 deletions.
8 changes: 8 additions & 0 deletions kv/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,17 @@ func (k Key) String() string {
}

// KeyRange represents a range where StartKey <= key < EndKey.
// Hack: make the layout exactly the same with github.com/pingcap/kvproto/pkg/coprocessor.KeyRange
// So we can avoid allocation of converting kv.KeyRange to coprocessor.KeyRange
// Not defined as "type KeyRange = coprocessor.KeyRange" because their field name are different.
// kv.KeyRange use StartKey,EndKey while coprocessor.KeyRange use Start,End
type KeyRange struct {
StartKey Key
EndKey Key

XXXNoUnkeyedLiteral struct{}
XXXunrecognized []byte
XXXsizecache int32
}

// IsPoint checks if the key range represents a point.
Expand Down
14 changes: 14 additions & 0 deletions kv/key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ import (
"strconv"
"testing"
"time"
"unsafe"

"github.com/pingcap/kvproto/pkg/coprocessor"
. "github.com/pingcap/tidb/kv"
"github.com/pingcap/tidb/sessionctx/stmtctx"
"github.com/pingcap/tidb/testkit/testutil"
Expand Down Expand Up @@ -212,6 +214,18 @@ func TestHandleMap(t *testing.T) {
assert.Equal(t, 2, cnt)
}

func TestKeyRangeDefinition(t *testing.T) {
// The struct layout for kv.KeyRange and coprocessor.KeyRange should be exactly the same.
// This allow us to use unsafe pointer to convert them and reduce allocation.
var r1 KeyRange
var r2 coprocessor.KeyRange
// Same size.
require.Equal(t, unsafe.Sizeof(r1), unsafe.Sizeof(r2))
// And same default value.
require.Equal(t, (*coprocessor.KeyRange)(unsafe.Pointer(&r1)), &r2)
require.Equal(t, &r1, (*KeyRange)(unsafe.Pointer(&r2)))
}

func BenchmarkIsPoint(b *testing.B) {
b.ReportAllocs()
kr := KeyRange{
Expand Down
11 changes: 5 additions & 6 deletions store/copr/key_ranges.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"bytes"
"fmt"
"sort"
"unsafe"

"github.com/pingcap/kvproto/pkg/coprocessor"
"github.com/pingcap/tidb/kv"
Expand Down Expand Up @@ -104,8 +105,7 @@ func (r *KeyRanges) Do(f func(ran *kv.KeyRange)) {
f(r.first)
}
for i := range r.mid {
ran := r.mid[i]
f(&ran)
f(&r.mid[i])
}
if r.last != nil {
f(r.last)
Expand Down Expand Up @@ -136,10 +136,9 @@ func (r *KeyRanges) Split(key []byte) (*KeyRanges, *KeyRanges) {
func (r *KeyRanges) ToPBRanges() []*coprocessor.KeyRange {
ranges := make([]*coprocessor.KeyRange, 0, r.Len())
r.Do(func(ran *kv.KeyRange) {
ranges = append(ranges, &coprocessor.KeyRange{
Start: ran.StartKey,
End: ran.EndKey,
})
// kv.KeyRange and coprocessor.KeyRange are the same,
// so use unsafe.Pointer to avoid allocation here.
ranges = append(ranges, (*coprocessor.KeyRange)(unsafe.Pointer(ran)))
})
return ranges
}
2 changes: 1 addition & 1 deletion util/logutil/hex.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func prettyPrint(w io.Writer, val reflect.Value) {
for i := 0; i < val.NumField(); i++ {
fv := val.Field(i)
ft := tp.Field(i)
if strings.HasPrefix(ft.Name, "XXX_") {
if strings.HasPrefix(ft.Name, "XXX") {
continue
}
if i != 0 {
Expand Down

0 comments on commit fe4e6ba

Please sign in to comment.