github.com/pingcap/ticdc@v0.0.0-20220526033649-485a10ef2652/cdc/model/sink.go (about)

     1  // Copyright 2020 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  	"fmt"
    18  	"strconv"
    19  	"sync"
    20  
    21  	"github.com/pingcap/log"
    22  	"github.com/pingcap/parser/model"
    23  	"github.com/pingcap/ticdc/pkg/quotes"
    24  	"github.com/pingcap/ticdc/pkg/util"
    25  	"go.uber.org/zap"
    26  )
    27  
    28  // MqMessageType is the type of message
    29  type MqMessageType int
    30  
    31  const (
    32  	// MqMessageTypeUnknown is unknown type of message key
    33  	MqMessageTypeUnknown MqMessageType = iota
    34  	// MqMessageTypeRow is row type of message key
    35  	MqMessageTypeRow
    36  	// MqMessageTypeDDL is ddl type of message key
    37  	MqMessageTypeDDL
    38  	// MqMessageTypeResolved is resolved type of message key
    39  	MqMessageTypeResolved
    40  )
    41  
    42  // ColumnFlagType is for encapsulating the flag operations for different flags.
    43  type ColumnFlagType util.Flag
    44  
    45  const (
    46  	// BinaryFlag means the column charset is binary
    47  	BinaryFlag ColumnFlagType = 1 << ColumnFlagType(iota)
    48  	// HandleKeyFlag means the column is selected as the handle key
    49  	HandleKeyFlag
    50  	// GeneratedColumnFlag means the column is a generated column
    51  	GeneratedColumnFlag
    52  	// PrimaryKeyFlag means the column is primary key
    53  	PrimaryKeyFlag
    54  	// UniqueKeyFlag means the column is unique key
    55  	UniqueKeyFlag
    56  	// MultipleKeyFlag means the column is multiple key
    57  	MultipleKeyFlag
    58  	// NullableFlag means the column is nullable
    59  	NullableFlag
    60  	// UnsignedFlag means the column stores an unsigned integer
    61  	UnsignedFlag
    62  )
    63  
    64  // SetIsBinary sets BinaryFlag
    65  func (b *ColumnFlagType) SetIsBinary() {
    66  	(*util.Flag)(b).Add(util.Flag(BinaryFlag))
    67  }
    68  
    69  // UnsetIsBinary unsets BinaryFlag
    70  func (b *ColumnFlagType) UnsetIsBinary() {
    71  	(*util.Flag)(b).Remove(util.Flag(BinaryFlag))
    72  }
    73  
    74  // IsBinary shows whether BinaryFlag is set
    75  func (b *ColumnFlagType) IsBinary() bool {
    76  	return (*util.Flag)(b).HasAll(util.Flag(BinaryFlag))
    77  }
    78  
    79  // SetIsHandleKey sets HandleKey
    80  func (b *ColumnFlagType) SetIsHandleKey() {
    81  	(*util.Flag)(b).Add(util.Flag(HandleKeyFlag))
    82  }
    83  
    84  // UnsetIsHandleKey unsets HandleKey
    85  func (b *ColumnFlagType) UnsetIsHandleKey() {
    86  	(*util.Flag)(b).Remove(util.Flag(HandleKeyFlag))
    87  }
    88  
    89  // IsHandleKey shows whether HandleKey is set
    90  func (b *ColumnFlagType) IsHandleKey() bool {
    91  	return (*util.Flag)(b).HasAll(util.Flag(HandleKeyFlag))
    92  }
    93  
    94  // SetIsGeneratedColumn sets GeneratedColumn
    95  func (b *ColumnFlagType) SetIsGeneratedColumn() {
    96  	(*util.Flag)(b).Add(util.Flag(GeneratedColumnFlag))
    97  }
    98  
    99  // UnsetIsGeneratedColumn unsets GeneratedColumn
   100  func (b *ColumnFlagType) UnsetIsGeneratedColumn() {
   101  	(*util.Flag)(b).Remove(util.Flag(GeneratedColumnFlag))
   102  }
   103  
   104  // IsGeneratedColumn shows whether GeneratedColumn is set
   105  func (b *ColumnFlagType) IsGeneratedColumn() bool {
   106  	return (*util.Flag)(b).HasAll(util.Flag(GeneratedColumnFlag))
   107  }
   108  
   109  // SetIsPrimaryKey sets PrimaryKeyFlag
   110  func (b *ColumnFlagType) SetIsPrimaryKey() {
   111  	(*util.Flag)(b).Add(util.Flag(PrimaryKeyFlag))
   112  }
   113  
   114  // UnsetIsPrimaryKey unsets PrimaryKeyFlag
   115  func (b *ColumnFlagType) UnsetIsPrimaryKey() {
   116  	(*util.Flag)(b).Remove(util.Flag(PrimaryKeyFlag))
   117  }
   118  
   119  // IsPrimaryKey shows whether PrimaryKeyFlag is set
   120  func (b *ColumnFlagType) IsPrimaryKey() bool {
   121  	return (*util.Flag)(b).HasAll(util.Flag(PrimaryKeyFlag))
   122  }
   123  
   124  // SetIsUniqueKey sets UniqueKeyFlag
   125  func (b *ColumnFlagType) SetIsUniqueKey() {
   126  	(*util.Flag)(b).Add(util.Flag(UniqueKeyFlag))
   127  }
   128  
   129  // UnsetIsUniqueKey unsets UniqueKeyFlag
   130  func (b *ColumnFlagType) UnsetIsUniqueKey() {
   131  	(*util.Flag)(b).Remove(util.Flag(UniqueKeyFlag))
   132  }
   133  
   134  // IsUniqueKey shows whether UniqueKeyFlag is set
   135  func (b *ColumnFlagType) IsUniqueKey() bool {
   136  	return (*util.Flag)(b).HasAll(util.Flag(UniqueKeyFlag))
   137  }
   138  
   139  // IsMultipleKey shows whether MultipleKeyFlag is set
   140  func (b *ColumnFlagType) IsMultipleKey() bool {
   141  	return (*util.Flag)(b).HasAll(util.Flag(MultipleKeyFlag))
   142  }
   143  
   144  // SetIsMultipleKey sets MultipleKeyFlag
   145  func (b *ColumnFlagType) SetIsMultipleKey() {
   146  	(*util.Flag)(b).Add(util.Flag(MultipleKeyFlag))
   147  }
   148  
   149  // UnsetIsMultipleKey unsets MultipleKeyFlag
   150  func (b *ColumnFlagType) UnsetIsMultipleKey() {
   151  	(*util.Flag)(b).Remove(util.Flag(MultipleKeyFlag))
   152  }
   153  
   154  // IsNullable shows whether NullableFlag is set
   155  func (b *ColumnFlagType) IsNullable() bool {
   156  	return (*util.Flag)(b).HasAll(util.Flag(NullableFlag))
   157  }
   158  
   159  // SetIsNullable sets NullableFlag
   160  func (b *ColumnFlagType) SetIsNullable() {
   161  	(*util.Flag)(b).Add(util.Flag(NullableFlag))
   162  }
   163  
   164  // UnsetIsNullable unsets NullableFlag
   165  func (b *ColumnFlagType) UnsetIsNullable() {
   166  	(*util.Flag)(b).Remove(util.Flag(NullableFlag))
   167  }
   168  
   169  // IsUnsigned shows whether UnsignedFlag is set
   170  func (b *ColumnFlagType) IsUnsigned() bool {
   171  	return (*util.Flag)(b).HasAll(util.Flag(UnsignedFlag))
   172  }
   173  
   174  // SetIsUnsigned sets UnsignedFlag
   175  func (b *ColumnFlagType) SetIsUnsigned() {
   176  	(*util.Flag)(b).Add(util.Flag(UnsignedFlag))
   177  }
   178  
   179  // UnsetIsUnsigned unsets UnsignedFlag
   180  func (b *ColumnFlagType) UnsetIsUnsigned() {
   181  	(*util.Flag)(b).Remove(util.Flag(UnsignedFlag))
   182  }
   183  
   184  // TableName represents name of a table, includes table name and schema name.
   185  type TableName struct {
   186  	Schema      string `toml:"db-name" json:"db-name"`
   187  	Table       string `toml:"tbl-name" json:"tbl-name"`
   188  	TableID     int64  `toml:"tbl-id" json:"tbl-id"`
   189  	IsPartition bool   `toml:"is-partition" json:"is-partition"`
   190  }
   191  
   192  // String implements fmt.Stringer interface.
   193  func (t TableName) String() string {
   194  	return fmt.Sprintf("%s.%s", t.Schema, t.Table)
   195  }
   196  
   197  // QuoteString returns quoted full table name
   198  func (t TableName) QuoteString() string {
   199  	return quotes.QuoteSchema(t.Schema, t.Table)
   200  }
   201  
   202  // GetSchema returns schema name.
   203  func (t *TableName) GetSchema() string {
   204  	return t.Schema
   205  }
   206  
   207  // GetTable returns table name.
   208  func (t *TableName) GetTable() string {
   209  	return t.Table
   210  }
   211  
   212  // GetTableID returns table ID.
   213  func (t *TableName) GetTableID() int64 {
   214  	return t.TableID
   215  }
   216  
   217  // RowChangedEvent represents a row changed event
   218  type RowChangedEvent struct {
   219  	StartTs  uint64 `json:"start-ts"`
   220  	CommitTs uint64 `json:"commit-ts"`
   221  
   222  	RowID int64 `json:"row-id"` // Deprecated. It is empty when the RowID comes from clustered index table.
   223  
   224  	Table *TableName `json:"table"`
   225  
   226  	TableInfoVersion uint64 `json:"table-info-version,omitempty"`
   227  
   228  	ReplicaID    uint64    `json:"replica-id"`
   229  	Columns      []*Column `json:"columns"`
   230  	PreColumns   []*Column `json:"pre-columns"`
   231  	IndexColumns [][]int   `json:"-"`
   232  
   233  	// approximate size of this event, calculate by tikv proto bytes size
   234  	ApproximateSize int64 `json:"-"`
   235  }
   236  
   237  // IsDelete returns true if the row is a delete event
   238  func (r *RowChangedEvent) IsDelete() bool {
   239  	return len(r.PreColumns) != 0 && len(r.Columns) == 0
   240  }
   241  
   242  // PrimaryKeyColumns returns the column(s) corresponding to the handle key(s)
   243  func (r *RowChangedEvent) PrimaryKeyColumns() []*Column {
   244  	pkeyCols := make([]*Column, 0)
   245  
   246  	var cols []*Column
   247  	if r.IsDelete() {
   248  		cols = r.PreColumns
   249  	} else {
   250  		cols = r.Columns
   251  	}
   252  
   253  	for _, col := range cols {
   254  		if col != nil && (col.Flag.IsPrimaryKey()) {
   255  			pkeyCols = append(pkeyCols, col)
   256  		}
   257  	}
   258  
   259  	// It is okay not to have primary keys, so the empty array is an acceptable result
   260  	return pkeyCols
   261  }
   262  
   263  // HandleKeyColumns returns the column(s) corresponding to the handle key(s)
   264  func (r *RowChangedEvent) HandleKeyColumns() []*Column {
   265  	pkeyCols := make([]*Column, 0)
   266  
   267  	var cols []*Column
   268  	if r.IsDelete() {
   269  		cols = r.PreColumns
   270  	} else {
   271  		cols = r.Columns
   272  	}
   273  
   274  	for _, col := range cols {
   275  		if col != nil && col.Flag.IsHandleKey() {
   276  			pkeyCols = append(pkeyCols, col)
   277  		}
   278  	}
   279  
   280  	if len(pkeyCols) == 0 {
   281  		// TODO redact the message
   282  		log.Panic("Cannot find handle key columns, bug?", zap.Reflect("event", r))
   283  	}
   284  
   285  	return pkeyCols
   286  }
   287  
   288  // Column represents a column value in row changed event
   289  type Column struct {
   290  	Name  string         `json:"name"`
   291  	Type  byte           `json:"type"`
   292  	Flag  ColumnFlagType `json:"flag"`
   293  	Value interface{}    `json:"value"`
   294  }
   295  
   296  // ColumnValueString returns the string representation of the column value
   297  func ColumnValueString(c interface{}) string {
   298  	var data string
   299  	switch v := c.(type) {
   300  	case nil:
   301  		data = "null"
   302  	case bool:
   303  		if v {
   304  			data = "1"
   305  		} else {
   306  			data = "0"
   307  		}
   308  	case int:
   309  		data = strconv.FormatInt(int64(v), 10)
   310  	case int8:
   311  		data = strconv.FormatInt(int64(v), 10)
   312  	case int16:
   313  		data = strconv.FormatInt(int64(v), 10)
   314  	case int32:
   315  		data = strconv.FormatInt(int64(v), 10)
   316  	case int64:
   317  		data = strconv.FormatInt(v, 10)
   318  	case uint8:
   319  		data = strconv.FormatUint(uint64(v), 10)
   320  	case uint16:
   321  		data = strconv.FormatUint(uint64(v), 10)
   322  	case uint32:
   323  		data = strconv.FormatUint(uint64(v), 10)
   324  	case uint64:
   325  		data = strconv.FormatUint(v, 10)
   326  	case float32:
   327  		data = strconv.FormatFloat(float64(v), 'f', -1, 32)
   328  	case float64:
   329  		data = strconv.FormatFloat(v, 'f', -1, 64)
   330  	case string:
   331  		data = v
   332  	case []byte:
   333  		data = string(v)
   334  	default:
   335  		data = fmt.Sprintf("%v", v)
   336  	}
   337  	return data
   338  }
   339  
   340  // ColumnInfo represents the name and type information passed to the sink
   341  type ColumnInfo struct {
   342  	Name string
   343  	Type byte
   344  }
   345  
   346  // FromTiColumnInfo populates cdc's ColumnInfo from TiDB's model.ColumnInfo
   347  func (c *ColumnInfo) FromTiColumnInfo(tiColumnInfo *model.ColumnInfo) {
   348  	c.Type = tiColumnInfo.Tp
   349  	c.Name = tiColumnInfo.Name.O
   350  }
   351  
   352  // SimpleTableInfo is the simplified table info passed to the sink
   353  type SimpleTableInfo struct {
   354  	// db name
   355  	Schema string
   356  	// table name
   357  	Table string
   358  	// table ID
   359  	TableID    int64
   360  	ColumnInfo []*ColumnInfo
   361  }
   362  
   363  // DDLEvent represents a DDL event
   364  type DDLEvent struct {
   365  	StartTs      uint64
   366  	CommitTs     uint64
   367  	TableInfo    *SimpleTableInfo
   368  	PreTableInfo *SimpleTableInfo
   369  	Query        string
   370  	Type         model.ActionType
   371  }
   372  
   373  // FromJob fills the values of DDLEvent from DDL job
   374  func (d *DDLEvent) FromJob(job *model.Job, preTableInfo *TableInfo) {
   375  	d.TableInfo = new(SimpleTableInfo)
   376  	d.TableInfo.Schema = job.SchemaName
   377  	d.StartTs = job.StartTS
   378  	d.CommitTs = job.BinlogInfo.FinishedTS
   379  	d.Query = job.Query
   380  	d.Type = job.Type
   381  
   382  	if job.BinlogInfo.TableInfo != nil {
   383  		tableName := job.BinlogInfo.TableInfo.Name.O
   384  		tableInfo := job.BinlogInfo.TableInfo
   385  		d.TableInfo.ColumnInfo = make([]*ColumnInfo, len(tableInfo.Columns))
   386  
   387  		for i, colInfo := range tableInfo.Columns {
   388  			d.TableInfo.ColumnInfo[i] = new(ColumnInfo)
   389  			d.TableInfo.ColumnInfo[i].FromTiColumnInfo(colInfo)
   390  		}
   391  
   392  		d.TableInfo.Table = tableName
   393  		d.TableInfo.TableID = job.TableID
   394  	}
   395  	d.fillPreTableInfo(preTableInfo)
   396  }
   397  
   398  func (d *DDLEvent) fillPreTableInfo(preTableInfo *TableInfo) {
   399  	if preTableInfo == nil {
   400  		return
   401  	}
   402  	d.PreTableInfo = new(SimpleTableInfo)
   403  	d.PreTableInfo.Schema = preTableInfo.TableName.Schema
   404  	d.PreTableInfo.Table = preTableInfo.TableName.Table
   405  	d.PreTableInfo.TableID = preTableInfo.ID
   406  
   407  	d.PreTableInfo.ColumnInfo = make([]*ColumnInfo, len(preTableInfo.Columns))
   408  	for i, colInfo := range preTableInfo.Columns {
   409  		d.PreTableInfo.ColumnInfo[i] = new(ColumnInfo)
   410  		d.PreTableInfo.ColumnInfo[i].FromTiColumnInfo(colInfo)
   411  	}
   412  }
   413  
   414  // SingleTableTxn represents a transaction which includes many row events in a single table
   415  type SingleTableTxn struct {
   416  	// data fields of SingleTableTxn
   417  	Table     *TableName
   418  	StartTs   uint64
   419  	CommitTs  uint64
   420  	Rows      []*RowChangedEvent
   421  	ReplicaID uint64
   422  
   423  	// control fields of SingleTableTxn
   424  	// FinishWg is a barrier txn, after this txn is received, the worker must
   425  	// flush cached txns and call FinishWg.Done() to mark txns have been flushed.
   426  	FinishWg *sync.WaitGroup
   427  }
   428  
   429  // Append adds a row changed event into SingleTableTxn
   430  func (t *SingleTableTxn) Append(row *RowChangedEvent) {
   431  	if row.StartTs != t.StartTs || row.CommitTs != t.CommitTs || row.Table.TableID != t.Table.TableID {
   432  		log.Panic("unexpected row change event",
   433  			zap.Uint64("startTs of txn", t.StartTs),
   434  			zap.Uint64("commitTs of txn", t.CommitTs),
   435  			zap.Any("table of txn", t.Table),
   436  			zap.Any("row", row))
   437  	}
   438  	t.Rows = append(t.Rows, row)
   439  }