talent-plan-tinykv/scheduler/server/cluster_worker.go
Connor 5e089a2cd1 init course framework
Signed-off-by: Connor <zbk602423539@gmail.com>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: linning <linningde25@gmail.com>
Co-authored-by: YangKeao <keao.yang@yahoo.com>
Co-authored-by: andylokandy <andylokandy@hotmail.com>
Co-authored-by: Iosmanthus Teng <myosmanthustree@gmail.com>
2020-04-30 15:25:07 +08:00

147 lines
4.5 KiB
Go

// Copyright 2016 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,
// See the License for the specific language governing permissions and
// limitations under the License.
package server
import (
"bytes"
"github.com/gogo/protobuf/proto"
"github.com/pingcap-incubator/tinykv/proto/pkg/metapb"
"github.com/pingcap-incubator/tinykv/proto/pkg/schedulerpb"
"github.com/pingcap-incubator/tinykv/scheduler/server/core"
"github.com/pingcap-incubator/tinykv/scheduler/server/schedule"
"github.com/pingcap/log"
"github.com/pkg/errors"
"go.uber.org/zap"
)
// HandleRegionHeartbeat processes RegionInfo reports from client.
func (c *RaftCluster) HandleRegionHeartbeat(region *core.RegionInfo) error {
if err := c.processRegionHeartbeat(region); err != nil {
return err
}
// If the region peer count is 0, then we should not handle this.
if len(region.GetPeers()) == 0 {
log.Warn("invalid region, zero region peer count", zap.Stringer("region-meta", core.RegionToHexMeta(region.GetMeta())))
return errors.Errorf("invalid region, zero region peer count: %v", core.RegionToHexMeta(region.GetMeta()))
}
c.RLock()
co := c.coordinator
c.RUnlock()
co.opController.Dispatch(region, schedule.DispatchFromHeartBeat)
return nil
}
func (c *RaftCluster) handleAskSplit(request *schedulerpb.AskSplitRequest) (*schedulerpb.AskSplitResponse, error) {
reqRegion := request.GetRegion()
err := c.validRequestRegion(reqRegion)
if err != nil {
return nil, err
}
newRegionID, err := c.s.idAllocator.Alloc()
if err != nil {
return nil, err
}
peerIDs := make([]uint64, len(request.Region.Peers))
for i := 0; i < len(peerIDs); i++ {
if peerIDs[i], err = c.s.idAllocator.Alloc(); err != nil {
return nil, err
}
}
split := &schedulerpb.AskSplitResponse{
NewRegionId: newRegionID,
NewPeerIds: peerIDs,
}
return split, nil
}
func (c *RaftCluster) validRequestRegion(reqRegion *metapb.Region) error {
startKey := reqRegion.GetStartKey()
region, _ := c.GetRegionByKey(startKey)
if region == nil {
return errors.Errorf("region not found, request region: %v", core.RegionToHexMeta(reqRegion))
}
// If the request epoch is less than current region epoch, then returns an error.
reqRegionEpoch := reqRegion.GetRegionEpoch()
regionEpoch := region.GetRegionEpoch()
if reqRegionEpoch.GetVersion() < regionEpoch.GetVersion() ||
reqRegionEpoch.GetConfVer() < regionEpoch.GetConfVer() {
return errors.Errorf("invalid region epoch, request: %v, currenrt: %v", reqRegionEpoch, regionEpoch)
}
return nil
}
func (c *RaftCluster) checkSplitRegion(left *metapb.Region, right *metapb.Region) error {
if left == nil || right == nil {
return errors.New("invalid split region")
}
if !bytes.Equal(left.GetEndKey(), right.GetStartKey()) {
return errors.New("invalid split region")
}
if len(right.GetEndKey()) == 0 || bytes.Compare(left.GetStartKey(), right.GetEndKey()) < 0 {
return nil
}
return errors.New("invalid split region")
}
func (c *RaftCluster) checkSplitRegions(regions []*metapb.Region) error {
if len(regions) <= 1 {
return errors.New("invalid split region")
}
for i := 1; i < len(regions); i++ {
left := regions[i-1]
right := regions[i]
if !bytes.Equal(left.GetEndKey(), right.GetStartKey()) {
return errors.New("invalid split region")
}
if len(right.GetEndKey()) != 0 && bytes.Compare(left.GetStartKey(), right.GetEndKey()) >= 0 {
return errors.New("invalid split region")
}
}
return nil
}
func (c *RaftCluster) handleReportSplit(request *schedulerpb.ReportSplitRequest) (*schedulerpb.ReportSplitResponse, error) {
left := request.GetLeft()
right := request.GetRight()
err := c.checkSplitRegion(left, right)
if err != nil {
log.Warn("report split region is invalid",
zap.Stringer("left-region", core.RegionToHexMeta(left)),
zap.Stringer("right-region", core.RegionToHexMeta(right)),
zap.Error(err))
return nil, err
}
// Build origin region by using left and right.
originRegion := proto.Clone(right).(*metapb.Region)
originRegion.RegionEpoch = nil
originRegion.StartKey = left.GetStartKey()
log.Info("region split, generate new region",
zap.Uint64("region-id", originRegion.GetId()),
zap.Stringer("region-meta", core.RegionToHexMeta(left)))
return &schedulerpb.ReportSplitResponse{}, nil
}