Skip to content

Commit

Permalink
/api/v1/regions optimization (#1970)
Browse files Browse the repository at this point in the history
  • Loading branch information
ekalinin authored and rleungx committed Dec 5, 2019
1 parent 7a83ca7 commit c8cb4b4
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 23 deletions.
45 changes: 28 additions & 17 deletions server/api/region.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,23 +45,29 @@ type RegionInfo struct {

// NewRegionInfo create a new api RegionInfo.
func NewRegionInfo(r *core.RegionInfo) *RegionInfo {
return InitRegion(r, &RegionInfo{})
}

// InitRegion init a new api RegionInfo from the core.RegionInfo.
func InitRegion(r *core.RegionInfo, s *RegionInfo) *RegionInfo {
if r == nil {
return nil
}
return &RegionInfo{
ID: r.GetID(),
StartKey: string(core.HexRegionKey(r.GetStartKey())),
EndKey: string(core.HexRegionKey(r.GetEndKey())),
RegionEpoch: r.GetRegionEpoch(),
Peers: r.GetPeers(),
Leader: r.GetLeader(),
DownPeers: r.GetDownPeers(),
PendingPeers: r.GetPendingPeers(),
WrittenBytes: r.GetBytesWritten(),
ReadBytes: r.GetBytesRead(),
ApproximateSize: r.GetApproximateSize(),
ApproximateKeys: r.GetApproximateKeys(),
}

s.ID = r.GetID()
s.StartKey = core.HexRegionKeyStr(r.GetStartKey())
s.EndKey = core.HexRegionKeyStr(r.GetEndKey())
s.RegionEpoch = r.GetRegionEpoch()
s.Peers = r.GetPeers()
s.Leader = r.GetLeader()
s.DownPeers = r.GetDownPeers()
s.PendingPeers = r.GetPendingPeers()
s.WrittenBytes = r.GetBytesWritten()
s.ReadBytes = r.GetBytesRead()
s.ApproximateSize = r.GetApproximateSize()
s.ApproximateKeys = r.GetApproximateKeys()

return s
}

// RegionsInfo contains some regions with the detailed region info.
Expand Down Expand Up @@ -126,13 +132,18 @@ func newRegionsHandler(svr *server.Server, rd *render.Render) *regionsHandler {
}

func convertToAPIRegions(regions []*core.RegionInfo) *RegionsInfo {
regionInfos := make([]*RegionInfo, len(regions))
regionInfos := make([]RegionInfo, len(regions))
regionInfosRefs := make([]*RegionInfo, len(regions))

for i := 0; i < len(regions); i++ {
regionInfosRefs[i] = &regionInfos[i]
}
for i, r := range regions {
regionInfos[i] = NewRegionInfo(r)
regionInfosRefs[i] = InitRegion(r, regionInfosRefs[i])
}
return &RegionsInfo{
Count: len(regions),
Regions: regionInfos,
Regions: regionInfosRefs,
}
}

Expand Down
69 changes: 69 additions & 0 deletions server/api/region_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@
package api

import (
"bytes"
"fmt"
"math/rand"
"net/url"
"sort"
"testing"

. "github.com/pingcap/check"
"github.com/pingcap/kvproto/pkg/metapb"
Expand Down Expand Up @@ -320,3 +322,70 @@ func (s *testGetRegionSuite) TestScanRegionByKey(c *C) {
c.Assert(v, Equals, regions.Regions[i].ID)
}
}

// Create n regions (0..n) of n stores (0..n).
// Each region contains np peers, the first peer is the leader.
// (copied from server/cluster_test.go)
func newTestRegions() []*core.RegionInfo {
n := uint64(10000)
np := uint64(3)

regions := make([]*core.RegionInfo, 0, n)
for i := uint64(0); i < n; i++ {
peers := make([]*metapb.Peer, 0, np)
for j := uint64(0); j < np; j++ {
peer := &metapb.Peer{
Id: i*np + j,
}
peer.StoreId = (i + j) % n
peers = append(peers, peer)
}
region := &metapb.Region{
Id: i,
Peers: peers,
StartKey: []byte(fmt.Sprintf("%d", i)),
EndKey: []byte(fmt.Sprintf("%d", i+1)),
RegionEpoch: &metapb.RegionEpoch{ConfVer: 2, Version: 2},
}
regions = append(regions, core.NewRegionInfo(region, peers[0]))
}
return regions
}

func BenchmarkRenderJSON(b *testing.B) {
regionInfos := newTestRegions()
rd := createStreamingRender()
regions := convertToAPIRegions(regionInfos)

b.ResetTimer()
for i := 0; i < b.N; i++ {
var buffer bytes.Buffer
rd.JSON(&buffer, 200, regions)
}
}

func BenchmarkConvertToAPIRegions(b *testing.B) {
regionInfos := newTestRegions()

b.ResetTimer()
for i := 0; i < b.N; i++ {
regions := convertToAPIRegions(regionInfos)
_ = regions.Count
}
}

func BenchmarkHexRegionKey(b *testing.B) {
key := []byte("region_number_infinity")
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = core.HexRegionKey(key)
}
}

func BenchmarkHexRegionKeyStr(b *testing.B) {
key := []byte("region_number_infinity")
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = core.HexRegionKeyStr(key)
}
}
21 changes: 16 additions & 5 deletions server/api/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,20 @@ import (
"github.com/unrolled/render"
)

