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  }