github.com/pingcap/ticdc@v0.0.0-20220526033649-485a10ef2652/cdc/sink/causality_test.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 sink 15 16 import ( 17 "bytes" 18 "sort" 19 20 "github.com/pingcap/check" 21 "github.com/pingcap/parser/mysql" 22 "github.com/pingcap/ticdc/cdc/model" 23 "github.com/pingcap/ticdc/pkg/util/testleak" 24 ) 25 26 type testCausalitySuite struct{} 27 28 var _ = check.Suite(&testCausalitySuite{}) 29 30 func (s *testCausalitySuite) TestCausality(c *check.C) { 31 defer testleak.AfterTest(c)() 32 rows := [][][]byte{ 33 {[]byte("a")}, 34 {[]byte("b")}, 35 {[]byte("c")}, 36 } 37 ca := newCausality() 38 for i, row := range rows { 39 conflict, idx := ca.detectConflict(row) 40 c.Assert(conflict, check.IsFalse) 41 c.Assert(idx, check.Equals, -1) 42 ca.add(row, i) 43 // Test for single key index conflict. 44 conflict, idx = ca.detectConflict(row) 45 c.Assert(conflict, check.IsTrue) 46 c.Assert(idx, check.Equals, i) 47 } 48 c.Assert(len(ca.relations), check.Equals, 3) 49 cases := []struct { 50 keys [][]byte 51 conflict bool 52 idx int 53 }{ 54 // Test for single key index conflict. 55 {[][]byte{[]byte("a"), []byte("ab")}, true, 0}, 56 {[][]byte{[]byte("b"), []byte("ba")}, true, 1}, 57 {[][]byte{[]byte("a"), []byte("a")}, true, 0}, 58 {[][]byte{[]byte("b"), []byte("b")}, true, 1}, 59 {[][]byte{[]byte("c"), []byte("c")}, true, 2}, 60 // Test for multi-key index conflict. 61 {[][]byte{[]byte("a"), []byte("b")}, true, -1}, 62 {[][]byte{[]byte("b"), []byte("a")}, true, -1}, 63 {[][]byte{[]byte("b"), []byte("c")}, true, -1}, 64 } 65 for _, cas := range cases { 66 conflict, idx := ca.detectConflict(cas.keys) 67 comment := check.Commentf("keys: %v", cas.keys) 68 c.Assert(conflict, check.Equals, cas.conflict, comment) 69 c.Assert(idx, check.Equals, cas.idx, comment) 70 } 71 ca.reset() 72 c.Assert(len(ca.relations), check.Equals, 0) 73 } 74 75 func (s *testCausalitySuite) TestGenKeys(c *check.C) { 76 defer testleak.AfterTest(c)() 77 testCases := []struct { 78 txn *model.SingleTableTxn 79 expected [][]byte 80 }{{ 81 txn: &model.SingleTableTxn{}, 82 expected: nil, 83 }, { 84 txn: &model.SingleTableTxn{ 85 Rows: []*model.RowChangedEvent{ 86 { 87 StartTs: 418658114257813514, 88 CommitTs: 418658114257813515, 89 Table: &model.TableName{Schema: "common_1", Table: "uk_without_pk", TableID: 47}, 90 PreColumns: []*model.Column{nil, { 91 Name: "a1", 92 Type: mysql.TypeLong, 93 Flag: model.BinaryFlag | model.MultipleKeyFlag | model.HandleKeyFlag, 94 Value: 12, 95 }, { 96 Name: "a3", 97 Type: mysql.TypeLong, 98 Flag: model.BinaryFlag | model.MultipleKeyFlag | model.HandleKeyFlag, 99 Value: 1, 100 }}, 101 IndexColumns: [][]int{{1, 2}}, 102 }, { 103 StartTs: 418658114257813514, 104 CommitTs: 418658114257813515, 105 Table: &model.TableName{Schema: "common_1", Table: "uk_without_pk", TableID: 47}, 106 PreColumns: []*model.Column{nil, { 107 Name: "a1", 108 Type: mysql.TypeLong, 109 Flag: model.BinaryFlag | model.MultipleKeyFlag | model.HandleKeyFlag, 110 Value: 1, 111 }, { 112 Name: "a3", 113 Type: mysql.TypeLong, 114 Flag: model.BinaryFlag | model.MultipleKeyFlag | model.HandleKeyFlag, 115 Value: 21, 116 }}, 117 IndexColumns: [][]int{{1, 2}}, 118 }, 119 }, 120 }, 121 expected: [][]byte{ 122 {'1', '2', 0x0, '1', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 47}, 123 {'1', 0x0, '2', '1', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 47}, 124 }, 125 }, { 126 txn: &model.SingleTableTxn{ 127 Rows: []*model.RowChangedEvent{ 128 { 129 StartTs: 418658114257813514, 130 CommitTs: 418658114257813515, 131 Table: &model.TableName{Schema: "common_1", Table: "uk_without_pk", TableID: 47}, 132 PreColumns: []*model.Column{nil, { 133 Name: "a1", 134 Type: mysql.TypeLong, 135 Flag: model.BinaryFlag | model.HandleKeyFlag, 136 Value: 12, 137 }, { 138 Name: "a3", 139 Type: mysql.TypeLong, 140 Flag: model.BinaryFlag | model.HandleKeyFlag, 141 Value: 1, 142 }}, 143 IndexColumns: [][]int{{1}, {2}}, 144 }, { 145 StartTs: 418658114257813514, 146 CommitTs: 418658114257813515, 147 Table: &model.TableName{Schema: "common_1", Table: "uk_without_pk", TableID: 47}, 148 PreColumns: []*model.Column{nil, { 149 Name: "a1", 150 Type: mysql.TypeLong, 151 Flag: model.BinaryFlag | model.HandleKeyFlag, 152 Value: 1, 153 }, { 154 Name: "a3", 155 Type: mysql.TypeLong, 156 Flag: model.BinaryFlag | model.HandleKeyFlag, 157 Value: 21, 158 }}, 159 IndexColumns: [][]int{{1}, {2}}, 160 }, 161 }, 162 }, 163 expected: [][]byte{ 164 {'2', '1', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 47}, 165 {'1', '2', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 47}, 166 {'1', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 47}, 167 {'1', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 47}, 168 }, 169 }, { 170 txn: &model.SingleTableTxn{ 171 Rows: []*model.RowChangedEvent{ 172 { 173 StartTs: 418658114257813514, 174 CommitTs: 418658114257813515, 175 Table: &model.TableName{Schema: "common_1", Table: "uk_without_pk", TableID: 47}, 176 PreColumns: []*model.Column{nil, { 177 Name: "a1", 178 Type: mysql.TypeLong, 179 Flag: model.BinaryFlag | model.NullableFlag, 180 Value: nil, 181 }, { 182 Name: "a3", 183 Type: mysql.TypeLong, 184 Flag: model.BinaryFlag | model.NullableFlag, 185 Value: nil, 186 }}, 187 IndexColumns: [][]int{{1}, {2}}, 188 }, { 189 StartTs: 418658114257813514, 190 CommitTs: 418658114257813515, 191 Table: &model.TableName{Schema: "common_1", Table: "uk_without_pk", TableID: 47}, 192 PreColumns: []*model.Column{nil, { 193 Name: "a1", 194 Type: mysql.TypeLong, 195 Flag: model.BinaryFlag | model.HandleKeyFlag, 196 Value: 1, 197 }, { 198 Name: "a3", 199 Type: mysql.TypeLong, 200 Flag: model.BinaryFlag | model.HandleKeyFlag, 201 Value: 21, 202 }}, 203 IndexColumns: [][]int{{1}, {2}}, 204 }, 205 }, 206 }, 207 expected: [][]uint8{ 208 {'2', '1', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 47}, 209 {'1', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 47}, 210 {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 47}, 211 }, 212 }} 213 for _, tc := range testCases { 214 keys := genTxnKeys(tc.txn) 215 sort.Slice(keys, func(i, j int) bool { 216 return bytes.Compare(keys[i], keys[j]) > 0 217 }) 218 c.Assert(keys, check.DeepEquals, tc.expected) 219 } 220 }