const pingAPI = "/ping"
func createStreamingRender() *render.Render {
return render.New(render.Options{
StreamingJSON: true,
})
}

func createRouter(prefix string, svr *server.Server) *mux.Router {
rd := render.New(render.Options{
func createIndentRender() *render.Render {
return render.New(render.Options{
IndentJSON: true,
})
}

func createRouter(prefix string, svr *server.Server) *mux.Router {
rd := createIndentRender()

router := mux.NewRouter().PathPrefix(prefix).Subrouter()
handler := svr.GetHandler()
Expand Down Expand Up @@ -88,8 +96,11 @@ func createRouter(prefix string, svr *server.Server) *mux.Router {
router.HandleFunc("/api/v1/region/id/{id}", regionHandler.GetRegionByID).Methods("GET")
router.HandleFunc("/api/v1/region/key/{key}", regionHandler.GetRegionByKey).Methods("GET")

srd := createStreamingRender()
regionsAllHandler := newRegionsHandler(svr, srd)
router.HandleFunc("/api/v1/regions", regionsAllHandler.GetAll).Methods("GET")

regionsHandler := newRegionsHandler(svr, rd)
router.HandleFunc("/api/v1/regions", regionsHandler.GetAll).Methods("GET")
router.HandleFunc("/api/v1/regions/key", regionsHandler.ScanRegions).Methods("GET")
router.HandleFunc("/api/v1/regions/count", regionsHandler.GetRegionCount).Methods("GET")
router.HandleFunc("/api/v1/regions/store/{id}", regionsHandler.GetStoreRegions).Methods("GET")
Expand Down Expand Up @@ -138,7 +149,7 @@ func createRouter(prefix string, svr *server.Server) *mux.Router {
logHanler := newlogHandler(svr, rd)
router.HandleFunc("/api/v1/admin/log", logHanler.Handle).Methods("POST")

router.HandleFunc(pingAPI, func(w http.ResponseWriter, r *http.Request) {}).Methods("GET")
router.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {}).Methods("GET")
router.Handle("/health", newHealthHandler(svr, rd)).Methods("GET")
router.Handle("/diagnose", newDiagnoseHandler(svr, rd)).Methods("GET")
return router
Expand Down
50 changes: 49 additions & 1 deletion server/core/region.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"math/rand"
"reflect"
"strings"
"unsafe"

"github.com/gogo/protobuf/proto"
"github.com/pingcap/kvproto/pkg/metapb"
Expand Down Expand Up @@ -807,10 +808,57 @@ func DiffRegionKeyInfo(origin *RegionInfo, other *RegionInfo) string {
return strings.Join(ret, ", ")
}

// String converts slice of bytes to string without copy.
func String(b []byte) (s string) {
if len(b) == 0 {
return ""
}
pbytes := (*reflect.SliceHeader)(unsafe.Pointer(&b))
pstring := (*reflect.StringHeader)(unsafe.Pointer(&s))
pstring.Data = pbytes.Data
pstring.Len = pbytes.Len
return
}

// ToUpperASCIIInplace bytes.ToUpper but zero-cost
func ToUpperASCIIInplace(s []byte) []byte {
hasLower := false
for i := 0; i < len(s); i++ {
c := s[i]
hasLower = hasLower || ('a' <= c && c <= 'z')
}

if !hasLower {
return s
}
var c byte
for i := 0; i < len(s); i++ {
c = s[i]
if 'a' <= c && c <= 'z' {
c -= 'a' - 'A'
}
s[i] = c
}
return s
}

// EncodeToString overrides hex.EncodeToString implementation. Difference: returns []byte, not string
func EncodeToString(src []byte) []byte {
dst := make([]byte, hex.EncodedLen(len(src)))
hex.Encode(dst, src)
return dst
}

// HexRegionKey converts region key to hex format. Used for formating region in
// logs.
func HexRegionKey(key []byte) []byte {
return []byte(strings.ToUpper(hex.EncodeToString(key)))
return ToUpperASCIIInplace(EncodeToString(key))
}

// HexRegionKeyStr converts region key to hex format. Used for formating region in
// logs.
func HexRegionKeyStr(key []byte) string {
return String(HexRegionKey(key))
}

// RegionToHexMeta converts a region meta's keys to hex format. Used for formating
Expand Down

0 comments on commit c8cb4b4

Please sign in to comment.