mirror of https://github.com/tikv/client-go.git
region cache: retry scan or batch scan regions when returned region has no leader (#1480)
Signed-off-by: cfzjywxk <cfzjywxk@gmail.com>
This commit is contained in:
parent
8dfa86b5d1
commit
691e80ae0e
|
|
@ -2223,7 +2223,18 @@ func (c *RegionCache) scanRegions(bo *retry.Backoffer, startKey, endKey []byte,
|
||||||
backoffErr = errors.Errorf("PD returned regions have gaps, limit: %d", limit)
|
backoffErr = errors.Errorf("PD returned regions have gaps, limit: %d", limit)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return c.handleRegionInfos(bo, regionsInfo, true)
|
validRegions, err := c.handleRegionInfos(bo, regionsInfo, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// If the region information is loaded from the local disk and the current leader has not
|
||||||
|
// yet reported a heartbeat to PD, the region information scanned at this time will not include the leader.
|
||||||
|
// Retry if there is no valid regions with leaders.
|
||||||
|
if len(validRegions) == 0 {
|
||||||
|
backoffErr = errors.Errorf("All returned regions have no leaders, limit: %d", limit)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return validRegions, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2290,7 +2301,18 @@ func (c *RegionCache) batchScanRegions(bo *retry.Backoffer, keyRanges []pd.KeyRa
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return c.handleRegionInfos(bo, regionsInfo, opt.needRegionHasLeaderPeer)
|
validRegions, err := c.handleRegionInfos(bo, regionsInfo, opt.needRegionHasLeaderPeer)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// If the region information is loaded from the local disk and the current leader has not
|
||||||
|
// yet reported a heartbeat to PD, the region information scanned at this time will not include the leader.
|
||||||
|
// Retry if there is no valid regions with leaders.
|
||||||
|
if len(validRegions) == 0 {
|
||||||
|
backoffErr = errors.Errorf("All returned regions have no leaders, limit: %d", limit)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return validRegions, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2397,7 +2419,7 @@ func (c *RegionCache) handleRegionInfos(bo *retry.Backoffer, regionsInfo []*pd.R
|
||||||
regions = append(regions, region)
|
regions = append(regions, region)
|
||||||
}
|
}
|
||||||
if len(regions) == 0 {
|
if len(regions) == 0 {
|
||||||
return nil, errors.New("receive Regions with no peer")
|
return nil, nil
|
||||||
}
|
}
|
||||||
if len(regions) < len(regionsInfo) {
|
if len(regions) < len(regionsInfo) {
|
||||||
logutil.Logger(context.Background()).Debug(
|
logutil.Logger(context.Background()).Debug(
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,8 @@ import (
|
||||||
|
|
||||||
type inspectedPDClient struct {
|
type inspectedPDClient struct {
|
||||||
pd.Client
|
pd.Client
|
||||||
getRegion func(ctx context.Context, cli pd.Client, key []byte, opts ...pd.GetRegionOption) (*pd.Region, error)
|
getRegion func(ctx context.Context, cli pd.Client, key []byte, opts ...pd.GetRegionOption) (*pd.Region, error)
|
||||||
|
batchScanRegions func(ctx context.Context, keyRanges []pd.KeyRange, limit int, opts ...pd.GetRegionOption) ([]*pd.Region, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *inspectedPDClient) GetRegion(ctx context.Context, key []byte, opts ...pd.GetRegionOption) (*pd.Region, error) {
|
func (c *inspectedPDClient) GetRegion(ctx context.Context, key []byte, opts ...pd.GetRegionOption) (*pd.Region, error) {
|
||||||
|
|
@ -76,6 +77,13 @@ func (c *inspectedPDClient) GetRegion(ctx context.Context, key []byte, opts ...p
|
||||||
return c.Client.GetRegion(ctx, key, opts...)
|
return c.Client.GetRegion(ctx, key, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *inspectedPDClient) BatchScanRegions(ctx context.Context, keyRanges []pd.KeyRange, limit int, opts ...pd.GetRegionOption) ([]*pd.Region, error) {
|
||||||
|
if c.batchScanRegions != nil {
|
||||||
|
return c.batchScanRegions(ctx, keyRanges, limit, opts...)
|
||||||
|
}
|
||||||
|
return c.Client.BatchScanRegions(ctx, keyRanges, limit, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
func TestBackgroundRunner(t *testing.T) {
|
func TestBackgroundRunner(t *testing.T) {
|
||||||
t.Run("ShutdownWait", func(t *testing.T) {
|
t.Run("ShutdownWait", func(t *testing.T) {
|
||||||
dur := 100 * time.Millisecond
|
dur := 100 * time.Millisecond
|
||||||
|
|
@ -459,6 +467,40 @@ func (s *testRegionCacheSuite) TestResolveStateTransition() {
|
||||||
s.cluster.AddStore(storeMeta.GetId(), storeMeta.GetAddress(), storeMeta.GetLabels()...)
|
s.cluster.AddStore(storeMeta.GetId(), storeMeta.GetAddress(), storeMeta.GetLabels()...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *testRegionCacheSuite) TestReturnRegionWithNoLeader() {
|
||||||
|
region := s.getRegion([]byte("x"))
|
||||||
|
NoLeaderRegion := &pd.Region{
|
||||||
|
Meta: region.meta,
|
||||||
|
Leader: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
originalBatchScanRegions := s.cache.pdClient.BatchScanRegions
|
||||||
|
|
||||||
|
batchScanCnt := 0
|
||||||
|
s.cache.pdClient = &inspectedPDClient{
|
||||||
|
Client: s.cache.pdClient,
|
||||||
|
batchScanRegions: func(ctx context.Context, keyRanges []pd.KeyRange, limit int, opts ...pd.GetRegionOption) ([]*pd.Region, error) {
|
||||||
|
if batchScanCnt == 0 {
|
||||||
|
batchScanCnt++
|
||||||
|
return []*pd.Region{NoLeaderRegion}, nil
|
||||||
|
} else {
|
||||||
|
return originalBatchScanRegions(ctx, keyRanges, limit, opts...)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
bo := retry.NewBackofferWithVars(context.Background(), 1000, nil)
|
||||||
|
returnedRegions, err := s.cache.scanRegions(bo, nil, nil, 100)
|
||||||
|
s.Nil(err)
|
||||||
|
s.Equal(len(returnedRegions), 1)
|
||||||
|
s.Equal(returnedRegions[0].meta.GetId(), region.GetID())
|
||||||
|
|
||||||
|
returnedRegions, err = s.cache.batchScanRegions(bo, []pd.KeyRange{{StartKey: nil, EndKey: nil}}, 100, WithNeedRegionHasLeaderPeer())
|
||||||
|
s.Nil(err)
|
||||||
|
s.Equal(len(returnedRegions), 1)
|
||||||
|
s.Equal(returnedRegions[0].meta.GetId(), region.GetID())
|
||||||
|
}
|
||||||
|
|
||||||
func (s *testRegionCacheSuite) TestNeedExpireRegionAfterTTL() {
|
func (s *testRegionCacheSuite) TestNeedExpireRegionAfterTTL() {
|
||||||
s.onClosed = func() { SetRegionCacheTTLWithJitter(600, 60) }
|
s.onClosed = func() { SetRegionCacheTTLWithJitter(600, 60) }
|
||||||
SetRegionCacheTTLWithJitter(2, 0)
|
SetRegionCacheTTLWithJitter(2, 0)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue