Skip to content

Commit

Permalink
Merge branch 'master' into timer
Browse files Browse the repository at this point in the history
  • Loading branch information
ti-chi-bot[bot] committed Jul 3, 2023
2 parents a40b03a + 05f71e0 commit ac7bb65
Show file tree
Hide file tree
Showing 18 changed files with 270 additions and 61 deletions.
17 changes: 17 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,20 @@ coverage:
# basic
target: auto
threshold: 3%

comment:
layout: "header, diff, flags"
behavior: default
require_changes: false

flag_management:
default_rules: # the rules that will be followed for any flag added, generally
carryforward: true
statuses:
- type: project
target: 85%
- type: patch
target: 85%

ignore:
- tests/** # integration test cases or tools.
5 changes: 0 additions & 5 deletions errors.toml
Original file line number Diff line number Diff line change
Expand Up @@ -606,11 +606,6 @@ error = '''
invalid group settings, please check the group name, priority and the number of resources
'''

["PD:resourcemanager:ErrResourceGroupAlreadyExists"]
error = '''
the %s resource group already exists
'''

["PD:schedule:ErrCreateOperator"]
error = '''
unable to create operator, %s
Expand Down
7 changes: 3 additions & 4 deletions pkg/errs/errno.go
Original file line number Diff line number Diff line change
Expand Up @@ -372,8 +372,7 @@ var (

// Resource Manager errors
var (
ErrResourceGroupAlreadyExists = errors.Normalize("the %s resource group already exists", errors.RFCCodeText("PD:resourcemanager:ErrResourceGroupAlreadyExists"))
ErrResourceGroupNotExists = errors.Normalize("the %s resource group does not exist", errors.RFCCodeText("PD:resourcemanager:ErrGroupNotExists"))
ErrDeleteReservedGroup = errors.Normalize("cannot delete reserved group", errors.RFCCodeText("PD:resourcemanager:ErrDeleteReservedGroup"))
ErrInvalidGroup = errors.Normalize("invalid group settings, please check the group name, priority and the number of resources", errors.RFCCodeText("PD:resourcemanager:ErrInvalidGroup"))
ErrResourceGroupNotExists = errors.Normalize("the %s resource group does not exist", errors.RFCCodeText("PD:resourcemanager:ErrGroupNotExists"))
ErrDeleteReservedGroup = errors.Normalize("cannot delete reserved group", errors.RFCCodeText("PD:resourcemanager:ErrDeleteReservedGroup"))
ErrInvalidGroup = errors.Normalize("invalid group settings, please check the group name, priority and the number of resources", errors.RFCCodeText("PD:resourcemanager:ErrInvalidGroup"))
)
4 changes: 0 additions & 4 deletions pkg/keyspace/keyspace.go
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,6 @@ func (manager *Manager) LoadKeyspace(name string) (*keyspacepb.KeyspaceMeta, err
if meta == nil {
return ErrKeyspaceNotFound
}
meta.Id = id
return nil
})
return meta, err
Expand All @@ -399,9 +398,6 @@ func (manager *Manager) LoadKeyspaceByID(spaceID uint32) (*keyspacepb.KeyspaceMe
}
return nil
})
if meta != nil {
meta.Id = spaceID
}
return meta, err
}

Expand Down
16 changes: 14 additions & 2 deletions pkg/keyspace/tso_keyspace_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,17 @@ func buildSplitKeyspaces(
oldSplit = append(oldSplit, keyspace)
}
}
return oldSplit, new, nil
// If newNum != len(newKeyspaceMap), it means the provided new keyspace list contains
// duplicate keyspaces, and we need to dedup them (https://github.com/tikv/pd/issues/6687);
// otherwise, we can just return the old split and new keyspace list.
if newNum == len(newKeyspaceMap) {
return oldSplit, new, nil
}
newSplit := make([]uint32, 0, len(newKeyspaceMap))
for keyspace := range newKeyspaceMap {
newSplit = append(newSplit, keyspace)
}
return oldSplit, newSplit, nil
}
// Split according to the start and end keyspace ID.
if startKeyspaceID == 0 && endKeyspaceID == 0 {
Expand All @@ -634,7 +644,9 @@ func buildSplitKeyspaces(
)
for _, keyspace := range old {
if keyspace == utils.DefaultKeyspaceID {
return nil, nil, ErrModifyDefaultKeyspace
// The source keyspace group must be the default keyspace group and we always keep the default
// keyspace in the default keyspace group.
continue
}
if startKeyspaceID <= keyspace && keyspace <= endKeyspaceID {
newSplit = append(newSplit, keyspace)
Expand Down
41 changes: 41 additions & 0 deletions pkg/keyspace/tso_keyspace_group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -483,27 +483,68 @@ func TestBuildSplitKeyspaces(t *testing.T) {
new: []uint32{6},
err: ErrKeyspaceNotInKeyspaceGroup,
},
{
old: []uint32{1, 2},
new: []uint32{2, 2},
expectedOld: []uint32{1},
expectedNew: []uint32{2},
},
{
old: []uint32{0, 1, 2, 3, 4, 5},
startKeyspaceID: 2,
endKeyspaceID: 4,
expectedOld: []uint32{0, 1, 5},
expectedNew: []uint32{2, 3, 4},
},
{
old: []uint32{0, 1, 2, 3, 4, 5},
startKeyspaceID: 0,
endKeyspaceID: 4,
expectedOld: []uint32{0, 5},
expectedNew: []uint32{1, 2, 3, 4},
},
{
old: []uint32{1, 2, 3, 4, 5},
startKeyspaceID: 2,
endKeyspaceID: 4,
expectedOld: []uint32{1, 5},
expectedNew: []uint32{2, 3, 4},
},
{
old: []uint32{1, 2, 3, 4, 5},
startKeyspaceID: 5,
endKeyspaceID: 6,
expectedOld: []uint32{1, 2, 3, 4},
expectedNew: []uint32{5},
},
{
old: []uint32{1, 2, 3, 4, 5},
startKeyspaceID: 2,
endKeyspaceID: 6,
expectedOld: []uint32{1},
expectedNew: []uint32{2, 3, 4, 5},
},
{
old: []uint32{1, 2, 3, 4, 5},
startKeyspaceID: 1,
endKeyspaceID: 1,
expectedOld: []uint32{2, 3, 4, 5},
expectedNew: []uint32{1},
},
{
old: []uint32{1, 2, 3, 4, 5},
startKeyspaceID: 0,
endKeyspaceID: 6,
expectedOld: []uint32{},
expectedNew: []uint32{1, 2, 3, 4, 5},
},
{
old: []uint32{1, 2, 3, 4, 5},
startKeyspaceID: 7,
endKeyspaceID: 10,
expectedOld: []uint32{1, 2, 3, 4, 5},
expectedNew: []uint32{},
},
{
old: []uint32{1, 2, 3, 4, 5},
err: ErrKeyspaceNotInKeyspaceGroup,
Expand Down
35 changes: 25 additions & 10 deletions pkg/keyspace/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ func MaskKeyspaceID(id uint32) uint32 {
return id & 0xFF
}

// makeKeyRanges encodes keyspace ID to correct LabelRule data.
// RegionBound represents the region boundary of the given keyspace.
// For a keyspace with id ['a', 'b', 'c'], it has four boundaries:
//
// Lower bound for raw mode: ['r', 'a', 'b', 'c']
Expand All @@ -147,23 +147,38 @@ func MaskKeyspaceID(id uint32) uint32 {
// And shares upper bound with keyspace with id ['a', 'b', 'c + 1'].
// These repeated bound will not cause any problem, as repetitive bound will be ignored during rangeListBuild,
// but provides guard against hole in keyspace allocations should it occur.
func makeKeyRanges(id uint32) []interface{} {
type RegionBound struct {
RawLeftBound []byte
RawRightBound []byte
TxnLeftBound []byte
TxnRightBound []byte
}

// MakeRegionBound constructs the correct region boundaries of the given keyspace.
func MakeRegionBound(id uint32) *RegionBound {
keyspaceIDBytes := make([]byte, 4)
nextKeyspaceIDBytes := make([]byte, 4)
binary.BigEndian.PutUint32(keyspaceIDBytes, id)
binary.BigEndian.PutUint32(nextKeyspaceIDBytes, id+1)
rawLeftBound := hex.EncodeToString(codec.EncodeBytes(append([]byte{'r'}, keyspaceIDBytes[1:]...)))
rawRightBound := hex.EncodeToString(codec.EncodeBytes(append([]byte{'r'}, nextKeyspaceIDBytes[1:]...)))
txnLeftBound := hex.EncodeToString(codec.EncodeBytes(append([]byte{'x'}, keyspaceIDBytes[1:]...)))
txnRightBound := hex.EncodeToString(codec.EncodeBytes(append([]byte{'x'}, nextKeyspaceIDBytes[1:]...)))
return &RegionBound{
RawLeftBound: codec.EncodeBytes(append([]byte{'r'}, keyspaceIDBytes[1:]...)),
RawRightBound: codec.EncodeBytes(append([]byte{'r'}, nextKeyspaceIDBytes[1:]...)),
TxnLeftBound: codec.EncodeBytes(append([]byte{'x'}, keyspaceIDBytes[1:]...)),
TxnRightBound: codec.EncodeBytes(append([]byte{'x'}, nextKeyspaceIDBytes[1:]...)),
}
}

// makeKeyRanges encodes keyspace ID to correct LabelRule data.
func makeKeyRanges(id uint32) []interface{} {
regionBound := MakeRegionBound(id)
return []interface{}{
map[string]interface{}{
"start_key": rawLeftBound,
"end_key": rawRightBound,
"start_key": hex.EncodeToString(regionBound.RawLeftBound),
"end_key": hex.EncodeToString(regionBound.RawRightBound),
},
map[string]interface{}{
"start_key": txnLeftBound,
"end_key": txnRightBound,
"start_key": hex.EncodeToString(regionBound.TxnLeftBound),
"end_key": hex.EncodeToString(regionBound.TxnRightBound),
},
}
}
Expand Down
8 changes: 2 additions & 6 deletions pkg/mcs/resourcemanager/server/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ func (m *Manager) Init(ctx context.Context) {
}

// AddResourceGroup puts a resource group.
// NOTE: AddResourceGroup should also be idempotent because tidb depends
// on this retry mechanism.
func (m *Manager) AddResourceGroup(grouppb *rmpb.ResourceGroup) error {
// Check the name.
if len(grouppb.Name) == 0 || len(grouppb.Name) > 32 {
Expand All @@ -163,12 +165,6 @@ func (m *Manager) AddResourceGroup(grouppb *rmpb.ResourceGroup) error {
if grouppb.GetPriority() > 16 {
return errs.ErrInvalidGroup
}
m.RLock()
_, ok := m.groups[grouppb.Name]
m.RUnlock()
if ok {
return errs.ErrResourceGroupAlreadyExists.FastGenByArgs(grouppb.Name)
}
group := FromProtoResourceGroup(grouppb)
m.Lock()
defer m.Unlock()
Expand Down
51 changes: 51 additions & 0 deletions server/api/region.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/pingcap/kvproto/pkg/replication_modepb"
"github.com/pingcap/log"
"github.com/tikv/pd/pkg/core"
"github.com/tikv/pd/pkg/keyspace"
"github.com/tikv/pd/pkg/schedule/filter"
"github.com/tikv/pd/pkg/statistics"
"github.com/tikv/pd/pkg/utils/apiutil"
Expand Down Expand Up @@ -398,6 +399,56 @@ func (h *regionsHandler) GetStoreRegions(w http.ResponseWriter, r *http.Request)
h.rd.JSON(w, http.StatusOK, regionsInfo)
}

// @Tags region
// @Summary List regions belongs to the given keyspace ID.
// @Param keyspace_id query string true "Keyspace ID"
// @Param limit query integer false "Limit count" default(16)
// @Produce json
// @Success 200 {object} RegionsInfo
// @Failure 400 {string} string "The input is invalid."
// @Router /regions/keyspace/id/{id} [get]
func (h *regionsHandler) GetKeyspaceRegions(w http.ResponseWriter, r *http.Request) {
rc := getCluster(r)
vars := mux.Vars(r)
keyspaceIDStr := vars["id"]
if keyspaceIDStr == "" {
h.rd.JSON(w, http.StatusBadRequest, "keyspace id is empty")
return
}

keyspaceID64, err := strconv.ParseUint(keyspaceIDStr, 10, 32)
if err != nil {
h.rd.JSON(w, http.StatusBadRequest, err.Error())
return
}
keyspaceID := uint32(keyspaceID64)
keyspaceManager := h.svr.GetKeyspaceManager()
if _, err := keyspaceManager.LoadKeyspaceByID(keyspaceID); err != nil {
h.rd.JSON(w, http.StatusBadRequest, err.Error())
return
}

limit := defaultRegionLimit
if limitStr := r.URL.Query().Get("limit"); limitStr != "" {
limit, err = strconv.Atoi(limitStr)
if err != nil {
h.rd.JSON(w, http.StatusBadRequest, err.Error())
return
}
}
if limit > maxRegionLimit {
limit = maxRegionLimit
}
regionBound := keyspace.MakeRegionBound(keyspaceID)
regions := rc.ScanRegions(regionBound.RawLeftBound, regionBound.RawRightBound, limit)
if limit <= 0 || limit > len(regions) {
txnRegion := rc.ScanRegions(regionBound.TxnLeftBound, regionBound.TxnRightBound, limit-len(regions))
regions = append(regions, txnRegion...)
}
regionsInfo := convertToAPIRegions(regions)
h.rd.JSON(w, http.StatusOK, regionsInfo)
}

// @Tags region
// @Summary List all regions that miss peer.
// @Produce json
Expand Down
1 change: 1 addition & 0 deletions server/api/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ func createRouter(prefix string, svr *server.Server) *mux.Router {
registerFunc(clusterRouter, "/regions/key", regionsHandler.ScanRegions, setMethods(http.MethodGet), setAuditBackend(prometheus))
registerFunc(clusterRouter, "/regions/count", regionsHandler.GetRegionCount, setMethods(http.MethodGet), setAuditBackend(prometheus))
registerFunc(clusterRouter, "/regions/store/{id}", regionsHandler.GetStoreRegions, setMethods(http.MethodGet), setAuditBackend(prometheus))
registerFunc(clusterRouter, "/regions/keyspace/id/{id}", regionsHandler.GetKeyspaceRegions, setMethods(http.MethodGet), setAuditBackend(prometheus))
registerFunc(clusterRouter, "/regions/writeflow", regionsHandler.GetTopWriteFlowRegions, setMethods(http.MethodGet), setAuditBackend(prometheus))
registerFunc(clusterRouter, "/regions/readflow", regionsHandler.GetTopReadFlowRegions, setMethods(http.MethodGet), setAuditBackend(prometheus))
registerFunc(clusterRouter, "/regions/confver", regionsHandler.GetTopConfVerRegions, setMethods(http.MethodGet), setAuditBackend(prometheus))
Expand Down
29 changes: 23 additions & 6 deletions server/apiv2/handlers/tso_keyspace_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ func RegisterTSOKeyspaceGroup(r *gin.RouterGroup) {
router.GET("", GetKeyspaceGroups)
router.GET("/:id", GetKeyspaceGroupByID)
router.DELETE("/:id", DeleteKeyspaceGroupByID)
router.PATCH("/:id", SetNodesForKeyspaceGroup) // only to support set nodes
router.PATCH("/:id/*node", SetPriorityForKeyspaceGroup) // only to support set priority
router.POST("/:id/alloc", AllocNodesForKeyspaceGroup)
router.POST("/:id/nodes", SetNodesForKeyspaceGroup)
router.POST("/:id/priority", SetPriorityForKeyspaceGroup)
router.POST("/:id/split", SplitKeyspaceGroupByID)
router.DELETE("/:id/split", FinishSplitKeyspaceByID)
router.POST("/:id/merge", MergeKeyspaceGroups)
Expand Down Expand Up @@ -436,8 +436,7 @@ func SetNodesForKeyspaceGroup(c *gin.Context) {

// SetPriorityForKeyspaceGroupParams defines the params for setting priority of tso node for the keyspace group.
type SetPriorityForKeyspaceGroupParams struct {
Node string `json:"node"`
Priority int `json:"priority"`
Priority int `json:"priority"`
}

// SetPriorityForKeyspaceGroup sets priority of tso node for the keyspace group.
Expand All @@ -447,6 +446,11 @@ func SetPriorityForKeyspaceGroup(c *gin.Context) {
c.AbortWithStatusJSON(http.StatusBadRequest, "invalid keyspace group id")
return
}
node, err := parseNodeAddress(c)
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, "invalid node address")
return
}
svr := c.MustGet(middlewares.ServerContextKey).(*server.Server)
manager := svr.GetKeyspaceGroupManager()
if manager == nil {
Expand All @@ -468,12 +472,12 @@ func SetPriorityForKeyspaceGroup(c *gin.Context) {
// check if node exists
members := kg.Members
if slice.NoneOf(members, func(i int) bool {
return members[i].Address == setParams.Node
return members[i].Address == node
}) {
c.AbortWithStatusJSON(http.StatusBadRequest, "tso node does not exist in the keyspace group")
}
// set priority
err = manager.SetPriorityForKeyspaceGroup(id, setParams.Node, setParams.Priority)
err = manager.SetPriorityForKeyspaceGroup(id, node, setParams.Priority)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, err.Error())
return
Expand All @@ -492,6 +496,19 @@ func validateKeyspaceGroupID(c *gin.Context) (uint32, error) {
return uint32(id), nil
}

func parseNodeAddress(c *gin.Context) (string, error) {
node := c.Param("node")
if node == "" {
return "", errors.New("invalid node address")
}
// In pd-ctl, we use url.PathEscape to escape the node address and replace the % to \%.
// But in the gin framework, it will unescape the node address automatically.
// So we need to replace the \/ to /.
node = strings.ReplaceAll(node, "\\/", "/")
node = strings.TrimPrefix(node, "/")
return node, nil
}

func isValid(id uint32) bool {
return id >= utils.DefaultKeyspaceGroupID && id <= utils.MaxKeyspaceGroupCountInUse
}
Loading

0 comments on commit ac7bb65

Please sign in to comment.