github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/ddl/bg_worker.go (about) 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 14 package ddl 15 16 import ( 17 "time" 18 19 "github.com/insionng/yougam/libraries/juju/errors" 20 "github.com/insionng/yougam/libraries/ngaut/log" 21 "github.com/insionng/yougam/libraries/pingcap/tidb/kv" 22 "github.com/insionng/yougam/libraries/pingcap/tidb/meta" 23 "github.com/insionng/yougam/libraries/pingcap/tidb/model" 24 "github.com/insionng/yougam/libraries/pingcap/tidb/terror" 25 ) 26 27 // handleBgJobQueue handles the background job queue. 28 func (d *ddl) handleBgJobQueue() error { 29 if d.isClosed() { 30 return nil 31 } 32 33 job := &model.Job{} 34 err := kv.RunInNewTxn(d.store, false, func(txn kv.Transaction) error { 35 t := meta.NewMeta(txn) 36 owner, err := d.checkOwner(t, bgJobFlag) 37 if terror.ErrorEqual(err, errNotOwner) { 38 return nil 39 } 40 if err != nil { 41 return errors.Trace(err) 42 } 43 44 // get the first background job and run 45 job, err = d.getFirstBgJob(t) 46 if err != nil { 47 return errors.Trace(err) 48 } 49 if job == nil { 50 return nil 51 } 52 53 d.runBgJob(t, job) 54 if job.IsFinished() { 55 err = d.finishBgJob(t, job) 56 } else { 57 err = d.updateBgJob(t, job) 58 } 59 if err != nil { 60 return errors.Trace(err) 61 } 62 63 owner.LastUpdateTS = time.Now().UnixNano() 64 err = t.SetBgJobOwner(owner) 65 66 return errors.Trace(err) 67 }) 68 69 if err != nil { 70 return errors.Trace(err) 71 } 72 73 return nil 74 } 75 76 // runBgJob runs a background job. 77 func (d *ddl) runBgJob(t *meta.Meta, job *model.Job) { 78 job.State = model.JobRunning 79 80 var err error 81 switch job.Type { 82 case model.ActionDropSchema: 83 err = d.delReorgSchema(t, job) 84 case model.ActionDropTable: 85 err = d.delReorgTable(t, job) 86 default: 87 job.State = model.JobCancelled 88 err = errInvalidBgJob 89 } 90 91 if err != nil { 92 if job.State != model.JobCancelled { 93 log.Errorf("run background job err %v", errors.ErrorStack(err)) 94 } 95 96 job.Error = err.Error() 97 job.ErrorCount++ 98 } 99 } 100 101 // prepareBgJob prepares a background job. 102 func (d *ddl) prepareBgJob(ddlJob *model.Job) error { 103 job := &model.Job{ 104 ID: ddlJob.ID, 105 SchemaID: ddlJob.SchemaID, 106 TableID: ddlJob.TableID, 107 Type: ddlJob.Type, 108 Args: ddlJob.Args, 109 } 110 111 err := kv.RunInNewTxn(d.store, true, func(txn kv.Transaction) error { 112 t := meta.NewMeta(txn) 113 err1 := t.EnQueueBgJob(job) 114 115 return errors.Trace(err1) 116 }) 117 118 return errors.Trace(err) 119 } 120 121 // startBgJob starts a background job. 122 func (d *ddl) startBgJob(tp model.ActionType) { 123 switch tp { 124 case model.ActionDropSchema, model.ActionDropTable: 125 asyncNotify(d.bgJobCh) 126 } 127 } 128 129 // getFirstBgJob gets the first background job. 130 func (d *ddl) getFirstBgJob(t *meta.Meta) (*model.Job, error) { 131 job, err := t.GetBgJob(0) 132 return job, errors.Trace(err) 133 } 134 135 // updateBgJob updates a background job. 136 func (d *ddl) updateBgJob(t *meta.Meta, job *model.Job) error { 137 err := t.UpdateBgJob(0, job) 138 return errors.Trace(err) 139 } 140 141 // finishBgJob finishs a background job. 142 func (d *ddl) finishBgJob(t *meta.Meta, job *model.Job) error { 143 log.Warnf("[ddl] finish background job %v", job) 144 if _, err := t.DeQueueBgJob(); err != nil { 145 return errors.Trace(err) 146 } 147 148 err := t.AddHistoryBgJob(job) 149 150 return errors.Trace(err) 151 } 152 153 func (d *ddl) onBackgroundWorker() { 154 defer d.wait.Done() 155 156 // we use 4 * lease time to check owner's timeout, so here, we will update owner's status 157 // every 2 * lease time, if lease is 0, we will use default 10s. 158 checkTime := chooseLeaseTime(2*d.lease, 10*time.Second) 159 160 ticker := time.NewTicker(checkTime) 161 defer ticker.Stop() 162 163 for { 164 select { 165 case <-ticker.C: 166 log.Debugf("[ddl] wait %s to check background job status again", checkTime) 167 case <-d.bgJobCh: 168 case <-d.quitCh: 169 return 170 } 171 172 err := d.handleBgJobQueue() 173 if err != nil { 174 log.Errorf("[ddl] handle background job err %v", errors.ErrorStack(err)) 175 } 176 } 177 }