github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/pkg/shardddl/pessimism/ops.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 pessimism 15 16 import ( 17 "context" 18 19 "github.com/pingcap/tiflow/dm/common" 20 "github.com/pingcap/tiflow/dm/pkg/etcdutil" 21 clientv3 "go.etcd.io/etcd/client/v3" 22 ) 23 24 // TODO(csuzhangxc): assign terror code before merged into the master branch. 25 26 // PutOperationDeleteExistInfo puts an operation and deletes an info in one txn, 27 // if the info exists in etcd before. 28 // This function should often be called by DM-worker. 29 func PutOperationDeleteExistInfo(cli *clientv3.Client, op Operation, info Info) (done bool, rev int64, err error) { 30 putOp, err := putOperationOp(op) 31 if err != nil { 32 return false, 0, nil 33 } 34 delOp := deleteInfoOp(info) 35 36 infoCmp := infoExistCmp(info) 37 38 getOp := getOperationOp(op) 39 40 ctx, cancel := context.WithTimeout(cli.Ctx(), etcdutil.DefaultRequestTimeout) 41 defer cancel() 42 43 resp, err := cli.Txn(ctx).If(infoCmp).Then(putOp, delOp).Else(getOp).Commit() 44 if err != nil { 45 return false, 0, err 46 } 47 48 if !resp.Succeeded && len(resp.Responses) == 1 { 49 if getResponse := resp.Responses[0].GetResponseRange(); getResponse.GetCount() == 1 { 50 // err must be nil here, or the last putOperationOp will return an error. 51 opBytes, _ := op.toJSON() 52 // we may successfully delete the info in the previous txn but fail to get the result 53 // before the connection is broken. If we check the operation is the same with the put 54 // operation, we can safely assume the done operation is okay. 55 return opBytes == string(getResponse.Kvs[0].Value), resp.Header.Revision, nil 56 } 57 } 58 return resp.Succeeded, resp.Header.Revision, nil 59 } 60 61 // DeleteInfosOperations deletes the shard DDL infos and operations in etcd. 62 // This function should often be called by DM-master when calling UnlockDDL. 63 func DeleteInfosOperations(cli *clientv3.Client, infos []Info, ops []Operation) (int64, error) { 64 opsDel := make([]clientv3.Op, 0, len(infos)+len(ops)) 65 for _, info := range infos { 66 opsDel = append(opsDel, deleteInfoOp(info)) 67 } 68 for _, op := range ops { 69 opsDel = append(opsDel, deleteOperationOp(op)) 70 } 71 _, rev, err := etcdutil.DoTxnWithRepeatable(cli, etcdutil.ThenOpFunc(opsDel...)) 72 return rev, err 73 } 74 75 // DeleteInfosOperationsByTask deletes the shard DDL infos and operations of a specified task in etcd. 76 // This function should often be called by DM-master when deleting ddl meta data. 77 func DeleteInfosOperationsByTask(cli *clientv3.Client, task string) (int64, error) { 78 opsDel := make([]clientv3.Op, 0, 2) 79 opsDel = append(opsDel, clientv3.OpDelete(common.ShardDDLPessimismInfoKeyAdapter.Encode(task), clientv3.WithPrefix())) 80 opsDel = append(opsDel, clientv3.OpDelete(common.ShardDDLPessimismOperationKeyAdapter.Encode(task), clientv3.WithPrefix())) 81 _, rev, err := etcdutil.DoTxnWithRepeatable(cli, etcdutil.ThenOpFunc(opsDel...)) 82 return rev, err 83 }