Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions internal/locate/region_cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
pd.Client
getRegion func(ctx context.Context, cli pd.Client, key []byte, opts ...opt.GetRegionOption) (*router.Region, error)
getRegionByID func(ctx context.Context, cli pd.Client, id uint64, opts ...opt.GetRegionOption) (*router.Region, error)
scanRegions func(ctx context.Context, startKey, endKey []byte, limit int, opts ...opt.GetRegionOption) ([]*router.Region, error)
batchScanRegions func(ctx context.Context, keyRanges []router.KeyRange, limit int, opts ...opt.GetRegionOption) ([]*router.Region, error)
}

Expand All @@ -90,6 +91,13 @@
return c.Client.GetRegionByID(ctx, id, opts...)
}

func (c *inspectedPDClient) ScanRegions(ctx context.Context, startKey, endKey []byte, limit int, opts ...opt.GetRegionOption) ([]*router.Region, error) {
if c.scanRegions != nil {
return c.scanRegions(ctx, startKey, endKey, limit, opts...)
}
return c.Client.ScanRegions(ctx, startKey, endKey, limit, opts...)

Check failure on line 98 in internal/locate/region_cache_test.go

View workflow job for this annotation

GitHub Actions / golangci

SA1019: c.Client.ScanRegions is deprecated: use BatchScanRegions instead. (staticcheck)
}

func (c *inspectedPDClient) BatchScanRegions(ctx context.Context, keyRanges []router.KeyRange, limit int, opts ...opt.GetRegionOption) ([]*router.Region, error) {
if c.batchScanRegions != nil {
return c.batchScanRegions(ctx, keyRanges, limit, opts...)
Expand Down Expand Up @@ -524,6 +532,105 @@
s.Equal(returnedRegions[0].meta.GetId(), region.GetID())
}

func (s *testRegionCacheSuite) TestRegionAPIFallbackFromStaleFollowerToLeader() {
splitKey := []byte("m")
oldMeta, oldLeader, _, _ := s.cluster.GetRegionByID(s.region1)
s.NotNil(oldMeta)
s.NotNil(oldLeader)

newRegionID := s.cluster.AllocID()
newPeers := s.cluster.AllocIDs(2)
s.cluster.Split(s.region1, newRegionID, splitKey, newPeers, newPeers[0])

// Keep the fresh right region in cache. A stale pre-split region returned by
// the follower intersects with it and must be rejected before retrying leader.
loc, err := s.cache.LocateKey(s.bo, splitKey)
s.NoError(err)
s.Equal(newRegionID, loc.Region.GetID())

currentLeft, err := s.cache.pdClient.GetRegion(withPDCircuitBreaker(context.Background()), []byte("a"))
s.NoError(err)
currentRight, err := s.cache.pdClient.GetRegion(withPDCircuitBreaker(context.Background()), splitKey)
s.NoError(err)
staleLeftMeta := proto.Clone(currentLeft.Meta).(*metapb.Region)
staleLeftMeta.RegionEpoch.Version--
staleLeft := &router.Region{
Meta: staleLeftMeta,
Leader: proto.Clone(currentLeft.Leader).(*metapb.Peer),
}
staleWholeRegion := &router.Region{
Meta: oldMeta,
Leader: oldLeader,
}
allowActiveFollower := func(opts ...opt.GetRegionOption) bool {
op := &opt.GetRegionOp{}
for _, opt := range opts {
opt(op)
}
return op.AllowFollowerHandle || op.AllowRouterServiceHandle
}

originalGetRegion := s.cache.pdClient.GetRegion
originalScanRegions := s.cache.pdClient.ScanRegions

Check failure on line 574 in internal/locate/region_cache_test.go

View workflow job for this annotation

GitHub Actions / golangci

SA1019: s.cache.pdClient.ScanRegions is deprecated: use BatchScanRegions instead. (staticcheck)
originalBatchScanRegions := s.cache.pdClient.BatchScanRegions

getRegionCnt := 0
scanRegionsCnt := 0
batchScanRegionsCnt := 0
s.cache.pdClient = &inspectedPDClient{
Client: s.cache.pdClient,
getRegion: func(ctx context.Context, cli pd.Client, key []byte, opts ...opt.GetRegionOption) (*router.Region, error) {
getRegionCnt++
if getRegionCnt == 1 {
s.True(allowActiveFollower(opts...))
return staleWholeRegion, nil
}
s.False(allowActiveFollower(opts...))
return originalGetRegion(ctx, key, opts...)
},
scanRegions: func(ctx context.Context, startKey, endKey []byte, limit int, opts ...opt.GetRegionOption) ([]*router.Region, error) {
scanRegionsCnt++
if scanRegionsCnt == 1 {
s.True(allowActiveFollower(opts...))
return []*router.Region{staleLeft}, nil
}
s.False(allowActiveFollower(opts...))
return originalScanRegions(ctx, startKey, endKey, limit, opts...)
},
batchScanRegions: func(ctx context.Context, keyRanges []router.KeyRange, limit int, opts ...opt.GetRegionOption) ([]*router.Region, error) {
batchScanRegionsCnt++
if batchScanRegionsCnt == 1 {
s.True(allowActiveFollower(opts...))
return []*router.Region{staleLeft}, nil
}
s.False(allowActiveFollower(opts...))
return originalBatchScanRegions(ctx, keyRanges, limit, opts...)
},
}

bo := retry.NewBackofferWithVars(context.Background(), 1000, nil)
loc, err = s.cache.LocateKey(bo, []byte("a"))
s.NoError(err)
s.Equal(2, getRegionCnt)
s.Equal(s.region1, loc.Region.GetID())
s.Equal(splitKey, loc.EndKey)

returnedRegions, err := s.cache.scanRegions(bo, nil, nil, 100)
s.NoError(err)
s.Equal(2, scanRegionsCnt)
s.Equal(2, len(returnedRegions))
s.Equal(s.region1, returnedRegions[0].meta.GetId())
s.Equal(newRegionID, returnedRegions[1].meta.GetId())

returnedRegions, err = s.cache.batchScanRegions(bo, []router.KeyRange{{StartKey: nil, EndKey: nil}}, 100, WithNeedRegionHasLeaderPeer())
s.NoError(err)
s.Equal(2, batchScanRegionsCnt)
s.Equal(2, len(returnedRegions))
s.Equal(s.region1, returnedRegions[0].meta.GetId())
s.Equal(newRegionID, returnedRegions[1].meta.GetId())
s.Equal(currentRight.Meta.GetId(), returnedRegions[1].meta.GetId())
}

func (s *testRegionCacheSuite) TestNeedExpireRegionAfterTTL() {
s.onClosed = func() { SetRegionCacheTTLWithJitter(600, 60) }
SetRegionCacheTTLWithJitter(2, 0)
Expand Down
Loading