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  }