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  }