func (job *Job) IsSynced() bool {
	return job.State == JobStateSynced
}
IsSynced returns whether the DDL modification is synced among all TiDB servers.
package model
import (
	"encoding/json"
	"fmt"
	"math"
	"sync"
	"time"
	"github.com/pingcap/errors"
	"github.com/pingcap/parser/terror"
)
type ActionType byte
const (
	ActionNone               ActionType = 0
	ActionCreateSchema       ActionType = 1
	ActionDropSchema         ActionType = 2
	ActionCreateTable        ActionType = 3
	ActionDropTable          ActionType = 4
	ActionAddColumn          ActionType = 5
	ActionDropColumn         ActionType = 6
	ActionAddIndex           ActionType = 7
	ActionDropIndex          ActionType = 8
	ActionAddForeignKey      ActionType = 9
	ActionDropForeignKey     ActionType = 10
	ActionTruncateTable      ActionType = 11
	ActionModifyColumn       ActionType = 12
	ActionRebaseAutoID       ActionType = 13
	ActionRenameTable        ActionType = 14
	ActionSetDefaultValue    ActionType = 15
	ActionShardRowID         ActionType = 16
	ActionModifyTableComment ActionType = 17
	ActionRenameIndex        ActionType = 18
	ActionAddTablePartition  ActionType = 19
	ActionDropTablePartition ActionType = 20
)
const AddIndexStr = "add index"
var actionMap = map[ActionType]string{
	ActionCreateSchema:       "create schema",
	ActionDropSchema:         "drop schema",
	ActionCreateTable:        "create table",
	ActionDropTable:          "drop table",
	ActionAddColumn:          "add column",
	ActionDropColumn:         "drop column",
	ActionAddIndex:           AddIndexStr,
	ActionDropIndex:          "drop index",
	ActionAddForeignKey:      "add foreign key",
	ActionDropForeignKey:     "drop foreign key",
	ActionTruncateTable:      "truncate table",
	ActionModifyColumn:       "modify column",
	ActionRebaseAutoID:       "rebase auto_increment ID",
	ActionRenameTable:        "rename table",
	ActionSetDefaultValue:    "set default value",
	ActionShardRowID:         "shard row ID",
	ActionModifyTableComment: "modify table comment",
	ActionRenameIndex:        "rename index",
	ActionAddTablePartition:  "add partition",
	ActionDropTablePartition: "drop table partition",
}
func (action ActionType) String() string {
	if v, ok := actionMap[action]; ok {
		return v
	}
	return "none"
}
type HistoryInfo struct {
	SchemaVersion int64
	DBInfo        *DBInfo
	TableInfo     *TableInfo
	FinishedTS    uint64
}
func (h *HistoryInfo) AddDBInfo(schemaVer int64, dbInfo *DBInfo) {
	h.SchemaVersion = schemaVer
	h.DBInfo = dbInfo
}
func (h *HistoryInfo) AddTableInfo(schemaVer int64, tblInfo *TableInfo) {
	h.SchemaVersion = schemaVer
	h.TableInfo = tblInfo
}
func (h *HistoryInfo) Clean() {
	h.SchemaVersion = 0
	h.DBInfo = nil
	h.TableInfo = nil
}
type DDLReorgMeta struct {
	EndHandle int64 `json:"end_handle"`
}
func NewDDLReorgMeta() *DDLReorgMeta {
	return &DDLReorgMeta{
		EndHandle: math.MaxInt64,
	}
}
type Job struct {
	ID       int64         `json:"id"`
	Type     ActionType    `json:"type"`
	SchemaID int64         `json:"schema_id"`
	TableID  int64         `json:"table_id"`
	State    JobState      `json:"state"`
	Error    *terror.Error `json:"err"`
	ErrorCount int64 `json:"err_count"`
	RowCount int64         `json:"row_count"`
	Mu       sync.Mutex    `json:"-"`
	Args     []interface{} `json:"-"`
	RawArgs     json.RawMessage `json:"raw_args"`
	SchemaState SchemaState     `json:"schema_state"`
	SnapshotVer uint64 `json:"snapshot_ver"`
	StartTS uint64 `json:"start_ts"`
	DependencyID int64 `json:"dependency_id"`
	Query      string       `json:"query"`
	BinlogInfo *HistoryInfo `json:"binlog"`
	Version int64 `json:"version"`
	ReorgMeta *DDLReorgMeta `json:"reorg_meta"`
	Priority int `json:"priority"`
}
func (job *Job) FinishTableJob(jobState JobState, schemaState SchemaState, ver int64, tblInfo *TableInfo) {
	job.State = jobState
	job.SchemaState = schemaState
	job.BinlogInfo.AddTableInfo(ver, tblInfo)
}
func (job *Job) FinishDBJob(jobState JobState, schemaState SchemaState, ver int64, dbInfo *DBInfo) {
	job.State = jobState
	job.SchemaState = schemaState
	job.BinlogInfo.AddDBInfo(ver, dbInfo)
}
func TSConvert2Time(ts uint64) time.Time {
	t := int64(ts >> 18)  
	return time.Unix(t/1e3, (t%1e3)*1e6)
}
func (job *Job) SetRowCount(count int64) {
	job.Mu.Lock()
	defer job.Mu.Unlock()
	job.RowCount = count
}
func (job *Job) GetRowCount() int64 {
	job.Mu.Lock()
	defer job.Mu.Unlock()
	return job.RowCount
}
func (job *Job) Encode(updateRawArgs bool) ([]byte, error) {
	var err error
	if updateRawArgs {
		job.RawArgs, err = json.Marshal(job.Args)
		if err != nil {
			return nil, errors.Trace(err)
		}
	}
	var b []byte
	job.Mu.Lock()
	defer job.Mu.Unlock()
	b, err = json.Marshal(job)
	return b, errors.Trace(err)
}
func (job *Job) Decode(b []byte) error {
	err := json.Unmarshal(b, job)
	return errors.Trace(err)
}
func (job *Job) DecodeArgs(args ...interface{}) error {
	job.Args = args
	err := json.Unmarshal(job.RawArgs, &job.Args)
	return errors.Trace(err)
}
func (job *Job) String() string {
	rowCount := job.GetRowCount()
	return fmt.Sprintf("ID:%d, Type:%s, State:%s, SchemaState:%s, SchemaID:%d, TableID:%d, RowCount:%d, ArgLen:%d, start time: %v, Err:%v, ErrCount:%d, SnapshotVersion:%v",
		job.ID, job.Type, job.State, job.SchemaState, job.SchemaID, job.TableID, rowCount, len(job.Args), TSConvert2Time(job.StartTS), job.Error, job.ErrorCount, job.SnapshotVer)
}
func (job *Job) hasDependentSchema(other *Job) (bool, error) {
	if other.Type == ActionDropSchema || other.Type == ActionCreateSchema {
		if other.SchemaID == job.SchemaID {
			return true, nil
		}
		if job.Type == ActionRenameTable {
			var oldSchemaID int64
			if err := job.DecodeArgs(&oldSchemaID); err != nil {
				return false, errors.Trace(err)
			}
			if other.SchemaID == oldSchemaID {
				return true, nil
			}
		}
	}
	return false, nil
}
func (job *Job) IsDependentOn(other *Job) (bool, error) {
	isDependent, err := job.hasDependentSchema(other)
	if err != nil || isDependent {
		return isDependent, errors.Trace(err)
	}
	isDependent, err = other.hasDependentSchema(job)
	if err != nil || isDependent {
		return isDependent, errors.Trace(err)
	}
	if other.TableID == job.TableID {
		return true, nil
	}
	return false, nil
}
func (job *Job) IsFinished() bool {
	return job.State == JobStateDone || job.State == JobStateRollbackDone || job.State == JobStateCancelled
}
func (job *Job) IsCancelled() bool {
	return job.State == JobStateCancelled
}
func (job *Job) IsRollbackDone() bool {
	return job.State == JobStateRollbackDone
}
func (job *Job) IsRollingback() bool {
	return job.State == JobStateRollingback
}
func (job *Job) IsCancelling() bool {
	return job.State == JobStateCancelling
}