@@ -44,6 +44,67 @@ type testSplitClient struct {
4444 splitCount atomic.Int32
4545 splitKeysAndScatterF func (context.Context , [][]byte , int32 ) ([]* split.RegionInfo , error )
4646 hook clientHook
47+ func TestSplitAndScatterRegionInBatchesTwoLevel (t * testing.T ) {
48+ makeSplitKeys := func (n int ) [][]byte {
49+ keys := make ([][]byte , n )
50+ for i := 0 ; i < n ; i ++ {
51+ keys [i ] = []byte {byte (i >> 8 ), byte (i )}
52+ }
53+ return keys
54+ }
55+
56+ t .Run ("large split keys trigger coarse and fine layers" , func (t * testing.T ) {
57+ splitCli := & testSplitClient {}
58+ local := & Backend {splitCli : splitCli }
59+
60+ err := local .splitAndScatterRegionInBatches (context .Background (), makeSplitKeys (121 ), 50 , 0 )
61+ require .NoError (t , err )
62+ // 121 keys => coarse pass(11 keys, 1 batch) + fine pass(121 keys, 3 batches) = 4 calls.
63+ require .Equal (t , int32 (4 ), splitCli .splitCount .Load ())
64+ })
65+
66+ t .Run ("small split keys only use fine layer" , func (t * testing.T ) {
67+ splitCli := & testSplitClient {}
68+ local := & Backend {splitCli : splitCli }
69+
70+ err := local .splitAndScatterRegionInBatches (context .Background (), makeSplitKeys (coarseGrainedSplitKeysThreshold ), 50 , 0 )
71+ require .NoError (t , err )
72+ require .Equal (t , int32 (2 ), splitCli .splitCount .Load ())
73+ })
74+
75+ t .Run ("coarse layer error returns immediately" , func (t * testing.T ) {
76+ splitCli := & testSplitClient {
77+ splitKeysAndScatterF : func (_ context.Context , _ [][]byte , splitCnt int32 ) ([]* split.RegionInfo , error ) {
78+ if splitCnt == 1 {
79+ return nil , errors .New ("mock split error" )
80+ }
81+ return []* split.RegionInfo {
82+ {
83+ Region : & metapb.Region {Id : 1 },
84+ },
85+ }, nil
86+ },
87+ }
88+ local := & Backend {splitCli : splitCli }
89+
90+ err := local .splitAndScatterRegionInBatches (context .Background (), makeSplitKeys (121 ), 50 , 0 )
91+ require .ErrorContains (t , err , "mock split error" )
92+ require .Equal (t , int32 (1 ), splitCli .splitCount .Load ())
93+ })
94+
95+ t .Run ("limiter is still enforced after restoring two levels" , func (t * testing.T ) {
96+ splitCli := & testSplitClient {}
97+ local := & Backend {splitCli : splitCli }
98+ ctx , cancel := context .WithTimeout (context .Background (), 100 * time .Millisecond )
99+ defer cancel ()
100+
101+ // maxCntPerSec=0.5 => burstPerSec=1, so after first batch, limiter blocks
102+ // and should hit context deadline before entering fine-grained stage.
103+ err := local .splitAndScatterRegionInBatches (ctx , makeSplitKeys (121 ), 50 , 0.5 )
104+ require .ErrorContains (t , err , "context deadline" )
105+ require .Equal (t , int32 (1 ), splitCli .splitCount .Load ())
106+ })
107+ }
47108}
48109
49110func newTestSplitClient (
@@ -340,7 +401,6 @@ func TestStoreWriteLimiter(t *testing.T) {
340401 wg .Wait ()
341402}
342403
343- << << << < HEAD
344404func TestTuneStoreWriteLimiter (t * testing.T ) {
345405 limiter := newStoreWriteLimiter (100 )
346406 testLimiter := func (ctx context.Context , maxT int ) {
@@ -462,5 +522,4 @@ func TestGetCoarseGrainedSplitKeys(t *testing.T) {
462522
463523 require .Equal (t , 1 , lastKeyCount )
464524 })
465- >> >> >> > 4 ffecda589a (lightning : restore two - level split / scatter while keeping limiter behavior (#66312 ))
466525}
0 commit comments