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 }