You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

178 lines
4.0 KiB

  1. // Copyright 2015 PingCAP, Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. package ddl
  14. import (
  15. "time"
  16. "github.com/juju/errors"
  17. "github.com/ngaut/log"
  18. "github.com/pingcap/tidb/kv"
  19. "github.com/pingcap/tidb/meta"
  20. "github.com/pingcap/tidb/model"
  21. "github.com/pingcap/tidb/terror"
  22. )
  23. // handleBgJobQueue handles the background job queue.
  24. func (d *ddl) handleBgJobQueue() error {
  25. if d.isClosed() {
  26. return nil
  27. }
  28. job := &model.Job{}
  29. err := kv.RunInNewTxn(d.store, false, func(txn kv.Transaction) error {
  30. t := meta.NewMeta(txn)
  31. owner, err := d.checkOwner(t, bgJobFlag)
  32. if terror.ErrorEqual(err, ErrNotOwner) {
  33. return nil
  34. }
  35. if err != nil {
  36. return errors.Trace(err)
  37. }
  38. // get the first background job and run
  39. job, err = d.getFirstBgJob(t)
  40. if err != nil {
  41. return errors.Trace(err)
  42. }
  43. if job == nil {
  44. return nil
  45. }
  46. d.runBgJob(t, job)
  47. if job.IsFinished() {
  48. err = d.finishBgJob(t, job)
  49. } else {
  50. err = d.updateBgJob(t, job)
  51. }
  52. if err != nil {
  53. return errors.Trace(err)
  54. }
  55. owner.LastUpdateTS = time.Now().UnixNano()
  56. err = t.SetBgJobOwner(owner)
  57. return errors.Trace(err)
  58. })
  59. if err != nil {
  60. return errors.Trace(err)
  61. }
  62. return nil
  63. }
  64. // runBgJob runs a background job.
  65. func (d *ddl) runBgJob(t *meta.Meta, job *model.Job) {
  66. job.State = model.JobRunning
  67. var err error
  68. switch job.Type {
  69. case model.ActionDropSchema:
  70. err = d.delReorgSchema(t, job)
  71. case model.ActionDropTable:
  72. err = d.delReorgTable(t, job)
  73. default:
  74. job.State = model.JobCancelled
  75. err = errors.Errorf("invalid background job %v", job)
  76. }
  77. if err != nil {
  78. if job.State != model.JobCancelled {
  79. log.Errorf("run background job err %v", errors.ErrorStack(err))
  80. }
  81. job.Error = err.Error()
  82. job.ErrorCount++
  83. }
  84. }
  85. // prepareBgJob prepares a background job.
  86. func (d *ddl) prepareBgJob(ddlJob *model.Job) error {
  87. job := &model.Job{
  88. ID: ddlJob.ID,
  89. SchemaID: ddlJob.SchemaID,
  90. TableID: ddlJob.TableID,
  91. Type: ddlJob.Type,
  92. Args: ddlJob.Args,
  93. }
  94. err := kv.RunInNewTxn(d.store, true, func(txn kv.Transaction) error {
  95. t := meta.NewMeta(txn)
  96. err1 := t.EnQueueBgJob(job)
  97. return errors.Trace(err1)
  98. })
  99. return errors.Trace(err)
  100. }
  101. // startBgJob starts a background job.
  102. func (d *ddl) startBgJob(tp model.ActionType) {
  103. switch tp {
  104. case model.ActionDropSchema, model.ActionDropTable:
  105. asyncNotify(d.bgJobCh)
  106. }
  107. }
  108. // getFirstBgJob gets the first background job.
  109. func (d *ddl) getFirstBgJob(t *meta.Meta) (*model.Job, error) {
  110. job, err := t.GetBgJob(0)
  111. return job, errors.Trace(err)
  112. }
  113. // updateBgJob updates a background job.
  114. func (d *ddl) updateBgJob(t *meta.Meta, job *model.Job) error {
  115. err := t.UpdateBgJob(0, job)
  116. return errors.Trace(err)
  117. }
  118. // finishBgJob finishs a background job.
  119. func (d *ddl) finishBgJob(t *meta.Meta, job *model.Job) error {
  120. log.Warnf("[ddl] finish background job %v", job)
  121. if _, err := t.DeQueueBgJob(); err != nil {
  122. return errors.Trace(err)
  123. }
  124. err := t.AddHistoryBgJob(job)
  125. return errors.Trace(err)
  126. }
  127. func (d *ddl) onBackgroundWorker() {
  128. defer d.wait.Done()
  129. // we use 4 * lease time to check owner's timeout, so here, we will update owner's status
  130. // every 2 * lease time, if lease is 0, we will use default 10s.
  131. checkTime := chooseLeaseTime(2*d.lease, 10*time.Second)
  132. ticker := time.NewTicker(checkTime)
  133. defer ticker.Stop()
  134. for {
  135. select {
  136. case <-ticker.C:
  137. log.Debugf("[ddl] wait %s to check background job status again", checkTime)
  138. case <-d.bgJobCh:
  139. case <-d.quitCh:
  140. return
  141. }
  142. err := d.handleBgJobQueue()
  143. if err != nil {
  144. log.Errorf("[ddl] handle background job err %v", errors.ErrorStack(err))
  145. }
  146. }
  147. }