github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/syncer/shardddl/pessimist_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 shardddl 15 16 import ( 17 "context" 18 "testing" 19 "time" 20 21 . "github.com/pingcap/check" 22 "github.com/pingcap/tiflow/dm/common" 23 "github.com/pingcap/tiflow/dm/pkg/log" 24 "github.com/pingcap/tiflow/dm/pkg/shardddl/pessimism" 25 clientv3 "go.etcd.io/etcd/client/v3" 26 "go.etcd.io/etcd/tests/v3/integration" 27 ) 28 29 var etcdTestCli *clientv3.Client 30 31 type testPessimist struct{} 32 33 var _ = Suite(&testPessimist{}) 34 35 func TestShardDDL(t *testing.T) { 36 err := log.InitLogger(&log.Config{}) 37 if err != nil { 38 t.Fatal(err) 39 } 40 41 integration.BeforeTestExternal(t) 42 mockCluster := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1}) 43 defer mockCluster.Terminate(t) 44 45 etcdTestCli = mockCluster.RandClient() 46 47 TestingT(t) 48 } 49 50 // clear keys in etcd test cluster. 51 func clearTestInfoOperation(c *C) { 52 clearInfo := clientv3.OpDelete(common.ShardDDLPessimismInfoKeyAdapter.Path(), clientv3.WithPrefix()) 53 clearOp := clientv3.OpDelete(common.ShardDDLPessimismOperationKeyAdapter.Path(), clientv3.WithPrefix()) 54 _, err := etcdTestCli.Txn(context.Background()).Then(clearInfo, clearOp).Commit() 55 c.Assert(err, IsNil) 56 } 57 58 func (t *testPessimist) TestPessimist(c *C) { 59 defer clearTestInfoOperation(c) 60 61 var ( 62 task = "task" 63 source = "mysql-replicate-1" 64 schema, table = "foo", "bar" 65 DDLs = []string{"ALTER TABLE bar ADD COLUMN c1 INT"} 66 ID = "task-`foo`.`bar`" 67 op = pessimism.NewOperation(ID, task, source, DDLs, true, false) 68 69 logger = log.L() 70 p = NewPessimist(&logger, etcdTestCli, task, source) 71 info = p.ConstructInfo(schema, table, DDLs) 72 ) 73 74 ctx, cancel := context.WithCancel(context.Background()) 75 defer cancel() 76 77 // no info and operation in pending 78 c.Assert(p.PendingInfo(), IsNil) 79 c.Assert(p.PendingOperation(), IsNil) 80 81 // put shard DDL info. 82 rev1, err := p.PutInfo(ctx, info) 83 c.Assert(err, IsNil) 84 c.Assert(rev1, Greater, int64(0)) 85 86 // have info in pending 87 info2 := p.PendingInfo() 88 c.Assert(info2, NotNil) 89 c.Assert(*info2, DeepEquals, info) 90 91 // put the lock operation. 92 rev2, putted, err := pessimism.PutOperations(etcdTestCli, false, op) 93 c.Assert(err, IsNil) 94 c.Assert(rev2, Greater, rev1) 95 c.Assert(putted, IsTrue) 96 97 // wait for the lock operation. 98 op2, err := p.GetOperation(ctx, info, rev1) 99 c.Assert(err, IsNil) 100 c.Assert(op2, DeepEquals, op) 101 102 // have operation in pending. 103 op3 := p.PendingOperation() 104 c.Assert(op3, NotNil) 105 c.Assert(*op3, DeepEquals, op) 106 107 // mark the operation as done and delete the info. 108 c.Assert(p.DoneOperationDeleteInfo(op, info), IsNil) 109 // make this op reentrant. 110 c.Assert(p.DoneOperationDeleteInfo(op, info), IsNil) 111 112 // verify the operation and info. 113 opc := op2 114 opc.Done = true 115 opm, _, err := pessimism.GetAllOperations(etcdTestCli) 116 c.Assert(err, IsNil) 117 c.Assert(opm, HasLen, 1) 118 c.Assert(opm[task], HasLen, 1) 119 c.Assert(opm[task][source], DeepEquals, opc) 120 ifm, _, err := pessimism.GetAllInfo(etcdTestCli) 121 c.Assert(err, IsNil) 122 c.Assert(ifm, HasLen, 0) 123 124 // no info and operation in pending now. 125 c.Assert(p.PendingInfo(), IsNil) 126 c.Assert(p.PendingOperation(), IsNil) 127 128 // try to put info again, but timeout because a `done` operation exist in etcd. 129 ctx2, cancel2 := context.WithTimeout(ctx, time.Second) 130 defer cancel2() 131 _, err = p.PutInfo(ctx2, info) 132 c.Assert(err, Equals, context.DeadlineExceeded) 133 134 // start a goroutine to delete the `done` operation in background, then we can put info again. 135 go func() { 136 time.Sleep(500 * time.Millisecond) // wait `PutInfo` to start watch the deletion of the operation. 137 _, err2 := pessimism.DeleteOperations(etcdTestCli, op) 138 c.Assert(err2, IsNil) 139 }() 140 141 // put info again, but do not complete the flow. 142 _, err = p.PutInfo(ctx, info) 143 c.Assert(err, IsNil) 144 c.Assert(p.PendingInfo(), NotNil) 145 146 // put the lock operation again. 147 rev3, _, err := pessimism.PutOperations(etcdTestCli, false, op) 148 c.Assert(err, IsNil) 149 // wait for the lock operation. 150 _, err = p.GetOperation(ctx, info, rev3) 151 c.Assert(err, IsNil) 152 c.Assert(p.PendingOperation(), NotNil) 153 154 // reset the pessimist. 155 p.Reset() 156 c.Assert(p.PendingInfo(), IsNil) 157 c.Assert(p.PendingOperation(), IsNil) 158 }