github.com/pingcap/ticdc@v0.0.0-20220526033649-485a10ef2652/pkg/filter/filter.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 filter
    15  
    16  import (
    17  	"github.com/pingcap/parser/model"
    18  	"github.com/pingcap/ticdc/pkg/config"
    19  	"github.com/pingcap/ticdc/pkg/cyclic/mark"
    20  	cerror "github.com/pingcap/ticdc/pkg/errors"
    21  	filterV1 "github.com/pingcap/tidb-tools/pkg/filter"
    22  	filterV2 "github.com/pingcap/tidb-tools/pkg/table-filter"
    23  )
    24  
    25  // Filter is a event filter implementation.
    26  type Filter struct {
    27  	filter           filterV2.Filter
    28  	ignoreTxnStartTs []uint64
    29  	ddlAllowlist     []model.ActionType
    30  	isCyclicEnabled  bool
    31  }
    32  
    33  // VerifyRules checks the filter rules in the configuration
    34  // and returns an invalid rule error if the verification fails, otherwise it will return the parsed filter.
    35  func VerifyRules(cfg *config.ReplicaConfig) (filterV2.Filter, error) {
    36  	var f filterV2.Filter
    37  	var err error
    38  	if len(cfg.Filter.Rules) == 0 && cfg.Filter.MySQLReplicationRules != nil {
    39  		f, err = filterV2.ParseMySQLReplicationRules(cfg.Filter.MySQLReplicationRules)
    40  	} else {
    41  		rules := cfg.Filter.Rules
    42  		if len(rules) == 0 {
    43  			rules = []string{"*.*"}
    44  		}
    45  		f, err = filterV2.Parse(rules)
    46  	}
    47  	if err != nil {
    48  		return nil, cerror.WrapError(cerror.ErrFilterRuleInvalid, err)
    49  	}
    50  
    51  	return f, nil
    52  }
    53  
    54  // NewFilter creates a filter.
    55  func NewFilter(cfg *config.ReplicaConfig) (*Filter, error) {
    56  	f, err := VerifyRules(cfg)
    57  	if err != nil {
    58  		return nil, cerror.WrapError(cerror.ErrFilterRuleInvalid, err)
    59  	}
    60  
    61  	if !cfg.CaseSensitive {
    62  		f = filterV2.CaseInsensitive(f)
    63  	}
    64  	return &Filter{
    65  		filter:           f,
    66  		ignoreTxnStartTs: cfg.Filter.IgnoreTxnStartTs,
    67  		ddlAllowlist:     cfg.Filter.DDLAllowlist,
    68  		isCyclicEnabled:  cfg.Cyclic.IsEnabled(),
    69  	}, nil
    70  }
    71  
    72  func (f *Filter) shouldIgnoreStartTs(ts uint64) bool {
    73  	for _, ignoreTs := range f.ignoreTxnStartTs {
    74  		if ignoreTs == ts {
    75  			return true
    76  		}
    77  	}
    78  	return false
    79  }
    80  
    81  // ShouldIgnoreTable returns true if the specified table should be ignored by this change feed.
    82  // NOTICE: Set `tbl` to an empty string to test against the whole database.
    83  func (f *Filter) ShouldIgnoreTable(db, tbl string) bool {
    84  	if isSysSchema(db) {
    85  		return true
    86  	}
    87  	if f.isCyclicEnabled && mark.IsMarkTable(db, tbl) {
    88  		// Always replicate mark tables.
    89  		return false
    90  	}
    91  	return !f.filter.MatchTable(db, tbl)
    92  }
    93  
    94  // ShouldIgnoreDMLEvent removes DMLs that's not wanted by this change feed.
    95  // CDC only supports filtering by database/table now.
    96  func (f *Filter) ShouldIgnoreDMLEvent(ts uint64, schema, table string) bool {
    97  	return f.shouldIgnoreStartTs(ts) || f.ShouldIgnoreTable(schema, table)
    98  }
    99  
   100  // ShouldIgnoreDDLEvent removes DDLs that's not wanted by this change feed.
   101  // CDC only supports filtering by database/table now.
   102  func (f *Filter) ShouldIgnoreDDLEvent(ts uint64, ddlType model.ActionType, schema, table string) bool {
   103  	var shouldIgnoreTableOrSchema bool
   104  	switch ddlType {
   105  	case model.ActionCreateSchema, model.ActionDropSchema,
   106  		model.ActionModifySchemaCharsetAndCollate:
   107  		shouldIgnoreTableOrSchema = !f.filter.MatchSchema(schema)
   108  	default:
   109  		shouldIgnoreTableOrSchema = f.ShouldIgnoreTable(schema, table)
   110  	}
   111  	return f.shouldIgnoreStartTs(ts) || shouldIgnoreTableOrSchema
   112  }
   113  
   114  // ShouldDiscardDDL returns true if this DDL should be discarded.
   115  func (f *Filter) ShouldDiscardDDL(ddlType model.ActionType) bool {
   116  	if !f.shouldDiscardByBuiltInDDLAllowlist(ddlType) {
   117  		return false
   118  	}
   119  	for _, allowDDLType := range f.ddlAllowlist {
   120  		if allowDDLType == ddlType {
   121  			return false
   122  		}
   123  	}
   124  	return true
   125  }
   126  
   127  func (f *Filter) shouldDiscardByBuiltInDDLAllowlist(ddlType model.ActionType) bool {
   128  	/* The following DDL will be filter:
   129  	ActionAddForeignKey                 ActionType = 9
   130  	ActionDropForeignKey                ActionType = 10
   131  	ActionRebaseAutoID                  ActionType = 13
   132  	ActionShardRowID                    ActionType = 16
   133  	ActionLockTable                     ActionType = 27
   134  	ActionUnlockTable                   ActionType = 28
   135  	ActionRepairTable                   ActionType = 29
   136  	ActionSetTiFlashReplica             ActionType = 30
   137  	ActionUpdateTiFlashReplicaStatus    ActionType = 31
   138  	ActionCreateSequence                ActionType = 34
   139  	ActionAlterSequence                 ActionType = 35
   140  	ActionDropSequence                  ActionType = 36
   141  	ActionModifyTableAutoIdCache        ActionType = 39
   142  	ActionRebaseAutoRandomBase          ActionType = 40
   143  	ActionAlterIndexVisibility          ActionType = 41
   144  	ActionExchangeTablePartition        ActionType = 42
   145  	ActionAddCheckConstraint            ActionType = 43
   146  	ActionDropCheckConstraint           ActionType = 44
   147  	ActionAlterCheckConstraint          ActionType = 45
   148  	ActionAlterTableAlterPartition      ActionType = 46
   149  
   150  	... Any Action which of value is greater than 46 ...
   151  	*/
   152  	switch ddlType {
   153  	case model.ActionCreateSchema,
   154  		model.ActionDropSchema,
   155  		model.ActionCreateTable,
   156  		model.ActionDropTable,
   157  		model.ActionAddColumn,
   158  		model.ActionDropColumn,
   159  		model.ActionAddIndex,
   160  		model.ActionDropIndex,
   161  		model.ActionTruncateTable,
   162  		model.ActionModifyColumn,
   163  		model.ActionRenameTable,
   164  		model.ActionSetDefaultValue,
   165  		model.ActionModifyTableComment,
   166  		model.ActionRenameIndex,
   167  		model.ActionAddTablePartition,
   168  		model.ActionDropTablePartition,
   169  		model.ActionCreateView,
   170  		model.ActionModifyTableCharsetAndCollate,
   171  		model.ActionTruncateTablePartition,
   172  		model.ActionDropView,
   173  		model.ActionRecoverTable,
   174  		model.ActionModifySchemaCharsetAndCollate,
   175  		model.ActionAddPrimaryKey,
   176  		model.ActionDropPrimaryKey,
   177  		model.ActionAddColumns,
   178  		model.ActionDropColumns:
   179  		return false
   180  	}
   181  	return true
   182  }
   183  
   184  // isSysSchema returns true if the given schema is a system schema
   185  func isSysSchema(db string) bool {
   186  	return filterV1.IsSystemSchema(db)
   187  }