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 }