diff --git a/ddl/index.go b/ddl/index.go index 8cbb784f8d9b7..845873b7589c6 100644 --- a/ddl/index.go +++ b/ddl/index.go @@ -626,7 +626,10 @@ func (w *worker) onCreateIndex(d *ddlCtx, t *meta.Meta, job *model.Job, isPK boo var reorgTp model.ReorgType reorgTp, err = pickBackfillType(w.ctx, job, indexInfo.Unique, d) if err != nil { - break + if !errorIsRetryable(err, job) { + job.State = model.JobStateCancelled + } + return ver, err } if reorgTp.NeedMergeProcess() { // Increase telemetryAddIndexIngestUsage diff --git a/ddl/ingest/disk_root.go b/ddl/ingest/disk_root.go index 2c351a196d186..9af58325cb3ee 100644 --- a/ddl/ingest/disk_root.go +++ b/ddl/ingest/disk_root.go @@ -16,12 +16,15 @@ package ingest import ( "fmt" + "os" "sync" "sync/atomic" "github.com/pingcap/errors" + "github.com/pingcap/failpoint" lcom "github.com/pingcap/tidb/br/pkg/lightning/common" "github.com/pingcap/tidb/sessionctx/variable" + "github.com/pingcap/tidb/util/dbterror" "github.com/pingcap/tidb/util/logutil" "go.uber.org/zap" ) @@ -114,13 +117,21 @@ func (d *diskRootImpl) usageInfo() string { // PreCheckUsage implements DiskRoot interface. func (d *diskRootImpl) PreCheckUsage() error { + failpoint.Inject("mockIngestCheckEnvFailed", func(_ failpoint.Value) { + failpoint.Return(dbterror.ErrIngestCheckEnvFailed.FastGenByArgs("mock error")) + }) + err := os.MkdirAll(d.path, 0700) + if err != nil { + return dbterror.ErrIngestCheckEnvFailed.FastGenByArgs(err.Error()) + } sz, err := lcom.GetStorageSize(d.path) if err != nil { - return errors.Trace(err) + return dbterror.ErrIngestCheckEnvFailed.FastGenByArgs(err.Error()) } if RiskOfDiskFull(sz.Available, sz.Capacity) { sortPath := ConfigSortPath() - return errors.Errorf("sort path: %s, %s, please clean up the disk and retry", sortPath, d.UsageInfo()) + msg := fmt.Sprintf("sort path: %s, %s, please clean up the disk and retry", sortPath, d.UsageInfo()) + return dbterror.ErrIngestCheckEnvFailed.FastGenByArgs(msg) } return nil } diff --git a/errno/errcode.go b/errno/errcode.go index 08fda5f4d2a4c..f3e8cfeb1e2a3 100644 --- a/errno/errcode.go +++ b/errno/errcode.go @@ -1127,6 +1127,7 @@ const ( ErrColumnInChange = 8245 ErrDDLSetting = 8246 ErrIngestFailed = 8247 + ErrIngestCheckEnvFailed = 8256 ErrCannotPauseDDLJob = 8260 ErrCannotResumeDDLJob = 8261 diff --git a/errno/errname.go b/errno/errname.go index a5b4350318cae..aee780becb0ed 100644 --- a/errno/errname.go +++ b/errno/errname.go @@ -1119,6 +1119,7 @@ var MySQLErrName = map[uint16]*mysql.ErrMessage{ ErrPartitionColumnStatsMissing: mysql.Message("Build global-level stats failed due to missing partition-level column stats: %s, please run analyze table to refresh columns of all partitions", nil), ErrDDLSetting: mysql.Message("Error happened when %s DDL: %s", nil), ErrIngestFailed: mysql.Message("Ingest failed: %s", nil), + ErrIngestCheckEnvFailed: mysql.Message("Check ingest environment failed: %s", nil), ErrNotSupportedWithSem: mysql.Message("Feature '%s' is not supported when security enhanced mode is enabled", nil), ErrPlacementPolicyCheck: mysql.Message("Placement policy didn't meet the constraint, reason: %s", nil), diff --git a/errors.toml b/errors.toml index a27fa923a9bbb..3183ba52004ec 100644 --- a/errors.toml +++ b/errors.toml @@ -1466,6 +1466,11 @@ error = ''' Ingest failed: %s ''' +["ddl:8256"] +error = ''' +Check ingest environment failed: %s +''' + ["ddl:8260"] error = ''' Job [%v] can't be paused: %s diff --git a/tests/realtikvtest/addindextest/integration_test.go b/tests/realtikvtest/addindextest/integration_test.go index ded5a49c19a14..6bc617e50d1ac 100644 --- a/tests/realtikvtest/addindextest/integration_test.go +++ b/tests/realtikvtest/addindextest/integration_test.go @@ -433,9 +433,9 @@ func TestAddIndexBackfillLostUpdate(t *testing.T) { d := dom.DDL() originalCallback := d.GetHook() defer d.SetHook(originalCallback) - callback := &callback.TestDDLCallback{} + hook := &callback.TestDDLCallback{} var runDML bool - callback.OnJobRunAfterExported = func(job *model.Job) { + hook.OnJobRunAfterExported = func(job *model.Job) { if t.Failed() || runDML { return } @@ -470,10 +470,25 @@ func TestAddIndexBackfillLostUpdate(t *testing.T) { _, err = tk1.Exec("commit;") assert.NoError(t, err) } - d.SetHook(callback) + d.SetHook(hook) require.NoError(t, failpoint.Enable("github.com/pingcap/tidb/ddl/mockDMLExecutionStateBeforeImport", "1*return")) tk.MustExec("alter table t add unique index idx(b);") tk.MustExec("admin check table t;") tk.MustQuery("select * from t;").Check(testkit.Rows("1 2 1")) require.NoError(t, failpoint.Disable("github.com/pingcap/tidb/ddl/mockDMLExecutionStateBeforeImport")) } + +func TestAddIndexPreCheckFailed(t *testing.T) { + store := realtikvtest.CreateMockStoreAndSetup(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("drop database if exists addindexlit;") + tk.MustExec("create database addindexlit;") + tk.MustExec("use addindexlit;") + tk.MustExec(`set global tidb_ddl_enable_fast_reorg=on;`) + + tk.MustExec("create table t(id int primary key, b int, k int);") + tk.MustExec("insert into t values (1, 1, 1);") + require.NoError(t, failpoint.Enable("github.com/pingcap/tidb/ddl/ingest/mockIngestCheckEnvFailed", "return")) + tk.MustGetErrMsg("alter table t add index idx(b);", "[ddl:8256]Check ingest environment failed: mock error") + require.NoError(t, failpoint.Disable("github.com/pingcap/tidb/ddl/ingest/mockIngestCheckEnvFailed")) +} diff --git a/util/dbterror/ddl_terror.go b/util/dbterror/ddl_terror.go index 0453bcd84a2e3..fb230e138e8c5 100644 --- a/util/dbterror/ddl_terror.go +++ b/util/dbterror/ddl_terror.go @@ -403,6 +403,8 @@ var ( ErrDDLSetting = ClassDDL.NewStd(mysql.ErrDDLSetting) // ErrIngestFailed returns when the DDL ingest job is failed. ErrIngestFailed = ClassDDL.NewStd(mysql.ErrIngestFailed) + // ErrIngestCheckEnvFailed returns when the DDL ingest env is failed to init. + ErrIngestCheckEnvFailed = ClassDDL.NewStd(mysql.ErrIngestCheckEnvFailed) // ErrColumnInChange indicates there is modification on the column in parallel. ErrColumnInChange = ClassDDL.NewStd(mysql.ErrColumnInChange)