| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package undo |
| |
| import ( |
| "context" |
| "database/sql" |
| "database/sql/driver" |
| "fmt" |
| "sync" |
| |
| "seata.apache.org/seata-go/pkg/datasource/sql/types" |
| ) |
| |
| var ( |
| undoLogManagerMap = map[types.DBType]*undoLogMgrHolder{} |
| builders = map[types.ExecutorType]func() UndoLogBuilder{} |
| ) |
| |
| type undoLogMgrHolder struct { |
| once sync.Once |
| mgr UndoLogManager |
| } |
| |
| func RegisterUndoLogManager(m UndoLogManager) error { |
| if _, exist := undoLogManagerMap[m.DBType()]; exist { |
| return nil |
| } |
| |
| undoLogManagerMap[m.DBType()] = &undoLogMgrHolder{ |
| mgr: m, |
| once: sync.Once{}, |
| } |
| return nil |
| } |
| |
| func RegisterUndoLogBuilder(executorType types.ExecutorType, fun func() UndoLogBuilder) { |
| if _, ok := builders[executorType]; !ok { |
| builders[executorType] = fun |
| } |
| } |
| |
| func GetUndologBuilder(sqlType types.ExecutorType) UndoLogBuilder { |
| if f, ok := builders[sqlType]; ok { |
| return f() |
| } |
| return nil |
| } |
| |
| // UndoLogManager |
| type UndoLogManager interface { |
| Init() |
| // DeleteUndoLog |
| DeleteUndoLog(ctx context.Context, xid string, branchID int64, conn *sql.Conn) error |
| // BatchDeleteUndoLog |
| BatchDeleteUndoLog(xid []string, branchID []int64, conn *sql.Conn) error |
| //FlushUndoLog |
| FlushUndoLog(tranCtx *types.TransactionContext, conn driver.Conn) error |
| // RunUndo |
| RunUndo(ctx context.Context, xid string, branchID int64, conn *sql.DB, dbName string) error |
| // DBType |
| DBType() types.DBType |
| // HasUndoLogTable |
| HasUndoLogTable(ctx context.Context, conn *sql.Conn) (bool, error) |
| } |
| |
| // GetUndoLogManager |
| func GetUndoLogManager(d types.DBType) (UndoLogManager, error) { |
| v, ok := undoLogManagerMap[d] |
| |
| if !ok { |
| return nil, fmt.Errorf("not found UndoLogManager") |
| } |
| |
| v.once.Do(func() { |
| v.mgr.Init() |
| }) |
| |
| return v.mgr, nil |
| } |
| |
| type UndoLogStatue int8 |
| |
| const ( |
| UndoLogStatueNormnal UndoLogStatue = 0 |
| UndoLogStatueGlobalFinished UndoLogStatue = 1 |
| ) |
| |
| type UndologRecord struct { |
| BranchID uint64 `json:"branchId"` |
| XID string `json:"xid"` |
| Context []byte `json:"context"` |
| RollbackInfo []byte `json:"rollbackInfo"` |
| LogStatus UndoLogStatue `json:"logStatus"` |
| LogCreated []byte `json:"logCreated"` |
| LogModified []byte `json:"logModified"` |
| } |
| |
| func (u *UndologRecord) CanUndo() bool { |
| return u.LogStatus == UndoLogStatueNormnal |
| } |
| |
| // BranchUndoLog |
| type BranchUndoLog struct { |
| // Xid |
| Xid string `json:"xid"` |
| // BranchID |
| BranchID uint64 `json:"branchId"` |
| // Logs |
| Logs []SQLUndoLog `json:"sqlUndoLogs"` |
| } |
| |
| // Marshal |
| func (b *BranchUndoLog) Marshal() []byte { |
| return nil |
| } |
| |
| func (b *BranchUndoLog) Reverse() { |
| if len(b.Logs) == 0 { |
| return |
| } |
| |
| left, right := 0, len(b.Logs)-1 |
| |
| for left < right { |
| b.Logs[left], b.Logs[right] = b.Logs[right], b.Logs[left] |
| left++ |
| right-- |
| } |
| } |
| |
| // SQLUndoLog |
| type SQLUndoLog struct { |
| SQLType types.SQLType `json:"sqlType"` |
| TableName string `json:"tableName"` |
| BeforeImage *types.RecordImage `json:"beforeImage"` |
| AfterImage *types.RecordImage `json:"afterImage"` |
| } |
| |
| func (s SQLUndoLog) SetTableMeta(tableMeta *types.TableMeta) { |
| if s.BeforeImage != nil { |
| s.BeforeImage.TableMeta = tableMeta |
| s.BeforeImage.TableName = tableMeta.TableName |
| } |
| if s.AfterImage != nil { |
| s.AfterImage.TableMeta = tableMeta |
| s.AfterImage.TableName = tableMeta.TableName |
| } |
| } |
| |
| type UndoLogBuilder interface { |
| BeforeImage(ctx context.Context, execCtx *types.ExecContext) ([]*types.RecordImage, error) |
| AfterImage(ctx context.Context, execCtx *types.ExecContext, beforImages []*types.RecordImage) ([]*types.RecordImage, error) |
| GetExecutorType() types.ExecutorType |
| } |