diff --git a/ddl/ddl_worker.go b/ddl/ddl_worker.go index 66064dac98886..24573287cd8fd 100644 --- a/ddl/ddl_worker.go +++ b/ddl/ddl_worker.go @@ -456,6 +456,15 @@ func (w *worker) handleDDLJobQueue(d *ddlCtx) error { err = w.finishDDLJob(t, job) return errors.Trace(err) } + if runJobErr != nil && !job.IsRollingback() && !job.IsRollbackDone() { + // If the running job meets an error + // and the job state is rolling back, it means that we have already handled this error. + // Some DDL jobs (such as adding indexes) may need to update the table info and the schema version, + // then shouldn't discard the KV modification. + // And the job state is rollback done, it means the job was already finished, also shouldn't discard too. + // Otherwise, we should discard the KV modification when running job. + txn.Reset() + } err = w.updateDDLJob(t, job, runJobErr != nil) if err = w.handleUpdateJobError(t, job, err); err != nil { return errors.Trace(err) diff --git a/ddl/serial_test.go b/ddl/serial_test.go index f6acbd9648b0b..51518da8113b7 100644 --- a/ddl/serial_test.go +++ b/ddl/serial_test.go @@ -28,6 +28,7 @@ import ( "github.com/pingcap/parser/mysql" "github.com/pingcap/tidb/config" "github.com/pingcap/tidb/ddl" + ddlutil "github.com/pingcap/tidb/ddl/util" "github.com/pingcap/tidb/domain" "github.com/pingcap/tidb/infoschema" "github.com/pingcap/tidb/kv" @@ -777,6 +778,25 @@ func (s *testSerialSuite) TestCancelJobByErrorCountLimit(c *C) { c.Assert(err.Error(), Equals, "[ddl:12]cancelled DDL job") } +func (s *testSerialSuite) TestTruncateTableUpdateSchemaVersionErr(c *C) { + tk := testkit.NewTestKit(c, s.store) + c.Assert(failpoint.Enable("github.com/pingcap/tidb/ddl/mockTruncateTableUpdateVersionError", `return(true)`), IsNil) + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + + tk.MustExec("set @@global.tidb_ddl_error_count_limit = 5") + err := ddlutil.LoadDDLVars(tk.Se) + c.Assert(err, IsNil) + + tk.MustExec("create table t (a int)") + _, err = tk.Exec("truncate table t") + c.Assert(err, NotNil) + c.Assert(err.Error(), Equals, "[ddl:12]cancelled DDL job") + // Disable fail point. + c.Assert(failpoint.Disable("github.com/pingcap/tidb/ddl/mockTruncateTableUpdateVersionError"), IsNil) + tk.MustExec("truncate table t") +} + func (s *testSerialSuite) TestCanceledJobTakeTime(c *C) { tk := testkit.NewTestKit(c, s.store) tk.MustExec("use test") diff --git a/ddl/table.go b/ddl/table.go index 9399909628b15..ad9a1d562036c 100644 --- a/ddl/table.go +++ b/ddl/table.go @@ -449,6 +449,12 @@ func onTruncateTable(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64, _ erro return ver, errors.Trace(err) } + failpoint.Inject("mockTruncateTableUpdateVersionError", func(val failpoint.Value) { + if val.(bool) { + failpoint.Return(ver, errors.New("mock update version error")) + } + }) + ver, err = updateSchemaVersion(t, job) if err != nil { return ver, errors.Trace(err)