github.com/pingcap/ticdc@v0.0.0-20220526033649-485a10ef2652/cdc/owner/schema.go (about) 1 // Copyright 2021 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 owner 15 16 import ( 17 "github.com/pingcap/errors" 18 "github.com/pingcap/log" 19 timodel "github.com/pingcap/parser/model" 20 "github.com/pingcap/ticdc/cdc/entry" 21 "github.com/pingcap/ticdc/cdc/kv" 22 "github.com/pingcap/ticdc/cdc/model" 23 "github.com/pingcap/ticdc/pkg/config" 24 "github.com/pingcap/ticdc/pkg/cyclic/mark" 25 "github.com/pingcap/ticdc/pkg/filter" 26 tidbkv "github.com/pingcap/tidb/kv" 27 timeta "github.com/pingcap/tidb/meta" 28 "go.uber.org/zap" 29 ) 30 31 type schemaWrap4Owner struct { 32 schemaSnapshot *entry.SingleSchemaSnapshot 33 filter *filter.Filter 34 config *config.ReplicaConfig 35 36 allPhysicalTablesCache []model.TableID 37 ddlHandledTs model.Ts 38 } 39 40 func newSchemaWrap4Owner(kvStorage tidbkv.Storage, startTs model.Ts, config *config.ReplicaConfig) (*schemaWrap4Owner, error) { 41 var meta *timeta.Meta 42 if kvStorage != nil { 43 var err error 44 meta, err = kv.GetSnapshotMeta(kvStorage, startTs) 45 if err != nil { 46 return nil, errors.Trace(err) 47 } 48 } 49 // We do a snapshot read of the metadata from TiKV at (startTs-1) instead of startTs, 50 // because the DDL puller might send a DDL at startTs, which would cause schema conflicts if 51 // the DDL's result is already contained in the snapshot. 52 schemaSnap, err := entry.NewSingleSchemaSnapshotFromMeta(meta, startTs-1, config.ForceReplicate) 53 if err != nil { 54 return nil, errors.Trace(err) 55 } 56 f, err := filter.NewFilter(config) 57 if err != nil { 58 return nil, errors.Trace(err) 59 } 60 return &schemaWrap4Owner{ 61 schemaSnapshot: schemaSnap, 62 filter: f, 63 config: config, 64 ddlHandledTs: startTs, 65 }, nil 66 } 67 68 // AllPhysicalTables returns the table IDs of all tables and partition tables. 69 func (s *schemaWrap4Owner) AllPhysicalTables() []model.TableID { 70 if s.allPhysicalTablesCache != nil { 71 return s.allPhysicalTablesCache 72 } 73 tables := s.schemaSnapshot.Tables() 74 s.allPhysicalTablesCache = make([]model.TableID, 0, len(tables)) 75 for _, tblInfo := range tables { 76 if s.shouldIgnoreTable(tblInfo) { 77 continue 78 } 79 80 if pi := tblInfo.GetPartitionInfo(); pi != nil { 81 for _, partition := range pi.Definitions { 82 s.allPhysicalTablesCache = append(s.allPhysicalTablesCache, partition.ID) 83 } 84 } else { 85 s.allPhysicalTablesCache = append(s.allPhysicalTablesCache, tblInfo.ID) 86 } 87 } 88 return s.allPhysicalTablesCache 89 } 90 91 func (s *schemaWrap4Owner) HandleDDL(job *timodel.Job) error { 92 if job.BinlogInfo.FinishedTS <= s.ddlHandledTs { 93 return nil 94 } 95 s.allPhysicalTablesCache = nil 96 err := s.schemaSnapshot.HandleDDL(job) 97 if err != nil { 98 return errors.Trace(err) 99 } 100 s.ddlHandledTs = job.BinlogInfo.FinishedTS 101 return nil 102 } 103 104 func (s *schemaWrap4Owner) IsIneligibleTableID(tableID model.TableID) bool { 105 return s.schemaSnapshot.IsIneligibleTableID(tableID) 106 } 107 108 func (s *schemaWrap4Owner) BuildDDLEvent(job *timodel.Job) (*model.DDLEvent, error) { 109 ddlEvent := new(model.DDLEvent) 110 preTableInfo, err := s.schemaSnapshot.PreTableInfo(job) 111 if err != nil { 112 return nil, errors.Trace(err) 113 } 114 err = s.schemaSnapshot.FillSchemaName(job) 115 if err != nil { 116 return nil, errors.Trace(err) 117 } 118 ddlEvent.FromJob(job, preTableInfo) 119 return ddlEvent, nil 120 } 121 122 func (s *schemaWrap4Owner) SinkTableInfos() []*model.SimpleTableInfo { 123 var sinkTableInfos []*model.SimpleTableInfo 124 for tableID := range s.schemaSnapshot.CloneTables() { 125 tblInfo, ok := s.schemaSnapshot.TableByID(tableID) 126 if !ok { 127 log.Panic("table not found for table ID", zap.Int64("tid", tableID)) 128 } 129 if s.shouldIgnoreTable(tblInfo) { 130 continue 131 } 132 dbInfo, ok := s.schemaSnapshot.SchemaByTableID(tableID) 133 if !ok { 134 log.Panic("schema not found for table ID", zap.Int64("tid", tableID)) 135 } 136 137 // TODO separate function for initializing SimpleTableInfo 138 sinkTableInfo := new(model.SimpleTableInfo) 139 sinkTableInfo.Schema = dbInfo.Name.O 140 sinkTableInfo.TableID = tableID 141 sinkTableInfo.Table = tblInfo.TableName.Table 142 sinkTableInfo.ColumnInfo = make([]*model.ColumnInfo, len(tblInfo.Cols())) 143 for i, colInfo := range tblInfo.Cols() { 144 sinkTableInfo.ColumnInfo[i] = new(model.ColumnInfo) 145 sinkTableInfo.ColumnInfo[i].FromTiColumnInfo(colInfo) 146 } 147 sinkTableInfos = append(sinkTableInfos, sinkTableInfo) 148 } 149 return sinkTableInfos 150 } 151 152 func (s *schemaWrap4Owner) shouldIgnoreTable(tableInfo *model.TableInfo) bool { 153 schemaName := tableInfo.TableName.Schema 154 tableName := tableInfo.TableName.Table 155 if s.filter.ShouldIgnoreTable(schemaName, tableName) { 156 return true 157 } 158 if s.config.Cyclic.IsEnabled() && mark.IsMarkTable(schemaName, tableName) { 159 // skip the mark table if cyclic is enabled 160 return true 161 } 162 if !tableInfo.IsEligible(s.config.ForceReplicate) { 163 log.Warn("skip ineligible table", zap.Int64("tid", tableInfo.ID), zap.Stringer("table", tableInfo.TableName)) 164 return true 165 } 166 return false 167 }