Skip to content

Commit 7569592

Browse files
authored
ddl: refine range validation after scaning regions (#59767)
close #59701
1 parent f3f8968 commit 7569592

File tree

6 files changed

+51
-5
lines changed

6 files changed

+51
-5
lines changed

pkg/ddl/backfilling.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,11 @@ func loadTableRanges(
511511
maxSleep := 10000 // ms
512512
bo := tikv.NewBackofferWithVars(ctx, maxSleep, nil)
513513
var ranges []kv.KeyRange
514-
err := util.RunWithRetry(util.DefaultMaxRetries, util.RetryInterval, func() (bool, error) {
514+
maxRetryTimes := util.DefaultMaxRetries
515+
failpoint.Inject("loadTableRangesNoRetry", func() {
516+
maxRetryTimes = 1
517+
})
518+
err := util.RunWithRetry(maxRetryTimes, util.RetryInterval, func() (bool, error) {
515519
logutil.DDLLogger().Info("load table ranges from PD",
516520
zap.Int64("physicalTableID", t.GetPhysicalID()),
517521
zap.String("start key", hex.EncodeToString(startKey)),
@@ -549,6 +553,9 @@ func loadTableRanges(
549553
}
550554

551555
func validateAndFillRanges(ranges []kv.KeyRange, startKey, endKey []byte) error {
556+
failpoint.Inject("validateAndFillRangesErr", func() {
557+
failpoint.Return(dbterror.ErrInvalidSplitRegionRanges.GenWithStackByArgs("mock"))
558+
})
552559
if len(ranges) == 0 {
553560
errMsg := fmt.Sprintf("cannot find region in range [%s, %s]",
554561
hex.EncodeToString(startKey), hex.EncodeToString(endKey))
@@ -559,19 +566,26 @@ func validateAndFillRanges(ranges []kv.KeyRange, startKey, endKey []byte) error
559566
s := r.StartKey
560567
if len(s) == 0 || bytes.Compare(s, startKey) < 0 {
561568
ranges[i].StartKey = startKey
569+
} else if bytes.Compare(s, startKey) > 0 {
570+
errMsg := fmt.Sprintf("get empty range at the beginning of ranges, expected %s, but got %s",
571+
hex.EncodeToString(startKey), hex.EncodeToString(s))
572+
return dbterror.ErrInvalidSplitRegionRanges.GenWithStackByArgs(errMsg)
562573
}
563574
}
564575
if i == len(ranges)-1 {
565576
e := r.EndKey
566577
if len(e) == 0 || bytes.Compare(e, endKey) > 0 {
567578
ranges[i].EndKey = endKey
568579
}
580+
// We don't need to check the end key because a limit may set before scanning regions.
569581
}
570582
if len(ranges[i].StartKey) == 0 || len(ranges[i].EndKey) == 0 {
571-
return errors.Errorf("get empty start/end key in the middle of ranges")
583+
return dbterror.ErrInvalidSplitRegionRanges.GenWithStackByArgs("get empty start/end key in the middle of ranges")
572584
}
573585
if i > 0 && !bytes.Equal(ranges[i-1].EndKey, ranges[i].StartKey) {
574-
return errors.Errorf("ranges are not continuous")
586+
errMsg := fmt.Sprintf("ranges are not continuous, last end key %s, next start key %s",
587+
hex.EncodeToString(ranges[i-1].EndKey), hex.EncodeToString(ranges[i].StartKey))
588+
return dbterror.ErrInvalidSplitRegionRanges.GenWithStackByArgs(errMsg)
575589
}
576590
}
577591
return nil

pkg/ddl/backfilling_test.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ func TestValidateAndFillRanges(t *testing.T) {
418418
mkRange("c", "d"),
419419
mkRange("d", "e"),
420420
}
421-
err := validateAndFillRanges(ranges, []byte("a"), []byte("e"))
421+
err := validateAndFillRanges(ranges, []byte("b"), []byte("e"))
422422
require.NoError(t, err)
423423
require.EqualValues(t, []kv.KeyRange{
424424
mkRange("b", "c"),
@@ -480,6 +480,22 @@ func TestValidateAndFillRanges(t *testing.T) {
480480
}
481481
err = validateAndFillRanges(ranges, []byte("b"), []byte("f"))
482482
require.Error(t, err)
483+
484+
ranges = []kv.KeyRange{
485+
mkRange("b", "c"),
486+
mkRange("c", "d"),
487+
mkRange("d", "e"),
488+
}
489+
err = validateAndFillRanges(ranges, []byte("a"), []byte("e"))
490+
require.Error(t, err)
491+
492+
ranges = []kv.KeyRange{
493+
mkRange("b", "c"),
494+
mkRange("c", "d"),
495+
mkRange("d", "e"),
496+
}
497+
err = validateAndFillRanges(ranges, []byte("b"), []byte("f"))
498+
require.NoError(t, err)
483499
}
484500

485501
func TestTuneTableScanWorkerBatchSize(t *testing.T) {

pkg/ddl/ingest/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ go_test(
7474
],
7575
flaky = True,
7676
race = "on",
77-
shard_count = 23,
77+
shard_count = 24,
7878
deps = [
7979
":ingest",
8080
"//pkg/config",

pkg/ddl/ingest/integration_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,3 +525,17 @@ func TestAddGlobalIndexInIngestWithUpdate(t *testing.T) {
525525
rsTable := tk.MustQuery("select *,_tidb_rowid from t use index()").Sort()
526526
require.Equal(t, rsGlobalIndex.String(), rsTable.String())
527527
}
528+
529+
func TestAddIndexValidateRangesFailed(t *testing.T) {
530+
store := testkit.CreateMockStore(t)
531+
defer ingesttestutil.InjectMockBackendCtx(t, store)()
532+
tk := testkit.NewTestKit(t, store)
533+
tk.MustExec("use test")
534+
tk.MustExec("create table t (a int primary key, b int);")
535+
tk.MustExec("insert into t values (1, 1);")
536+
537+
testfailpoint.Enable(t, "github.com/pingcap/tidb/pkg/ddl/loadTableRangesNoRetry", "return")
538+
testfailpoint.Enable(t, "github.com/pingcap/tidb/pkg/ddl/validateAndFillRangesErr", "2*return")
539+
tk.MustExec("alter table t add index idx(b);")
540+
tk.MustExec("admin check table t;")
541+
}

pkg/util/dbterror/ddl_terror.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,7 @@ var ReorgRetryableErrCodes = map[uint16]struct{}{
531531
mysql.ErrWriteConflictInTiDB: {},
532532
mysql.ErrTxnRetryable: {},
533533
mysql.ErrNotOwner: {},
534+
mysql.ErrInvalidSplitRegionRanges: {}, // PD client returns regions with no leader.
534535

535536
// Temporary network partitioning may cause pk commit failure.
536537
uint16(terror.CodeResultUndetermined): {},

tests/realtikvtest/addindextest4/failure_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
)
3434

3535
func TestAddIndexIngestRecoverPartition(t *testing.T) {
36+
t.Skip("the test is too hacky, use another way to test")
3637
partCnt := 0
3738
block := make(chan struct{})
3839
ExecuteBlocks(t, func() {

0 commit comments

Comments
 (0)