You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

undo.go 5.7 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package base
  18. import (
  19. "context"
  20. "database/sql"
  21. "database/sql/driver"
  22. "strconv"
  23. "strings"
  24. "github.com/arana-db/parser/mysql"
  25. "github.com/pkg/errors"
  26. "github.com/seata/seata-go/pkg/constant"
  27. "github.com/seata/seata-go/pkg/datasource/sql/undo"
  28. "github.com/seata/seata-go/pkg/util/log"
  29. "github.com/seata/seata-go/pkg/datasource/sql/types"
  30. )
  31. var _ undo.UndoLogManager = (*BaseUndoLogManager)(nil)
  32. var ErrorDeleteUndoLogParamsFault = errors.New("xid or branch_id can't nil")
  33. // CheckUndoLogTableExistSql check undo log if exist
  34. const CheckUndoLogTableExistSql = "SELECT 1 FROM " + constant.UndoLogTableName + " LIMIT 1"
  35. // BaseUndoLogManager
  36. type BaseUndoLogManager struct{}
  37. // Init
  38. func (m *BaseUndoLogManager) Init() {
  39. }
  40. // InsertUndoLog
  41. func (m *BaseUndoLogManager) InsertUndoLog(l []undo.BranchUndoLog, tx driver.Conn) error {
  42. return nil
  43. }
  44. // DeleteUndoLog exec delete single undo log operate
  45. func (m *BaseUndoLogManager) DeleteUndoLog(ctx context.Context, xid string, branchID int64, conn *sql.Conn) error {
  46. stmt, err := conn.PrepareContext(ctx, constant.DeleteUndoLogSql)
  47. if err != nil {
  48. log.Errorf("[DeleteUndoLog] prepare sql fail, err: %v", err)
  49. return err
  50. }
  51. if _, err = stmt.ExecContext(ctx, branchID, xid); err != nil {
  52. log.Errorf("[DeleteUndoLog] exec delete undo log fail, err: %v", err)
  53. return err
  54. }
  55. return nil
  56. }
  57. // BatchDeleteUndoLog exec delete undo log operate
  58. func (m *BaseUndoLogManager) BatchDeleteUndoLog(xid []string, branchID []int64, conn *sql.Conn) error {
  59. // build delete undo log sql
  60. batchDeleteSql, err := m.getBatchDeleteUndoLogSql(xid, branchID)
  61. if err != nil {
  62. log.Errorf("get undo sql log fail, err: %v", err)
  63. return err
  64. }
  65. ctx := context.Background()
  66. // prepare deal sql
  67. stmt, err := conn.PrepareContext(ctx, batchDeleteSql)
  68. if err != nil {
  69. log.Errorf("prepare sql fail, err: %v", err)
  70. return err
  71. }
  72. branchIDStr, err := Int64Slice2Str(branchID, ",")
  73. if err != nil {
  74. log.Errorf("slice to string transfer fail, err: %v", err)
  75. return err
  76. }
  77. // exec sql stmt
  78. if _, err = stmt.ExecContext(ctx, branchIDStr, strings.Join(xid, ",")); err != nil {
  79. log.Errorf("exec delete undo log fail, err: %v", err)
  80. return err
  81. }
  82. return nil
  83. }
  84. // FlushUndoLog flush undo log
  85. func (m *BaseUndoLogManager) FlushUndoLog(txCtx *types.TransactionContext, tx driver.Conn) error {
  86. if !txCtx.HasUndoLog() {
  87. return nil
  88. }
  89. logs := []undo.SQLUndoLog{
  90. {
  91. SQLType: types.SQLTypeInsert,
  92. TableName: constant.UndoLogTableName,
  93. Images: *txCtx.RoundImages,
  94. },
  95. }
  96. branchUndoLogs := []undo.BranchUndoLog{
  97. {
  98. Xid: txCtx.XaID,
  99. BranchID: strconv.FormatUint(txCtx.BranchID, 10),
  100. Logs: logs,
  101. },
  102. }
  103. return m.InsertUndoLog(branchUndoLogs, tx)
  104. }
  105. // RunUndo
  106. func (m *BaseUndoLogManager) RunUndo(xid string, branchID int64, conn *sql.Conn) error {
  107. return nil
  108. }
  109. // DBType
  110. func (m *BaseUndoLogManager) DBType() types.DBType {
  111. panic("implement me")
  112. }
  113. // HasUndoLogTable check undo log table if exist
  114. func (m *BaseUndoLogManager) HasUndoLogTable(ctx context.Context, conn *sql.Conn) (res bool, err error) {
  115. if _, err = conn.QueryContext(ctx, CheckUndoLogTableExistSql); err != nil {
  116. // 1146 mysql table not exist fault code
  117. if e, ok := err.(*mysql.SQLError); ok && e.Code == mysql.ErrNoSuchTable {
  118. return false, nil
  119. }
  120. log.Errorf("[HasUndoLogTable] query sql fail, err: %v", err)
  121. return
  122. }
  123. return true, nil
  124. }
  125. // getBatchDeleteUndoLogSql build batch delete undo log
  126. func (m *BaseUndoLogManager) getBatchDeleteUndoLogSql(xid []string, branchID []int64) (string, error) {
  127. if len(xid) == 0 || len(branchID) == 0 {
  128. return "", ErrorDeleteUndoLogParamsFault
  129. }
  130. var undoLogDeleteSql strings.Builder
  131. undoLogDeleteSql.WriteString(constant.DeleteFrom)
  132. undoLogDeleteSql.WriteString(constant.UndoLogTableName)
  133. undoLogDeleteSql.WriteString(" WHERE ")
  134. undoLogDeleteSql.WriteString(constant.UndoLogBranchXid)
  135. undoLogDeleteSql.WriteString(" IN ")
  136. m.appendInParam(len(branchID), &undoLogDeleteSql)
  137. undoLogDeleteSql.WriteString(" AND ")
  138. undoLogDeleteSql.WriteString(constant.UndoLogXid)
  139. undoLogDeleteSql.WriteString(" IN ")
  140. m.appendInParam(len(xid), &undoLogDeleteSql)
  141. return undoLogDeleteSql.String(), nil
  142. }
  143. // appendInParam build in param
  144. func (m *BaseUndoLogManager) appendInParam(size int, str *strings.Builder) {
  145. if size <= 0 {
  146. return
  147. }
  148. str.WriteString(" (")
  149. for i := 0; i < size; i++ {
  150. str.WriteString("?")
  151. if i < size-1 {
  152. str.WriteString(",")
  153. }
  154. }
  155. str.WriteString(") ")
  156. }
  157. // Int64Slice2Str
  158. func Int64Slice2Str(values interface{}, sep string) (string, error) {
  159. v, ok := values.([]int64)
  160. if !ok {
  161. return "", errors.New("param type is fault")
  162. }
  163. var valuesText []string
  164. for i := range v {
  165. text := strconv.FormatInt(v[i], 10)
  166. valuesText = append(valuesText, text)
  167. }
  168. return strings.Join(valuesText, sep), nil
  169. }