fix barrier return

This commit is contained in:
yedongfu 2021-07-21 10:30:22 +08:00
parent e73e20a867
commit b9ef5c8005
3 changed files with 28 additions and 11 deletions

View File

@ -46,6 +46,16 @@ type BarrierModel struct {
TransInfo TransInfo
} }
func logExec(tx *sql.Tx, query string, args ...interface{}) (sql.Result, error) {
logrus.Printf("executing: "+query, args...)
return tx.Exec(query, args...)
}
func logQueryRow(tx *sql.Tx, query string, args ...interface{}) *sql.Row {
logrus.Printf("querying: "+query, args...)
return tx.QueryRow(query, args...)
}
// TableName gorm table name // TableName gorm table name
func (BarrierModel) TableName() string { return "dtm_barrier.barrier" } func (BarrierModel) TableName() string { return "dtm_barrier.barrier" }
@ -53,14 +63,14 @@ func insertBarrier(tx *sql.Tx, transType string, gid string, branchID string, br
if branchType == "" { if branchType == "" {
return 0, nil return 0, nil
} }
res, err := tx.Exec("insert into dtm_barrier.barrier(trans_type, gid, branch_id, branch_type, reason) values(?,?,?,?,?)", transType, gid, branchID, branchType, reason) res, err := logExec(tx, "insert into dtm_barrier.barrier(trans_type, gid, branch_id, branch_type, reason) values(?,?,?,?,?)", transType, gid, branchID, branchType, reason)
if err != nil { if err != nil {
return 0, err return 0, err
} }
return res.RowsAffected() return res.RowsAffected()
} }
// ThroughBarrierCall2 子事务屏障,详细介绍见 https://zhuanlan.zhihu.com/p/388444465 // ThroughBarrierCall 子事务屏障,详细介绍见 https://zhuanlan.zhihu.com/p/388444465
// db: 本地数据库 // db: 本地数据库
// transInfo: 事务信息 // transInfo: 事务信息
// bisiCall: 业务函数,仅在必要时被调用 // bisiCall: 业务函数,仅在必要时被调用
@ -94,10 +104,11 @@ func ThroughBarrierCall(db *sql.DB, transInfo *TransInfo, busiCall BusiFunc) (re
currentAffected, rerr := insertBarrier(tx, ti.TransType, ti.Gid, ti.BranchID, ti.BranchType, ti.BranchType) currentAffected, rerr := insertBarrier(tx, ti.TransType, ti.Gid, ti.BranchID, ti.BranchType, ti.BranchType)
logrus.Printf("originAffected: %d currentAffected: %d", originAffected, currentAffected) logrus.Printf("originAffected: %d currentAffected: %d", originAffected, currentAffected)
if (ti.BranchType == "cancel" || ti.BranchType == "compensate") && originAffected > 0 { // 这个是空补偿,返回成功 if (ti.BranchType == "cancel" || ti.BranchType == "compensate") && originAffected > 0 { // 这个是空补偿,返回成功
return common.MS{"dtm_result": "SUCCESS"}, nil res = common.MS{"dtm_result": "SUCCESS"}
return
} else if currentAffected == 0 { // 插入不成功 } else if currentAffected == 0 { // 插入不成功
var result string var result sql.NullString
err := tx.QueryRow("select result from dtm_barrier.barrier where trans_type=? and gid=? and branch_id=? and branch_type=? and reason=?", err := logQueryRow(tx, "select result from dtm_barrier.barrier where trans_type=? and gid=? and branch_id=? and branch_type=? and reason=?",
ti.TransType, ti.Gid, ti.BranchID, ti.BranchType, ti.BranchType).Scan(&result) ti.TransType, ti.Gid, ti.BranchID, ti.BranchType, ti.BranchType).Scan(&result)
if err == sql.ErrNoRows { // 这个是悬挂操作返回失败AP收到这个返回会尽快回滚 if err == sql.ErrNoRows { // 这个是悬挂操作返回失败AP收到这个返回会尽快回滚
res = common.MS{"dtm_result": "FAILURE"} res = common.MS{"dtm_result": "FAILURE"}
@ -107,14 +118,18 @@ func ThroughBarrierCall(db *sql.DB, transInfo *TransInfo, busiCall BusiFunc) (re
rerr = err rerr = err
return return
} }
// 返回上一次的结果 if result.Valid { // 数据库里有上一次结果,返回上一次的结果
rerr = json.Unmarshal([]byte(result), &res) res = json.Unmarshal([]byte(result.String), &res)
return return
} else { // 数据库里没有上次的结果,属于重复空补偿,直接返回成功
res = common.MS{"dtm_result": "SUCCESS"}
return
}
} }
res, rerr = busiCall(db) res, rerr = busiCall(db)
if rerr == nil { // 正确返回了,需要将结果保存到数据库 if rerr == nil { // 正确返回了,需要将结果保存到数据库
sval := common.MustMarshalString(res) sval := common.MustMarshalString(res)
_, rerr = tx.Exec("update dtm_barrier.barrier set result=? where trans_type=? and gid=? and branch_id=? and branch_type=?", sval, _, rerr = logExec(tx, "update dtm_barrier.barrier set result=? where trans_type=? and gid=? and branch_id=? and branch_type=?", sval,
ti.TransType, ti.Gid, ti.BranchID, ti.BranchType) ti.TransType, ti.Gid, ti.BranchID, ti.BranchType)
} }
return return

View File

@ -36,8 +36,9 @@ func lockOneTrans(expireIn time.Duration) *TransGlobal {
owner := GenGid() owner := GenGid()
db := dbGet() db := dbGet()
// 这里next_cron_time需要限定范围否则数据量累计之后会导致查询变慢 // 这里next_cron_time需要限定范围否则数据量累计之后会导致查询变慢
// 限定update_time < now - 3否则会出现刚被这个应用取出又被另一个取出
dbr := db.Must().Model(&trans). dbr := db.Must().Model(&trans).
Where("next_cron_time < date_add(now(), interval ? second) and next_cron_time > date_add(now(), interval -3600 second) and status in ('prepared', 'aborting', 'submitted')", int(expireIn/time.Second)). Where("next_cron_time < date_add(now(), interval ? second) and next_cron_time > date_add(now(), interval -3600 second) and update_time < date_add(now(), interval ? second) and status in ('prepared', 'aborting', 'submitted')", int(expireIn/time.Second), -3+int(expireIn/time.Second)).
Limit(1).Update("owner", owner) Limit(1).Update("owner", owner)
if dbr.RowsAffected == 0 { if dbr.RowsAffected == 0 {
return nil return nil

View File

@ -366,7 +366,7 @@ func tccBarrierDisorder(t *testing.T) {
return res, err return res, err
})) }))
// 注册子事务 // 注册子事务
_, err := common.RestyClient.R(). r, err := common.RestyClient.R().
SetBody(&M{ SetBody(&M{
"gid": tcc.Gid, "gid": tcc.Gid,
"branch_id": branchID, "branch_id": branchID,
@ -379,6 +379,7 @@ func tccBarrierDisorder(t *testing.T) {
}). }).
Post(tcc.Dtm + "/registerTccBranch") Post(tcc.Dtm + "/registerTccBranch")
e2p(err) e2p(err)
assert.True(t, strings.Contains(r.String(), "SUCCESS"))
go func() { go func() {
logrus.Printf("sleeping to wait for tcc try timeout") logrus.Printf("sleeping to wait for tcc try timeout")
<-timeoutChan <-timeoutChan