github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/sqlparse/tidbparser/dependency/model/ddl.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 model
    15  
    16  import (
    17  	"encoding/json"
    18  	"fmt"
    19  	"sync"
    20  	"time"
    21  
    22  	"github.com/bingoohuang/gg/pkg/sqlparse/tidbparser/dependency/terror"
    23  	"github.com/juju/errors"
    24  )
    25  
    26  // ActionType is the type for DDL action.
    27  type ActionType byte
    28  
    29  // List DDL actions.
    30  const (
    31  	ActionNone            ActionType = 0
    32  	ActionCreateSchema    ActionType = 1
    33  	ActionDropSchema      ActionType = 2
    34  	ActionCreateTable     ActionType = 3
    35  	ActionDropTable       ActionType = 4
    36  	ActionAddColumn       ActionType = 5
    37  	ActionDropColumn      ActionType = 6
    38  	ActionAddIndex        ActionType = 7
    39  	ActionDropIndex       ActionType = 8
    40  	ActionAddForeignKey   ActionType = 9
    41  	ActionDropForeignKey  ActionType = 10
    42  	ActionTruncateTable   ActionType = 11
    43  	ActionModifyColumn    ActionType = 12
    44  	ActionRebaseAutoID    ActionType = 13
    45  	ActionRenameTable     ActionType = 14
    46  	ActionSetDefaultValue ActionType = 15
    47  	ActionShardRowID      ActionType = 16
    48  )
    49  
    50  var actionMap = map[ActionType]string{
    51  	ActionCreateSchema:    "create schema",
    52  	ActionDropSchema:      "drop schema",
    53  	ActionCreateTable:     "create table",
    54  	ActionDropTable:       "drop table",
    55  	ActionAddColumn:       "add column",
    56  	ActionDropColumn:      "drop column",
    57  	ActionAddIndex:        "add index",
    58  	ActionDropIndex:       "drop index",
    59  	ActionAddForeignKey:   "add foreign key",
    60  	ActionDropForeignKey:  "drop foreign key",
    61  	ActionTruncateTable:   "truncate table",
    62  	ActionModifyColumn:    "modify column",
    63  	ActionRebaseAutoID:    "rebase auto_increment ID",
    64  	ActionRenameTable:     "rename table",
    65  	ActionSetDefaultValue: "set default value",
    66  	ActionShardRowID:      "shard row ID",
    67  }
    68  
    69  // String return current ddl action in string
    70  func (action ActionType) String() string {
    71  	if v, ok := actionMap[action]; ok {
    72  		return v
    73  	}
    74  	return "none"
    75  }
    76  
    77  // HistoryInfo is used for binlog.
    78  type HistoryInfo struct {
    79  	SchemaVersion int64
    80  	DBInfo        *DBInfo
    81  	TableInfo     *TableInfo
    82  }
    83  
    84  // AddDBInfo adds schema version and schema information that are used for binlog.
    85  // dbInfo is added in the following operations: create database, drop database.
    86  func (h *HistoryInfo) AddDBInfo(schemaVer int64, dbInfo *DBInfo) {
    87  	h.SchemaVersion = schemaVer
    88  	h.DBInfo = dbInfo
    89  }
    90  
    91  // AddTableInfo adds schema version and table information that are used for binlog.
    92  // tblInfo is added except for the following operations: create database, drop database.
    93  func (h *HistoryInfo) AddTableInfo(schemaVer int64, tblInfo *TableInfo) {
    94  	h.SchemaVersion = schemaVer
    95  	h.TableInfo = tblInfo
    96  }
    97  
    98  // Clean cleans history information.
    99  func (h *HistoryInfo) Clean() {
   100  	h.SchemaVersion = 0
   101  	h.DBInfo = nil
   102  	h.TableInfo = nil
   103  }
   104  
   105  // Job is for a DDL operation.
   106  type Job struct {
   107  	ID       int64         `json:"id"`
   108  	Type     ActionType    `json:"type"`
   109  	SchemaID int64         `json:"schema_id"`
   110  	TableID  int64         `json:"table_id"`
   111  	State    JobState      `json:"state"`
   112  	Error    *terror.Error `json:"err"`
   113  	// ErrorCount will be increased, every time we meet an error when running job.
   114  	ErrorCount int64 `json:"err_count"`
   115  	// RowCount means the number of rows that are processed.
   116  	RowCount int64         `json:"row_count"`
   117  	Mu       sync.Mutex    `json:"-"`
   118  	Args     []interface{} `json:"-"`
   119  	// RawArgs : We must use json raw message to delay parsing special args.
   120  	RawArgs     json.RawMessage `json:"raw_args"`
   121  	SchemaState SchemaState     `json:"schema_state"`
   122  	// SnapshotVer means snapshot version for this job.
   123  	SnapshotVer uint64 `json:"snapshot_ver"`
   124  	// StartTS uses timestamp allocated by TSO.
   125  	// Now it's the TS when we put the job to TiKV queue.
   126  	StartTS uint64 `json:"start_ts"`
   127  	// Query string of the ddl job.
   128  	Query      string       `json:"query"`
   129  	BinlogInfo *HistoryInfo `json:"binlog"`
   130  
   131  	// Version indicates the DDL job version. For old jobs, it will be 0.
   132  	Version int64 `json:"version"`
   133  }
   134  
   135  // FinishTableJob is called when a job is finished.
   136  // It updates the job's state information and adds tblInfo to the binlog.
   137  func (job *Job) FinishTableJob(jobState JobState, schemaState SchemaState, ver int64, tblInfo *TableInfo) {
   138  	job.State = jobState
   139  	job.SchemaState = schemaState
   140  	job.BinlogInfo.AddTableInfo(ver, tblInfo)
   141  }
   142  
   143  // FinishDBJob is called when a job is finished.
   144  // It updates the job's state information and adds dbInfo the binlog.
   145  func (job *Job) FinishDBJob(jobState JobState, schemaState SchemaState, ver int64, dbInfo *DBInfo) {
   146  	job.State = jobState
   147  	job.SchemaState = schemaState
   148  	job.BinlogInfo.AddDBInfo(ver, dbInfo)
   149  }
   150  
   151  // tsConvert2Time converts timestamp to time.
   152  func tsConvert2Time(ts uint64) time.Time {
   153  	t := int64(ts >> 18) // 18 is for the logical time.
   154  	return time.Unix(t/1e3, (t%1e3)*1e6)
   155  }
   156  
   157  // SetRowCount sets the number of rows. Make sure it can pass `make race`.
   158  func (job *Job) SetRowCount(count int64) {
   159  	job.Mu.Lock()
   160  	defer job.Mu.Unlock()
   161  
   162  	job.RowCount = count
   163  }
   164  
   165  // GetRowCount gets the number of rows. Make sure it can pass `make race`.
   166  func (job *Job) GetRowCount() int64 {
   167  	job.Mu.Lock()
   168  	defer job.Mu.Unlock()
   169  
   170  	return job.RowCount
   171  }
   172  
   173  // Encode encodes job with json format.
   174  // updateRawArgs is used to determine whether to update the raw args.
   175  func (job *Job) Encode(updateRawArgs bool) ([]byte, error) {
   176  	var err error
   177  	if updateRawArgs {
   178  		job.RawArgs, err = json.Marshal(job.Args)
   179  		if err != nil {
   180  			return nil, errors.Trace(err)
   181  		}
   182  	}
   183  
   184  	var b []byte
   185  	job.Mu.Lock()
   186  	defer job.Mu.Unlock()
   187  	b, err = json.Marshal(job)
   188  
   189  	return b, errors.Trace(err)
   190  }
   191  
   192  // Decode decodes job from the json buffer, we must use DecodeArgs later to
   193  // decode special args for this job.
   194  func (job *Job) Decode(b []byte) error {
   195  	err := json.Unmarshal(b, job)
   196  	return errors.Trace(err)
   197  }
   198  
   199  // DecodeArgs decodes job args.
   200  func (job *Job) DecodeArgs(args ...interface{}) error {
   201  	job.Args = args
   202  	err := json.Unmarshal(job.RawArgs, &job.Args)
   203  	return errors.Trace(err)
   204  }
   205  
   206  // String implements fmt.Stringer interface.
   207  func (job *Job) String() string {
   208  	rowCount := job.GetRowCount()
   209  	return fmt.Sprintf("ID:%d, Type:%s, State:%s, SchemaState:%s, SchemaID:%d, TableID:%d, RowCount:%d, ArgLen:%d, start time: %v",
   210  		job.ID, job.Type, job.State, job.SchemaState, job.SchemaID, job.TableID, rowCount, len(job.Args), tsConvert2Time(job.StartTS))
   211  }
   212  
   213  // IsFinished returns whether job is finished or not.
   214  // If the job state is Done or Cancelled, it is finished.
   215  func (job *Job) IsFinished() bool {
   216  	return job.State == JobStateDone || job.State == JobStateRollbackDone || job.State == JobStateCancelled
   217  }
   218  
   219  // IsCancelled returns whether the job is cancelled or not.
   220  func (job *Job) IsCancelled() bool {
   221  	return job.State == JobStateCancelled || job.State == JobStateRollbackDone
   222  }
   223  
   224  // IsRollingback returns whether the job is rolling back or not.
   225  func (job *Job) IsRollingback() bool {
   226  	return job.State == JobStateRollingback
   227  }
   228  
   229  // IsCancelling returns whether the job is cancelling or not.
   230  func (job *Job) IsCancelling() bool {
   231  	return job.State == JobStateCancelling
   232  }
   233  
   234  // IsSynced returns whether the DDL modification is synced among all TiDB servers.
   235  func (job *Job) IsSynced() bool {
   236  	return job.State == JobStateSynced
   237  }
   238  
   239  // IsDone returns whether job is done.
   240  func (job *Job) IsDone() bool {
   241  	return job.State == JobStateDone
   242  }
   243  
   244  // IsRunning returns whether job is still running or not.
   245  func (job *Job) IsRunning() bool {
   246  	return job.State == JobStateRunning
   247  }
   248  
   249  // JobState is for job state.
   250  type JobState byte
   251  
   252  // List job states.
   253  const (
   254  	JobStateNone    JobState = 0
   255  	JobStateRunning JobState = 1
   256  	// When DDL encountered an unrecoverable error at reorganization state,
   257  	// some keys has been added already, we need to remove them.
   258  	// JobStateRollingback is the state to do the rolling back job.
   259  	JobStateRollingback  JobState = 2
   260  	JobStateRollbackDone JobState = 3
   261  	JobStateDone         JobState = 4
   262  	JobStateCancelled    JobState = 5
   263  	// JobStateSynced is used to mark the information about the completion of this job
   264  	// has been synchronized to all servers.
   265  	JobStateSynced JobState = 6
   266  	// JobStateCancelling is used to mark the DDL job is cancelled by the client, but the DDL work hasn't handle it.
   267  	JobStateCancelling JobState = 7
   268  )
   269  
   270  // String implements fmt.Stringer interface.
   271  func (s JobState) String() string {
   272  	switch s {
   273  	case JobStateRunning:
   274  		return "running"
   275  	case JobStateRollingback:
   276  		return "rollingback"
   277  	case JobStateRollbackDone:
   278  		return "rollback done"
   279  	case JobStateDone:
   280  		return "done"
   281  	case JobStateCancelled:
   282  		return "cancelled"
   283  	case JobStateCancelling:
   284  		return "cancelling"
   285  	case JobStateSynced:
   286  		return "synced"
   287  	default:
   288  		return "none"
   289  	}
   290  }
   291  
   292  // SchemaDiff contains the schema modification at a particular schema version.
   293  // It is used to reduce schema reload cost.
   294  type SchemaDiff struct {
   295  	Version  int64      `json:"version"`
   296  	Type     ActionType `json:"type"`
   297  	SchemaID int64      `json:"schema_id"`
   298  	TableID  int64      `json:"table_id"`
   299  
   300  	// OldTableID is the table ID before truncate, only used by truncate table DDL.
   301  	OldTableID int64 `json:"old_table_id"`
   302  	// OldSchemaID is the schema ID before rename table, only used by rename table DDL.
   303  	OldSchemaID int64 `json:"old_schema_id"`
   304  }