mirror of
https://github.com/talent-plan/tinykv.git
synced 2024-12-28 13:50:13 +08:00
5e089a2cd1
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>
147 lines
4.5 KiB
Go
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
|
|
}
|