tikv: add function SplitRegionRanges to get the split ranges from region. (#5931)

This commit is contained in:
winkyao
2018-03-02 10:14:44 +08:00
committed by Jack Yu
parent 12be4037e2
commit cd1151644f
2 changed files with 133 additions and 40 deletions

View File

@ -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) {

View File

@ -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")},
)
}