diff --git a/ddl/db_test.go b/ddl/db_test.go index f575210ebaf74..56e1c162ee3bb 100644 --- a/ddl/db_test.go +++ b/ddl/db_test.go @@ -4595,3 +4595,33 @@ func (s *testDBSuite) TestModifyColumnCharset(c *C) { ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin")) } + +func (s *testDBSuite) TestCanceledJobTakeTime(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("create table t_cjtt(a int)") + + hook := &ddl.TestDDLCallback{} + once := sync.Once{} + hook.OnJobUpdatedExported = func(job *model.Job) { + once.Do(func() { + err := kv.RunInNewTxn(s.store, false, func(txn kv.Transaction) error { + t := meta.NewMeta(txn) + return t.DropTable(job.SchemaID, job.TableID, true) + }) + c.Assert(err, IsNil) + }) + } + s.dom.DDL().(ddl.DDLForTest).SetHook(hook) + + originalWT := ddl.WaitTimeWhenErrorOccured + ddl.WaitTimeWhenErrorOccured = 1 * time.Second + defer func() { ddl.WaitTimeWhenErrorOccured = originalWT }() + startTime := time.Now() + s.testErrorCode(c, "alter table t_cjtt add column b int", mysql.ErrNoSuchTable) + sub := time.Since(startTime) + c.Assert(sub, Less, ddl.WaitTimeWhenErrorOccured) + + hook = &ddl.TestDDLCallback{} + s.dom.DDL().(ddl.DDLForTest).SetHook(hook) +} diff --git a/ddl/ddl_worker.go b/ddl/ddl_worker.go index 5a5762d3a65b8..1874874e0de41 100644 --- a/ddl/ddl_worker.go +++ b/ddl/ddl_worker.go @@ -419,7 +419,7 @@ func (w *worker) handleDDLJobQueue(d *ddlCtx) error { // If the job is done or still running or rolling back, we will wait 2 * lease time to guarantee other servers to update // the newest schema. w.waitSchemaChanged(nil, d, waitTime, schemaVer, job) - if job.IsSynced() { + if job.IsSynced() || job.IsCancelled() { asyncNotify(d.ddlJobDoneCh) } } @@ -519,15 +519,15 @@ func (w *worker) runDDLJob(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64, // Save errors in job, so that others can know errors happened. if err != nil { - // If job is not cancelled, we should log this error. - if job.State != model.JobStateCancelled { - log.Errorf("[ddl-%s] run DDL job err %v", w, errors.ErrorStack(err)) - } else { - log.Infof("[ddl-%s] the DDL job is normal to cancel because %v", w, errors.ErrorStack(err)) - } - job.Error = toTError(err) job.ErrorCount++ + + // If job is cancelled, we shouldn't return this error. + if job.State == model.JobStateCancelled { + log.Infof("[ddl-%s] the DDL job is normal to cancel because %v", w, errors.ErrorStack(err)) + return ver, nil + } + log.Errorf("[ddl-%s] run DDL job err %v", w, errors.ErrorStack(err)) } return }