tikv: add function SplitRegionRanges to get the split ranges from region. (#5931)
This commit is contained in:
@ -278,10 +278,26 @@ func buildCopTasks(bo *Backoffer, cache *RegionCache, ranges *copRanges, desc bo
|
||||
})
|
||||
}
|
||||
|
||||
err := splitRanges(bo, cache, ranges, appendTask)
|
||||
if err != nil {
|
||||
return nil, errors.Trace(err)
|
||||
}
|
||||
|
||||
if desc {
|
||||
reverseTasks(tasks)
|
||||
}
|
||||
if elapsed := time.Since(start); elapsed > time.Millisecond*500 {
|
||||
log.Warnf("buildCopTasks takes too much time (%v), range len %v, task len %v", elapsed, rangesLen, len(tasks))
|
||||
}
|
||||
metrics.TiKVTxnRegionsNumHistogram.WithLabelValues("coprocessor").Observe(float64(len(tasks)))
|
||||
return tasks, nil
|
||||
}
|
||||
|
||||
func splitRanges(bo *Backoffer, cache *RegionCache, ranges *copRanges, fn func(region RegionVerID, ranges *copRanges)) error {
|
||||
for ranges.len() > 0 {
|
||||
loc, err := cache.LocateKey(bo, ranges.at(0).StartKey)
|
||||
if err != nil {
|
||||
return nil, errors.Trace(err)
|
||||
return errors.Trace(err)
|
||||
}
|
||||
|
||||
// Iterate to the first range that is not complete in the region.
|
||||
@ -294,7 +310,7 @@ func buildCopTasks(bo *Backoffer, cache *RegionCache, ranges *copRanges, desc bo
|
||||
}
|
||||
// All rest ranges belong to the same region.
|
||||
if i == ranges.len() {
|
||||
appendTask(loc.Region, ranges)
|
||||
fn(loc.Region, ranges)
|
||||
break
|
||||
}
|
||||
|
||||
@ -306,7 +322,7 @@ func buildCopTasks(bo *Backoffer, cache *RegionCache, ranges *copRanges, desc bo
|
||||
StartKey: r.StartKey,
|
||||
EndKey: loc.EndKey,
|
||||
}
|
||||
appendTask(loc.Region, taskRanges)
|
||||
fn(loc.Region, taskRanges)
|
||||
|
||||
ranges = ranges.slice(i+1, ranges.len())
|
||||
ranges.first = &kv.KeyRange{
|
||||
@ -315,19 +331,31 @@ func buildCopTasks(bo *Backoffer, cache *RegionCache, ranges *copRanges, desc bo
|
||||
}
|
||||
} else {
|
||||
// rs[i] is not in the region.
|
||||
appendTask(loc.Region, ranges.slice(0, i))
|
||||
taskRanges := ranges.slice(0, i)
|
||||
fn(loc.Region, taskRanges)
|
||||
ranges = ranges.slice(i, ranges.len())
|
||||
}
|
||||
}
|
||||
|
||||
if desc {
|
||||
reverseTasks(tasks)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SplitRegionRanges get the split ranges from pd region.
|
||||
func SplitRegionRanges(bo *Backoffer, cache *RegionCache, keyRanges []kv.KeyRange) ([]kv.KeyRange, error) {
|
||||
ranges := copRanges{mid: keyRanges}
|
||||
|
||||
var ret []kv.KeyRange
|
||||
appendRange := func(region RegionVerID, ranges *copRanges) {
|
||||
for i := 0; i < ranges.len(); i++ {
|
||||
ret = append(ret, ranges.at(i))
|
||||
}
|
||||
}
|
||||
if elapsed := time.Since(start); elapsed > time.Millisecond*500 {
|
||||
log.Warnf("buildCopTasks takes too much time (%v), range len %v, task len %v", elapsed, rangesLen, len(tasks))
|
||||
|
||||
err := splitRanges(bo, cache, &ranges, appendRange)
|
||||
if err != nil {
|
||||
return nil, errors.Trace(err)
|
||||
}
|
||||
metrics.TiKVTxnRegionsNumHistogram.WithLabelValues("coprocessor").Observe(float64(len(tasks)))
|
||||
return tasks, nil
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func reverseTasks(tasks []*copTask) {
|
||||
|
||||
@ -35,28 +35,28 @@ func (s *testCoprocessorSuite) TestBuildTasks(c *C) {
|
||||
|
||||
bo := NewBackoffer(context.Background(), 3000)
|
||||
|
||||
tasks, err := buildCopTasks(bo, cache, buildKeyRanges("a", "c"), false, false)
|
||||
tasks, err := buildCopTasks(bo, cache, buildCopRanges("a", "c"), false, false)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(tasks, HasLen, 1)
|
||||
s.taskEqual(c, tasks[0], regionIDs[0], "a", "c")
|
||||
|
||||
tasks, err = buildCopTasks(bo, cache, buildKeyRanges("g", "n"), false, false)
|
||||
tasks, err = buildCopTasks(bo, cache, buildCopRanges("g", "n"), false, false)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(tasks, HasLen, 1)
|
||||
s.taskEqual(c, tasks[0], regionIDs[1], "g", "n")
|
||||
|
||||
tasks, err = buildCopTasks(bo, cache, buildKeyRanges("m", "n"), false, false)
|
||||
tasks, err = buildCopTasks(bo, cache, buildCopRanges("m", "n"), false, false)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(tasks, HasLen, 1)
|
||||
s.taskEqual(c, tasks[0], regionIDs[1], "m", "n")
|
||||
|
||||
tasks, err = buildCopTasks(bo, cache, buildKeyRanges("a", "k"), false, false)
|
||||
tasks, err = buildCopTasks(bo, cache, buildCopRanges("a", "k"), false, false)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(tasks, HasLen, 2)
|
||||
s.taskEqual(c, tasks[0], regionIDs[0], "a", "g")
|
||||
s.taskEqual(c, tasks[1], regionIDs[1], "g", "k")
|
||||
|
||||
tasks, err = buildCopTasks(bo, cache, buildKeyRanges("a", "x"), false, false)
|
||||
tasks, err = buildCopTasks(bo, cache, buildCopRanges("a", "x"), false, false)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(tasks, HasLen, 4)
|
||||
s.taskEqual(c, tasks[0], regionIDs[0], "a", "g")
|
||||
@ -64,29 +64,81 @@ func (s *testCoprocessorSuite) TestBuildTasks(c *C) {
|
||||
s.taskEqual(c, tasks[2], regionIDs[2], "n", "t")
|
||||
s.taskEqual(c, tasks[3], regionIDs[3], "t", "x")
|
||||
|
||||
tasks, err = buildCopTasks(bo, cache, buildKeyRanges("a", "b", "b", "c"), false, false)
|
||||
tasks, err = buildCopTasks(bo, cache, buildCopRanges("a", "b", "b", "c"), false, false)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(tasks, HasLen, 1)
|
||||
s.taskEqual(c, tasks[0], regionIDs[0], "a", "b", "b", "c")
|
||||
|
||||
tasks, err = buildCopTasks(bo, cache, buildKeyRanges("a", "b", "e", "f"), false, false)
|
||||
tasks, err = buildCopTasks(bo, cache, buildCopRanges("a", "b", "e", "f"), false, false)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(tasks, HasLen, 1)
|
||||
s.taskEqual(c, tasks[0], regionIDs[0], "a", "b", "e", "f")
|
||||
|
||||
tasks, err = buildCopTasks(bo, cache, buildKeyRanges("g", "n", "o", "p"), false, false)
|
||||
tasks, err = buildCopTasks(bo, cache, buildCopRanges("g", "n", "o", "p"), false, false)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(tasks, HasLen, 2)
|
||||
s.taskEqual(c, tasks[0], regionIDs[1], "g", "n")
|
||||
s.taskEqual(c, tasks[1], regionIDs[2], "o", "p")
|
||||
|
||||
tasks, err = buildCopTasks(bo, cache, buildKeyRanges("h", "k", "m", "p"), false, false)
|
||||
tasks, err = buildCopTasks(bo, cache, buildCopRanges("h", "k", "m", "p"), false, false)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(tasks, HasLen, 2)
|
||||
s.taskEqual(c, tasks[0], regionIDs[1], "h", "k", "m", "n")
|
||||
s.taskEqual(c, tasks[1], regionIDs[2], "n", "p")
|
||||
}
|
||||
|
||||
func (s *testCoprocessorSuite) TestSplitRegionRanges(c *C) {
|
||||
// nil --- 'g' --- 'n' --- 't' --- nil
|
||||
// <- 0 -> <- 1 -> <- 2 -> <- 3 ->
|
||||
cluster := mocktikv.NewCluster()
|
||||
mocktikv.BootstrapWithMultiRegions(cluster, []byte("g"), []byte("n"), []byte("t"))
|
||||
pdCli := &codecPDClient{mocktikv.NewPDClient(cluster)}
|
||||
cache := NewRegionCache(pdCli)
|
||||
|
||||
bo := NewBackoffer(context.Background(), 3000)
|
||||
|
||||
ranges, err := SplitRegionRanges(bo, cache, buildKeyRanges("a", "c"))
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(ranges, HasLen, 1)
|
||||
s.rangeEqual(c, ranges, "a", "c")
|
||||
|
||||
ranges, err = SplitRegionRanges(bo, cache, buildKeyRanges("h", "y"))
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(len(ranges), Equals, 3)
|
||||
s.rangeEqual(c, ranges, "h", "n", "n", "t", "t", "y")
|
||||
|
||||
ranges, err = SplitRegionRanges(bo, cache, buildKeyRanges("s", "z"))
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(len(ranges), Equals, 2)
|
||||
s.rangeEqual(c, ranges, "s", "t", "t", "z")
|
||||
|
||||
ranges, err = SplitRegionRanges(bo, cache, buildKeyRanges("s", "s"))
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(len(ranges), Equals, 1)
|
||||
s.rangeEqual(c, ranges, "s", "s")
|
||||
|
||||
ranges, err = SplitRegionRanges(bo, cache, buildKeyRanges("t", "t"))
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(len(ranges), Equals, 1)
|
||||
s.rangeEqual(c, ranges, "t", "t")
|
||||
|
||||
ranges, err = SplitRegionRanges(bo, cache, buildKeyRanges("t", "u"))
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(len(ranges), Equals, 1)
|
||||
s.rangeEqual(c, ranges, "t", "u")
|
||||
|
||||
ranges, err = SplitRegionRanges(bo, cache, buildKeyRanges("u", "z"))
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(len(ranges), Equals, 1)
|
||||
s.rangeEqual(c, ranges, "u", "z")
|
||||
|
||||
// min --> max
|
||||
ranges, err = SplitRegionRanges(bo, cache, buildKeyRanges("a", "z"))
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(ranges, HasLen, 4)
|
||||
s.rangeEqual(c, ranges, "a", "g", "g", "n", "n", "t", "t", "z")
|
||||
}
|
||||
|
||||
func (s *testCoprocessorSuite) TestRebuild(c *C) {
|
||||
// nil --- 'm' --- nil
|
||||
// <- 0 -> <- 1 ->
|
||||
@ -96,7 +148,7 @@ func (s *testCoprocessorSuite) TestRebuild(c *C) {
|
||||
cache := NewRegionCache(pdCli)
|
||||
bo := NewBackoffer(context.Background(), 3000)
|
||||
|
||||
tasks, err := buildCopTasks(bo, cache, buildKeyRanges("a", "z"), false, false)
|
||||
tasks, err := buildCopTasks(bo, cache, buildCopRanges("a", "z"), false, false)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(tasks, HasLen, 2)
|
||||
s.taskEqual(c, tasks[0], regionIDs[0], "a", "m")
|
||||
@ -109,7 +161,7 @@ func (s *testCoprocessorSuite) TestRebuild(c *C) {
|
||||
cluster.Split(regionIDs[1], regionIDs[2], []byte("q"), []uint64{peerIDs[2]}, storeID)
|
||||
cache.DropRegion(tasks[1].region)
|
||||
|
||||
tasks, err = buildCopTasks(bo, cache, buildKeyRanges("a", "z"), true, false)
|
||||
tasks, err = buildCopTasks(bo, cache, buildCopRanges("a", "z"), true, false)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(tasks, HasLen, 3)
|
||||
s.taskEqual(c, tasks[2], regionIDs[0], "a", "m")
|
||||
@ -117,7 +169,7 @@ func (s *testCoprocessorSuite) TestRebuild(c *C) {
|
||||
s.taskEqual(c, tasks[0], regionIDs[2], "q", "z")
|
||||
}
|
||||
|
||||
func buildKeyRanges(keys ...string) *copRanges {
|
||||
func buildKeyRanges(keys ...string) []kv.KeyRange {
|
||||
var ranges []kv.KeyRange
|
||||
for i := 0; i < len(keys); i += 2 {
|
||||
ranges = append(ranges, kv.KeyRange{
|
||||
@ -125,6 +177,11 @@ func buildKeyRanges(keys ...string) *copRanges {
|
||||
EndKey: []byte(keys[i+1]),
|
||||
})
|
||||
}
|
||||
return ranges
|
||||
}
|
||||
|
||||
func buildCopRanges(keys ...string) *copRanges {
|
||||
ranges := buildKeyRanges(keys...)
|
||||
return &copRanges{mid: ranges}
|
||||
}
|
||||
|
||||
@ -137,6 +194,14 @@ func (s *testCoprocessorSuite) taskEqual(c *C, task *copTask, regionID uint64, k
|
||||
}
|
||||
}
|
||||
|
||||
func (s *testCoprocessorSuite) rangeEqual(c *C, ranges []kv.KeyRange, keys ...string) {
|
||||
for i := 0; i < len(ranges); i++ {
|
||||
r := ranges[i]
|
||||
c.Assert(string(r.StartKey), Equals, keys[2*i])
|
||||
c.Assert(string(r.EndKey), Equals, keys[2*i+1])
|
||||
}
|
||||
}
|
||||
|
||||
func (s *testCoprocessorSuite) TestCopRanges(c *C) {
|
||||
ranges := []kv.KeyRange{
|
||||
{StartKey: []byte("a"), EndKey: []byte("b")},
|
||||
@ -178,49 +243,49 @@ func (s *testCoprocessorSuite) TestCopRangeSplit(c *C) {
|
||||
// input range: [c-d) [e-g) [l-o)
|
||||
ranges := &copRanges{mid: mid}
|
||||
s.testSplit(c, ranges, right,
|
||||
splitCase{"c", buildKeyRanges("c", "d", "e", "g", "l", "o")},
|
||||
splitCase{"d", buildKeyRanges("e", "g", "l", "o")},
|
||||
splitCase{"f", buildKeyRanges("f", "g", "l", "o")},
|
||||
splitCase{"c", buildCopRanges("c", "d", "e", "g", "l", "o")},
|
||||
splitCase{"d", buildCopRanges("e", "g", "l", "o")},
|
||||
splitCase{"f", buildCopRanges("f", "g", "l", "o")},
|
||||
)
|
||||
|
||||
// input range: [a-b) [c-d) [e-g) [l-o)
|
||||
ranges = &copRanges{first: first, mid: mid}
|
||||
s.testSplit(c, ranges, right,
|
||||
splitCase{"a", buildKeyRanges("a", "b", "c", "d", "e", "g", "l", "o")},
|
||||
splitCase{"c", buildKeyRanges("c", "d", "e", "g", "l", "o")},
|
||||
splitCase{"m", buildKeyRanges("m", "o")},
|
||||
splitCase{"a", buildCopRanges("a", "b", "c", "d", "e", "g", "l", "o")},
|
||||
splitCase{"c", buildCopRanges("c", "d", "e", "g", "l", "o")},
|
||||
splitCase{"m", buildCopRanges("m", "o")},
|
||||
)
|
||||
|
||||
// input range: [a-b) [c-d) [e-g) [l-o) [q-t)
|
||||
ranges = &copRanges{first: first, mid: mid, last: last}
|
||||
s.testSplit(c, ranges, right,
|
||||
splitCase{"f", buildKeyRanges("f", "g", "l", "o", "q", "t")},
|
||||
splitCase{"h", buildKeyRanges("l", "o", "q", "t")},
|
||||
splitCase{"r", buildKeyRanges("r", "t")},
|
||||
splitCase{"f", buildCopRanges("f", "g", "l", "o", "q", "t")},
|
||||
splitCase{"h", buildCopRanges("l", "o", "q", "t")},
|
||||
splitCase{"r", buildCopRanges("r", "t")},
|
||||
)
|
||||
|
||||
// input range: [c-d) [e-g) [l-o)
|
||||
ranges = &copRanges{mid: mid}
|
||||
s.testSplit(c, ranges, left,
|
||||
splitCase{"m", buildKeyRanges("c", "d", "e", "g", "l", "m")},
|
||||
splitCase{"g", buildKeyRanges("c", "d", "e", "g")},
|
||||
splitCase{"g", buildKeyRanges("c", "d", "e", "g")},
|
||||
splitCase{"m", buildCopRanges("c", "d", "e", "g", "l", "m")},
|
||||
splitCase{"g", buildCopRanges("c", "d", "e", "g")},
|
||||
splitCase{"g", buildCopRanges("c", "d", "e", "g")},
|
||||
)
|
||||
|
||||
// input range: [a-b) [c-d) [e-g) [l-o)
|
||||
ranges = &copRanges{first: first, mid: mid}
|
||||
s.testSplit(c, ranges, left,
|
||||
splitCase{"d", buildKeyRanges("a", "b", "c", "d")},
|
||||
splitCase{"d", buildKeyRanges("a", "b", "c", "d")},
|
||||
splitCase{"o", buildKeyRanges("a", "b", "c", "d", "e", "g", "l", "o")},
|
||||
splitCase{"d", buildCopRanges("a", "b", "c", "d")},
|
||||
splitCase{"d", buildCopRanges("a", "b", "c", "d")},
|
||||
splitCase{"o", buildCopRanges("a", "b", "c", "d", "e", "g", "l", "o")},
|
||||
)
|
||||
|
||||
// input range: [a-b) [c-d) [e-g) [l-o) [q-t)
|
||||
ranges = &copRanges{first: first, mid: mid, last: last}
|
||||
s.testSplit(c, ranges, left,
|
||||
splitCase{"o", buildKeyRanges("a", "b", "c", "d", "e", "g", "l", "o")},
|
||||
splitCase{"p", buildKeyRanges("a", "b", "c", "d", "e", "g", "l", "o")},
|
||||
splitCase{"t", buildKeyRanges("a", "b", "c", "d", "e", "g", "l", "o", "q", "t")},
|
||||
splitCase{"o", buildCopRanges("a", "b", "c", "d", "e", "g", "l", "o")},
|
||||
splitCase{"p", buildCopRanges("a", "b", "c", "d", "e", "g", "l", "o")},
|
||||
splitCase{"t", buildCopRanges("a", "b", "c", "d", "e", "g", "l", "o", "q", "t")},
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user