Browse Source

refactor to use new grpc interface

pull/52/head
yedf2 4 years ago
parent
commit
d284b92f1d
  1. 10
      README-cn.md
  2. 3
      app/main.go
  3. 63
      bench/http.go
  4. 27
      common/types.go
  5. 12
      common/types_test.go
  6. 24
      common/utils.go
  7. 14
      dtmcli/barrier.go
  8. 26
      dtmcli/consts.go
  9. 14
      dtmcli/dtmimp/consts.go
  10. 2
      dtmcli/dtmimp/db_special.go
  11. 2
      dtmcli/dtmimp/db_special_test.go
  12. 117
      dtmcli/dtmimp/trans_base.go
  13. 9
      dtmcli/dtmimp/trans_xa_base.go
  14. 6
      dtmcli/dtmimp/types.go
  15. 19
      dtmcli/dtmimp/types_test.go
  16. 34
      dtmcli/dtmimp/utils.go
  17. 2
      dtmcli/dtmimp/utils_test.go
  18. 38
      dtmcli/dtmimp/vars.go
  19. 39
      dtmcli/message.go
  20. 31
      dtmcli/msg.go
  21. 28
      dtmcli/saga.go
  22. 40
      dtmcli/tcc.go
  23. 2
      dtmcli/trans_test.go
  24. 104
      dtmcli/types.go
  25. 12
      dtmcli/types_test.go
  26. 61
      dtmcli/xa.go
  27. 18
      dtmgrpc/barrier.go
  28. 674
      dtmgrpc/dtmgimp/dtmgimp.pb.go
  29. 58
      dtmgrpc/dtmgimp/dtmgimp.proto
  30. 30
      dtmgrpc/dtmgimp/dtmgimp_grpc.pb.go
  31. 67
      dtmgrpc/dtmgimp/grpc_clients.go
  32. 61
      dtmgrpc/dtmgimp/types.go
  33. 73
      dtmgrpc/dtmgimp/utils.go
  34. 717
      dtmgrpc/dtmgrpc.pb.go
  35. 66
      dtmgrpc/dtmgrpc.proto
  36. 50
      dtmgrpc/message.go
  37. 36
      dtmgrpc/msg.go
  38. 41
      dtmgrpc/saga.go
  39. 55
      dtmgrpc/tcc.go
  40. 92
      dtmgrpc/type.go
  41. 5
      dtmgrpc/type_test.go
  42. 86
      dtmgrpc/xa.go
  43. 12
      dtmsvr/api.go
  44. 26
      dtmsvr/api_grpc.go
  45. 13
      dtmsvr/api_http.go
  46. 10
      dtmsvr/cron.go
  47. 24
      dtmsvr/dtmsvr.go
  48. 1
      dtmsvr/dtmsvr.mysql.sql
  49. 1
      dtmsvr/dtmsvr.postgres.sql
  50. 113
      dtmsvr/trans.go
  51. 19
      dtmsvr/trans_msg.go
  52. 23
      dtmsvr/trans_saga.go
  53. 5
      dtmsvr/trans_tcc.go
  54. 5
      dtmsvr/trans_xa.go
  55. 23
      dtmsvr/utils.go
  56. 8
      dtmsvr/utils_test.go
  57. 133
      examples/base_grpc.go
  58. 42
      examples/base_http.go
  59. 34
      examples/base_types.go
  60. 318
      examples/busi.pb.go
  61. 43
      examples/busi.proto
  62. 240
      examples/busi_grpc.pb.go
  63. 40
      examples/data.go
  64. 6
      examples/grpc_msg.go
  65. 14
      examples/grpc_saga.go
  66. 52
      examples/grpc_saga_barrier.go
  67. 14
      examples/grpc_tcc.go
  68. 24
      examples/grpc_xa.go
  69. 3
      examples/http_gorm_xa.go
  70. 9
      examples/http_msg.go
  71. 25
      examples/http_saga.go
  72. 9
      examples/http_saga_barrier.go
  73. 7
      examples/http_saga_gorm_barrier.go
  74. 11
      examples/http_tcc.go
  75. 9
      examples/http_tcc_barrier.go
  76. 5
      examples/http_xa.go
  77. 7
      examples/quick_start.go
  78. 3
      go.mod
  79. 12
      go.sum
  80. 44
      test/api_test.go
  81. 22
      test/base_test.go
  82. 50
      test/dtmsvr_test.go
  83. 1
      test/examples_test.go
  84. 36
      test/grpc_msg_test.go
  85. 19
      test/grpc_saga_barrier_test.go
  86. 26
      test/grpc_saga_test.go
  87. 49
      test/grpc_tcc_test.go
  88. 44
      test/grpc_xa_test.go
  89. 17
      test/main_test.go
  90. 48
      test/msg_test.go
  91. 19
      test/saga_barrier_test.go
  92. 21
      test/saga_compatible_test.go
  93. 76
      test/saga_concurrent_test.go
  94. 82
      test/saga_options_test.go
  95. 59
      test/saga_test.go
  96. 44
      test/tcc_barrier_test.go
  97. 15
      test/tcc_test.go
  98. 22
      test/types.go
  99. 50
      test/wait_saga_test.go
  100. 33
      test/xa_test.go

10
README-cn.md

@ -66,15 +66,19 @@ DTM是一款golang开发的分布式事务管理器,解决了跨数据库、
## 快速开始
### 安装
### 获取代码
`git clone https://github.com/yedf/dtm`
### dtm依赖于mysql
配置mysql:
安装[docker 20.04+](https://docs.docker.com/get-docker/)之后
`cp conf.sample.yml conf.yml # 修改conf.yml`
`docker-compose helper/compose.mysql.yml`
> 您也可以配置使用现有的mysql,需要高级权限,允许dtm创建数据库
>
> `cp conf.sample.yml conf.yml # 修改conf.yml`
### 启动并运行saga示例
`go run app/main.go saga`

3
app/main.go

@ -8,6 +8,7 @@ import (
"github.com/yedf/dtm/bench"
"github.com/yedf/dtm/common"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/dtmsvr"
"github.com/yedf/dtm/examples"
)
@ -56,7 +57,7 @@ func main() {
examples.BaseAppStartup()
sample := examples.Samples[os.Args[1]]
dtmcli.LogIfFatalf(sample == nil, "no sample name for %s", os.Args[1])
dtmimp.LogIfFatalf(sample == nil, "no sample name for %s", os.Args[1])
sample.Action()
}
select {}

63
bench/http.go

@ -10,6 +10,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/yedf/dtm/common"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/dtmsvr"
"github.com/yedf/dtm/examples"
)
@ -24,15 +25,15 @@ const total = 200000
var benchBusi = fmt.Sprintf("http://localhost:%d%s", benchPort, benchAPI)
func sdbGet() *sql.DB {
db, err := dtmcli.PooledDB(common.DtmConfig.DB)
dtmcli.FatalIfError(err)
db, err := dtmimp.PooledDB(common.DtmConfig.DB)
dtmimp.FatalIfError(err)
return db
}
func txGet() *sql.Tx {
db := sdbGet()
tx, err := db.Begin()
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
return tx
}
@ -42,17 +43,17 @@ func reloadData() {
db := sdbGet()
tables := []string{"dtm_busi.user_account", "dtm_busi.user_account_log", "dtm.trans_global", "dtm.trans_branch", "dtm_barrier.barrier"}
for _, t := range tables {
_, err := dtmcli.DBExec(db, fmt.Sprintf("truncate %s", t))
dtmcli.FatalIfError(err)
_, err := dtmimp.DBExec(db, fmt.Sprintf("truncate %s", t))
dtmimp.FatalIfError(err)
}
s := "insert ignore into dtm_busi.user_account(user_id, balance) values "
ss := []string{}
for i := 1; i <= total; i++ {
ss = append(ss, fmt.Sprintf("(%d, 1000000)", i))
}
_, err := dtmcli.DBExec(db, s+strings.Join(ss, ","))
dtmcli.FatalIfError(err)
dtmcli.Logf("%d users inserted. used: %dms", total, time.Since(began).Milliseconds())
_, err := dtmimp.DBExec(db, s+strings.Join(ss, ","))
dtmimp.FatalIfError(err)
dtmimp.Logf("%d users inserted. used: %dms", total, time.Since(began).Milliseconds())
}
var uidCounter int32 = 0
@ -63,12 +64,12 @@ var sqls int = 1
func StartSvr() {
app := common.GetGinApp()
benchAddRoute(app)
dtmcli.Logf("bench listening at %d", benchPort)
dtmimp.Logf("bench listening at %d", benchPort)
go app.Run(fmt.Sprintf(":%d", benchPort))
db := sdbGet()
_, err := dtmcli.DBExec(db, "drop table if exists dtm_busi.user_account_log")
dtmcli.FatalIfError(err)
_, err = dtmcli.DBExec(db, `create table if not exists dtm_busi.user_account_log (
_, err := dtmimp.DBExec(db, "drop table if exists dtm_busi.user_account_log")
dtmimp.FatalIfError(err)
_, err = dtmimp.DBExec(db, `create table if not exists dtm_busi.user_account_log (
id INT(11) AUTO_INCREMENT PRIMARY KEY,
user_id INT(11) NOT NULL,
delta DECIMAL(11, 2) not null,
@ -82,33 +83,33 @@ func StartSvr() {
key(create_time)
)
`)
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
}
func qsAdjustBalance(uid int, amount int, c *gin.Context) (interface{}, error) {
if strings.Contains(mode, "empty") {
return dtmcli.MapSuccess, nil
}
tb := dtmcli.TransBaseFromQuery(c.Request.URL.Query())
tb := dtmimp.TransBaseFromQuery(c.Request.URL.Query())
f := func(tx dtmcli.DB) error {
for i := 0; i < sqls; i++ {
_, err := dtmcli.DBExec(tx, "insert into dtm_busi.user_account_log(user_id, delta, gid, branch_id, branch_type, reason) values(?,?,?,?,?,?)",
_, err := dtmimp.DBExec(tx, "insert into dtm_busi.user_account_log(user_id, delta, gid, branch_id, branch_type, reason) values(?,?,?,?,?,?)",
uid, amount, tb.Gid, c.Query("branch_id"), tb.TransType, fmt.Sprintf("inserted by dtm transaction %s %s", tb.Gid, c.Query("branch_id")))
dtmcli.FatalIfError(err)
_, err = dtmcli.DBExec(tx, "update dtm_busi.user_account set balance = balance + ?, update_time = now() where user_id = ?", amount, uid)
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
_, err = dtmimp.DBExec(tx, "update dtm_busi.user_account set balance = balance + ?, update_time = now() where user_id = ?", amount, uid)
dtmimp.FatalIfError(err)
}
return nil
}
if strings.Contains(mode, "barrier") {
barrier, err := dtmcli.BarrierFromQuery(c.Request.URL.Query())
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
barrier.Call(txGet(), f)
} else {
tx := txGet()
f(tx)
err := tx.Commit()
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
}
return dtmcli.MapSuccess, nil
@ -116,23 +117,23 @@ func qsAdjustBalance(uid int, amount int, c *gin.Context) (interface{}, error) {
func benchAddRoute(app *gin.Engine) {
app.POST(benchAPI+"/TransIn", common.WrapHandler(func(c *gin.Context) (interface{}, error) {
return qsAdjustBalance(dtmcli.MustAtoi(c.Query("uid")), 1, c)
return qsAdjustBalance(dtmimp.MustAtoi(c.Query("uid")), 1, c)
}))
app.POST(benchAPI+"/TransInCompensate", common.WrapHandler(func(c *gin.Context) (interface{}, error) {
return qsAdjustBalance(dtmcli.MustAtoi(c.Query("uid")), -1, c)
return qsAdjustBalance(dtmimp.MustAtoi(c.Query("uid")), -1, c)
}))
app.POST(benchAPI+"/TransOut", common.WrapHandler(func(c *gin.Context) (interface{}, error) {
return qsAdjustBalance(dtmcli.MustAtoi(c.Query("uid")), -1, c)
return qsAdjustBalance(dtmimp.MustAtoi(c.Query("uid")), -1, c)
}))
app.POST(benchAPI+"/TransOutCompensate", common.WrapHandler(func(c *gin.Context) (interface{}, error) {
return qsAdjustBalance(dtmcli.MustAtoi(c.Query("uid")), 30, c)
return qsAdjustBalance(dtmimp.MustAtoi(c.Query("uid")), 30, c)
}))
app.Any(benchAPI+"/reloadData", common.WrapHandler(func(c *gin.Context) (interface{}, error) {
reloadData()
mode = c.Query("m")
s := c.Query("sqls")
if s != "" {
sqls = dtmcli.MustAtoi(s)
sqls = dtmimp.MustAtoi(s)
}
return nil, nil
}))
@ -143,19 +144,19 @@ func benchAddRoute(app *gin.Engine) {
req := gin.H{}
params := fmt.Sprintf("?uid=%s", suid)
params2 := fmt.Sprintf("?uid=%s", suid2)
dtmcli.Logf("mode: %s contains dtm: %t", mode, strings.Contains(mode, "dtm"))
dtmimp.Logf("mode: %s contains dtm: %t", mode, strings.Contains(mode, "dtm"))
if strings.Contains(mode, "dtm") {
saga := dtmcli.NewSaga(examples.DtmServer, fmt.Sprintf("bench-%d", uid)).
Add(benchBusi+"/TransOut"+params, benchBusi+"/TransOutCompensate"+params, req).
Add(benchBusi+"/TransIn"+params2, benchBusi+"/TransInCompensate"+params2, req)
saga.WaitResult = true
err := saga.Submit()
dtmcli.E2P(err)
dtmimp.E2P(err)
} else {
_, err := dtmcli.RestyClient.R().SetBody(gin.H{}).SetQueryParam("uid", suid2).Post(benchBusi + "/TransOut")
dtmcli.E2P(err)
_, err = dtmcli.RestyClient.R().SetBody(gin.H{}).SetQueryParam("uid", suid).Post(benchBusi + "/TransIn")
dtmcli.E2P(err)
_, err := dtmimp.RestyClient.R().SetBody(gin.H{}).SetQueryParam("uid", suid2).Post(benchBusi + "/TransOut")
dtmimp.E2P(err)
_, err = dtmimp.RestyClient.R().SetBody(gin.H{}).SetQueryParam("uid", suid).Post(benchBusi + "/TransIn")
dtmimp.E2P(err)
}
return nil, nil
}))

27
common/types.go

@ -18,6 +18,7 @@ import (
"gorm.io/gorm"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
)
// ModelBase model base for gorm to provide base fields
@ -31,7 +32,7 @@ func getGormDialetor(driver string, dsn string) gorm.Dialector {
if driver == dtmcli.DBTypePostgres {
return postgres.Open(dsn)
}
dtmcli.PanicIf(driver != dtmcli.DBTypeMysql, fmt.Errorf("unkown driver: %s", driver))
dtmimp.PanicIf(driver != dtmcli.DBTypeMysql, fmt.Errorf("unkown driver: %s", driver))
return mysql.Open(dsn)
}
@ -57,7 +58,7 @@ func (m *DB) NoMust() *DB {
// ToSQLDB get the sql.DB
func (m *DB) ToSQLDB() *sql.DB {
d, err := m.DB.DB()
dtmcli.E2P(err)
dtmimp.E2P(err)
return d
}
@ -75,7 +76,7 @@ func (op *tracePlugin) Initialize(db *gorm.DB) (err error) {
after := func(db *gorm.DB) {
_ts, _ := db.InstanceGet("ivy.startTime")
sql := db.Dialector.Explain(db.Statement.SQL.String(), db.Statement.Vars...)
dtmcli.Logf("used: %d ms affected: %d sql is: %s", time.Since(_ts.(time.Time)).Milliseconds(), db.RowsAffected, sql)
dtmimp.Logf("used: %d ms affected: %d sql is: %s", time.Since(_ts.(time.Time)).Milliseconds(), db.RowsAffected, sql)
if v, ok := db.InstanceGet("ivy.must"); ok && v.(bool) {
if db.Error != nil && db.Error != gorm.ErrRecordNotFound {
panic(db.Error)
@ -86,7 +87,7 @@ func (op *tracePlugin) Initialize(db *gorm.DB) (err error) {
beforeName := "cb_before"
afterName := "cb_after"
dtmcli.Logf("installing db plugin: %s", op.Name())
dtmimp.Logf("installing db plugin: %s", op.Name())
// 开始前
_ = db.Callback().Create().Before("gorm:before_create").Register(beforeName, before)
_ = db.Callback().Query().Before("gorm:query").Register(beforeName, before)
@ -107,14 +108,14 @@ func (op *tracePlugin) Initialize(db *gorm.DB) (err error) {
// DbGet get db connection for specified conf
func DbGet(conf map[string]string) *DB {
dsn := dtmcli.GetDsn(conf)
dsn := dtmimp.GetDsn(conf)
db, ok := dbs.Load(dsn)
if !ok {
dtmcli.Logf("connecting %s", strings.Replace(dsn, conf["password"], "****", 1))
dtmimp.Logf("connecting %s", strings.Replace(dsn, conf["password"], "****", 1))
db1, err := gorm.Open(getGormDialetor(conf["driver"], dsn), &gorm.Config{
SkipDefaultTransaction: true,
})
dtmcli.E2P(err)
dtmimp.E2P(err)
db1.Use(&tracePlugin{})
db = &DB{DB: db1}
dbs.Store(dsn, db)
@ -135,7 +136,7 @@ type dtmConfigType struct {
var DtmConfig = dtmConfigType{}
func getIntEnv(key string, defaultV string) int64 {
return int64(dtmcli.MustAtoi(dtmcli.OrString(os.Getenv(key), defaultV)))
return int64(dtmimp.MustAtoi(dtmimp.OrString(os.Getenv(key), defaultV)))
}
func init() {
@ -146,9 +147,9 @@ func init() {
DtmConfig.TimeoutToFail = getIntEnv("TIMEOUT_TO_FAIL", "35")
DtmConfig.RetryInterval = getIntEnv("RETRY_INTERVAL", "10")
DtmConfig.DB = map[string]string{
"driver": dtmcli.OrString(os.Getenv("DB_DRIVER"), "mysql"),
"driver": dtmimp.OrString(os.Getenv("DB_DRIVER"), "mysql"),
"host": os.Getenv("DB_HOST"),
"port": dtmcli.OrString(os.Getenv("DB_PORT"), "3306"),
"port": dtmimp.OrString(os.Getenv("DB_PORT"), "3306"),
"user": os.Getenv("DB_USER"),
"password": os.Getenv("DB_PASSWORD"),
}
@ -166,12 +167,12 @@ func init() {
}
}
if cont != nil && len(cont) != 0 {
dtmcli.Logf("cont is: \n%s", string(cont))
dtmimp.Logf("cont is: \n%s", string(cont))
err := yaml.Unmarshal(cont, &DtmConfig)
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
}
errStr := checkConfig()
dtmcli.LogIfFatalf(errStr != "",
dtmimp.LogIfFatalf(errStr != "",
`config error: '%s'.
check you env, and conf.yml/conf.sample.yml in current and parent path: %s.
please visit http://d.dtm.pub to see the config document.

12
common/types_test.go

@ -4,13 +4,13 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
)
func TestDb(t *testing.T) {
db := DbGet(DtmConfig.DB)
err := func() (rerr error) {
defer dtmcli.P2E(&rerr)
defer dtmimp.P2E(&rerr)
dbr := db.NoMust().Exec("select a")
assert.NotEqual(t, nil, dbr.Error)
db.Must().Exec("select a")
@ -20,14 +20,14 @@ func TestDb(t *testing.T) {
}
func TestDbAlone(t *testing.T) {
db, err := dtmcli.StandaloneDB(DtmConfig.DB)
db, err := dtmimp.StandaloneDB(DtmConfig.DB)
assert.Nil(t, err)
_, err = dtmcli.DBExec(db, "select 1")
_, err = dtmimp.DBExec(db, "select 1")
assert.Equal(t, nil, err)
_, err = dtmcli.DBExec(db, "")
_, err = dtmimp.DBExec(db, "")
assert.Equal(t, nil, err)
db.Close()
_, err = dtmcli.DBExec(db, "select 1")
_, err = dtmimp.DBExec(db, "select 1")
assert.NotEqual(t, nil, err)
}

24
common/utils.go

@ -14,6 +14,7 @@ import (
"github.com/go-resty/resty/v2"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
)
// GetGinApp init and return gin
@ -24,19 +25,19 @@ func GetGinApp() *gin.Engine {
body := ""
if c.Request.Body != nil {
rb, err := c.GetRawData()
dtmcli.E2P(err)
dtmimp.E2P(err)
if len(rb) > 0 {
body = string(rb)
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(rb))
}
}
began := time.Now()
dtmcli.Logf("begin %s %s query: %s body: %s", c.Request.Method, c.FullPath(), c.Request.URL.RawQuery, body)
dtmimp.Logf("begin %s %s query: %s body: %s", c.Request.Method, c.FullPath(), c.Request.URL.RawQuery, body)
c.Next()
dtmcli.Logf("used %d ms %s %s query: %s body: %s", time.Since(began).Milliseconds(), c.Request.Method, c.FullPath(), c.Request.URL.RawQuery, body)
dtmimp.Logf("used %d ms %s %s query: %s body: %s", time.Since(began).Milliseconds(), c.Request.Method, c.FullPath(), c.Request.URL.RawQuery, body)
})
app.Any("/api/ping", func(c *gin.Context) { c.JSON(200, dtmcli.M{"msg": "pong"}) })
app.Any("/api/ping", func(c *gin.Context) { c.JSON(200, map[string]interface{}{"msg": "pong"}) })
return app
}
@ -44,24 +45,27 @@ func GetGinApp() *gin.Engine {
func WrapHandler(fn func(*gin.Context) (interface{}, error)) gin.HandlerFunc {
return func(c *gin.Context) {
r, err := func() (r interface{}, rerr error) {
defer dtmcli.P2E(&rerr)
defer dtmimp.P2E(&rerr)
return fn(c)
}()
var b = []byte{}
if resp, ok := r.(*resty.Response); ok { // 如果是response,则取出body直接处理
b = resp.Body()
} else if err != nil && (strings.Contains(err.Error(), dtmcli.ResultFailure) || strings.Contains(err.Error(), dtmcli.ResultOngoing)) {
b = []byte(err.Error())
err = nil
} else if err == nil {
b, err = json.Marshal(r)
}
if err != nil {
dtmcli.Logf("status: 500, code: 500 message: %s", err.Error())
c.JSON(500, dtmcli.M{"code": 500, "message": err.Error()})
dtmimp.Logf("status: 500, code: 500 message: %s", err.Error())
c.JSON(500, map[string]interface{}{"code": 500, "message": err.Error()})
} else {
dtmcli.Logf("status: 200, content: %s", string(b))
dtmimp.Logf("status: 200, content: %s", string(b))
c.Status(200)
c.Writer.Header().Add("Content-Type", "application/json")
_, err = c.Writer.Write(b)
dtmcli.E2P(err)
dtmimp.E2P(err)
}
}
}
@ -69,7 +73,7 @@ func WrapHandler(fn func(*gin.Context) (interface{}, error)) gin.HandlerFunc {
// MustGetwd must version of os.Getwd
func MustGetwd() string {
wd, err := os.Getwd()
dtmcli.E2P(err)
dtmimp.E2P(err)
return wd
}

14
dtmcli/barrier.go

@ -3,10 +3,12 @@ package dtmcli
import (
"fmt"
"net/url"
"github.com/yedf/dtm/dtmcli/dtmimp"
)
// BusiFunc type for busi func
type BusiFunc func(db DB) error
// BarrierBusiFunc type for busi func
type BarrierBusiFunc func(db DB) error
// BranchBarrier every branch info
type BranchBarrier struct {
@ -44,14 +46,14 @@ func insertBarrier(tx Tx, transType string, gid string, branchID string, branchT
if branchType == "" {
return 0, nil
}
sql := GetDBSpecial().GetInsertIgnoreTemplate("dtm_barrier.barrier(trans_type, gid, branch_id, branch_type, barrier_id, reason) values(?,?,?,?,?,?)", "uniq_barrier")
return DBExec(tx, sql, transType, gid, branchID, branchType, barrierID, reason)
sql := dtmimp.GetDBSpecial().GetInsertIgnoreTemplate("dtm_barrier.barrier(trans_type, gid, branch_id, branch_type, barrier_id, reason) values(?,?,?,?,?,?)", "uniq_barrier")
return dtmimp.DBExec(tx, sql, transType, gid, branchID, branchType, barrierID, reason)
}
// Call 子事务屏障,详细介绍见 https://zhuanlan.zhihu.com/p/388444465
// tx: 本地数据库的事务对象,允许子事务屏障进行事务操作
// busiCall: 业务函数,仅在必要时被调用
func (bb *BranchBarrier) Call(tx Tx, busiCall BusiFunc) (rerr error) {
func (bb *BranchBarrier) Call(tx Tx, busiCall BarrierBusiFunc) (rerr error) {
bb.BarrierID = bb.BarrierID + 1
bid := fmt.Sprintf("%02d", bb.BarrierID)
defer func() {
@ -73,7 +75,7 @@ func (bb *BranchBarrier) Call(tx Tx, busiCall BusiFunc) (rerr error) {
originAffected, _ := insertBarrier(tx, ti.TransType, ti.Gid, ti.BranchID, originType, bid, ti.BranchType)
currentAffected, rerr := insertBarrier(tx, ti.TransType, ti.Gid, ti.BranchID, ti.BranchType, bid, ti.BranchType)
Logf("originAffected: %d currentAffected: %d", originAffected, currentAffected)
dtmimp.Logf("originAffected: %d currentAffected: %d", originAffected, currentAffected)
if (ti.BranchType == BranchCancel || ti.BranchType == BranchCompensate) && originAffected > 0 || // 这个是空补偿
currentAffected == 0 { // 这个是重复请求或者悬挂
return

26
dtmcli/consts.go

@ -1,5 +1,9 @@
package dtmcli
import (
"github.com/yedf/dtm/dtmcli/dtmimp"
)
const (
// StatusPrepared status for global/branch trans status.
StatusPrepared = "prepared"
@ -28,14 +32,26 @@ const (
BranchRollback = "rollback"
// ResultSuccess for result of a trans/trans branch
ResultSuccess = "SUCCESS"
ResultSuccess = dtmimp.ResultSuccess
// ResultFailure for result of a trans/trans branch
ResultFailure = "FAILURE"
ResultFailure = dtmimp.ResultFailure
// ResultOngoing for result of a trans/trans branch
ResultOngoing = "ONGOING"
ResultOngoing = dtmimp.ResultOngoing
// DBTypeMysql const for driver mysql
DBTypeMysql = "mysql"
DBTypeMysql = dtmimp.DBTypeMysql
// DBTypePostgres const for driver postgres
DBTypePostgres = "postgres"
DBTypePostgres = dtmimp.DBTypePostgres
)
// MapSuccess HTTP result of SUCCESS
var MapSuccess = dtmimp.MapSuccess
// MapFailure HTTP result of FAILURE
var MapFailure = dtmimp.MapSuccess
// ErrFailure error for returned failure
var ErrFailure = dtmimp.ErrFailure
// ErrOngoing error for returned ongoing
var ErrOngoing = dtmimp.ErrOngoing

14
dtmcli/dtmimp/consts.go

@ -0,0 +1,14 @@
package dtmimp
const (
// ResultFailure for result of a trans/trans branch
ResultFailure = "FAILURE"
// ResultSuccess for result of a trans/trans branch
ResultSuccess = "SUCCESS"
// ResultOngoing for result of a trans/trans branch
ResultOngoing = "ONGOING"
// DBTypeMysql const for driver mysql
DBTypeMysql = "mysql"
// DBTypePostgres const for driver postgres
DBTypePostgres = "postgres"
)

2
dtmcli/db_special.go → dtmcli/dtmimp/db_special.go

@ -1,4 +1,4 @@
package dtmcli
package dtmimp
import (
"fmt"

2
dtmcli/db_special_test.go → dtmcli/dtmimp/db_special_test.go

@ -1,4 +1,4 @@
package dtmcli
package dtmimp
import (
"testing"

117
dtmcli/dtmimp/trans_base.go

@ -0,0 +1,117 @@
package dtmimp
import (
"errors"
"fmt"
"net/url"
"strings"
"github.com/go-resty/resty/v2"
)
// BranchIDGen used to generate a sub branch id
type BranchIDGen struct {
BranchID string
subBranchID int
}
// NewSubBranchID generate a sub branch id
func (g *BranchIDGen) NewSubBranchID() string {
if g.subBranchID >= 99 {
panic(fmt.Errorf("branch id is larger than 99"))
}
if len(g.BranchID) >= 20 {
panic(fmt.Errorf("total branch id is longer than 20"))
}
g.subBranchID = g.subBranchID + 1
return g.CurrentSubBranchID()
}
// CurrentSubBranchID return current branchID
func (g *BranchIDGen) CurrentSubBranchID() string {
return g.BranchID + fmt.Sprintf("%02d", g.subBranchID)
}
// TransOptions transaction options
type TransOptions struct {
WaitResult bool `json:"wait_result,omitempty" gorm:"-"`
TimeoutToFail int64 `json:"timeout_to_fail,omitempty" gorm:"-"` // for trans type: xa, tcc
RetryInterval int64 `json:"retry_interval,omitempty" gorm:"-"` // for trans type: msg saga xa tcc
}
// TransBase base for all trans
type TransBase struct {
Gid string `json:"gid"`
TransType string `json:"trans_type"`
Dtm string `json:"-"`
CustomData string `json:"custom_data,omitempty"`
TransOptions
Steps []map[string]string `json:"steps,omitempty"` // use in MSG/SAGA
Payloads []string `json:"payloads,omitempty"` // used in MSG/SAGA
BinPayloads [][]byte `json:"-"`
BranchIDGen `json:"-"` // used in XA/TCC
BranchType string `json:"-"` // used in XA/TCC
QueryPrepared string `json:"query_prepared"` // used in MSG
}
// SetOptions set options
func (tb *TransBase) SetOptions(options *TransOptions) {
tb.TransOptions = *options
}
// NewTransBase new a TransBase
func NewTransBase(gid string, transType string, dtm string, branchID string) *TransBase {
return &TransBase{
Gid: gid,
TransType: transType,
BranchIDGen: BranchIDGen{BranchID: branchID},
Dtm: dtm,
}
}
// TransBaseFromQuery construct transaction info from request
func TransBaseFromQuery(qs url.Values) *TransBase {
return NewTransBase(qs.Get("gid"), qs.Get("trans_type"), qs.Get("dtm"), qs.Get("branch_id"))
}
// TransCallDtm TransBase call dtm
func TransCallDtm(tb *TransBase, body interface{}, operation string) error {
resp, err := RestyClient.R().
SetBody(body).Post(fmt.Sprintf("%s/%s", tb.Dtm, operation))
if err != nil {
return err
}
if !strings.Contains(resp.String(), ResultSuccess) {
return errors.New(resp.String())
}
return nil
}
// TransRegisterBranch TransBase register a branch to dtm
func TransRegisterBranch(tb *TransBase, added map[string]string, operation string) error {
m := map[string]string{
"gid": tb.Gid,
"trans_type": tb.TransType,
}
for k, v := range added {
m[k] = v
}
return TransCallDtm(tb, m, operation)
}
// TransRequestBranch TransBAse request branch result
func TransRequestBranch(t *TransBase, body interface{}, branchID string, branchType string, url string) (*resty.Response, error) {
resp, err := RestyClient.R().
SetBody(body).
SetQueryParams(map[string]string{
"dtm": t.Dtm,
"gid": t.Gid,
"branch_id": branchID,
"trans_type": t.TransType,
"branch_type": branchType,
}).
Post(url)
return resp, CheckResponse(resp, err)
}

9
dtmcli/xa_base.go → dtmcli/dtmimp/trans_xa_base.go

@ -1,4 +1,4 @@
package dtmcli
package dtmimp
import (
"database/sql"
@ -29,9 +29,8 @@ func (xc *XaClientBase) HandleCallback(gid string, branchID string, action strin
}
// HandleLocalTrans http/grpc 处理LocalTransaction的公共方法
func (xc *XaClientBase) HandleLocalTrans(xa *TransBase, cb func(*sql.DB) (interface{}, error)) (ret interface{}, rerr error) {
branchID := xa.NewBranchID()
xaBranch := xa.Gid + "-" + branchID
func (xc *XaClientBase) HandleLocalTrans(xa *TransBase, cb func(*sql.DB) error) (rerr error) {
xaBranch := xa.Gid + "-" + xa.BranchID
db, rerr := StandaloneDB(xc.Conf)
if rerr != nil {
return
@ -54,7 +53,7 @@ func (xc *XaClientBase) HandleLocalTrans(xa *TransBase, cb func(*sql.DB) (interf
if rerr != nil {
return
}
ret, rerr = cb(db)
rerr = cb(db)
return
}

6
dtmcli/adapter.go → dtmcli/dtmimp/types.go

@ -1,8 +1,6 @@
package dtmcli
package dtmimp
import (
"database/sql"
)
import "database/sql"
// DB inteface of dtmcli db
type DB interface {

19
dtmcli/dtmimp/types_test.go

@ -0,0 +1,19 @@
package dtmimp
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestTypes(t *testing.T) {
err := CatchP(func() {
idGen := BranchIDGen{BranchID: "12345678901234567890123"}
idGen.NewSubBranchID()
})
assert.Error(t, err)
err = CatchP(func() {
idGen := BranchIDGen{subBranchID: 99}
idGen.NewSubBranchID()
})
}

34
dtmcli/utils.go → dtmcli/dtmimp/utils.go

@ -1,4 +1,4 @@
package dtmcli
package dtmimp
import (
"database/sql"
@ -19,6 +19,7 @@ import (
// AsError wrap a panic value as an error
func AsError(x interface{}) error {
LogRedf("panic to error: '%v', stack: \n%s", x, debug.Stack())
if e, ok := x.(error); ok {
return e
}
@ -111,7 +112,7 @@ func MustRemarshal(from interface{}, to interface{}) {
E2P(err)
}
var layout = "2006-01-02 15:04:05.999"
var layout = "2006/01/02 15:04:05.999"
// Logf 输出日志
func Logf(format string, args ...interface{}) {
@ -157,29 +158,11 @@ func FatalIfError(err error) {
LogIfFatalf(err != nil, "Fatal error: %v", err)
}
// RestyClient the resty object
var RestyClient = resty.New()
func init() {
// RestyClient.SetTimeout(3 * time.Second)
// RestyClient.SetRetryCount(2)
// RestyClient.SetRetryWaitTime(1 * time.Second)
RestyClient.OnBeforeRequest(func(c *resty.Client, r *resty.Request) error {
r.URL = MayReplaceLocalhost(r.URL)
Logf("requesting: %s %s %v %v", r.Method, r.URL, r.Body, r.QueryParam)
return nil
})
RestyClient.OnAfterResponse(func(c *resty.Client, resp *resty.Response) error {
r := resp.Request
Logf("requested: %s %s %s", r.Method, r.URL, resp.String())
return nil
})
}
// GetFuncName get current call func name
func GetFuncName() string {
pc, _, _, _ := runtime.Caller(1)
return runtime.FuncForPC(pc).Name()
nm := runtime.FuncForPC(pc).Name()
return nm[strings.LastIndex(nm, ".")+1:]
}
// MayReplaceLocalhost when run in docker compose, change localhost to host.docker.internal for accessing host network
@ -234,7 +217,7 @@ func DBExec(db DB, sql string, values ...interface{}) (affected int64, rerr erro
func GetDsn(conf map[string]string) string {
host := MayReplaceLocalhost(conf["host"])
driver := conf["driver"]
dsn := MS{
dsn := map[string]string{
"mysql": fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=true&loc=Local",
conf["user"], conf["password"], host, conf["port"], conf["database"]),
"postgres": fmt.Sprintf("host=%s user=%s password=%s dbname='%s' port=%s sslmode=disable TimeZone=Asia/Shanghai",
@ -251,6 +234,8 @@ func CheckResponse(resp *resty.Response, err error) error {
return errors.New(resp.String())
} else if strings.Contains(resp.String(), ResultFailure) {
return ErrFailure
} else if strings.Contains(resp.String(), ResultOngoing) {
return ErrOngoing
}
}
return err
@ -258,6 +243,9 @@ func CheckResponse(resp *resty.Response, err error) error {
// CheckResult 检查Result,返回错误
func CheckResult(res interface{}, err error) error {
if err != nil {
return err
}
resp, ok := res.(*resty.Response)
if ok {
return CheckResponse(resp, err)

2
dtmcli/utils_test.go → dtmcli/dtmimp/utils_test.go

@ -1,4 +1,4 @@
package dtmcli
package dtmimp
import (
"errors"

38
dtmcli/dtmimp/vars.go

@ -0,0 +1,38 @@
package dtmimp
import (
"errors"
"github.com/go-resty/resty/v2"
)
// ErrFailure error of FAILURE
var ErrFailure = errors.New("FAILURE")
// ErrOngoing error of ONGOING
var ErrOngoing = errors.New("ONGOING")
// MapSuccess HTTP result of SUCCESS
var MapSuccess = map[string]interface{}{"dtm_result": ResultSuccess}
// MapFailure HTTP result of FAILURE
var MapFailure = map[string]interface{}{"dtm_result": ResultFailure}
// RestyClient the resty object
var RestyClient = resty.New()
func init() {
// RestyClient.SetTimeout(3 * time.Second)
// RestyClient.SetRetryCount(2)
// RestyClient.SetRetryWaitTime(1 * time.Second)
RestyClient.OnBeforeRequest(func(c *resty.Client, r *resty.Request) error {
r.URL = MayReplaceLocalhost(r.URL)
Logf("requesting: %s %s %v %v", r.Method, r.URL, r.Body, r.QueryParam)
return nil
})
RestyClient.OnAfterResponse(func(c *resty.Client, resp *resty.Response) error {
r := resp.Request
Logf("requested: %s %s %s", r.Method, r.URL, resp.String())
return nil
})
}

39
dtmcli/message.go

@ -1,39 +0,0 @@
package dtmcli
// Msg reliable msg type
type Msg struct {
TransBase
Steps []MsgStep `json:"steps"`
QueryPrepared string `json:"query_prepared"`
}
// MsgStep struct of one step msg
type MsgStep struct {
Action string `json:"action"`
Data string `json:"data"`
}
// NewMsg create new msg
func NewMsg(server string, gid string) *Msg {
return &Msg{TransBase: *NewTransBase(gid, "msg", server, "")}
}
// Add add a new step
func (s *Msg) Add(action string, postData interface{}) *Msg {
s.Steps = append(s.Steps, MsgStep{
Action: action,
Data: MustMarshalString(postData),
})
return s
}
// Prepare prepare the msg
func (s *Msg) Prepare(queryPrepared string) error {
s.QueryPrepared = OrString(queryPrepared, s.QueryPrepared)
return s.callDtm(s, "prepare")
}
// Submit submit the msg
func (s *Msg) Submit() error {
return s.callDtm(s, "submit")
}

31
dtmcli/msg.go

@ -0,0 +1,31 @@
package dtmcli
import "github.com/yedf/dtm/dtmcli/dtmimp"
// Msg reliable msg type
type Msg struct {
dtmimp.TransBase
}
// NewMsg create new msg
func NewMsg(server string, gid string) *Msg {
return &Msg{TransBase: *dtmimp.NewTransBase(gid, "msg", server, "")}
}
// Add add a new step
func (s *Msg) Add(action string, postData interface{}) *Msg {
s.Steps = append(s.Steps, map[string]string{"action": action})
s.Payloads = append(s.Payloads, dtmimp.MustMarshalString(postData))
return s
}
// Prepare prepare the msg, msg will later be submitted
func (s *Msg) Prepare(queryPrepared string) error {
s.QueryPrepared = dtmimp.OrString(queryPrepared, s.QueryPrepared)
return dtmimp.TransCallDtm(&s.TransBase, s, "prepare")
}
// Submit submit the msg
func (s *Msg) Submit() error {
return dtmimp.TransCallDtm(&s.TransBase, s, "submit")
}

28
dtmcli/saga.go

@ -1,40 +1,30 @@
package dtmcli
import "fmt"
import (
"github.com/yedf/dtm/dtmcli/dtmimp"
)
// Saga struct of saga
type Saga struct {
TransBase
Steps []SagaStep `json:"steps"`
dtmimp.TransBase
orders map[int][]int
concurrent bool
}
// SagaStep one step of saga
type SagaStep struct {
Action string `json:"action"`
Compensate string `json:"compensate"`
Data string `json:"data"`
}
// NewSaga create a saga
func NewSaga(server string, gid string) *Saga {
return &Saga{TransBase: *NewTransBase(gid, "saga", server, ""), orders: map[int][]int{}}
return &Saga{TransBase: *dtmimp.NewTransBase(gid, "saga", server, ""), orders: map[int][]int{}}
}
// Add add a saga step
func (s *Saga) Add(action string, compensate string, postData interface{}) *Saga {
s.Steps = append(s.Steps, SagaStep{
Action: action,
Compensate: compensate,
Data: MustMarshalString(postData),
})
s.Steps = append(s.Steps, map[string]string{"action": action, "compensate": compensate})
s.Payloads = append(s.Payloads, dtmimp.MustMarshalString(postData))
return s
}
// AddBranchOrder specify that branch should be after preBranches. branch should is larger than all the element in preBranches
func (s *Saga) AddBranchOrder(branch int, preBranches []int) *Saga {
PanicIf(branch > len(s.Steps), fmt.Errorf("step value: %d is invalid. which cannot be larger than total steps: %d", branch, len(s.Steps)))
s.orders[branch] = preBranches
return s
}
@ -48,7 +38,7 @@ func (s *Saga) EnableConcurrent() *Saga {
// Submit submit the saga trans
func (s *Saga) Submit() error {
if s.concurrent {
s.CustomData = MustMarshalString(M{"orders": s.orders, "concurrent": s.concurrent})
s.CustomData = dtmimp.MustMarshalString(map[string]interface{}{"orders": s.orders, "concurrent": s.concurrent})
}
return s.callDtm(s, "submit")
return dtmimp.TransCallDtm(&s.TransBase, s, "submit")
}

40
dtmcli/tcc.go

@ -5,11 +5,12 @@ import (
"net/url"
"github.com/go-resty/resty/v2"
"github.com/yedf/dtm/dtmcli/dtmimp"
)
// Tcc struct of tcc
type Tcc struct {
TransBase
dtmimp.TransBase
}
// TccGlobalFunc type of global tcc call
@ -20,16 +21,16 @@ type TccGlobalFunc func(tcc *Tcc) (*resty.Response, error)
// gid 全局事务id
// tccFunc tcc事务函数,里面会定义全局事务的分支
func TccGlobalTransaction(dtm string, gid string, tccFunc TccGlobalFunc) (rerr error) {
tcc := &Tcc{TransBase: *NewTransBase(gid, "tcc", dtm, "")}
rerr = tcc.callDtm(tcc, "prepare")
tcc := &Tcc{TransBase: *dtmimp.NewTransBase(gid, "tcc", dtm, "")}
rerr = dtmimp.TransCallDtm(&tcc.TransBase, tcc, "prepare")
if rerr != nil {
return rerr
}
// 小概率情况下,prepare成功了,但是由于网络状况导致上面Failure,那么不执行下面defer的内容,等待超时后再回滚标记事务失败,也没有问题
defer func() {
x := recover()
operation := If(x == nil && rerr == nil, "submit", "abort").(string)
err := tcc.callDtm(tcc, operation)
operation := dtmimp.If(x == nil && rerr == nil, "submit", "abort").(string)
err := dtmimp.TransCallDtm(&tcc.TransBase, tcc, operation)
if rerr == nil {
rerr = err
}
@ -37,16 +38,15 @@ func TccGlobalTransaction(dtm string, gid string, tccFunc TccGlobalFunc) (rerr e
panic(x)
}
}()
resp, rerr := tccFunc(tcc)
rerr = CheckResponse(resp, rerr)
_, rerr = tccFunc(tcc)
return
}
// TccFromQuery tcc from request info
func TccFromQuery(qs url.Values) (*Tcc, error) {
tcc := &Tcc{TransBase: *TransBaseFromQuery(qs)}
tcc := &Tcc{TransBase: *dtmimp.TransBaseFromQuery(qs)}
if tcc.Dtm == "" || tcc.Gid == "" {
return nil, fmt.Errorf("bad tcc info. dtm: %s, gid: %s parentID: %s", tcc.Dtm, tcc.Gid, tcc.parentID)
return nil, fmt.Errorf("bad tcc info. dtm: %s, gid: %s parentID: %s", tcc.Dtm, tcc.Gid, tcc.BranchID)
}
return tcc, nil
}
@ -54,28 +54,16 @@ func TccFromQuery(qs url.Values) (*Tcc, error) {
// CallBranch call a tcc branch
// 函数首先注册子事务的所有分支,成功后调用try分支,返回try分支的调用结果
func (t *Tcc) CallBranch(body interface{}, tryURL string, confirmURL string, cancelURL string) (*resty.Response, error) {
branchID := t.NewBranchID()
err := t.callDtm(&M{
"gid": t.Gid,
branchID := t.NewSubBranchID()
err := dtmimp.TransRegisterBranch(&t.TransBase, map[string]string{
"data": dtmimp.MustMarshalString(body),
"branch_id": branchID,
"trans_type": "tcc",
"data": string(MustMarshal(body)),
BranchTry: tryURL,
BranchConfirm: confirmURL,
"cancel": cancelURL,
BranchCancel: cancelURL,
}, "registerTccBranch")
if err != nil {
return nil, err
}
resp, err := RestyClient.R().
SetBody(body).
SetQueryParams(MS{
"dtm": t.Dtm,
"gid": t.Gid,
"branch_id": branchID,
"trans_type": "tcc",
"branch_type": BranchTry,
}).
Post(tryURL)
return resp, CheckResponse(resp, err)
return dtmimp.TransRequestBranch(&t.TransBase, body, branchID, BranchTry, tryURL)
}

2
dtmcli/trans_test.go

@ -19,6 +19,6 @@ func TestQuery(t *testing.T) {
}
func TestXa(t *testing.T) {
_, err := NewXaClient("http://localhost:8080", MS{}, ":::::", nil)
_, err := NewXaClient("http://localhost:8080", map[string]string{}, ":::::", nil)
assert.Error(t, err)
}

104
dtmcli/types.go

@ -1,109 +1,33 @@
package dtmcli
import (
"errors"
"fmt"
"net/url"
"strings"
)
// M a short name
type M = map[string]interface{}
// MS a short name
type MS = map[string]string
"github.com/yedf/dtm/dtmcli/dtmimp"
)
// MustGenGid generate a new gid
func MustGenGid(server string) string {
res := MS{}
resp, err := RestyClient.R().SetResult(&res).Get(server + "/newGid")
res := map[string]string{}
resp, err := dtmimp.RestyClient.R().SetResult(&res).Get(server + "/newGid")
if err != nil || res["gid"] == "" {
panic(fmt.Errorf("newGid error: %v, resp: %s", err, resp))
}
return res["gid"]
}
// IDGenerator used to generate a branch id
type IDGenerator struct {
parentID string
branchID int
}
// NewBranchID generate a branch id
func (g *IDGenerator) NewBranchID() string {
if g.branchID >= 99 {
panic(fmt.Errorf("branch id is larger than 99"))
}
if len(g.parentID) >= 20 {
panic(fmt.Errorf("total branch id is longer than 20"))
}
g.branchID = g.branchID + 1
return g.CurrentBranchID()
}
// CurrentBranchID return current branchID
func (g *IDGenerator) CurrentBranchID() string {
return g.parentID + fmt.Sprintf("%02d", g.branchID)
}
// TransOptions transaction options
type TransOptions struct {
WaitResult bool `json:"wait_result,omitempty" gorm:"-"`
TimeoutToFail int64 `json:"timeout_to_fail,omitempty" gorm:"-"` // for trans type: xa, tcc
RetryInterval int64 `json:"retry_interval,omitempty" gorm:"-"` // for trans type: msg saga xa tcc
}
// TransBase 事务的基础类
type TransBase struct {
Gid string `json:"gid"`
TransType string `json:"trans_type"`
Dtm string `json:"-"`
CustomData string `json:"custom_data,omitempty"`
IDGenerator
TransOptions
}
// SetOptions set options
func (tb *TransBase) SetOptions(options *TransOptions) {
tb.TransOptions = *options
}
// DB interface
type DB = dtmimp.DB
// NewTransBase 1
func NewTransBase(gid string, transType string, dtm string, parentID string) *TransBase {
return &TransBase{
Gid: gid,
TransType: transType,
IDGenerator: IDGenerator{parentID: parentID},
Dtm: dtm,
}
}
// Tx interface
type Tx = dtmimp.Tx
// TransBaseFromQuery construct transaction info from request
func TransBaseFromQuery(qs url.Values) *TransBase {
return NewTransBase(qs.Get("gid"), qs.Get("trans_type"), qs.Get("dtm"), qs.Get("branch_id"))
// SetCurrentDBType set currentDBType
func SetCurrentDBType(dbType string) {
dtmimp.SetCurrentDBType(dbType)
}
// callDtm 调用dtm服务器,返回事务的状态
func (tb *TransBase) callDtm(body interface{}, operation string) error {
resp, err := RestyClient.R().
SetBody(body).Post(fmt.Sprintf("%s/%s", tb.Dtm, operation))
if err != nil {
return err
}
if strings.Contains(resp.String(), ResultFailure) {
return errors.New(resp.String())
}
return nil
// GetCurrentDBType get currentDBType
func GetCurrentDBType() string {
return dtmimp.GetCurrentDBType()
}
// ErrFailure 表示返回失败,要求回滚
var ErrFailure = errors.New("FAILURE")
// ErrOngoing 表示暂时失败,要求重试
var ErrOngoing = errors.New("ONGOING")
// MapSuccess 表示返回成功,可以进行下一步
var MapSuccess = M{"dtm_result": ResultSuccess}
// MapFailure 表示返回失败,要求回滚
var MapFailure = M{"dtm_result": ResultFailure}

12
dtmcli/types_test.go

@ -5,19 +5,11 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/dtmcli/dtmimp"
)
func TestTypes(t *testing.T) {
err := CatchP(func() {
idGen := IDGenerator{parentID: "12345678901234567890123"}
idGen.NewBranchID()
})
assert.Error(t, err)
err = CatchP(func() {
idGen := IDGenerator{branchID: 99}
idGen.NewBranchID()
})
err = CatchP(func() {
err := dtmimp.CatchP(func() {
MustGenGid("http://localhost:8080/api/no")
})
assert.Error(t, err)

61
dtmcli/xa.go

@ -6,39 +6,40 @@ import (
"net/url"
"github.com/go-resty/resty/v2"
"github.com/yedf/dtm/dtmcli/dtmimp"
)
// XaGlobalFunc type of xa global function
type XaGlobalFunc func(xa *Xa) (*resty.Response, error)
// XaLocalFunc type of xa local function
type XaLocalFunc func(db *sql.DB, xa *Xa) (interface{}, error)
type XaLocalFunc func(db *sql.DB, xa *Xa) error
// XaRegisterCallback type of xa register callback handler
type XaRegisterCallback func(path string, xa *XaClient)
// XaClient xa client
type XaClient struct {
XaClientBase
dtmimp.XaClientBase
}
// Xa xa transaction
type Xa struct {
TransBase
dtmimp.TransBase
}
// XaFromQuery construct xa info from request
func XaFromQuery(qs url.Values) (*Xa, error) {
xa := &Xa{TransBase: *TransBaseFromQuery(qs)}
if xa.Gid == "" || xa.parentID == "" {
return nil, fmt.Errorf("bad xa info: gid: %s parentid: %s", xa.Gid, xa.parentID)
xa := &Xa{TransBase: *dtmimp.TransBaseFromQuery(qs)}
if xa.Gid == "" || xa.BranchID == "" {
return nil, fmt.Errorf("bad xa info: gid: %s branchid: %s", xa.Gid, xa.BranchID)
}
return xa, nil
}
// NewXaClient construct a xa client
func NewXaClient(server string, mysqlConf map[string]string, notifyURL string, register XaRegisterCallback) (*XaClient, error) {
xa := &XaClient{XaClientBase: XaClientBase{
xa := &XaClient{XaClientBase: dtmimp.XaClientBase{
Server: server,
Conf: mysqlConf,
NotifyURL: notifyURL,
@ -57,46 +58,36 @@ func (xc *XaClient) HandleCallback(gid string, branchID string, action string) (
}
// XaLocalTransaction start a xa local transaction
func (xc *XaClient) XaLocalTransaction(qs url.Values, xaFunc XaLocalFunc) (ret interface{}, rerr error) {
xa, rerr := XaFromQuery(qs)
if rerr != nil {
return
func (xc *XaClient) XaLocalTransaction(qs url.Values, xaFunc XaLocalFunc) error {
xa, err := XaFromQuery(qs)
if err != nil {
return err
}
ret, rerr = xc.HandleLocalTrans(&xa.TransBase, func(db *sql.DB) (ret interface{}, rerr error) {
ret, rerr = xaFunc(db, xa)
rerr = CheckResult(ret, rerr)
if rerr != nil {
return
return xc.HandleLocalTrans(&xa.TransBase, func(db *sql.DB) error {
err := xaFunc(db, xa)
if err != nil {
return err
}
rerr = xa.callDtm(&M{"gid": xa.Gid, "branch_id": xa.CurrentBranchID(), "trans_type": "xa", "url": xc.XaClientBase.NotifyURL}, "registerXaBranch")
return
return dtmimp.TransRegisterBranch(&xa.TransBase, map[string]string{
"url": xc.XaClientBase.NotifyURL,
"branch_id": xa.BranchID,
}, "registerXaBranch")
})
return
}
// XaGlobalTransaction start a xa global transaction
func (xc *XaClient) XaGlobalTransaction(gid string, xaFunc XaGlobalFunc) (rerr error) {
xa := Xa{TransBase: *NewTransBase(gid, "xa", xc.XaClientBase.Server, "")}
xa := Xa{TransBase: *dtmimp.NewTransBase(gid, "xa", xc.XaClientBase.Server, "")}
return xc.HandleGlobalTrans(&xa.TransBase, func(action string) error {
return xa.callDtm(xa, action)
return dtmimp.TransCallDtm(&xa.TransBase, &xa, action)
}, func() error {
resp, rerr := xaFunc(&xa)
return CheckResponse(resp, rerr)
_, rerr := xaFunc(&xa)
return rerr
})
}
// CallBranch call a xa branch
func (x *Xa) CallBranch(body interface{}, url string) (*resty.Response, error) {
branchID := x.NewBranchID()
resp, err := RestyClient.R().
SetBody(body).
SetQueryParams(MS{
"dtm": x.Dtm,
"gid": x.Gid,
"branch_id": branchID,
"trans_type": "xa",
"branch_type": BranchAction,
}).
Post(url)
return resp, CheckResponse(resp, err)
branchID := x.NewSubBranchID()
return dtmimp.TransRequestBranch(&x.TransBase, body, branchID, BranchAction, url)
}

18
dtmgrpc/barrier.go

@ -1,18 +1,14 @@
package dtmgrpc
import (
"context"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmgrpc/dtmgimp"
)
// BranchBarrier 子事务屏障
type BranchBarrier struct {
*dtmcli.BranchBarrier
}
// BarrierFromGrpc 从BusiRequest生成一个Barrier
func BarrierFromGrpc(in *BusiRequest) (*BranchBarrier, error) {
b, err := dtmcli.BarrierFrom(in.Info.TransType, in.Info.Gid, in.Info.BranchID, in.Info.BranchType)
return &BranchBarrier{
BranchBarrier: b,
}, err
// BarrierFromGrpc generate a Barrier from grpc context
func BarrierFromGrpc(ctx context.Context) (*dtmcli.BranchBarrier, error) {
tb := dtmgimp.TransBaseFromGrpc(ctx)
return dtmcli.BarrierFrom(tb.TransType, tb.Gid, tb.BranchID, tb.BranchType)
}

674
dtmgrpc/dtmgimp/dtmgimp.pb.go

@ -0,0 +1,674 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.27.1
// protoc v3.17.3
// source: dtmgrpc/dtmgimp/dtmgimp.proto
package dtmgimp
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
emptypb "google.golang.org/protobuf/types/known/emptypb"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type DtmTransOptions struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
WaitResult bool `protobuf:"varint,1,opt,name=WaitResult,proto3" json:"WaitResult,omitempty"`
TimeoutToFail int64 `protobuf:"varint,2,opt,name=TimeoutToFail,proto3" json:"TimeoutToFail,omitempty"`
RetryInterval int64 `protobuf:"varint,3,opt,name=RetryInterval,proto3" json:"RetryInterval,omitempty"`
}
func (x *DtmTransOptions) Reset() {
*x = DtmTransOptions{}
if protoimpl.UnsafeEnabled {
mi := &file_dtmgrpc_dtmgimp_dtmgimp_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DtmTransOptions) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DtmTransOptions) ProtoMessage() {}
func (x *DtmTransOptions) ProtoReflect() protoreflect.Message {
mi := &file_dtmgrpc_dtmgimp_dtmgimp_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DtmTransOptions.ProtoReflect.Descriptor instead.
func (*DtmTransOptions) Descriptor() ([]byte, []int) {
return file_dtmgrpc_dtmgimp_dtmgimp_proto_rawDescGZIP(), []int{0}
}
func (x *DtmTransOptions) GetWaitResult() bool {
if x != nil {
return x.WaitResult
}
return false
}
func (x *DtmTransOptions) GetTimeoutToFail() int64 {
if x != nil {
return x.TimeoutToFail
}
return 0
}
func (x *DtmTransOptions) GetRetryInterval() int64 {
if x != nil {
return x.RetryInterval
}
return 0
}
// DtmRequest request sent to dtm server
type DtmRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Gid string `protobuf:"bytes,1,opt,name=Gid,proto3" json:"Gid,omitempty"`
TransType string `protobuf:"bytes,2,opt,name=TransType,proto3" json:"TransType,omitempty"`
TransOptions *DtmTransOptions `protobuf:"bytes,3,opt,name=TransOptions,proto3" json:"TransOptions,omitempty"`
CustomedData string `protobuf:"bytes,4,opt,name=CustomedData,proto3" json:"CustomedData,omitempty"`
BinPayloads [][]byte `protobuf:"bytes,5,rep,name=BinPayloads,proto3" json:"BinPayloads,omitempty"` // for MSG/SAGA branch payloads
QueryPrepared string `protobuf:"bytes,6,opt,name=QueryPrepared,proto3" json:"QueryPrepared,omitempty"` // for MSG
Steps string `protobuf:"bytes,7,opt,name=Steps,proto3" json:"Steps,omitempty"`
}
func (x *DtmRequest) Reset() {
*x = DtmRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_dtmgrpc_dtmgimp_dtmgimp_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DtmRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DtmRequest) ProtoMessage() {}
func (x *DtmRequest) ProtoReflect() protoreflect.Message {
mi := &file_dtmgrpc_dtmgimp_dtmgimp_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DtmRequest.ProtoReflect.Descriptor instead.
func (*DtmRequest) Descriptor() ([]byte, []int) {
return file_dtmgrpc_dtmgimp_dtmgimp_proto_rawDescGZIP(), []int{1}
}
func (x *DtmRequest) GetGid() string {
if x != nil {
return x.Gid
}
return ""
}
func (x *DtmRequest) GetTransType() string {
if x != nil {
return x.TransType
}
return ""
}
func (x *DtmRequest) GetTransOptions() *DtmTransOptions {
if x != nil {
return x.TransOptions
}
return nil
}
func (x *DtmRequest) GetCustomedData() string {
if x != nil {
return x.CustomedData
}
return ""
}
func (x *DtmRequest) GetBinPayloads() [][]byte {
if x != nil {
return x.BinPayloads
}
return nil
}
func (x *DtmRequest) GetQueryPrepared() string {
if x != nil {
return x.QueryPrepared
}
return ""
}
func (x *DtmRequest) GetSteps() string {
if x != nil {
return x.Steps
}
return ""
}
type DtmGidReply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Gid string `protobuf:"bytes,1,opt,name=Gid,proto3" json:"Gid,omitempty"`
}
func (x *DtmGidReply) Reset() {
*x = DtmGidReply{}
if protoimpl.UnsafeEnabled {
mi := &file_dtmgrpc_dtmgimp_dtmgimp_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DtmGidReply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DtmGidReply) ProtoMessage() {}
func (x *DtmGidReply) ProtoReflect() protoreflect.Message {
mi := &file_dtmgrpc_dtmgimp_dtmgimp_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DtmGidReply.ProtoReflect.Descriptor instead.
func (*DtmGidReply) Descriptor() ([]byte, []int) {
return file_dtmgrpc_dtmgimp_dtmgimp_proto_rawDescGZIP(), []int{2}
}
func (x *DtmGidReply) GetGid() string {
if x != nil {
return x.Gid
}
return ""
}
type DtmBranchInfo struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Gid string `protobuf:"bytes,1,opt,name=Gid,proto3" json:"Gid,omitempty"`
TransType string `protobuf:"bytes,2,opt,name=TransType,proto3" json:"TransType,omitempty"`
BranchID string `protobuf:"bytes,3,opt,name=BranchID,proto3" json:"BranchID,omitempty"`
BranchType string `protobuf:"bytes,4,opt,name=BranchType,proto3" json:"BranchType,omitempty"`
}
func (x *DtmBranchInfo) Reset() {
*x = DtmBranchInfo{}
if protoimpl.UnsafeEnabled {
mi := &file_dtmgrpc_dtmgimp_dtmgimp_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DtmBranchInfo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DtmBranchInfo) ProtoMessage() {}
func (x *DtmBranchInfo) ProtoReflect() protoreflect.Message {
mi := &file_dtmgrpc_dtmgimp_dtmgimp_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DtmBranchInfo.ProtoReflect.Descriptor instead.
func (*DtmBranchInfo) Descriptor() ([]byte, []int) {
return file_dtmgrpc_dtmgimp_dtmgimp_proto_rawDescGZIP(), []int{3}
}
func (x *DtmBranchInfo) GetGid() string {
if x != nil {
return x.Gid
}
return ""
}
func (x *DtmBranchInfo) GetTransType() string {
if x != nil {
return x.TransType
}
return ""
}
func (x *DtmBranchInfo) GetBranchID() string {
if x != nil {
return x.BranchID
}
return ""
}
func (x *DtmBranchInfo) GetBranchType() string {
if x != nil {
return x.BranchType
}
return ""
}
type DtmTccBranchRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Info *DtmBranchInfo `protobuf:"bytes,1,opt,name=Info,proto3" json:"Info,omitempty"`
BusiPayload []byte `protobuf:"bytes,2,opt,name=BusiPayload,proto3" json:"BusiPayload,omitempty"`
Try string `protobuf:"bytes,3,opt,name=Try,proto3" json:"Try,omitempty"`
Confirm string `protobuf:"bytes,4,opt,name=Confirm,proto3" json:"Confirm,omitempty"`
Cancel string `protobuf:"bytes,5,opt,name=Cancel,proto3" json:"Cancel,omitempty"`
}
func (x *DtmTccBranchRequest) Reset() {
*x = DtmTccBranchRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_dtmgrpc_dtmgimp_dtmgimp_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DtmTccBranchRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DtmTccBranchRequest) ProtoMessage() {}
func (x *DtmTccBranchRequest) ProtoReflect() protoreflect.Message {
mi := &file_dtmgrpc_dtmgimp_dtmgimp_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DtmTccBranchRequest.ProtoReflect.Descriptor instead.
func (*DtmTccBranchRequest) Descriptor() ([]byte, []int) {
return file_dtmgrpc_dtmgimp_dtmgimp_proto_rawDescGZIP(), []int{4}
}
func (x *DtmTccBranchRequest) GetInfo() *DtmBranchInfo {
if x != nil {
return x.Info
}
return nil
}
func (x *DtmTccBranchRequest) GetBusiPayload() []byte {
if x != nil {
return x.BusiPayload
}
return nil
}
func (x *DtmTccBranchRequest) GetTry() string {
if x != nil {
return x.Try
}
return ""
}
func (x *DtmTccBranchRequest) GetConfirm() string {
if x != nil {
return x.Confirm
}
return ""
}
func (x *DtmTccBranchRequest) GetCancel() string {
if x != nil {
return x.Cancel
}
return ""
}
type DtmXaBranchRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Info *DtmBranchInfo `protobuf:"bytes,1,opt,name=Info,proto3" json:"Info,omitempty"`
BusiPayload []byte `protobuf:"bytes,2,opt,name=BusiPayload,proto3" json:"BusiPayload,omitempty"`
Notify string `protobuf:"bytes,3,opt,name=Notify,proto3" json:"Notify,omitempty"` // dtm will call this url to commit/rollback
}
func (x *DtmXaBranchRequest) Reset() {
*x = DtmXaBranchRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_dtmgrpc_dtmgimp_dtmgimp_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DtmXaBranchRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DtmXaBranchRequest) ProtoMessage() {}
func (x *DtmXaBranchRequest) ProtoReflect() protoreflect.Message {
mi := &file_dtmgrpc_dtmgimp_dtmgimp_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DtmXaBranchRequest.ProtoReflect.Descriptor instead.
func (*DtmXaBranchRequest) Descriptor() ([]byte, []int) {
return file_dtmgrpc_dtmgimp_dtmgimp_proto_rawDescGZIP(), []int{5}
}
func (x *DtmXaBranchRequest) GetInfo() *DtmBranchInfo {
if x != nil {
return x.Info
}
return nil
}
func (x *DtmXaBranchRequest) GetBusiPayload() []byte {
if x != nil {
return x.BusiPayload
}
return nil
}
func (x *DtmXaBranchRequest) GetNotify() string {
if x != nil {
return x.Notify
}
return ""
}
var File_dtmgrpc_dtmgimp_dtmgimp_proto protoreflect.FileDescriptor
var file_dtmgrpc_dtmgimp_dtmgimp_proto_rawDesc = []byte{
0x0a, 0x1d, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x64, 0x74, 0x6d, 0x67, 0x69, 0x6d,
0x70, 0x2f, 0x64, 0x74, 0x6d, 0x67, 0x69, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
0x07, 0x64, 0x74, 0x6d, 0x67, 0x69, 0x6d, 0x70, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x7d, 0x0a, 0x0f, 0x44, 0x74, 0x6d, 0x54, 0x72, 0x61, 0x6e,
0x73, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x57, 0x61, 0x69, 0x74,
0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x57, 0x61,
0x69, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x54, 0x69, 0x6d, 0x65,
0x6f, 0x75, 0x74, 0x54, 0x6f, 0x46, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52,
0x0d, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x54, 0x6f, 0x46, 0x61, 0x69, 0x6c, 0x12, 0x24,
0x0a, 0x0d, 0x52, 0x65, 0x74, 0x72, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18,
0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x52, 0x65, 0x74, 0x72, 0x79, 0x49, 0x6e, 0x74, 0x65,
0x72, 0x76, 0x61, 0x6c, 0x22, 0xfc, 0x01, 0x0a, 0x0a, 0x44, 0x74, 0x6d, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x47, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x03, 0x47, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x54, 0x79,
0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x54,
0x79, 0x70, 0x65, 0x12, 0x3c, 0x0a, 0x0c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x4f, 0x70, 0x74, 0x69,
0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x64, 0x74, 0x6d, 0x67,
0x69, 0x6d, 0x70, 0x2e, 0x44, 0x74, 0x6d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x4f, 0x70, 0x74, 0x69,
0x6f, 0x6e, 0x73, 0x52, 0x0c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e,
0x73, 0x12, 0x22, 0x0a, 0x0c, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x65, 0x64, 0x44, 0x61, 0x74,
0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x65,
0x64, 0x44, 0x61, 0x74, 0x61, 0x12, 0x20, 0x0a, 0x0b, 0x42, 0x69, 0x6e, 0x50, 0x61, 0x79, 0x6c,
0x6f, 0x61, 0x64, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0b, 0x42, 0x69, 0x6e, 0x50,
0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79,
0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d,
0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x64, 0x12, 0x14, 0x0a,
0x05, 0x53, 0x74, 0x65, 0x70, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x53, 0x74,
0x65, 0x70, 0x73, 0x22, 0x1f, 0x0a, 0x0b, 0x44, 0x74, 0x6d, 0x47, 0x69, 0x64, 0x52, 0x65, 0x70,
0x6c, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x47, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x03, 0x47, 0x69, 0x64, 0x22, 0x7b, 0x0a, 0x0d, 0x44, 0x74, 0x6d, 0x42, 0x72, 0x61, 0x6e, 0x63,
0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x47, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x03, 0x47, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x54, 0x72, 0x61, 0x6e, 0x73,
0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x54, 0x72, 0x61, 0x6e,
0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x49,
0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x49,
0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x54, 0x79, 0x70, 0x65, 0x18,
0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x54, 0x79, 0x70,
0x65, 0x22, 0xa7, 0x01, 0x0a, 0x13, 0x44, 0x74, 0x6d, 0x54, 0x63, 0x63, 0x42, 0x72, 0x61, 0x6e,
0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x04, 0x49, 0x6e, 0x66,
0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x69, 0x6d,
0x70, 0x2e, 0x44, 0x74, 0x6d, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x52,
0x04, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20, 0x0a, 0x0b, 0x42, 0x75, 0x73, 0x69, 0x50, 0x61, 0x79,
0x6c, 0x6f, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x42, 0x75, 0x73, 0x69,
0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x54, 0x72, 0x79, 0x18, 0x03,
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x54, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x6f, 0x6e,
0x66, 0x69, 0x72, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x72, 0x6d, 0x12, 0x16, 0x0a, 0x06, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x18, 0x05, 0x20,
0x01, 0x28, 0x09, 0x52, 0x06, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x22, 0x7a, 0x0a, 0x12, 0x44,
0x74, 0x6d, 0x58, 0x61, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x2a, 0x0a, 0x04, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x16, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x69, 0x6d, 0x70, 0x2e, 0x44, 0x74, 0x6d, 0x42, 0x72, 0x61,
0x6e, 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20, 0x0a,
0x0b, 0x42, 0x75, 0x73, 0x69, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x0b, 0x42, 0x75, 0x73, 0x69, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12,
0x16, 0x0a, 0x06, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
0x06, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x32, 0x82, 0x03, 0x0a, 0x03, 0x44, 0x74, 0x6d, 0x12,
0x38, 0x0a, 0x06, 0x4e, 0x65, 0x77, 0x47, 0x69, 0x64, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74,
0x79, 0x1a, 0x14, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x69, 0x6d, 0x70, 0x2e, 0x44, 0x74, 0x6d, 0x47,
0x69, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x37, 0x0a, 0x06, 0x53, 0x75, 0x62,
0x6d, 0x69, 0x74, 0x12, 0x13, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x69, 0x6d, 0x70, 0x2e, 0x44, 0x74,
0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79,
0x22, 0x00, 0x12, 0x38, 0x0a, 0x07, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x12, 0x13, 0x2e,
0x64, 0x74, 0x6d, 0x67, 0x69, 0x6d, 0x70, 0x2e, 0x44, 0x74, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x36, 0x0a, 0x05,
0x41, 0x62, 0x6f, 0x72, 0x74, 0x12, 0x13, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x69, 0x6d, 0x70, 0x2e,
0x44, 0x74, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70,
0x74, 0x79, 0x22, 0x00, 0x12, 0x4b, 0x0a, 0x11, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72,
0x54, 0x63, 0x63, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x12, 0x1c, 0x2e, 0x64, 0x74, 0x6d, 0x67,
0x69, 0x6d, 0x70, 0x2e, 0x44, 0x74, 0x6d, 0x54, 0x63, 0x63, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22,
0x00, 0x12, 0x49, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x58, 0x61, 0x42,
0x72, 0x61, 0x6e, 0x63, 0x68, 0x12, 0x1b, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x69, 0x6d, 0x70, 0x2e,
0x44, 0x74, 0x6d, 0x58, 0x61, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x42, 0x25, 0x5a, 0x23,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x79, 0x65, 0x64, 0x66, 0x2f,
0x64, 0x74, 0x6d, 0x2f, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x64, 0x74, 0x6d, 0x67,
0x69, 0x6d, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_dtmgrpc_dtmgimp_dtmgimp_proto_rawDescOnce sync.Once
file_dtmgrpc_dtmgimp_dtmgimp_proto_rawDescData = file_dtmgrpc_dtmgimp_dtmgimp_proto_rawDesc
)
func file_dtmgrpc_dtmgimp_dtmgimp_proto_rawDescGZIP() []byte {
file_dtmgrpc_dtmgimp_dtmgimp_proto_rawDescOnce.Do(func() {
file_dtmgrpc_dtmgimp_dtmgimp_proto_rawDescData = protoimpl.X.CompressGZIP(file_dtmgrpc_dtmgimp_dtmgimp_proto_rawDescData)
})
return file_dtmgrpc_dtmgimp_dtmgimp_proto_rawDescData
}
var file_dtmgrpc_dtmgimp_dtmgimp_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_dtmgrpc_dtmgimp_dtmgimp_proto_goTypes = []interface{}{
(*DtmTransOptions)(nil), // 0: dtmgimp.DtmTransOptions
(*DtmRequest)(nil), // 1: dtmgimp.DtmRequest
(*DtmGidReply)(nil), // 2: dtmgimp.DtmGidReply
(*DtmBranchInfo)(nil), // 3: dtmgimp.DtmBranchInfo
(*DtmTccBranchRequest)(nil), // 4: dtmgimp.DtmTccBranchRequest
(*DtmXaBranchRequest)(nil), // 5: dtmgimp.DtmXaBranchRequest
(*emptypb.Empty)(nil), // 6: google.protobuf.Empty
}
var file_dtmgrpc_dtmgimp_dtmgimp_proto_depIdxs = []int32{
0, // 0: dtmgimp.DtmRequest.TransOptions:type_name -> dtmgimp.DtmTransOptions
3, // 1: dtmgimp.DtmTccBranchRequest.Info:type_name -> dtmgimp.DtmBranchInfo
3, // 2: dtmgimp.DtmXaBranchRequest.Info:type_name -> dtmgimp.DtmBranchInfo
6, // 3: dtmgimp.Dtm.NewGid:input_type -> google.protobuf.Empty
1, // 4: dtmgimp.Dtm.Submit:input_type -> dtmgimp.DtmRequest
1, // 5: dtmgimp.Dtm.Prepare:input_type -> dtmgimp.DtmRequest
1, // 6: dtmgimp.Dtm.Abort:input_type -> dtmgimp.DtmRequest
4, // 7: dtmgimp.Dtm.RegisterTccBranch:input_type -> dtmgimp.DtmTccBranchRequest
5, // 8: dtmgimp.Dtm.RegisterXaBranch:input_type -> dtmgimp.DtmXaBranchRequest
2, // 9: dtmgimp.Dtm.NewGid:output_type -> dtmgimp.DtmGidReply
6, // 10: dtmgimp.Dtm.Submit:output_type -> google.protobuf.Empty
6, // 11: dtmgimp.Dtm.Prepare:output_type -> google.protobuf.Empty
6, // 12: dtmgimp.Dtm.Abort:output_type -> google.protobuf.Empty
6, // 13: dtmgimp.Dtm.RegisterTccBranch:output_type -> google.protobuf.Empty
6, // 14: dtmgimp.Dtm.RegisterXaBranch:output_type -> google.protobuf.Empty
9, // [9:15] is the sub-list for method output_type
3, // [3:9] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_dtmgrpc_dtmgimp_dtmgimp_proto_init() }
func file_dtmgrpc_dtmgimp_dtmgimp_proto_init() {
if File_dtmgrpc_dtmgimp_dtmgimp_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_dtmgrpc_dtmgimp_dtmgimp_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DtmTransOptions); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_dtmgrpc_dtmgimp_dtmgimp_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DtmRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_dtmgrpc_dtmgimp_dtmgimp_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DtmGidReply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_dtmgrpc_dtmgimp_dtmgimp_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DtmBranchInfo); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_dtmgrpc_dtmgimp_dtmgimp_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DtmTccBranchRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_dtmgrpc_dtmgimp_dtmgimp_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DtmXaBranchRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_dtmgrpc_dtmgimp_dtmgimp_proto_rawDesc,
NumEnums: 0,
NumMessages: 6,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_dtmgrpc_dtmgimp_dtmgimp_proto_goTypes,
DependencyIndexes: file_dtmgrpc_dtmgimp_dtmgimp_proto_depIdxs,
MessageInfos: file_dtmgrpc_dtmgimp_dtmgimp_proto_msgTypes,
}.Build()
File_dtmgrpc_dtmgimp_dtmgimp_proto = out.File
file_dtmgrpc_dtmgimp_dtmgimp_proto_rawDesc = nil
file_dtmgrpc_dtmgimp_dtmgimp_proto_goTypes = nil
file_dtmgrpc_dtmgimp_dtmgimp_proto_depIdxs = nil
}

58
dtmgrpc/dtmgimp/dtmgimp.proto

@ -0,0 +1,58 @@
syntax = "proto3";
option go_package = "github.com/yedf/dtm/dtmgrpc/dtmgimp";
import "google/protobuf/empty.proto";
package dtmgimp;
// The dtm service definition.
service Dtm {
rpc NewGid(google.protobuf.Empty) returns (DtmGidReply) {}
rpc Submit(DtmRequest) returns (google.protobuf.Empty) {}
rpc Prepare(DtmRequest) returns (google.protobuf.Empty) {}
rpc Abort(DtmRequest) returns (google.protobuf.Empty) {}
rpc RegisterTccBranch(DtmTccBranchRequest) returns (google.protobuf.Empty) {}
rpc RegisterXaBranch(DtmXaBranchRequest) returns (google.protobuf.Empty) {}
}
message DtmTransOptions {
bool WaitResult = 1;
int64 TimeoutToFail = 2;
int64 RetryInterval = 3;
}
// DtmRequest request sent to dtm server
message DtmRequest {
string Gid = 1;
string TransType = 2;
DtmTransOptions TransOptions = 3;
string CustomedData = 4;
repeated bytes BinPayloads = 5; // for MSG/SAGA branch payloads
string QueryPrepared = 6; // for MSG
string Steps = 7;
}
message DtmGidReply {
string Gid = 1;
}
message DtmBranchInfo {
string Gid = 1;
string TransType = 2;
string BranchID = 3;
string BranchType = 4;
}
message DtmTccBranchRequest {
DtmBranchInfo Info = 1;
bytes BusiPayload = 2;
string Try = 3;
string Confirm = 4;
string Cancel = 5;
}
message DtmXaBranchRequest {
DtmBranchInfo Info = 1;
bytes BusiPayload = 2;
string Notify = 3; // dtm will call this url to commit/rollback
}

30
dtmgrpc/dtmgrpc_grpc.pb.go → dtmgrpc/dtmgimp/dtmgimp_grpc.pb.go

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
package dtmgrpc
package dtmgimp
import (
context "context"
@ -37,7 +37,7 @@ func NewDtmClient(cc grpc.ClientConnInterface) DtmClient {
func (c *dtmClient) NewGid(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*DtmGidReply, error) {
out := new(DtmGidReply)
err := c.cc.Invoke(ctx, "/dtmgrpc.Dtm/NewGid", in, out, opts...)
err := c.cc.Invoke(ctx, "/dtmgimp.Dtm/NewGid", in, out, opts...)
if err != nil {
return nil, err
}
@ -46,7 +46,7 @@ func (c *dtmClient) NewGid(ctx context.Context, in *emptypb.Empty, opts ...grpc.
func (c *dtmClient) Submit(ctx context.Context, in *DtmRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/dtmgrpc.Dtm/Submit", in, out, opts...)
err := c.cc.Invoke(ctx, "/dtmgimp.Dtm/Submit", in, out, opts...)
if err != nil {
return nil, err
}
@ -55,7 +55,7 @@ func (c *dtmClient) Submit(ctx context.Context, in *DtmRequest, opts ...grpc.Cal
func (c *dtmClient) Prepare(ctx context.Context, in *DtmRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/dtmgrpc.Dtm/Prepare", in, out, opts...)
err := c.cc.Invoke(ctx, "/dtmgimp.Dtm/Prepare", in, out, opts...)
if err != nil {
return nil, err
}
@ -64,7 +64,7 @@ func (c *dtmClient) Prepare(ctx context.Context, in *DtmRequest, opts ...grpc.Ca
func (c *dtmClient) Abort(ctx context.Context, in *DtmRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/dtmgrpc.Dtm/Abort", in, out, opts...)
err := c.cc.Invoke(ctx, "/dtmgimp.Dtm/Abort", in, out, opts...)
if err != nil {
return nil, err
}
@ -73,7 +73,7 @@ func (c *dtmClient) Abort(ctx context.Context, in *DtmRequest, opts ...grpc.Call
func (c *dtmClient) RegisterTccBranch(ctx context.Context, in *DtmTccBranchRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/dtmgrpc.Dtm/RegisterTccBranch", in, out, opts...)
err := c.cc.Invoke(ctx, "/dtmgimp.Dtm/RegisterTccBranch", in, out, opts...)
if err != nil {
return nil, err
}
@ -82,7 +82,7 @@ func (c *dtmClient) RegisterTccBranch(ctx context.Context, in *DtmTccBranchReque
func (c *dtmClient) RegisterXaBranch(ctx context.Context, in *DtmXaBranchRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/dtmgrpc.Dtm/RegisterXaBranch", in, out, opts...)
err := c.cc.Invoke(ctx, "/dtmgimp.Dtm/RegisterXaBranch", in, out, opts...)
if err != nil {
return nil, err
}
@ -147,7 +147,7 @@ func _Dtm_NewGid_Handler(srv interface{}, ctx context.Context, dec func(interfac
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/dtmgrpc.Dtm/NewGid",
FullMethod: "/dtmgimp.Dtm/NewGid",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DtmServer).NewGid(ctx, req.(*emptypb.Empty))
@ -165,7 +165,7 @@ func _Dtm_Submit_Handler(srv interface{}, ctx context.Context, dec func(interfac
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/dtmgrpc.Dtm/Submit",
FullMethod: "/dtmgimp.Dtm/Submit",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DtmServer).Submit(ctx, req.(*DtmRequest))
@ -183,7 +183,7 @@ func _Dtm_Prepare_Handler(srv interface{}, ctx context.Context, dec func(interfa
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/dtmgrpc.Dtm/Prepare",
FullMethod: "/dtmgimp.Dtm/Prepare",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DtmServer).Prepare(ctx, req.(*DtmRequest))
@ -201,7 +201,7 @@ func _Dtm_Abort_Handler(srv interface{}, ctx context.Context, dec func(interface
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/dtmgrpc.Dtm/Abort",
FullMethod: "/dtmgimp.Dtm/Abort",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DtmServer).Abort(ctx, req.(*DtmRequest))
@ -219,7 +219,7 @@ func _Dtm_RegisterTccBranch_Handler(srv interface{}, ctx context.Context, dec fu
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/dtmgrpc.Dtm/RegisterTccBranch",
FullMethod: "/dtmgimp.Dtm/RegisterTccBranch",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DtmServer).RegisterTccBranch(ctx, req.(*DtmTccBranchRequest))
@ -237,7 +237,7 @@ func _Dtm_RegisterXaBranch_Handler(srv interface{}, ctx context.Context, dec fun
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/dtmgrpc.Dtm/RegisterXaBranch",
FullMethod: "/dtmgimp.Dtm/RegisterXaBranch",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DtmServer).RegisterXaBranch(ctx, req.(*DtmXaBranchRequest))
@ -249,7 +249,7 @@ func _Dtm_RegisterXaBranch_Handler(srv interface{}, ctx context.Context, dec fun
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Dtm_ServiceDesc = grpc.ServiceDesc{
ServiceName: "dtmgrpc.Dtm",
ServiceName: "dtmgimp.Dtm",
HandlerType: (*DtmServer)(nil),
Methods: []grpc.MethodDesc{
{
@ -278,5 +278,5 @@ var Dtm_ServiceDesc = grpc.ServiceDesc{
},
},
Streams: []grpc.StreamDesc{},
Metadata: "dtmgrpc/dtmgrpc.proto",
Metadata: "dtmgrpc/dtmgimp/dtmgimp.proto",
}

67
dtmgrpc/dtmgimp/grpc_clients.go

@ -0,0 +1,67 @@
package dtmgimp
import (
sync "sync"
"github.com/yedf/dtm/dtmcli/dtmimp"
grpc "google.golang.org/grpc"
)
type rawCodec struct{}
func (cb rawCodec) Marshal(v interface{}) ([]byte, error) {
return v.([]byte), nil
}
func (cb rawCodec) Unmarshal(data []byte, v interface{}) error {
ba, _ := v.([]byte)
for index, byte := range data {
ba[index] = byte
}
return nil
}
func (cb rawCodec) Name() string { return "dtm_raw" }
var normalClients, rawClients sync.Map
// MustGetDtmClient 1
func MustGetDtmClient(grpcServer string) DtmClient {
return NewDtmClient(MustGetGrpcConn(grpcServer, false))
}
// MustGetRawDtmClient must get raw codec grpc conn
func MustGetRawDtmClient(grpcServer string) DtmClient {
return NewDtmClient(MustGetGrpcConn(grpcServer, true))
}
// GetGrpcConn 1
func GetGrpcConn(grpcServer string, isRaw bool) (conn *grpc.ClientConn, rerr error) {
clients := &normalClients
if isRaw {
clients = &rawClients
}
grpcServer = dtmimp.MayReplaceLocalhost(grpcServer)
v, ok := clients.Load(grpcServer)
if !ok {
opts := grpc.WithDefaultCallOptions()
if isRaw {
opts = grpc.WithDefaultCallOptions(grpc.ForceCodec(rawCodec{}))
}
dtmimp.Logf("grpc client connecting %s", grpcServer)
conn, rerr := grpc.Dial(grpcServer, grpc.WithInsecure(), grpc.WithUnaryInterceptor(GrpcClientLog), opts)
if rerr == nil {
clients.Store(grpcServer, conn)
v = conn
dtmimp.Logf("grpc client inited for %s", grpcServer)
}
}
return v.(*grpc.ClientConn), rerr
}
// MustGetGrpcConn 1
func MustGetGrpcConn(grpcServer string, isRaw bool) *grpc.ClientConn {
conn, err := GetGrpcConn(grpcServer, isRaw)
dtmimp.E2P(err)
return conn
}

61
dtmgrpc/dtmgimp/types.go

@ -0,0 +1,61 @@
package dtmgimp
import (
"context"
"fmt"
"strings"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// GetServerAndMethod 将grpc的url分解为server和method
func GetServerAndMethod(grpcURL string) (string, string) {
fs := strings.Split(grpcURL, "/")
server := fs[0]
method := "/" + strings.Join(fs[1:], "/")
return server, method
}
// GrpcServerLog 打印grpc服务端的日志
func GrpcServerLog(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
dtmimp.Logf("grpc server handling: %s %v", info.FullMethod, req)
LogDtmCtx(ctx)
m, err := handler(ctx, req)
res := fmt.Sprintf("grpc server handled: %s %v result: %v err: %v", info.FullMethod, req, m, err)
if err != nil {
dtmimp.LogRedf("%s", res)
} else {
dtmimp.Logf("%s", res)
}
return m, err
}
// GrpcClientLog 打印grpc服务端的日志
func GrpcClientLog(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
dtmimp.Logf("grpc client calling: %s%s %v", cc.Target(), method, req)
LogDtmCtx(ctx)
err := invoker(ctx, method, req, reply, cc, opts...)
res := fmt.Sprintf("grpc client called: %s%s %v result: %v err: %v", cc.Target(), method, req, reply, err)
if err != nil {
dtmimp.LogRedf("%s", res)
} else {
dtmimp.Logf("%s", res)
}
return err
}
// Result2Error 将通用的result转成grpc的error
func Result2Error(res interface{}, err error) error {
e := dtmimp.CheckResult(res, err)
if e == dtmimp.ErrFailure {
dtmimp.LogRedf("failure: res: %v, err: %v", res, e)
return status.New(codes.Aborted, dtmcli.ResultFailure).Err()
} else if e == dtmimp.ErrOngoing {
return status.New(codes.Aborted, dtmcli.ResultOngoing).Err()
}
return e
}

73
dtmgrpc/dtmgimp/utils.go

@ -0,0 +1,73 @@
package dtmgimp
import (
context "context"
"github.com/yedf/dtm/dtmcli/dtmimp"
"google.golang.org/grpc/metadata"
"google.golang.org/protobuf/proto"
emptypb "google.golang.org/protobuf/types/known/emptypb"
)
// MustProtoMarshal must version of proto.Marshal
func MustProtoMarshal(msg proto.Message) []byte {
b, err := proto.Marshal(msg)
dtmimp.PanicIf(err != nil, err)
return b
}
// DtmGrpcCall make a convenient call to dtm
func DtmGrpcCall(s *dtmimp.TransBase, operation string) error {
reply := emptypb.Empty{}
return MustGetGrpcConn(s.Dtm, false).Invoke(context.Background(), "/dtmgimp.Dtm/"+operation, &DtmRequest{
Gid: s.Gid,
TransType: s.TransType,
TransOptions: &DtmTransOptions{
WaitResult: s.WaitResult,
TimeoutToFail: s.TimeoutToFail,
RetryInterval: s.RetryInterval,
},
QueryPrepared: s.QueryPrepared,
CustomedData: s.CustomData,
BinPayloads: s.BinPayloads,
Steps: dtmimp.MustMarshalString(s.Steps),
}, &reply)
}
const mdpre string = "dtm-"
// TransInfo2Ctx add trans info to grpc context
func TransInfo2Ctx(gid, transType, branchID, branchType, dtm string) context.Context {
md := metadata.Pairs(
mdpre+"gid", gid,
mdpre+"trans_type", transType,
mdpre+"branch_id", branchID,
mdpre+"branch_type", branchType,
mdpre+"dtm", dtm,
)
return metadata.NewOutgoingContext(context.Background(), md)
}
// LogDtmCtx logout dtm info in context metadata
func LogDtmCtx(ctx context.Context) {
tb := TransBaseFromGrpc(ctx)
if tb.Gid != "" {
dtmimp.Logf("gid: %s trans_type: %s branch_id: %s branch_type: %s dtm: %s", tb.Gid, tb.TransType, tb.BranchID, tb.BranchType, tb.Dtm)
}
}
func mdGet(md metadata.MD, key string) string {
v := md.Get(mdpre + key)
if len(v) == 0 {
return ""
}
return v[0]
}
// TransBaseFromGrpc get trans base info from a context metadata
func TransBaseFromGrpc(ctx context.Context) *dtmimp.TransBase {
md, _ := metadata.FromIncomingContext(ctx)
tb := dtmimp.NewTransBase(mdGet(md, "gid"), mdGet(md, "trans_type"), mdGet(md, "dtm"), mdGet(md, "branch_id"))
tb.BranchType = mdGet(md, "branch_type")
return tb
}

717
dtmgrpc/dtmgrpc.pb.go

@ -1,717 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc v3.17.3
// source: dtmgrpc/dtmgrpc.proto
package dtmgrpc
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
emptypb "google.golang.org/protobuf/types/known/emptypb"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// DtmRequest 发给dtm服务器的消息,响应为Emtpy,error == nil为成功,== Aborted 为失败 == 其他 可以重试
type DtmRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Gid string `protobuf:"bytes,1,opt,name=Gid,proto3" json:"Gid,omitempty"`
TransType string `protobuf:"bytes,2,opt,name=TransType,proto3" json:"TransType,omitempty"`
// QueryPrepared 对于事务消息处于prepared状态过期,责护查询QueryPrepared
QueryPrepared string `protobuf:"bytes,3,opt,name=QueryPrepared,proto3" json:"QueryPrepared,omitempty"`
// WaitResult 设定这个值,Submit操作会等待dtm处理一次请求,可能在返回时,就可以把分布式事务完成
WaitResult bool `protobuf:"varint,4,opt,name=WaitResult,proto3" json:"WaitResult,omitempty"`
// Data 包含saga、msg的子事务信息
Data string `protobuf:"bytes,5,opt,name=Data,proto3" json:"Data,omitempty"`
}
func (x *DtmRequest) Reset() {
*x = DtmRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_dtmgrpc_dtmgrpc_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DtmRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DtmRequest) ProtoMessage() {}
func (x *DtmRequest) ProtoReflect() protoreflect.Message {
mi := &file_dtmgrpc_dtmgrpc_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DtmRequest.ProtoReflect.Descriptor instead.
func (*DtmRequest) Descriptor() ([]byte, []int) {
return file_dtmgrpc_dtmgrpc_proto_rawDescGZIP(), []int{0}
}
func (x *DtmRequest) GetGid() string {
if x != nil {
return x.Gid
}
return ""
}
func (x *DtmRequest) GetTransType() string {
if x != nil {
return x.TransType
}
return ""
}
func (x *DtmRequest) GetQueryPrepared() string {
if x != nil {
return x.QueryPrepared
}
return ""
}
func (x *DtmRequest) GetWaitResult() bool {
if x != nil {
return x.WaitResult
}
return false
}
func (x *DtmRequest) GetData() string {
if x != nil {
return x.Data
}
return ""
}
type DtmGidReply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Gid string `protobuf:"bytes,1,opt,name=Gid,proto3" json:"Gid,omitempty"`
}
func (x *DtmGidReply) Reset() {
*x = DtmGidReply{}
if protoimpl.UnsafeEnabled {
mi := &file_dtmgrpc_dtmgrpc_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DtmGidReply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DtmGidReply) ProtoMessage() {}
func (x *DtmGidReply) ProtoReflect() protoreflect.Message {
mi := &file_dtmgrpc_dtmgrpc_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DtmGidReply.ProtoReflect.Descriptor instead.
func (*DtmGidReply) Descriptor() ([]byte, []int) {
return file_dtmgrpc_dtmgrpc_proto_rawDescGZIP(), []int{1}
}
func (x *DtmGidReply) GetGid() string {
if x != nil {
return x.Gid
}
return ""
}
// BranchInfo 事务分支信息
type BranchInfo struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Gid string `protobuf:"bytes,1,opt,name=Gid,proto3" json:"Gid,omitempty"`
TransType string `protobuf:"bytes,2,opt,name=TransType,proto3" json:"TransType,omitempty"`
BranchID string `protobuf:"bytes,3,opt,name=BranchID,proto3" json:"BranchID,omitempty"`
BranchType string `protobuf:"bytes,4,opt,name=BranchType,proto3" json:"BranchType,omitempty"`
}
func (x *BranchInfo) Reset() {
*x = BranchInfo{}
if protoimpl.UnsafeEnabled {
mi := &file_dtmgrpc_dtmgrpc_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *BranchInfo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BranchInfo) ProtoMessage() {}
func (x *BranchInfo) ProtoReflect() protoreflect.Message {
mi := &file_dtmgrpc_dtmgrpc_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BranchInfo.ProtoReflect.Descriptor instead.
func (*BranchInfo) Descriptor() ([]byte, []int) {
return file_dtmgrpc_dtmgrpc_proto_rawDescGZIP(), []int{2}
}
func (x *BranchInfo) GetGid() string {
if x != nil {
return x.Gid
}
return ""
}
func (x *BranchInfo) GetTransType() string {
if x != nil {
return x.TransType
}
return ""
}
func (x *BranchInfo) GetBranchID() string {
if x != nil {
return x.BranchID
}
return ""
}
func (x *BranchInfo) GetBranchType() string {
if x != nil {
return x.BranchType
}
return ""
}
type DtmTccBranchRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Info *BranchInfo `protobuf:"bytes,1,opt,name=Info,proto3" json:"Info,omitempty"`
BusiData string `protobuf:"bytes,2,opt,name=BusiData,proto3" json:"BusiData,omitempty"`
Try string `protobuf:"bytes,3,opt,name=Try,proto3" json:"Try,omitempty"`
Confirm string `protobuf:"bytes,4,opt,name=Confirm,proto3" json:"Confirm,omitempty"`
Cancel string `protobuf:"bytes,5,opt,name=Cancel,proto3" json:"Cancel,omitempty"`
}
func (x *DtmTccBranchRequest) Reset() {
*x = DtmTccBranchRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_dtmgrpc_dtmgrpc_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DtmTccBranchRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DtmTccBranchRequest) ProtoMessage() {}
func (x *DtmTccBranchRequest) ProtoReflect() protoreflect.Message {
mi := &file_dtmgrpc_dtmgrpc_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DtmTccBranchRequest.ProtoReflect.Descriptor instead.
func (*DtmTccBranchRequest) Descriptor() ([]byte, []int) {
return file_dtmgrpc_dtmgrpc_proto_rawDescGZIP(), []int{3}
}
func (x *DtmTccBranchRequest) GetInfo() *BranchInfo {
if x != nil {
return x.Info
}
return nil
}
func (x *DtmTccBranchRequest) GetBusiData() string {
if x != nil {
return x.BusiData
}
return ""
}
func (x *DtmTccBranchRequest) GetTry() string {
if x != nil {
return x.Try
}
return ""
}
func (x *DtmTccBranchRequest) GetConfirm() string {
if x != nil {
return x.Confirm
}
return ""
}
func (x *DtmTccBranchRequest) GetCancel() string {
if x != nil {
return x.Cancel
}
return ""
}
type DtmXaBranchRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Info *BranchInfo `protobuf:"bytes,1,opt,name=Info,proto3" json:"Info,omitempty"`
BusiData string `protobuf:"bytes,2,opt,name=BusiData,proto3" json:"BusiData,omitempty"`
// dtm通知业务提交和回滚的地址
Notify string `protobuf:"bytes,3,opt,name=Notify,proto3" json:"Notify,omitempty"`
}
func (x *DtmXaBranchRequest) Reset() {
*x = DtmXaBranchRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_dtmgrpc_dtmgrpc_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DtmXaBranchRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DtmXaBranchRequest) ProtoMessage() {}
func (x *DtmXaBranchRequest) ProtoReflect() protoreflect.Message {
mi := &file_dtmgrpc_dtmgrpc_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DtmXaBranchRequest.ProtoReflect.Descriptor instead.
func (*DtmXaBranchRequest) Descriptor() ([]byte, []int) {
return file_dtmgrpc_dtmgrpc_proto_rawDescGZIP(), []int{4}
}
func (x *DtmXaBranchRequest) GetInfo() *BranchInfo {
if x != nil {
return x.Info
}
return nil
}
func (x *DtmXaBranchRequest) GetBusiData() string {
if x != nil {
return x.BusiData
}
return ""
}
func (x *DtmXaBranchRequest) GetNotify() string {
if x != nil {
return x.Notify
}
return ""
}
// BusiRequest 请求业务的数据,需要携带事务信息,便于业务进行幂等处理
type BusiRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Info *BranchInfo `protobuf:"bytes,1,opt,name=Info,proto3" json:"Info,omitempty"`
Dtm string `protobuf:"bytes,2,opt,name=Dtm,proto3" json:"Dtm,omitempty"`
BusiData []byte `protobuf:"bytes,3,opt,name=BusiData,proto3" json:"BusiData,omitempty"`
}
func (x *BusiRequest) Reset() {
*x = BusiRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_dtmgrpc_dtmgrpc_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *BusiRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BusiRequest) ProtoMessage() {}
func (x *BusiRequest) ProtoReflect() protoreflect.Message {
mi := &file_dtmgrpc_dtmgrpc_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BusiRequest.ProtoReflect.Descriptor instead.
func (*BusiRequest) Descriptor() ([]byte, []int) {
return file_dtmgrpc_dtmgrpc_proto_rawDescGZIP(), []int{5}
}
func (x *BusiRequest) GetInfo() *BranchInfo {
if x != nil {
return x.Info
}
return nil
}
func (x *BusiRequest) GetDtm() string {
if x != nil {
return x.Dtm
}
return ""
}
func (x *BusiRequest) GetBusiData() []byte {
if x != nil {
return x.BusiData
}
return nil
}
// BusiReply 业务响应数据
type BusiReply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
BusiData []byte `protobuf:"bytes,1,opt,name=BusiData,proto3" json:"BusiData,omitempty"`
}
func (x *BusiReply) Reset() {
*x = BusiReply{}
if protoimpl.UnsafeEnabled {
mi := &file_dtmgrpc_dtmgrpc_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *BusiReply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BusiReply) ProtoMessage() {}
func (x *BusiReply) ProtoReflect() protoreflect.Message {
mi := &file_dtmgrpc_dtmgrpc_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BusiReply.ProtoReflect.Descriptor instead.
func (*BusiReply) Descriptor() ([]byte, []int) {
return file_dtmgrpc_dtmgrpc_proto_rawDescGZIP(), []int{6}
}
func (x *BusiReply) GetBusiData() []byte {
if x != nil {
return x.BusiData
}
return nil
}
var File_dtmgrpc_dtmgrpc_proto protoreflect.FileDescriptor
var file_dtmgrpc_dtmgrpc_proto_rawDesc = []byte{
0x0a, 0x15, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70,
0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63,
0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x96, 0x01,
0x0a, 0x0a, 0x44, 0x74, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03,
0x47, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x47, 0x69, 0x64, 0x12, 0x1c,
0x0a, 0x09, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x09, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0d,
0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x64, 0x18, 0x03, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72,
0x65, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x57, 0x61, 0x69, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74,
0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x57, 0x61, 0x69, 0x74, 0x52, 0x65, 0x73, 0x75,
0x6c, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09,
0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x22, 0x1f, 0x0a, 0x0b, 0x44, 0x74, 0x6d, 0x47, 0x69, 0x64,
0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x47, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x03, 0x47, 0x69, 0x64, 0x22, 0x78, 0x0a, 0x0a, 0x42, 0x72, 0x61, 0x6e, 0x63,
0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x47, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x03, 0x47, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x54, 0x72, 0x61, 0x6e, 0x73,
0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x54, 0x72, 0x61, 0x6e,
0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x49,
0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x49,
0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x54, 0x79, 0x70, 0x65, 0x18,
0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x54, 0x79, 0x70,
0x65, 0x22, 0x9e, 0x01, 0x0a, 0x13, 0x44, 0x74, 0x6d, 0x54, 0x63, 0x63, 0x42, 0x72, 0x61, 0x6e,
0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x04, 0x49, 0x6e, 0x66,
0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70,
0x63, 0x2e, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x49, 0x6e,
0x66, 0x6f, 0x12, 0x1a, 0x0a, 0x08, 0x42, 0x75, 0x73, 0x69, 0x44, 0x61, 0x74, 0x61, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x42, 0x75, 0x73, 0x69, 0x44, 0x61, 0x74, 0x61, 0x12, 0x10,
0x0a, 0x03, 0x54, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x54, 0x72, 0x79,
0x12, 0x18, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28,
0x09, 0x52, 0x07, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x12, 0x16, 0x0a, 0x06, 0x43, 0x61,
0x6e, 0x63, 0x65, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x43, 0x61, 0x6e, 0x63,
0x65, 0x6c, 0x22, 0x71, 0x0a, 0x12, 0x44, 0x74, 0x6d, 0x58, 0x61, 0x42, 0x72, 0x61, 0x6e, 0x63,
0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x04, 0x49, 0x6e, 0x66, 0x6f,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63,
0x2e, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x49, 0x6e, 0x66,
0x6f, 0x12, 0x1a, 0x0a, 0x08, 0x42, 0x75, 0x73, 0x69, 0x44, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x08, 0x42, 0x75, 0x73, 0x69, 0x44, 0x61, 0x74, 0x61, 0x12, 0x16, 0x0a,
0x06, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x4e,
0x6f, 0x74, 0x69, 0x66, 0x79, 0x22, 0x64, 0x0a, 0x0b, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x04, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x13, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x72, 0x61,
0x6e, 0x63, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a,
0x03, 0x44, 0x74, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x44, 0x74, 0x6d, 0x12,
0x1a, 0x0a, 0x08, 0x42, 0x75, 0x73, 0x69, 0x44, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x08, 0x42, 0x75, 0x73, 0x69, 0x44, 0x61, 0x74, 0x61, 0x22, 0x27, 0x0a, 0x09, 0x42,
0x75, 0x73, 0x69, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x42, 0x75, 0x73, 0x69,
0x44, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x42, 0x75, 0x73, 0x69,
0x44, 0x61, 0x74, 0x61, 0x32, 0x82, 0x03, 0x0a, 0x03, 0x44, 0x74, 0x6d, 0x12, 0x38, 0x0a, 0x06,
0x4e, 0x65, 0x77, 0x47, 0x69, 0x64, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x14,
0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x74, 0x6d, 0x47, 0x69, 0x64, 0x52,
0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x37, 0x0a, 0x06, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74,
0x12, 0x13, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x74, 0x6d, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12,
0x38, 0x0a, 0x07, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x12, 0x13, 0x2e, 0x64, 0x74, 0x6d,
0x67, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x74, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x36, 0x0a, 0x05, 0x41, 0x62, 0x6f,
0x72, 0x74, 0x12, 0x13, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x74, 0x6d,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22,
0x00, 0x12, 0x4b, 0x0a, 0x11, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x63, 0x63,
0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x12, 0x1c, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63,
0x2e, 0x44, 0x74, 0x6d, 0x54, 0x63, 0x63, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x49,
0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x58, 0x61, 0x42, 0x72, 0x61, 0x6e,
0x63, 0x68, 0x12, 0x1b, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x74, 0x6d,
0x58, 0x61, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x42, 0x1d, 0x5a, 0x1b, 0x67, 0x69, 0x74,
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x79, 0x65, 0x64, 0x66, 0x2f, 0x64, 0x74, 0x6d,
0x2f, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_dtmgrpc_dtmgrpc_proto_rawDescOnce sync.Once
file_dtmgrpc_dtmgrpc_proto_rawDescData = file_dtmgrpc_dtmgrpc_proto_rawDesc
)
func file_dtmgrpc_dtmgrpc_proto_rawDescGZIP() []byte {
file_dtmgrpc_dtmgrpc_proto_rawDescOnce.Do(func() {
file_dtmgrpc_dtmgrpc_proto_rawDescData = protoimpl.X.CompressGZIP(file_dtmgrpc_dtmgrpc_proto_rawDescData)
})
return file_dtmgrpc_dtmgrpc_proto_rawDescData
}
var file_dtmgrpc_dtmgrpc_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_dtmgrpc_dtmgrpc_proto_goTypes = []interface{}{
(*DtmRequest)(nil), // 0: dtmgrpc.DtmRequest
(*DtmGidReply)(nil), // 1: dtmgrpc.DtmGidReply
(*BranchInfo)(nil), // 2: dtmgrpc.BranchInfo
(*DtmTccBranchRequest)(nil), // 3: dtmgrpc.DtmTccBranchRequest
(*DtmXaBranchRequest)(nil), // 4: dtmgrpc.DtmXaBranchRequest
(*BusiRequest)(nil), // 5: dtmgrpc.BusiRequest
(*BusiReply)(nil), // 6: dtmgrpc.BusiReply
(*emptypb.Empty)(nil), // 7: google.protobuf.Empty
}
var file_dtmgrpc_dtmgrpc_proto_depIdxs = []int32{
2, // 0: dtmgrpc.DtmTccBranchRequest.Info:type_name -> dtmgrpc.BranchInfo
2, // 1: dtmgrpc.DtmXaBranchRequest.Info:type_name -> dtmgrpc.BranchInfo
2, // 2: dtmgrpc.BusiRequest.Info:type_name -> dtmgrpc.BranchInfo
7, // 3: dtmgrpc.Dtm.NewGid:input_type -> google.protobuf.Empty
0, // 4: dtmgrpc.Dtm.Submit:input_type -> dtmgrpc.DtmRequest
0, // 5: dtmgrpc.Dtm.Prepare:input_type -> dtmgrpc.DtmRequest
0, // 6: dtmgrpc.Dtm.Abort:input_type -> dtmgrpc.DtmRequest
3, // 7: dtmgrpc.Dtm.RegisterTccBranch:input_type -> dtmgrpc.DtmTccBranchRequest
4, // 8: dtmgrpc.Dtm.RegisterXaBranch:input_type -> dtmgrpc.DtmXaBranchRequest
1, // 9: dtmgrpc.Dtm.NewGid:output_type -> dtmgrpc.DtmGidReply
7, // 10: dtmgrpc.Dtm.Submit:output_type -> google.protobuf.Empty
7, // 11: dtmgrpc.Dtm.Prepare:output_type -> google.protobuf.Empty
7, // 12: dtmgrpc.Dtm.Abort:output_type -> google.protobuf.Empty
7, // 13: dtmgrpc.Dtm.RegisterTccBranch:output_type -> google.protobuf.Empty
7, // 14: dtmgrpc.Dtm.RegisterXaBranch:output_type -> google.protobuf.Empty
9, // [9:15] is the sub-list for method output_type
3, // [3:9] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_dtmgrpc_dtmgrpc_proto_init() }
func file_dtmgrpc_dtmgrpc_proto_init() {
if File_dtmgrpc_dtmgrpc_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_dtmgrpc_dtmgrpc_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DtmRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_dtmgrpc_dtmgrpc_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DtmGidReply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_dtmgrpc_dtmgrpc_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*BranchInfo); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_dtmgrpc_dtmgrpc_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DtmTccBranchRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_dtmgrpc_dtmgrpc_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DtmXaBranchRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_dtmgrpc_dtmgrpc_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*BusiRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_dtmgrpc_dtmgrpc_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*BusiReply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_dtmgrpc_dtmgrpc_proto_rawDesc,
NumEnums: 0,
NumMessages: 7,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_dtmgrpc_dtmgrpc_proto_goTypes,
DependencyIndexes: file_dtmgrpc_dtmgrpc_proto_depIdxs,
MessageInfos: file_dtmgrpc_dtmgrpc_proto_msgTypes,
}.Build()
File_dtmgrpc_dtmgrpc_proto = out.File
file_dtmgrpc_dtmgrpc_proto_rawDesc = nil
file_dtmgrpc_dtmgrpc_proto_goTypes = nil
file_dtmgrpc_dtmgrpc_proto_depIdxs = nil
}

66
dtmgrpc/dtmgrpc.proto

@ -1,66 +0,0 @@
syntax = "proto3";
option go_package = "github.com/yedf/dtm/dtmgrpc";
import "google/protobuf/empty.proto";
package dtmgrpc;
// The dtm service definition.
service Dtm {
rpc NewGid(google.protobuf.Empty) returns (DtmGidReply) {}
rpc Submit(DtmRequest) returns (google.protobuf.Empty) {}
rpc Prepare(DtmRequest) returns (google.protobuf.Empty) {}
rpc Abort(DtmRequest) returns (google.protobuf.Empty) {}
rpc RegisterTccBranch(DtmTccBranchRequest) returns (google.protobuf.Empty) {}
rpc RegisterXaBranch(DtmXaBranchRequest) returns (google.protobuf.Empty) {}
}
// DtmRequest dtm服务器的消息Emtpyerror == nil为成功== Aborted ==
message DtmRequest {
string Gid = 1;
string TransType = 2;
// QueryPrepared prepared状态过期QueryPrepared
string QueryPrepared = 3;
// WaitResult Submit操作会等待dtm处理一次请求
bool WaitResult = 4;
// Data sagamsg的子事务信息
string Data = 5;
}
message DtmGidReply {
string Gid = 1;
}
// BranchInfo
message BranchInfo {
string Gid = 1;
string TransType = 2;
string BranchID = 3;
string BranchType = 4;
}
message DtmTccBranchRequest {
BranchInfo Info = 1;
string BusiData = 2;
string Try = 3;
string Confirm = 4;
string Cancel = 5;
}
message DtmXaBranchRequest {
BranchInfo Info = 1;
string BusiData = 2;
// dtm通知业务提交和回滚的地址
string Notify = 3;
}
// BusiRequest 便
message BusiRequest {
BranchInfo Info = 1;
string Dtm = 2;
bytes BusiData = 3;
}
// BusiReply
message BusiReply {
bytes BusiData = 1;
}

50
dtmgrpc/message.go

@ -1,50 +0,0 @@
package dtmgrpc
import (
"context"
"github.com/yedf/dtm/dtmcli"
)
// MsgGrpc reliable msg type
type MsgGrpc struct {
dtmcli.TransBase
Steps []dtmcli.MsgStep `json:"steps"`
QueryPrepared string `json:"query_prepared"`
}
// NewMsgGrpc create new msg
func NewMsgGrpc(server string, gid string) *MsgGrpc {
return &MsgGrpc{TransBase: *dtmcli.NewTransBase(gid, "msg", server, "")}
}
// Add add a new step
func (s *MsgGrpc) Add(action string, data []byte) *MsgGrpc {
s.Steps = append(s.Steps, dtmcli.MsgStep{
Action: action,
Data: string(data),
})
return s
}
// Submit submit the msg
func (s *MsgGrpc) Submit() error {
_, err := MustGetDtmClient(s.Dtm).Submit(context.Background(), &DtmRequest{
Gid: s.Gid,
TransType: s.TransType,
Data: dtmcli.MustMarshalString(&s.Steps),
})
return err
}
// Prepare prepare the msg
func (s *MsgGrpc) Prepare(queryPrepared string) error {
s.QueryPrepared = dtmcli.OrString(queryPrepared, s.QueryPrepared)
_, err := MustGetDtmClient(s.Dtm).Prepare(context.Background(), &DtmRequest{
Gid: s.Gid,
TransType: s.TransType,
QueryPrepared: s.QueryPrepared,
Data: dtmcli.MustMarshalString(&s.Steps),
})
return err
}

36
dtmgrpc/msg.go

@ -0,0 +1,36 @@
package dtmgrpc
import (
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/dtmgrpc/dtmgimp"
"google.golang.org/protobuf/proto"
)
// MsgGrpc reliable msg type
type MsgGrpc struct {
dtmcli.Msg
}
// NewMsgGrpc create new msg
func NewMsgGrpc(server string, gid string) *MsgGrpc {
return &MsgGrpc{Msg: *dtmcli.NewMsg(server, gid)}
}
// Add add a new step
func (s *MsgGrpc) Add(action string, msg proto.Message) *MsgGrpc {
s.Steps = append(s.Steps, map[string]string{"action": action})
s.BinPayloads = append(s.BinPayloads, dtmgimp.MustProtoMarshal(msg))
return s
}
// Prepare prepare the msg, msg will later be submitted
func (s *MsgGrpc) Prepare(queryPrepared string) error {
s.QueryPrepared = dtmimp.OrString(queryPrepared, s.QueryPrepared)
return dtmgimp.DtmGrpcCall(&s.TransBase, "Prepare")
}
// Submit submit the msg
func (s *MsgGrpc) Submit() error {
return dtmgimp.DtmGrpcCall(&s.TransBase, "Submit")
}

41
dtmgrpc/saga.go

@ -1,38 +1,41 @@
package dtmgrpc
import (
context "context"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmgrpc/dtmgimp"
"google.golang.org/protobuf/proto"
)
// SagaGrpc struct of saga
type SagaGrpc struct {
dtmcli.TransBase
Steps []dtmcli.SagaStep `json:"steps"`
dtmcli.Saga
}
// NewSaga create a saga
func NewSaga(server string, gid string) *SagaGrpc {
return &SagaGrpc{TransBase: *dtmcli.NewTransBase(gid, "saga", server, "")}
// NewSagaGrpc create a saga
func NewSagaGrpc(server string, gid string) *SagaGrpc {
return &SagaGrpc{Saga: *dtmcli.NewSaga(server, gid)}
}
// Add add a saga step
func (s *SagaGrpc) Add(action string, compensate string, busiData []byte) *SagaGrpc {
s.Steps = append(s.Steps, dtmcli.SagaStep{
Action: action,
Compensate: compensate,
Data: string(busiData),
})
func (s *SagaGrpc) Add(action string, compensate string, payload proto.Message) *SagaGrpc {
s.Steps = append(s.Steps, map[string]string{"action": action, "compensate": compensate})
s.BinPayloads = append(s.BinPayloads, dtmgimp.MustProtoMarshal(payload))
return s
}
// AddBranchOrder specify that branch should be after preBranches. branch should is larger than all the element in preBranches
func (s *SagaGrpc) AddBranchOrder(branch int, preBranches []int) *SagaGrpc {
s.Saga.AddBranchOrder(branch, preBranches)
return s
}
// EnableConcurrent enable the concurrent exec of sub trans
func (s *SagaGrpc) EnableConcurrent() *SagaGrpc {
s.Saga.EnableConcurrent()
return s
}
// Submit submit the saga trans
func (s *SagaGrpc) Submit() error {
_, err := MustGetDtmClient(s.Dtm).Submit(context.Background(), &DtmRequest{
Gid: s.Gid,
TransType: s.TransType,
Data: dtmcli.MustMarshalString(&s.Steps),
})
return err
return dtmgimp.DtmGrpcCall(&s.Saga.TransBase, "Submit")
}

55
dtmgrpc/tcc.go

@ -4,12 +4,14 @@ import (
context "context"
"fmt"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/dtmgrpc/dtmgimp"
"google.golang.org/protobuf/proto"
)
// TccGrpc struct of tcc
type TccGrpc struct {
dtmcli.TransBase
dtmimp.TransBase
}
// TccGlobalFunc type of global tcc call
@ -20,9 +22,9 @@ type TccGlobalFunc func(tcc *TccGrpc) error
// gid 全局事务id
// tccFunc tcc事务函数,里面会定义全局事务的分支
func TccGlobalTransaction(dtm string, gid string, tccFunc TccGlobalFunc) (rerr error) {
tcc := &TccGrpc{TransBase: *dtmcli.NewTransBase(gid, "tcc", dtm, "")}
dc := MustGetDtmClient(tcc.Dtm)
dr := &DtmRequest{
tcc := &TccGrpc{TransBase: *dtmimp.NewTransBase(gid, "tcc", dtm, "")}
dc := dtmgimp.MustGetDtmClient(tcc.Dtm)
dr := &dtmgimp.DtmRequest{
Gid: tcc.Gid,
TransType: tcc.TransType,
}
@ -48,46 +50,37 @@ func TccGlobalTransaction(dtm string, gid string, tccFunc TccGlobalFunc) (rerr e
return tccFunc(tcc)
}
// TccFromRequest tcc from request info
func TccFromRequest(br *BusiRequest) (*TccGrpc, error) {
// TccFromGrpc tcc from request info
func TccFromGrpc(ctx context.Context) (*TccGrpc, error) {
tcc := &TccGrpc{
TransBase: *dtmcli.NewTransBase(br.Info.Gid, br.Info.TransType, br.Dtm, br.Info.BranchID),
TransBase: *dtmgimp.TransBaseFromGrpc(ctx),
}
if tcc.Dtm == "" || tcc.Gid == "" {
return nil, fmt.Errorf("bad tcc info. dtm: %s, gid: %s parentID: %s", tcc.Dtm, tcc.Gid, br.Info.BranchID)
return nil, fmt.Errorf("bad tcc info. dtm: %s, gid: %s branchid: %s", tcc.Dtm, tcc.Gid, tcc.BranchID)
}
return tcc, nil
}
// CallBranch call a tcc branch
// 函数首先注册子事务的所有分支,成功后调用try分支,返回try分支的调用结果
func (t *TccGrpc) CallBranch(busiData []byte, tryURL string, confirmURL string, cancelURL string) (*BusiReply, error) {
branchID := t.NewBranchID()
_, err := MustGetDtmClient(t.Dtm).RegisterTccBranch(context.Background(), &DtmTccBranchRequest{
Info: &BranchInfo{
func (t *TccGrpc) CallBranch(busiMsg proto.Message, tryURL string, confirmURL string, cancelURL string, reply interface{}) error {
branchID := t.NewSubBranchID()
bd, err := proto.Marshal(busiMsg)
_, err = dtmgimp.MustGetDtmClient(t.Dtm).RegisterTccBranch(context.Background(), &dtmgimp.DtmTccBranchRequest{
Info: &dtmgimp.DtmBranchInfo{
Gid: t.Gid,
TransType: t.TransType,
BranchID: branchID,
},
BusiData: string(busiData),
Try: tryURL,
Confirm: confirmURL,
Cancel: cancelURL,
BusiPayload: bd,
Try: tryURL,
Confirm: confirmURL,
Cancel: cancelURL,
})
if err != nil {
return nil, err
return err
}
server, method := GetServerAndMethod(tryURL)
reply := &BusiReply{}
err = MustGetGrpcConn(server).Invoke(context.Background(), method, &BusiRequest{
Info: &BranchInfo{
Gid: t.Gid,
TransType: t.TransType,
BranchID: branchID,
BranchType: t.TransType,
},
BusiData: busiData,
Dtm: t.Dtm,
}, reply)
return reply, err
server, method := dtmgimp.GetServerAndMethod(tryURL)
return dtmgimp.MustGetGrpcConn(server, false).Invoke(
dtmgimp.TransInfo2Ctx(t.Gid, t.TransType, branchID, "try", t.Dtm), method, busiMsg, reply)
}

92
dtmgrpc/type.go

@ -2,101 +2,21 @@ package dtmgrpc
import (
context "context"
"fmt"
"strings"
sync "sync"
"github.com/yedf/dtm/dtmcli"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/emptypb"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/dtmgrpc/dtmgimp"
emptypb "google.golang.org/protobuf/types/known/emptypb"
)
var clients sync.Map
// GetGrpcConn 1
func GetGrpcConn(grpcServer string) (conn *grpc.ClientConn, rerr error) {
grpcServer = dtmcli.MayReplaceLocalhost(grpcServer)
v, ok := clients.Load(grpcServer)
if !ok {
dtmcli.Logf("grpc client connecting %s", grpcServer)
conn, rerr := grpc.Dial(grpcServer, grpc.WithInsecure(), grpc.WithUnaryInterceptor(GrpcClientLog))
if rerr == nil {
clients.Store(grpcServer, conn)
v = conn
dtmcli.Logf("grpc client inited for %s", grpcServer)
}
}
return v.(*grpc.ClientConn), rerr
}
// MustGetGrpcConn 1
func MustGetGrpcConn(grpcServer string) *grpc.ClientConn {
conn, err := GetGrpcConn(grpcServer)
dtmcli.E2P(err)
return conn
}
// MustGetDtmClient 1
func MustGetDtmClient(grpcServer string) DtmClient {
return NewDtmClient(MustGetGrpcConn(grpcServer))
}
// MustGenGid 1
// MustGenGid must gen a gid from grpcServer
func MustGenGid(grpcServer string) string {
dc := MustGetDtmClient(grpcServer)
dc := dtmgimp.MustGetDtmClient(grpcServer)
r, err := dc.NewGid(context.Background(), &emptypb.Empty{})
dtmcli.E2P(err)
dtmimp.E2P(err)
return r.Gid
}
// GetServerAndMethod 将grpc的url分解为server和method
func GetServerAndMethod(grpcURL string) (string, string) {
fs := strings.Split(grpcURL, "/")
server := fs[0]
method := "/" + strings.Join(fs[1:], "/")
return server, method
}
// GrpcServerLog 打印grpc服务端的日志
func GrpcServerLog(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
dtmcli.Logf("grpc server handling: %s %v", info.FullMethod, req)
m, err := handler(ctx, req)
res := fmt.Sprintf("grpc server handled: %s %v result: %v err: %v", info.FullMethod, req, m, err)
if err != nil {
dtmcli.LogRedf("%s", res)
} else {
dtmcli.Logf("%s", res)
}
return m, err
}
// GrpcClientLog 打印grpc服务端的日志
func GrpcClientLog(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
dtmcli.Logf("grpc client calling: %s%s %v", cc.Target(), method, req)
err := invoker(ctx, method, req, reply, cc, opts...)
res := fmt.Sprintf("grpc client called: %s%s %v result: %v err: %v", cc.Target(), method, req, reply, err)
if err != nil {
dtmcli.LogRedf("%s", res)
} else {
dtmcli.Logf("%s", res)
}
return err
}
// Result2Error 将通用的result转成grpc的error
func Result2Error(res interface{}, err error) error {
e := dtmcli.CheckResult(res, err)
if e == dtmcli.ErrFailure {
dtmcli.LogRedf("failure: res: %v, err: %v", res, e)
return status.New(codes.Aborted, dtmcli.ResultFailure).Err()
} else if e == dtmcli.ErrOngoing {
return status.New(codes.Aborted, dtmcli.ResultOngoing).Err()
}
return e
}
// SetCurrentDBType set the current db type
func SetCurrentDBType(dbType string) {
dtmcli.SetCurrentDBType(dbType)

5
dtmgrpc/type_test.go

@ -1,15 +1,16 @@
package dtmgrpc
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
)
func TestType(t *testing.T) {
_, err := BarrierFromGrpc(&BusiRequest{Info: &BranchInfo{}})
_, err := BarrierFromGrpc(context.Background())
assert.Error(t, err)
_, err = TccFromRequest(&BusiRequest{Info: &BranchInfo{}})
_, err = TccFromGrpc(context.Background())
assert.Error(t, err)
}

86
dtmgrpc/xa.go

@ -5,8 +5,10 @@ import (
"database/sql"
"fmt"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/dtmgrpc/dtmgimp"
grpc "google.golang.org/grpc"
"google.golang.org/protobuf/proto"
emptypb "google.golang.org/protobuf/types/known/emptypb"
)
@ -18,28 +20,28 @@ type XaGrpcLocalFunc func(db *sql.DB, xa *XaGrpc) error
// XaGrpcClient xa client
type XaGrpcClient struct {
dtmcli.XaClientBase
dtmimp.XaClientBase
}
// XaGrpc xa transaction
type XaGrpc struct {
dtmcli.TransBase
dtmimp.TransBase
}
// XaGrpcFromRequest construct xa info from request
func XaGrpcFromRequest(br *BusiRequest) (*XaGrpc, error) {
func XaGrpcFromRequest(ctx context.Context) (*XaGrpc, error) {
xa := &XaGrpc{
TransBase: *dtmcli.NewTransBase(br.Info.Gid, br.Info.TransType, br.Dtm, br.Info.BranchID),
TransBase: *dtmgimp.TransBaseFromGrpc(ctx),
}
if xa.Gid == "" || br.Info.BranchID == "" {
return nil, fmt.Errorf("bad xa info: gid: %s parentid: %s", xa.Gid, br.Info.BranchID)
if xa.Gid == "" || xa.BranchID == "" {
return nil, fmt.Errorf("bad xa info: gid: %s branchid: %s", xa.Gid, xa.BranchID)
}
return xa, nil
}
// NewXaGrpcClient construct a xa client
func NewXaGrpcClient(server string, mysqlConf map[string]string, notifyURL string) *XaGrpcClient {
xa := &XaGrpcClient{XaClientBase: dtmcli.XaClientBase{
xa := &XaGrpcClient{XaClientBase: dtmimp.XaClientBase{
Server: server,
Conf: mysqlConf,
NotifyURL: notifyURL,
@ -48,45 +50,49 @@ func NewXaGrpcClient(server string, mysqlConf map[string]string, notifyURL strin
}
// HandleCallback 处理commit/rollback的回调
func (xc *XaGrpcClient) HandleCallback(gid string, branchID string, action string) error {
return xc.XaClientBase.HandleCallback(gid, branchID, action)
func (xc *XaGrpcClient) HandleCallback(ctx context.Context) (*emptypb.Empty, error) {
tb := dtmgimp.TransBaseFromGrpc(ctx)
return &emptypb.Empty{}, xc.XaClientBase.HandleCallback(tb.Gid, tb.BranchID, tb.BranchType)
}
// XaLocalTransaction start a xa local transaction
func (xc *XaGrpcClient) XaLocalTransaction(br *BusiRequest, xaFunc XaGrpcLocalFunc) (rerr error) {
xa, rerr := XaGrpcFromRequest(br)
if rerr != nil {
return
func (xc *XaGrpcClient) XaLocalTransaction(ctx context.Context, msg proto.Message, xaFunc XaGrpcLocalFunc) error {
xa, err := XaGrpcFromRequest(ctx)
if err != nil {
return err
}
data, err := proto.Marshal(msg)
if err != nil {
return err
}
_, rerr = xc.HandleLocalTrans(&xa.TransBase, func(db *sql.DB) (interface{}, error) {
rerr := xaFunc(db, xa)
if rerr != nil {
return nil, rerr
return xc.HandleLocalTrans(&xa.TransBase, func(db *sql.DB) error {
err := xaFunc(db, xa)
if err != nil {
return err
}
_, rerr = MustGetDtmClient(xa.Dtm).RegisterXaBranch(context.Background(), &DtmXaBranchRequest{
Info: &BranchInfo{
_, err = dtmgimp.MustGetDtmClient(xa.Dtm).RegisterXaBranch(context.Background(), &dtmgimp.DtmXaBranchRequest{
Info: &dtmgimp.DtmBranchInfo{
Gid: xa.Gid,
BranchID: xa.CurrentBranchID(),
BranchID: xa.BranchID,
TransType: xa.TransType,
},
BusiData: "",
Notify: xc.NotifyURL,
BusiPayload: data,
Notify: xc.NotifyURL,
})
return nil, rerr
return err
})
return
}
// XaGlobalTransaction start a xa global transaction
func (xc *XaGrpcClient) XaGlobalTransaction(gid string, xaFunc XaGrpcGlobalFunc) (rerr error) {
xa := XaGrpc{TransBase: *dtmcli.NewTransBase(gid, "xa", xc.Server, "")}
dc := MustGetDtmClient(xa.Dtm)
req := &DtmRequest{
func (xc *XaGrpcClient) XaGlobalTransaction(gid string, xaFunc XaGrpcGlobalFunc) error {
xa := XaGrpc{TransBase: *dtmimp.NewTransBase(gid, "xa", xc.Server, "")}
dc := dtmgimp.MustGetDtmClient(xa.Dtm)
req := &dtmgimp.DtmRequest{
Gid: gid,
TransType: xa.TransType,
}
return xc.HandleGlobalTrans(&xa.TransBase, func(action string) error {
f := map[string]func(context.Context, *DtmRequest, ...grpc.CallOption) (*emptypb.Empty, error){
f := map[string]func(context.Context, *dtmgimp.DtmRequest, ...grpc.CallOption) (*emptypb.Empty, error){
"prepare": dc.Prepare,
"submit": dc.Submit,
"abort": dc.Abort,
@ -99,20 +105,10 @@ func (xc *XaGrpcClient) XaGlobalTransaction(gid string, xaFunc XaGrpcGlobalFunc)
}
// CallBranch call a xa branch
func (x *XaGrpc) CallBranch(busiData []byte, url string) (*BusiReply, error) {
branchID := x.NewBranchID()
server, method := GetServerAndMethod(url)
reply := &BusiReply{}
err := MustGetGrpcConn(server).Invoke(context.Background(), method, &BusiRequest{
Info: &BranchInfo{
Gid: x.Gid,
TransType: x.TransType,
BranchID: branchID,
BranchType: "",
},
Dtm: x.Dtm,
BusiData: busiData,
}, reply)
return reply, err
func (x *XaGrpc) CallBranch(msg proto.Message, url string, reply interface{}) error {
server, method := dtmgimp.GetServerAndMethod(url)
err := dtmgimp.MustGetGrpcConn(server, false).Invoke(
dtmgimp.TransInfo2Ctx(x.Gid, x.TransType, x.NewSubBranchID(), "action", x.Dtm), method, msg, reply)
return err
}

12
dtmsvr/api.go

@ -18,7 +18,7 @@ func svcSubmit(t *TransGlobal) (interface{}, error) {
updates := t.setNextCron(cronReset)
db.Must().Model(t).Where("gid=? and status=?", t.Gid, dtmcli.StatusPrepared).Select(append(updates, "status")).Updates(t)
} else if dbt.Status != dtmcli.StatusSubmitted {
return M{"dtm_result": dtmcli.ResultFailure, "message": fmt.Sprintf("current status '%s', cannot sumbmit", dbt.Status)}, nil
return map[string]interface{}{"dtm_result": dtmcli.ResultFailure, "message": fmt.Sprintf("current status '%s', cannot sumbmit", dbt.Status)}, nil
}
}
return t.Process(db), nil
@ -30,7 +30,7 @@ func svcPrepare(t *TransGlobal) (interface{}, error) {
if err == errUniqueConflict {
dbt := transFromDb(dbGet(), t.Gid)
if dbt.Status != dtmcli.StatusPrepared {
return M{"dtm_result": dtmcli.ResultFailure, "message": fmt.Sprintf("current status '%s', cannot prepare", dbt.Status)}, nil
return map[string]interface{}{"dtm_result": dtmcli.ResultFailure, "message": fmt.Sprintf("current status '%s', cannot prepare", dbt.Status)}, nil
}
}
return dtmcli.MapSuccess, nil
@ -40,17 +40,17 @@ func svcAbort(t *TransGlobal) (interface{}, error) {
db := dbGet()
dbt := transFromDb(db, t.Gid)
if t.TransType != "xa" && t.TransType != "tcc" || dbt.Status != dtmcli.StatusPrepared && dbt.Status != dtmcli.StatusAborting {
return M{"dtm_result": dtmcli.ResultFailure, "message": fmt.Sprintf("trans type: '%s' current status '%s', cannot abort", dbt.TransType, dbt.Status)}, nil
return map[string]interface{}{"dtm_result": dtmcli.ResultFailure, "message": fmt.Sprintf("trans type: '%s' current status '%s', cannot abort", dbt.TransType, dbt.Status)}, nil
}
dbt.changeStatus(db, dtmcli.StatusAborting)
return dbt.Process(db), nil
}
func svcRegisterTccBranch(branch *TransBranch, data dtmcli.MS) (interface{}, error) {
func svcRegisterTccBranch(branch *TransBranch, data map[string]string) (interface{}, error) {
db := dbGet()
dbt := transFromDb(db, branch.Gid)
if dbt.Status != dtmcli.StatusPrepared {
return M{"dtm_result": dtmcli.ResultFailure, "message": fmt.Sprintf("current status: %s cannot register branch", dbt.Status)}, nil
return map[string]interface{}{"dtm_result": dtmcli.ResultFailure, "message": fmt.Sprintf("current status: %s cannot register branch", dbt.Status)}, nil
}
branches := []TransBranch{*branch, *branch, *branch}
@ -72,7 +72,7 @@ func svcRegisterXaBranch(branch *TransBranch) (interface{}, error) {
db := dbGet()
dbt := transFromDb(db, branch.Gid)
if dbt.Status != dtmcli.StatusPrepared {
return M{"dtm_result": dtmcli.ResultFailure, "message": fmt.Sprintf("current status: %s cannot register branch", dbt.Status)}, nil
return map[string]interface{}{"dtm_result": dtmcli.ResultFailure, "message": fmt.Sprintf("current status: %s cannot register branch", dbt.Status)}, nil
}
branches := []TransBranch{*branch, *branch}
branches[0].BranchType = dtmcli.BranchRollback

26
dtmsvr/api_grpc.go

@ -4,33 +4,33 @@ import (
"context"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmgrpc"
pb "github.com/yedf/dtm/dtmgrpc"
"github.com/yedf/dtm/dtmgrpc/dtmgimp"
pb "github.com/yedf/dtm/dtmgrpc/dtmgimp"
"google.golang.org/protobuf/types/known/emptypb"
)
// dtmServer is used to implement dtmgrpc.DtmServer.
// dtmServer is used to implement dtmgimp.DtmServer.
type dtmServer struct {
pb.UnimplementedDtmServer
}
func (s *dtmServer) NewGid(ctx context.Context, in *emptypb.Empty) (*dtmgrpc.DtmGidReply, error) {
return &dtmgrpc.DtmGidReply{Gid: GenGid()}, nil
func (s *dtmServer) NewGid(ctx context.Context, in *emptypb.Empty) (*dtmgimp.DtmGidReply, error) {
return &dtmgimp.DtmGidReply{Gid: GenGid()}, nil
}
func (s *dtmServer) Submit(ctx context.Context, in *pb.DtmRequest) (*emptypb.Empty, error) {
r, err := svcSubmit(TransFromDtmRequest(in))
return &emptypb.Empty{}, dtmgrpc.Result2Error(r, err)
return &emptypb.Empty{}, dtmgimp.Result2Error(r, err)
}
func (s *dtmServer) Prepare(ctx context.Context, in *pb.DtmRequest) (*emptypb.Empty, error) {
r, err := svcPrepare(TransFromDtmRequest(in))
return &emptypb.Empty{}, dtmgrpc.Result2Error(r, err)
return &emptypb.Empty{}, dtmgimp.Result2Error(r, err)
}
func (s *dtmServer) Abort(ctx context.Context, in *pb.DtmRequest) (*emptypb.Empty, error) {
r, err := svcAbort(TransFromDtmRequest(in))
return &emptypb.Empty{}, dtmgrpc.Result2Error(r, err)
return &emptypb.Empty{}, dtmgimp.Result2Error(r, err)
}
func (s *dtmServer) RegisterTccBranch(ctx context.Context, in *pb.DtmTccBranchRequest) (*emptypb.Empty, error) {
@ -38,13 +38,13 @@ func (s *dtmServer) RegisterTccBranch(ctx context.Context, in *pb.DtmTccBranchRe
Gid: in.Info.Gid,
BranchID: in.Info.BranchID,
Status: dtmcli.StatusPrepared,
Data: in.BusiData,
}, dtmcli.MS{
BinData: in.BusiPayload,
}, map[string]string{
dtmcli.BranchCancel: in.Cancel,
dtmcli.BranchConfirm: in.Confirm,
dtmcli.BranchTry: in.Try,
})
return &emptypb.Empty{}, dtmgrpc.Result2Error(r, err)
return &emptypb.Empty{}, dtmgimp.Result2Error(r, err)
}
func (s *dtmServer) RegisterXaBranch(ctx context.Context, in *pb.DtmXaBranchRequest) (*emptypb.Empty, error) {
@ -52,8 +52,8 @@ func (s *dtmServer) RegisterXaBranch(ctx context.Context, in *pb.DtmXaBranchRequ
Gid: in.Info.Gid,
BranchID: in.Info.BranchID,
Status: dtmcli.StatusPrepared,
Data: in.BusiData,
BinData: in.BusiPayload,
URL: in.Notify,
})
return &emptypb.Empty{}, dtmgrpc.Result2Error(r, err)
return &emptypb.Empty{}, dtmgimp.Result2Error(r, err)
}

13
dtmsvr/api_http.go

@ -7,6 +7,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/yedf/dtm/common"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
)
func addRoute(engine *gin.Engine) {
@ -21,7 +22,7 @@ func addRoute(engine *gin.Engine) {
}
func newGid(c *gin.Context) (interface{}, error) {
return M{"gid": GenGid(), "dtm_result": dtmcli.ResultSuccess}, nil
return map[string]interface{}{"gid": GenGid(), "dtm_result": dtmcli.ResultSuccess}, nil
}
func prepare(c *gin.Context) (interface{}, error) {
@ -44,14 +45,14 @@ func registerXaBranch(c *gin.Context) (interface{}, error) {
}
func registerTccBranch(c *gin.Context) (interface{}, error) {
data := dtmcli.MS{}
data := map[string]string{}
err := c.BindJSON(&data)
e2p(err)
branch := TransBranch{
Gid: data["gid"],
BranchID: data["branch_id"],
Status: dtmcli.StatusPrepared,
Data: data["data"],
BinData: []byte(data["data"]),
}
return svcRegisterTccBranch(&branch, data)
}
@ -65,16 +66,16 @@ func query(c *gin.Context) (interface{}, error) {
trans := transFromDb(db, gid)
branches := []TransBranch{}
db.Must().Where("gid", gid).Find(&branches)
return M{"transaction": trans, "branches": branches}, nil
return map[string]interface{}{"transaction": trans, "branches": branches}, nil
}
func all(c *gin.Context) (interface{}, error) {
lastID := c.Query("last_id")
lid := math.MaxInt64
if lastID != "" {
lid = dtmcli.MustAtoi(lastID)
lid = dtmimp.MustAtoi(lastID)
}
trans := []TransGlobal{}
dbGet().Must().Where("id < ?", lid).Order("id desc").Limit(100).Find(&trans)
return M{"transactions": trans}, nil
return map[string]interface{}{"transactions": trans}, nil
}

10
dtmsvr/cron.go

@ -6,7 +6,7 @@ import (
"runtime/debug"
"time"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
)
// NowForwardDuration will be set in test, trans may be timeout
@ -42,7 +42,7 @@ func lockOneTrans(expireIn time.Duration) *TransGlobal {
trans := TransGlobal{}
owner := GenGid()
db := dbGet()
getTime := dtmcli.GetDBSpecial().TimestampAdd
getTime := dtmimp.GetDBSpecial().TimestampAdd
expire := int(expireIn / time.Second)
whereTime := fmt.Sprintf("next_cron_time < %s and update_time < %s", getTime(expire), getTime(expire-3))
// 这里next_cron_time需要限定范围,否则数据量累计之后,会导致查询变慢
@ -60,7 +60,7 @@ func lockOneTrans(expireIn time.Duration) *TransGlobal {
func handlePanic(perr *error) {
if err := recover(); err != nil {
dtmcli.LogRedf("----recovered panic %v\n%s", err, string(debug.Stack()))
dtmimp.LogRedf("----recovered panic %v\n%s", err, string(debug.Stack()))
if perr != nil {
*perr = fmt.Errorf("dtm panic: %v", err)
}
@ -69,7 +69,7 @@ func handlePanic(perr *error) {
func sleepCronTime() {
normal := time.Duration((float64(config.TransCronInterval) - rand.Float64()) * float64(time.Second))
interval := dtmcli.If(CronForwardDuration > 0, 1*time.Millisecond, normal).(time.Duration)
dtmcli.Logf("sleeping for %v milli", interval/time.Microsecond)
interval := dtmimp.If(CronForwardDuration > 0, 1*time.Millisecond, normal).(time.Duration)
dtmimp.Logf("sleeping for %v milli", interval/time.Microsecond)
time.Sleep(interval)
}

24
dtmsvr/dtmsvr.go

@ -6,8 +6,8 @@ import (
"time"
"github.com/yedf/dtm/common"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmgrpc"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/dtmgrpc/dtmgimp"
"gorm.io/gorm/clause"
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
@ -22,29 +22,29 @@ var metricsPort = 8889
// StartSvr StartSvr
func StartSvr() {
dtmcli.Logf("start dtmsvr")
dtmimp.Logf("start dtmsvr")
app := common.GetGinApp()
app = httpMetrics(app)
addRoute(app)
dtmcli.Logf("dtmsvr listen at: %d", dtmsvrPort)
dtmimp.Logf("dtmsvr listen at: %d", dtmsvrPort)
go app.Run(fmt.Sprintf(":%d", dtmsvrPort))
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", dtmsvrGrpcPort))
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
s := grpc.NewServer(
grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
grpc.UnaryServerInterceptor(grpcMetrics), grpc.UnaryServerInterceptor(dtmgrpc.GrpcServerLog)),
grpc.UnaryServerInterceptor(grpcMetrics), grpc.UnaryServerInterceptor(dtmgimp.GrpcServerLog)),
))
dtmgrpc.RegisterDtmServer(s, &dtmServer{})
dtmcli.Logf("grpc listening at %v", lis.Addr())
dtmgimp.RegisterDtmServer(s, &dtmServer{})
dtmimp.Logf("grpc listening at %v", lis.Addr())
go func() {
err := s.Serve(lis)
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
}()
go updateBranchAsync()
// prometheus exporter
dtmcli.Logf("prometheus exporter listen at: %d", metricsPort)
dtmimp.Logf("prometheus exporter listen at: %d", metricsPort)
prometheusHTTPRun(fmt.Sprintf("%d", metricsPort))
time.Sleep(100 * time.Millisecond)
}
@ -80,9 +80,9 @@ func updateBranchAsync() {
OnConstraint: "trans_branch_pkey",
DoUpdates: clause.AssignmentColumns([]string{"status", "finish_time"}),
}).Create(updates)
dtmcli.Logf("flushed %d branch status to db. affected: %d", len(updates), dbr.RowsAffected)
dtmimp.Logf("flushed %d branch status to db. affected: %d", len(updates), dbr.RowsAffected)
if dbr.Error != nil {
dtmcli.LogRedf("async update branch status error: %v", dbr.Error)
dtmimp.LogRedf("async update branch status error: %v", dbr.Error)
time.Sleep(1 * time.Second)
} else {
updates = []TransBranch{}

1
dtmsvr/dtmsvr.mysql.sql

@ -33,6 +33,7 @@ CREATE TABLE IF NOT EXISTS dtm.trans_branch (
`gid` varchar(128) NOT NULL COMMENT '事务全局id',
`url` varchar(128) NOT NULL COMMENT '动作关联的url',
`data` TEXT COMMENT '请求所携带的数据',
`bin_data` BLOB COMMENT 'grpc的二进制数据',
`branch_id` VARCHAR(128) NOT NULL COMMENT '事务分支名称',
`branch_type` varchar(45) NOT NULL COMMENT '事务分支类型 saga_action | saga_compensate | xa',
`status` varchar(45) NOT NULL COMMENT '步骤的状态 submitted | finished | rollbacked',

1
dtmsvr/dtmsvr.postgres.sql

@ -36,6 +36,7 @@ CREATE TABLE IF NOT EXISTS dtm.trans_branch (
gid varchar(128) NOT NULL,
url varchar(128) NOT NULL,
data TEXT,
bin_data BLOB,
branch_id VARCHAR(128) NOT NULL,
branch_type varchar(45) NOT NULL,
status varchar(45) NOT NULL,

113
dtmsvr/trans.go

@ -1,7 +1,6 @@
package dtmsvr
import (
"context"
"errors"
"fmt"
"strings"
@ -10,10 +9,10 @@ import (
"github.com/gin-gonic/gin"
"github.com/yedf/dtm/common"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmgrpc"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/dtmgrpc/dtmgimp"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/emptypb"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
@ -23,12 +22,14 @@ var errUniqueConflict = errors.New("unique key conflict error")
// TransGlobal global transaction
type TransGlobal struct {
common.ModelBase
Gid string `json:"gid"`
TransType string `json:"trans_type"`
Data string `json:"data" gorm:"-"`
Status string `json:"status"`
QueryPrepared string `json:"query_prepared"`
Protocol string `json:"protocol"`
Gid string `json:"gid"`
TransType string `json:"trans_type"`
Steps []map[string]string `json:"steps" gorm:"-"`
Payloads []string `json:"payloads" gorm:"-"`
BinPayloads [][]byte `json:"-" gorm:"-"`
Status string `json:"status"`
QueryPrepared string `json:"query_prepared"`
Protocol string `json:"protocol"`
CommitTime *time.Time
FinishTime *time.Time
RollbackTime *time.Time
@ -36,7 +37,7 @@ type TransGlobal struct {
CustomData string `json:"custom_data"`
NextCronInterval int64
NextCronTime *time.Time
dtmcli.TransOptions
dtmimp.TransOptions
lastTouched time.Time // record the start time of process
}
@ -51,14 +52,12 @@ type transProcessor interface {
}
func (t *TransGlobal) touch(db *common.DB, ctype cronType) *gorm.DB {
writeTransLog(t.Gid, "touch trans", "", "", "")
t.lastTouched = time.Now()
updates := t.setNextCron(ctype)
return db.Model(&TransGlobal{}).Where("gid=?", t.Gid).Select(updates).Updates(t)
}
func (t *TransGlobal) changeStatus(db *common.DB, status string) *gorm.DB {
writeTransLog(t.Gid, "change status", status, "", "")
old := t.Status
t.Status = status
updates := t.setNextCron(cronReset)
@ -96,7 +95,7 @@ type TransBranch struct {
common.ModelBase
Gid string
URL string `json:"url"`
Data string
BinData []byte
BranchID string `json:"branch_id"`
BranchType string
Status string
@ -110,9 +109,8 @@ func (*TransBranch) TableName() string {
}
func (t *TransBranch) changeStatus(db *common.DB, status string) *gorm.DB {
writeTransLog(t.Gid, "branch change", status, t.BranchID, "")
if common.DtmConfig.UpdateBranchSync > 0 {
dbr := db.Must().Model(t).Updates(M{
dbr := db.Must().Model(t).Updates(map[string]interface{}{
"status": status,
"finish_time": time.Now(),
})
@ -126,7 +124,7 @@ func (t *TransBranch) changeStatus(db *common.DB, status string) *gorm.DB {
func checkAffected(db1 *gorm.DB) {
if db1.RowsAffected == 0 {
panic(fmt.Errorf("duplicate updating"))
panic(fmt.Errorf("rows affected 0, please check for abnormal trans"))
}
}
@ -143,15 +141,15 @@ func (t *TransGlobal) getProcessor() transProcessor {
}
// Process process global transaction once
func (t *TransGlobal) Process(db *common.DB) dtmcli.M {
func (t *TransGlobal) Process(db *common.DB) map[string]interface{} {
r := t.process(db)
transactionMetrics(t, r["dtm_result"] == dtmcli.ResultSuccess)
return r
}
func (t *TransGlobal) process(db *common.DB) dtmcli.M {
func (t *TransGlobal) process(db *common.DB) map[string]interface{} {
if t.Options != "" {
dtmcli.MustUnmarshalString(t.Options, &t.TransOptions)
dtmimp.MustUnmarshalString(t.Options, &t.TransOptions)
}
if !t.WaitResult {
@ -161,10 +159,10 @@ func (t *TransGlobal) process(db *common.DB) dtmcli.M {
submitting := t.Status == dtmcli.StatusSubmitted
err := t.processInner(db)
if err != nil {
return dtmcli.M{"dtm_result": dtmcli.ResultFailure, "message": err.Error()}
return map[string]interface{}{"dtm_result": dtmcli.ResultFailure, "message": err.Error()}
}
if submitting && t.Status != dtmcli.StatusSucceed {
return dtmcli.M{"dtm_result": dtmcli.ResultFailure, "message": "trans failed by user"}
return map[string]interface{}{"dtm_result": dtmcli.ResultFailure, "message": "trans failed by user"}
}
return dtmcli.MapSuccess
}
@ -173,15 +171,15 @@ func (t *TransGlobal) processInner(db *common.DB) (rerr error) {
defer handlePanic(&rerr)
defer func() {
if rerr != nil {
dtmcli.LogRedf("processInner got error: %s", rerr.Error())
dtmimp.LogRedf("processInner got error: %s", rerr.Error())
}
if TransProcessedTestChan != nil {
dtmcli.Logf("processed: %s", t.Gid)
dtmimp.Logf("processed: %s", t.Gid)
TransProcessedTestChan <- t.Gid
dtmcli.Logf("notified: %s", t.Gid)
dtmimp.Logf("notified: %s", t.Gid)
}
}()
dtmcli.Logf("processing: %s status: %s", t.Gid, t.Status)
dtmimp.Logf("processing: %s status: %s", t.Gid, t.Status)
branches := []TransBranch{}
db.Must().Where("gid=?", t.Gid).Order("id asc").Find(&branches)
t.lastTouched = time.Now()
@ -213,20 +211,13 @@ func (t *TransGlobal) setNextCron(ctype cronType) []string {
return []string{"next_cron_interval", "next_cron_time"}
}
func (t *TransGlobal) getURLResult(url string, branchID, branchType string, branchData []byte) (string, error) {
func (t *TransGlobal) getURLResult(url string, branchID, branchType string, branchPayload []byte) (string, error) {
if t.Protocol == "grpc" {
dtmcli.PanicIf(strings.HasPrefix(url, "http"), fmt.Errorf("bad url for grpc: %s", url))
server, method := dtmgrpc.GetServerAndMethod(url)
conn := dtmgrpc.MustGetGrpcConn(server)
err := conn.Invoke(context.Background(), method, &dtmgrpc.BusiRequest{
Info: &dtmgrpc.BranchInfo{
Gid: t.Gid,
TransType: t.TransType,
BranchID: branchID,
BranchType: branchType,
},
BusiData: branchData,
}, &emptypb.Empty{})
dtmimp.PanicIf(strings.HasPrefix(url, "http"), fmt.Errorf("bad url for grpc: %s", url))
server, method := dtmgimp.GetServerAndMethod(url)
conn := dtmgimp.MustGetGrpcConn(server, true)
ctx := dtmgimp.TransInfo2Ctx(t.Gid, t.TransType, branchID, branchType, "")
err := conn.Invoke(ctx, method, branchPayload, []byte{})
if err == nil {
return dtmcli.ResultSuccess, nil
}
@ -240,16 +231,16 @@ func (t *TransGlobal) getURLResult(url string, branchID, branchType string, bran
}
return "", err
}
dtmcli.PanicIf(!strings.HasPrefix(url, "http"), fmt.Errorf("bad url for http: %s", url))
resp, err := dtmcli.RestyClient.R().SetBody(string(branchData)).
SetQueryParams(dtmcli.MS{
dtmimp.PanicIf(!strings.HasPrefix(url, "http"), fmt.Errorf("bad url for http: %s", url))
resp, err := dtmimp.RestyClient.R().SetBody(string(branchPayload)).
SetQueryParams(map[string]string{
"gid": t.Gid,
"trans_type": t.TransType,
"branch_id": branchID,
"branch_type": branchType,
}).
SetHeader("Content-type", "application/json").
Execute(dtmcli.If(branchData == nil, "GET", "POST").(string), url)
Execute(dtmimp.If(branchPayload != nil || t.TransType == "xa", "POST", "GET").(string), url)
if err != nil {
return "", err
}
@ -257,7 +248,7 @@ func (t *TransGlobal) getURLResult(url string, branchID, branchType string, bran
}
func (t *TransGlobal) getBranchResult(branch *TransBranch) (string, error) {
body, err := t.getURLResult(branch.URL, branch.BranchID, branch.BranchType, []byte(branch.Data))
body, err := t.getURLResult(branch.URL, branch.BranchID, branch.BranchType, branch.BinData)
if err != nil {
return "", err
}
@ -266,7 +257,7 @@ func (t *TransGlobal) getBranchResult(branch *TransBranch) (string, error) {
} else if strings.HasSuffix(t.TransType, "saga") && branch.BranchType == dtmcli.BranchAction && strings.Contains(body, dtmcli.ResultFailure) {
return dtmcli.StatusFailed, nil
} else if strings.Contains(body, dtmcli.ResultOngoing) {
return "", dtmcli.ErrOngoing
return "", dtmimp.ErrOngoing
}
return "", fmt.Errorf("http result should contains SUCCESS|FAILURE|ONGOING. grpc error should return nil|Aborted with message(FAILURE|ONGOING). \nrefer to: https://dtm.pub/summary/arch.html#http\nunkown result will be retried: %s", body)
}
@ -281,7 +272,7 @@ func (t *TransGlobal) execBranch(db *common.DB, branch *TransBranch) error {
if err == nil && time.Since(t.lastTouched)+NowForwardDuration >= 1500*time.Millisecond ||
t.NextCronInterval > config.RetryInterval && t.NextCronInterval > t.RetryInterval {
t.touch(db, cronReset)
} else if err == dtmcli.ErrOngoing {
} else if err == dtmimp.ErrOngoing {
t.touch(db, cronKeep)
} else {
t.touch(db, cronBackoff)
@ -293,11 +284,10 @@ func (t *TransGlobal) saveNew(db *common.DB) error {
return db.Transaction(func(db1 *gorm.DB) error {
db := &common.DB{DB: db1}
t.setNextCron(cronReset)
t.Options = dtmcli.MustMarshalString(t.TransOptions)
t.Options = dtmimp.MustMarshalString(t.TransOptions)
if t.Options == "{}" {
t.Options = ""
}
writeTransLog(t.Gid, "create trans", t.Status, "", t.Data)
dbr := db.Must().Clauses(clause.OnConflict{
DoNothing: true,
}).Create(t)
@ -306,7 +296,6 @@ func (t *TransGlobal) saveNew(db *common.DB) error {
}
branches := t.getProcessor().GenBranches()
if len(branches) > 0 {
writeTransLog(t.Gid, "save branches", t.Status, "", dtmcli.MustMarshalString(branches))
checkLocalhost(branches)
db.Must().Clauses(clause.OnConflict{
DoNothing: true,
@ -318,27 +307,35 @@ func (t *TransGlobal) saveNew(db *common.DB) error {
// TransFromContext TransFromContext
func TransFromContext(c *gin.Context) *TransGlobal {
data := M{}
b, err := c.GetRawData()
e2p(err)
dtmcli.MustUnmarshal(b, &data)
dtmcli.Logf("creating trans in prepare")
if data["steps"] != nil {
data["data"] = dtmcli.MustMarshalString(data["steps"])
}
m := TransGlobal{}
dtmcli.MustRemarshal(data, &m)
dtmimp.MustUnmarshal(b, &m)
dtmimp.Logf("creating trans in prepare")
// Payloads will be store in BinPayloads, Payloads is only used to Unmarshal
for _, p := range m.Payloads {
m.BinPayloads = append(m.BinPayloads, []byte(p))
}
for _, d := range m.Steps {
if d["data"] != "" {
m.BinPayloads = append(m.BinPayloads, []byte(d["data"]))
}
}
m.Protocol = "http"
return &m
}
// TransFromDtmRequest TransFromContext
func TransFromDtmRequest(c *dtmgrpc.DtmRequest) *TransGlobal {
return &TransGlobal{
func TransFromDtmRequest(c *dtmgimp.DtmRequest) *TransGlobal {
r := TransGlobal{
Gid: c.Gid,
TransType: c.TransType,
QueryPrepared: c.QueryPrepared,
Data: c.Data,
Protocol: "grpc",
BinPayloads: c.BinPayloads,
}
if c.Steps != "" {
dtmimp.MustUnmarshalString(c.Steps, &r.Steps)
}
return &r
}

19
dtmsvr/trans_msg.go

@ -1,10 +1,12 @@
package dtmsvr
import (
"fmt"
"strings"
"github.com/yedf/dtm/common"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
)
type transMsgProcessor struct {
@ -17,17 +19,16 @@ func init() {
func (t *transMsgProcessor) GenBranches() []TransBranch {
branches := []TransBranch{}
steps := []M{}
dtmcli.MustUnmarshalString(t.Data, &steps)
for _, step := range steps {
branches = append(branches, TransBranch{
for i, step := range t.Steps {
b := &TransBranch{
Gid: t.Gid,
BranchID: GenGid(),
Data: step["data"].(string),
URL: step[dtmcli.BranchAction].(string),
BranchID: fmt.Sprintf("%02d", i+1),
BinData: t.BinPayloads[i],
URL: step[dtmcli.BranchAction],
BranchType: dtmcli.BranchAction,
Status: dtmcli.StatusPrepared,
})
}
branches = append(branches, *b)
}
return branches
}
@ -44,7 +45,7 @@ func (t *TransGlobal) mayQueryPrepared(db *common.DB) {
} else if strings.Contains(body, dtmcli.ResultOngoing) {
t.touch(db, cronReset)
} else {
dtmcli.LogRedf("getting result failed for %s. error: %s", t.QueryPrepared, err.Error())
dtmimp.LogRedf("getting result failed for %s. error: %s", t.QueryPrepared, err.Error())
t.touch(db, cronBackoff)
}
}

23
dtmsvr/trans_saga.go

@ -6,6 +6,7 @@ import (
"github.com/yedf/dtm/common"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
)
type transSagaProcessor struct {
@ -18,16 +19,14 @@ func init() {
func (t *transSagaProcessor) GenBranches() []TransBranch {
branches := []TransBranch{}
steps := []M{}
dtmcli.MustUnmarshalString(t.Data, &steps)
for i, step := range steps {
for i, step := range t.Steps {
branch := fmt.Sprintf("%02d", i+1)
for _, branchType := range []string{dtmcli.BranchCompensate, dtmcli.BranchAction} {
branches = append(branches, TransBranch{
Gid: t.Gid,
BranchID: branch,
Data: step["data"].(string),
URL: step[branchType].(string),
BinData: t.BinPayloads[i],
URL: step[branchType],
BranchType: branchType,
Status: dtmcli.StatusPrepared,
})
@ -50,7 +49,7 @@ type branchResult struct {
func (t *transSagaProcessor) ProcessOnce(db *common.DB, branches []TransBranch) error {
// when saga tasks is fetched, it always need to process
dtmcli.Logf("status: %s timeout: %t", t.Status, t.isTimeout())
dtmimp.Logf("status: %s timeout: %t", t.Status, t.isTimeout())
if t.Status == dtmcli.StatusSubmitted && t.isTimeout() {
t.changeStatus(db, dtmcli.StatusAborting)
}
@ -58,7 +57,7 @@ func (t *transSagaProcessor) ProcessOnce(db *common.DB, branches []TransBranch)
csc := cSagaCustom{Orders: map[int][]int{}}
if t.CustomData != "" {
dtmcli.MustUnmarshalString(t.CustomData, &csc)
dtmimp.MustUnmarshalString(t.CustomData, &csc)
}
// resultStats
var rsAToStart, rsAStarted, rsADone, rsAFailed, rsASucceed, rsCToStart, rsCDone, rsCSucceed int
@ -93,11 +92,11 @@ func (t *transSagaProcessor) ProcessOnce(db *common.DB, branches []TransBranch)
var err error
defer func() {
if x := recover(); x != nil {
err = dtmcli.AsError(x)
err = dtmimp.AsError(x)
}
resultChan <- branchResult{index: i, status: branches[i].Status, branchType: branches[i].BranchType}
if err != nil {
dtmcli.LogRedf("exec branch error: %v", err)
dtmimp.LogRedf("exec branch error: %v", err)
}
}()
err = t.execBranch(db, &branches[i])
@ -110,7 +109,7 @@ func (t *transSagaProcessor) ProcessOnce(db *common.DB, branches []TransBranch)
toRun = append(toRun, current)
}
}
dtmcli.Logf("toRun picked for action is: %v", toRun)
dtmimp.Logf("toRun picked for action is: %v", toRun)
return toRun
}
runBranches := func(toRun []int) {
@ -152,9 +151,9 @@ func (t *transSagaProcessor) ProcessOnce(db *common.DB, branches []TransBranch)
rsCSucceed++
}
}
dtmcli.Logf("branch done: %v", r)
dtmimp.Logf("branch done: %v", r)
case <-time.After(time.Duration(time.Second * 3)):
dtmcli.Logf("wait once for done")
dtmimp.Logf("wait once for done")
}
}

5
dtmsvr/trans_tcc.go

@ -3,6 +3,7 @@ package dtmsvr
import (
"github.com/yedf/dtm/common"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
)
type transTccProcessor struct {
@ -24,7 +25,7 @@ func (t *transTccProcessor) ProcessOnce(db *common.DB, branches []TransBranch) e
if t.Status == dtmcli.StatusPrepared && t.isTimeout() {
t.changeStatus(db, dtmcli.StatusAborting)
}
branchType := dtmcli.If(t.Status == dtmcli.StatusSubmitted, dtmcli.BranchConfirm, dtmcli.BranchCancel).(string)
branchType := dtmimp.If(t.Status == dtmcli.StatusSubmitted, dtmcli.BranchConfirm, dtmcli.BranchCancel).(string)
for current := len(branches) - 1; current >= 0; current-- {
if branches[current].BranchType == branchType && branches[current].Status == dtmcli.StatusPrepared {
err := t.execBranch(db, &branches[current])
@ -33,6 +34,6 @@ func (t *transTccProcessor) ProcessOnce(db *common.DB, branches []TransBranch) e
}
}
}
t.changeStatus(db, dtmcli.If(t.Status == dtmcli.StatusSubmitted, dtmcli.StatusSucceed, dtmcli.StatusFailed).(string))
t.changeStatus(db, dtmimp.If(t.Status == dtmcli.StatusSubmitted, dtmcli.StatusSucceed, dtmcli.StatusFailed).(string))
return nil
}

5
dtmsvr/trans_xa.go

@ -3,6 +3,7 @@ package dtmsvr
import (
"github.com/yedf/dtm/common"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
)
type transXaProcessor struct {
@ -24,7 +25,7 @@ func (t *transXaProcessor) ProcessOnce(db *common.DB, branches []TransBranch) er
if t.Status == dtmcli.StatusPrepared && t.isTimeout() {
t.changeStatus(db, dtmcli.StatusAborting)
}
currentType := dtmcli.If(t.Status == dtmcli.StatusSubmitted, dtmcli.BranchCommit, dtmcli.BranchRollback).(string)
currentType := dtmimp.If(t.Status == dtmcli.StatusSubmitted, dtmcli.BranchCommit, dtmcli.BranchRollback).(string)
for _, branch := range branches {
if branch.BranchType == currentType && branch.Status != dtmcli.StatusSucceed {
err := t.execBranch(db, &branch)
@ -33,6 +34,6 @@ func (t *transXaProcessor) ProcessOnce(db *common.DB, branches []TransBranch) er
}
}
}
t.changeStatus(db, dtmcli.If(t.Status == dtmcli.StatusSubmitted, dtmcli.StatusSucceed, dtmcli.StatusFailed).(string))
t.changeStatus(db, dtmimp.If(t.Status == dtmcli.StatusSubmitted, dtmcli.StatusSucceed, dtmcli.StatusFailed).(string))
return nil
}

23
dtmsvr/utils.go

@ -10,39 +10,24 @@ import (
"github.com/bwmarrin/snowflake"
"github.com/yedf/dtm/common"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"gorm.io/gorm"
)
// M a short name
type M = map[string]interface{}
type branchStatus struct {
id uint64
status string
finishTime *time.Time
}
var p2e = dtmcli.P2E
var e2p = dtmcli.E2P
var p2e = dtmimp.P2E
var e2p = dtmimp.E2P
var config = common.DtmConfig
func dbGet() *common.DB {
return common.DbGet(config.DB)
}
func writeTransLog(gid string, action string, status string, branch string, detail string) {
// if detail == "" {
// detail = "{}"
// }
// dbGet().Must().Table("trans_log").Create(M{
// "gid": gid,
// dtmcli.BranchAction: action,
// "new_status": status,
// "branch": branch,
// "detail": detail,
// })
}
// TransProcessedTestChan only for test usage. when transaction processed once, write gid to this chan
var TransProcessedTestChan chan string = nil
@ -69,7 +54,7 @@ func getOneHexIP() string {
ns := strings.Split(ip, ".")
r := []byte{}
for _, n := range ns {
r = append(r, byte(dtmcli.MustAtoi(n)))
r = append(r, byte(dtmimp.MustAtoi(n)))
}
return hex.EncodeToString(r)
}

8
dtmsvr/utils_test.go

@ -4,13 +4,13 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
)
func TestUtils(t *testing.T) {
db := dbGet()
db.NoMust()
err := dtmcli.CatchP(func() {
err := dtmimp.CatchP(func() {
checkAffected(db.DB)
})
assert.Error(t, err)
@ -21,12 +21,12 @@ func TestUtils(t *testing.T) {
func TestCheckLocalHost(t *testing.T) {
config.DisableLocalhost = 1
err := dtmcli.CatchP(func() {
err := dtmimp.CatchP(func() {
checkLocalhost([]TransBranch{{URL: "http://localhost"}})
})
assert.Error(t, err)
config.DisableLocalhost = 0
err = dtmcli.CatchP(func() {
err = dtmimp.CatchP(func() {
checkLocalhost([]TransBranch{{URL: "http://localhost"}})
})
assert.Nil(t, err)

133
examples/base_grpc.go

@ -7,45 +7,61 @@ import (
"net"
"time"
"github.com/gin-gonic/gin"
"github.com/yedf/dtm/dtmcli"
dtmgrpc "github.com/yedf/dtm/dtmgrpc"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/dtmgrpc"
"github.com/yedf/dtm/dtmgrpc/dtmgimp"
grpc "google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
emptypb "google.golang.org/protobuf/types/known/emptypb"
)
// BusiGrpc busi service grpc address
var BusiGrpc string = fmt.Sprintf("localhost:%d", BusiGrpcPort)
// DtmClient grpc client for dtm
var DtmClient dtmgrpc.DtmClient = nil
var DtmClient dtmgimp.DtmClient = nil
// XaGrpcClient XA client connection
var XaGrpcClient *dtmgrpc.XaGrpcClient = nil
func init() {
setupFuncs["XaGrpcSetup"] = func(app *gin.Engine) {
XaGrpcClient = dtmgrpc.NewXaGrpcClient(DtmGrpcServer, config.DB, BusiGrpc+"/examples.Busi/XaNotify")
}
}
// GrpcStartup for grpc
func GrpcStartup() {
conn, err := grpc.Dial(DtmGrpcServer, grpc.WithInsecure(), grpc.WithUnaryInterceptor(dtmgrpc.GrpcClientLog))
dtmcli.FatalIfError(err)
DtmClient = dtmgrpc.NewDtmClient(conn)
dtmcli.Logf("dtm client inited")
conn, err := grpc.Dial(DtmGrpcServer, grpc.WithInsecure(), grpc.WithUnaryInterceptor(dtmgimp.GrpcClientLog))
dtmimp.FatalIfError(err)
DtmClient = dtmgimp.NewDtmClient(conn)
dtmimp.Logf("dtm client inited")
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", BusiGrpcPort))
dtmcli.FatalIfError(err)
s := grpc.NewServer(grpc.UnaryInterceptor(dtmgrpc.GrpcServerLog))
dtmimp.FatalIfError(err)
s := grpc.NewServer(grpc.UnaryInterceptor(dtmgimp.GrpcServerLog))
RegisterBusiServer(s, &busiServer{})
go func() {
dtmcli.Logf("busi grpc listening at %v", lis.Addr())
dtmimp.Logf("busi grpc listening at %v", lis.Addr())
err := s.Serve(lis)
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
}()
time.Sleep(100 * time.Millisecond)
}
func handleGrpcBusiness(in *dtmgrpc.BusiRequest, result1 string, result2 string, busi string) error {
res := dtmcli.OrString(result1, result2, dtmcli.ResultSuccess)
dtmcli.Logf("grpc busi %s %s result: %s", busi, in.Info, res)
func handleGrpcBusiness(in *BusiReq, result1 string, result2 string, busi string) error {
res := dtmimp.OrString(result1, result2, dtmcli.ResultSuccess)
dtmimp.Logf("grpc busi %s %v %s %s result: %s", busi, in, result1, result2, res)
if res == dtmcli.ResultSuccess {
return nil
} else if res == dtmcli.ResultFailure {
return status.New(codes.Aborted, dtmcli.ResultFailure).Err()
} else if res == dtmcli.ResultOngoing {
return status.New(codes.Aborted, dtmcli.ResultOngoing).Err()
}
return status.New(codes.Internal, fmt.Sprintf("unknow result %s", res)).Err()
}
@ -55,89 +71,68 @@ type busiServer struct {
UnimplementedBusiServer
}
func (s *busiServer) CanSubmit(ctx context.Context, in *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
func (s *busiServer) CanSubmit(ctx context.Context, in *BusiReq) (*emptypb.Empty, error) {
res := MainSwitch.CanSubmitResult.Fetch()
return &dtmgrpc.BusiReply{}, dtmgrpc.Result2Error(res, nil)
return &emptypb.Empty{}, dtmgimp.Result2Error(res, nil)
}
func (s *busiServer) TransIn(ctx context.Context, in *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
req := TransReq{}
dtmcli.MustUnmarshal(in.BusiData, &req)
return &dtmgrpc.BusiReply{}, handleGrpcBusiness(in, MainSwitch.TransInResult.Fetch(), req.TransInResult, dtmcli.GetFuncName())
func (s *busiServer) TransIn(ctx context.Context, in *BusiReq) (*emptypb.Empty, error) {
return &emptypb.Empty{}, handleGrpcBusiness(in, MainSwitch.TransInResult.Fetch(), in.TransInResult, dtmimp.GetFuncName())
}
func (s *busiServer) TransOut(ctx context.Context, in *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
req := TransReq{}
dtmcli.MustUnmarshal(in.BusiData, &req)
return &dtmgrpc.BusiReply{}, handleGrpcBusiness(in, MainSwitch.TransOutResult.Fetch(), req.TransOutResult, dtmcli.GetFuncName())
func (s *busiServer) TransOut(ctx context.Context, in *BusiReq) (*emptypb.Empty, error) {
return &emptypb.Empty{}, handleGrpcBusiness(in, MainSwitch.TransOutResult.Fetch(), in.TransOutResult, dtmimp.GetFuncName())
}
func (s *busiServer) TransInRevert(ctx context.Context, in *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
req := TransReq{}
dtmcli.MustUnmarshal(in.BusiData, &req)
return &dtmgrpc.BusiReply{}, handleGrpcBusiness(in, MainSwitch.TransInRevertResult.Fetch(), "", dtmcli.GetFuncName())
func (s *busiServer) TransInRevert(ctx context.Context, in *BusiReq) (*emptypb.Empty, error) {
return &emptypb.Empty{}, handleGrpcBusiness(in, MainSwitch.TransInRevertResult.Fetch(), "", dtmimp.GetFuncName())
}
func (s *busiServer) TransOutRevert(ctx context.Context, in *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
req := TransReq{}
dtmcli.MustUnmarshal(in.BusiData, &req)
return &dtmgrpc.BusiReply{}, handleGrpcBusiness(in, MainSwitch.TransOutRevertResult.Fetch(), "", dtmcli.GetFuncName())
func (s *busiServer) TransOutRevert(ctx context.Context, in *BusiReq) (*emptypb.Empty, error) {
return &emptypb.Empty{}, handleGrpcBusiness(in, MainSwitch.TransOutRevertResult.Fetch(), "", dtmimp.GetFuncName())
}
func (s *busiServer) TransInConfirm(ctx context.Context, in *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
req := TransReq{}
dtmcli.MustUnmarshal(in.BusiData, &req)
return &dtmgrpc.BusiReply{}, handleGrpcBusiness(in, MainSwitch.TransInConfirmResult.Fetch(), "", dtmcli.GetFuncName())
func (s *busiServer) TransInConfirm(ctx context.Context, in *BusiReq) (*emptypb.Empty, error) {
return &emptypb.Empty{}, handleGrpcBusiness(in, MainSwitch.TransInConfirmResult.Fetch(), "", dtmimp.GetFuncName())
}
func (s *busiServer) TransOutConfirm(ctx context.Context, in *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
req := TransReq{}
dtmcli.MustUnmarshal(in.BusiData, &req)
return &dtmgrpc.BusiReply{}, handleGrpcBusiness(in, MainSwitch.TransOutConfirmResult.Fetch(), "", dtmcli.GetFuncName())
func (s *busiServer) TransOutConfirm(ctx context.Context, in *BusiReq) (*emptypb.Empty, error) {
return &emptypb.Empty{}, handleGrpcBusiness(in, MainSwitch.TransOutConfirmResult.Fetch(), "", dtmimp.GetFuncName())
}
func (s *busiServer) TransInTcc(ctx context.Context, in *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
req := TransReq{}
dtmcli.MustUnmarshal(in.BusiData, &req)
return &dtmgrpc.BusiReply{BusiData: []byte("reply")}, handleGrpcBusiness(in, MainSwitch.TransInResult.Fetch(), req.TransInResult, dtmcli.GetFuncName())
func (s *busiServer) TransInTcc(ctx context.Context, in *BusiReq) (*emptypb.Empty, error) {
return &emptypb.Empty{}, handleGrpcBusiness(in, MainSwitch.TransInResult.Fetch(), in.TransInResult, dtmimp.GetFuncName())
}
func (s *busiServer) TransOutTcc(ctx context.Context, in *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
req := TransReq{}
dtmcli.MustUnmarshal(in.BusiData, &req)
return &dtmgrpc.BusiReply{BusiData: []byte("reply")}, handleGrpcBusiness(in, MainSwitch.TransOutResult.Fetch(), req.TransOutResult, dtmcli.GetFuncName())
func (s *busiServer) TransOutTcc(ctx context.Context, in *BusiReq) (*emptypb.Empty, error) {
return &emptypb.Empty{}, handleGrpcBusiness(in, MainSwitch.TransOutResult.Fetch(), in.TransOutResult, dtmimp.GetFuncName())
}
func (s *busiServer) TransInXa(ctx context.Context, in *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
req := TransReq{}
dtmcli.MustUnmarshal(in.BusiData, &req)
return &dtmgrpc.BusiReply{BusiData: []byte("reply")}, XaGrpcClient.XaLocalTransaction(in, func(db *sql.DB, xa *dtmgrpc.XaGrpc) error {
if req.TransInResult == dtmcli.ResultFailure {
func (s *busiServer) TransInXa(ctx context.Context, in *BusiReq) (*emptypb.Empty, error) {
return &emptypb.Empty{}, XaGrpcClient.XaLocalTransaction(ctx, in, func(db *sql.DB, xa *dtmgrpc.XaGrpc) error {
if in.TransInResult == dtmcli.ResultFailure {
return status.New(codes.Aborted, dtmcli.ResultFailure).Err()
}
_, err := dtmcli.DBExec(db, "update dtm_busi.user_account set balance=balance+? where user_id=?", req.Amount, 2)
_, err := dtmimp.DBExec(db, "update dtm_busi.user_account set balance=balance+? where user_id=?", in.Amount, 2)
return err
})
}
func (s *busiServer) TransOutXa(ctx context.Context, in *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
req := TransReq{}
dtmcli.MustUnmarshal(in.BusiData, &req)
return &dtmgrpc.BusiReply{BusiData: []byte("reply")}, XaGrpcClient.XaLocalTransaction(in, func(db *sql.DB, xa *dtmgrpc.XaGrpc) error {
if req.TransOutResult == dtmcli.ResultFailure {
func (s *busiServer) TransOutXa(ctx context.Context, in *BusiReq) (*emptypb.Empty, error) {
return &emptypb.Empty{}, XaGrpcClient.XaLocalTransaction(ctx, in, func(db *sql.DB, xa *dtmgrpc.XaGrpc) error {
if in.TransOutResult == dtmcli.ResultFailure {
return status.New(codes.Aborted, dtmcli.ResultFailure).Err()
}
_, err := dtmcli.DBExec(db, "update dtm_busi.user_account set balance=balance-? where user_id=?", req.Amount, 1)
_, err := dtmimp.DBExec(db, "update dtm_busi.user_account set balance=balance-? where user_id=?", in.Amount, 1)
return err
})
}
func (s *busiServer) TransInTccNested(ctx context.Context, in *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
req := TransReq{}
dtmcli.MustUnmarshal(in.BusiData, &req)
tcc, err := dtmgrpc.TccFromRequest(in)
dtmcli.FatalIfError(err)
_, err = tcc.CallBranch(dtmcli.MustMarshal(req), BusiGrpc+"/examples.Busi/TransIn", BusiGrpc+"/examples.Busi/TransInConfirm", BusiGrpc+"/examples.Busi/TransInRevert")
dtmcli.FatalIfError(err)
return &dtmgrpc.BusiReply{BusiData: []byte("reply")}, handleGrpcBusiness(in, MainSwitch.TransInResult.Fetch(), req.TransInResult, dtmcli.GetFuncName())
func (s *busiServer) TransInTccNested(ctx context.Context, in *BusiReq) (*emptypb.Empty, error) {
tcc, err := dtmgrpc.TccFromGrpc(ctx)
dtmimp.FatalIfError(err)
r := &emptypb.Empty{}
err = tcc.CallBranch(in, BusiGrpc+"/examples.Busi/TransIn", BusiGrpc+"/examples.Busi/TransInConfirm", BusiGrpc+"/examples.Busi/TransInRevert", r)
dtmimp.FatalIfError(err)
return r, handleGrpcBusiness(in, MainSwitch.TransInResult.Fetch(), in.TransInResult, dtmimp.GetFuncName())
}

42
examples/base_http.go

@ -9,6 +9,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/yedf/dtm/common"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"gorm.io/driver/mysql"
"gorm.io/driver/postgres"
"gorm.io/gorm"
@ -32,14 +33,14 @@ var Busi string = fmt.Sprintf("http://localhost:%d%s", BusiPort, BusiAPI)
// BaseAppStartup base app startup
func BaseAppStartup() *gin.Engine {
dtmcli.Logf("examples starting")
dtmimp.Logf("examples starting")
app := common.GetGinApp()
BaseAddRoute(app)
for k, v := range setupFuncs {
dtmcli.Logf("initing %s", k)
dtmimp.Logf("initing %s", k)
v(app)
}
dtmcli.Logf("Starting busi at: %d", BusiPort)
dtmimp.Logf("Starting busi at: %d", BusiPort)
go app.Run(fmt.Sprintf(":%d", BusiPort))
time.Sleep(100 * time.Millisecond)
@ -58,6 +59,7 @@ func (s *AutoEmptyString) SetOnce(v string) {
// Fetch fetch the stored value, then reset the value to empty
func (s *AutoEmptyString) Fetch() string {
dtmimp.Logf("fetch result is: %s", s.value)
v := s.value
s.value = ""
return v
@ -78,12 +80,12 @@ var MainSwitch mainSwitchType
func handleGeneralBusiness(c *gin.Context, result1 string, result2 string, busi string) (interface{}, error) {
info := infoFromContext(c)
res := dtmcli.OrString(result1, result2, dtmcli.ResultSuccess)
dtmcli.Logf("%s %s result: %s", busi, info.String(), res)
res := dtmimp.OrString(result1, result2, dtmcli.ResultSuccess)
dtmimp.Logf("%s %s result: %s", busi, info.String(), res)
if res == "ERROR" {
return nil, errors.New("ERROR from user")
}
return M{"dtm_result": res}, nil
return map[string]interface{}{"dtm_result": res}, nil
}
// BaseAddRoute add base route handler
@ -107,32 +109,32 @@ func BaseAddRoute(app *gin.Engine) {
return handleGeneralBusiness(c, MainSwitch.TransOutRevertResult.Fetch(), "", "TransOutRevert")
}))
app.GET(BusiAPI+"/CanSubmit", common.WrapHandler(func(c *gin.Context) (interface{}, error) {
dtmcli.Logf("%s CanSubmit", c.Query("gid"))
return dtmcli.OrString(MainSwitch.CanSubmitResult.Fetch(), dtmcli.ResultSuccess), nil
dtmimp.Logf("%s CanSubmit", c.Query("gid"))
return dtmimp.OrString(MainSwitch.CanSubmitResult.Fetch(), dtmcli.ResultSuccess), nil
}))
app.POST(BusiAPI+"/TransInXa", common.WrapHandler(func(c *gin.Context) (interface{}, error) {
return XaClient.XaLocalTransaction(c.Request.URL.Query(), func(db *sql.DB, xa *dtmcli.Xa) (interface{}, error) {
return dtmcli.MapSuccess, XaClient.XaLocalTransaction(c.Request.URL.Query(), func(db *sql.DB, xa *dtmcli.Xa) error {
if reqFrom(c).TransInResult == dtmcli.ResultFailure {
return dtmcli.MapFailure, nil
return dtmcli.ErrFailure
}
_, err := dtmcli.DBExec(db, "update dtm_busi.user_account set balance=balance+? where user_id=?", reqFrom(c).Amount, 2)
return dtmcli.MapSuccess, err
_, err := dtmimp.DBExec(db, "update dtm_busi.user_account set balance=balance+? where user_id=?", reqFrom(c).Amount, 2)
return err
})
}))
app.POST(BusiAPI+"/TransOutXa", common.WrapHandler(func(c *gin.Context) (interface{}, error) {
return XaClient.XaLocalTransaction(c.Request.URL.Query(), func(db *sql.DB, xa *dtmcli.Xa) (interface{}, error) {
return dtmcli.MapSuccess, XaClient.XaLocalTransaction(c.Request.URL.Query(), func(db *sql.DB, xa *dtmcli.Xa) error {
if reqFrom(c).TransOutResult == dtmcli.ResultFailure {
return dtmcli.MapFailure, nil
return dtmcli.ErrFailure
}
_, err := dtmcli.DBExec(db, "update dtm_busi.user_account set balance=balance-? where user_id=?", reqFrom(c).Amount, 1)
return dtmcli.MapSuccess, err
_, err := dtmimp.DBExec(db, "update dtm_busi.user_account set balance=balance-? where user_id=?", reqFrom(c).Amount, 1)
return err
})
}))
app.POST(BusiAPI+"/TransOutXaGorm", common.WrapHandler(func(c *gin.Context) (interface{}, error) {
return XaClient.XaLocalTransaction(c.Request.URL.Query(), func(db *sql.DB, xa *dtmcli.Xa) (interface{}, error) {
return dtmcli.MapSuccess, XaClient.XaLocalTransaction(c.Request.URL.Query(), func(db *sql.DB, xa *dtmcli.Xa) error {
if reqFrom(c).TransOutResult == dtmcli.ResultFailure {
return dtmcli.MapFailure, nil
return dtmcli.ErrFailure
}
var dia gorm.Dialector = nil
if dtmcli.GetCurrentDBType() == dtmcli.DBTypeMysql {
@ -142,10 +144,10 @@ func BaseAddRoute(app *gin.Engine) {
}
gdb, err := gorm.Open(dia, &gorm.Config{})
if err != nil {
return nil, err
return err
}
dbr := gdb.Exec("update dtm_busi.user_account set balance=balance-? where user_id=?", reqFrom(c).Amount, 1)
return dtmcli.MapSuccess, dbr.Error
return dbr.Error
})
}))

34
examples/base_types.go

@ -1,18 +1,17 @@
package examples
import (
"context"
"database/sql"
"fmt"
"github.com/gin-gonic/gin"
"github.com/yedf/dtm/common"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/dtmgrpc"
)
// M alias
type M = map[string]interface{}
// DtmServer dtm service address
const DtmServer = "http://localhost:8080/api/dtmsvr"
@ -34,8 +33,17 @@ func (t *TransReq) String() string {
func GenTransReq(amount int, outFailed bool, inFailed bool) *TransReq {
return &TransReq{
Amount: amount,
TransOutResult: dtmcli.If(outFailed, dtmcli.ResultFailure, dtmcli.ResultSuccess).(string),
TransInResult: dtmcli.If(inFailed, dtmcli.ResultFailure, dtmcli.ResultSuccess).(string),
TransOutResult: dtmimp.If(outFailed, dtmcli.ResultFailure, dtmcli.ResultSuccess).(string),
TransInResult: dtmimp.If(inFailed, dtmcli.ResultFailure, dtmcli.ResultSuccess).(string),
}
}
// GenBusiReq 1
func GenBusiReq(amount int, outFailed bool, inFailed bool) *BusiReq {
return &BusiReq{
Amount: int64(amount),
TransOutResult: dtmimp.If(outFailed, dtmcli.ResultFailure, dtmcli.ResultSuccess).(string),
TransInResult: dtmimp.If(inFailed, dtmcli.ResultFailure, dtmcli.ResultSuccess).(string),
}
}
@ -44,7 +52,7 @@ func reqFrom(c *gin.Context) *TransReq {
if !ok {
req := TransReq{}
err := c.BindJSON(&req)
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
c.Set("trans_req", &req)
v = &req
}
@ -66,28 +74,28 @@ func dbGet() *common.DB {
}
func sdbGet() *sql.DB {
db, err := dtmcli.PooledDB(config.DB)
dtmcli.FatalIfError(err)
db, err := dtmimp.PooledDB(config.DB)
dtmimp.FatalIfError(err)
return db
}
func txGet() *sql.Tx {
db := sdbGet()
tx, err := db.Begin()
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
return tx
}
// MustBarrierFromGin 1
func MustBarrierFromGin(c *gin.Context) *dtmcli.BranchBarrier {
ti, err := dtmcli.BarrierFromQuery(c.Request.URL.Query())
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
return ti
}
// MustBarrierFromGrpc 1
func MustBarrierFromGrpc(in *dtmgrpc.BusiRequest) *dtmgrpc.BranchBarrier {
ti, err := dtmgrpc.BarrierFromGrpc(in)
dtmcli.FatalIfError(err)
func MustBarrierFromGrpc(ctx context.Context) *dtmcli.BranchBarrier {
ti, err := dtmgrpc.BarrierFromGrpc(ctx)
dtmimp.FatalIfError(err)
return ti
}

318
examples/busi.pb.go

@ -1,16 +1,17 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc-gen-go v1.27.1
// protoc v3.17.3
// source: examples/busi.proto
package examples
import (
dtmgrpc "github.com/yedf/dtm/dtmgrpc"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
emptypb "google.golang.org/protobuf/types/known/emptypb"
reflect "reflect"
sync "sync"
)
const (
@ -20,121 +21,207 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// DtmRequest request sent to dtm server
type BusiReq struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Amount int64 `protobuf:"varint,1,opt,name=Amount,proto3" json:"Amount,omitempty"`
TransOutResult string `protobuf:"bytes,2,opt,name=TransOutResult,proto3" json:"TransOutResult,omitempty"`
TransInResult string `protobuf:"bytes,3,opt,name=TransInResult,proto3" json:"TransInResult,omitempty"`
}
func (x *BusiReq) Reset() {
*x = BusiReq{}
if protoimpl.UnsafeEnabled {
mi := &file_examples_busi_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *BusiReq) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BusiReq) ProtoMessage() {}
func (x *BusiReq) ProtoReflect() protoreflect.Message {
mi := &file_examples_busi_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BusiReq.ProtoReflect.Descriptor instead.
func (*BusiReq) Descriptor() ([]byte, []int) {
return file_examples_busi_proto_rawDescGZIP(), []int{0}
}
func (x *BusiReq) GetAmount() int64 {
if x != nil {
return x.Amount
}
return 0
}
func (x *BusiReq) GetTransOutResult() string {
if x != nil {
return x.TransOutResult
}
return ""
}
func (x *BusiReq) GetTransInResult() string {
if x != nil {
return x.TransInResult
}
return ""
}
var File_examples_busi_proto protoreflect.FileDescriptor
var file_examples_busi_proto_rawDesc = []byte{
0x0a, 0x13, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x62, 0x75, 0x73, 0x69, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x1a,
0x15, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0x84, 0x08, 0x0a, 0x04, 0x42, 0x75, 0x73, 0x69, 0x12,
0x37, 0x0a, 0x09, 0x43, 0x61, 0x6e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x12, 0x14, 0x2e, 0x64,
0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x12, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x73,
0x69, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x35, 0x0a, 0x07, 0x54, 0x72, 0x61, 0x6e,
0x73, 0x49, 0x6e, 0x12, 0x14, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75,
0x73, 0x69, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x64, 0x74, 0x6d, 0x67,
0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12,
0x36, 0x0a, 0x08, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x4f, 0x75, 0x74, 0x12, 0x14, 0x2e, 0x64, 0x74,
0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x12, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x73, 0x69,
0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x3b, 0x0a, 0x0d, 0x54, 0x72, 0x61, 0x6e, 0x73,
0x49, 0x6e, 0x52, 0x65, 0x76, 0x65, 0x72, 0x74, 0x12, 0x14, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72,
0x70, 0x63, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12,
0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x70,
0x6c, 0x79, 0x22, 0x00, 0x12, 0x3c, 0x0a, 0x0e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x4f, 0x75, 0x74,
0x52, 0x65, 0x76, 0x65, 0x72, 0x74, 0x12, 0x14, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63,
0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x64,
0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x70, 0x6c, 0x79,
0x22, 0x00, 0x12, 0x3c, 0x0a, 0x0e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x49, 0x6e, 0x43, 0x6f, 0x6e,
0x66, 0x69, 0x72, 0x6d, 0x12, 0x14, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42,
0x75, 0x73, 0x69, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x64, 0x74, 0x6d,
0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00,
0x12, 0x3d, 0x0a, 0x0f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x4f, 0x75, 0x74, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x72, 0x6d, 0x12, 0x14, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75,
0x73, 0x69, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x64, 0x74, 0x6d, 0x67,
0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12,
0x36, 0x0a, 0x08, 0x58, 0x61, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x12, 0x14, 0x2e, 0x64, 0x74,
0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x12, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x73, 0x69,
0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x37, 0x0a, 0x09, 0x54, 0x72, 0x61, 0x6e, 0x73,
0x49, 0x6e, 0x58, 0x61, 0x12, 0x14, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42,
0x75, 0x73, 0x69, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x64, 0x74, 0x6d,
0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00,
0x12, 0x38, 0x0a, 0x0a, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x4f, 0x75, 0x74, 0x58, 0x61, 0x12, 0x14,
0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42,
0x75, 0x73, 0x69, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x38, 0x0a, 0x0a, 0x54, 0x72,
0x61, 0x6e, 0x73, 0x49, 0x6e, 0x54, 0x63, 0x63, 0x12, 0x14, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72,
0x70, 0x63, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12,
0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x70,
0x6c, 0x79, 0x22, 0x00, 0x12, 0x39, 0x0a, 0x0b, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x4f, 0x75, 0x74,
0x54, 0x63, 0x63, 0x12, 0x14, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75,
0x73, 0x69, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x64, 0x74, 0x6d, 0x67,
0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12,
0x3e, 0x0a, 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x49, 0x6e, 0x54, 0x63, 0x63, 0x4e, 0x65, 0x73,
0x74, 0x65, 0x64, 0x12, 0x14, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75,
0x73, 0x69, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x64, 0x74, 0x6d, 0x67,
0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12,
0x3a, 0x0a, 0x0c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x49, 0x6e, 0x42, 0x53, 0x61, 0x67, 0x61, 0x12,
0x14, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e,
0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x3b, 0x0a, 0x0d, 0x54,
0x72, 0x61, 0x6e, 0x73, 0x4f, 0x75, 0x74, 0x42, 0x53, 0x61, 0x67, 0x61, 0x12, 0x14, 0x2e, 0x64,
0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x12, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x73,
0x69, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x12, 0x54, 0x72, 0x61, 0x6e,
0x73, 0x49, 0x6e, 0x52, 0x65, 0x76, 0x65, 0x72, 0x74, 0x42, 0x53, 0x61, 0x67, 0x61, 0x12, 0x14,
0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42,
0x75, 0x73, 0x69, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x13, 0x54, 0x72,
0x61, 0x6e, 0x73, 0x4f, 0x75, 0x74, 0x52, 0x65, 0x76, 0x65, 0x72, 0x74, 0x42, 0x53, 0x61, 0x67,
0x61, 0x12, 0x14, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x73, 0x69,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x72, 0x70,
0x63, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x1e, 0x5a,
0x1c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x79, 0x65, 0x64, 0x66,
0x2f, 0x64, 0x74, 0x6d, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x6f, 0x0a, 0x07,
0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e,
0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12,
0x26, 0x0a, 0x0e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x4f, 0x75, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c,
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x4f, 0x75,
0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x54, 0x72, 0x61, 0x6e, 0x73,
0x49, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d,
0x54, 0x72, 0x61, 0x6e, 0x73, 0x49, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x32, 0x9a, 0x08,
0x0a, 0x04, 0x42, 0x75, 0x73, 0x69, 0x12, 0x38, 0x0a, 0x09, 0x43, 0x61, 0x6e, 0x53, 0x75, 0x62,
0x6d, 0x69, 0x74, 0x12, 0x11, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x42,
0x75, 0x73, 0x69, 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00,
0x12, 0x36, 0x0a, 0x07, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x49, 0x6e, 0x12, 0x11, 0x2e, 0x65, 0x78,
0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x71, 0x1a, 0x16,
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x37, 0x0a, 0x08, 0x54, 0x72, 0x61, 0x6e,
0x73, 0x4f, 0x75, 0x74, 0x12, 0x11, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e,
0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22,
0x00, 0x12, 0x3c, 0x0a, 0x0d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x49, 0x6e, 0x52, 0x65, 0x76, 0x65,
0x72, 0x74, 0x12, 0x11, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x42, 0x75,
0x73, 0x69, 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12,
0x3d, 0x0a, 0x0e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x4f, 0x75, 0x74, 0x52, 0x65, 0x76, 0x65, 0x72,
0x74, 0x12, 0x11, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x42, 0x75, 0x73,
0x69, 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x3d,
0x0a, 0x0e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x49, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d,
0x12, 0x11, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x42, 0x75, 0x73, 0x69,
0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x3e, 0x0a,
0x0f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x4f, 0x75, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d,
0x12, 0x11, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x42, 0x75, 0x73, 0x69,
0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x3c, 0x0a,
0x08, 0x58, 0x61, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74,
0x79, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x38, 0x0a, 0x09, 0x54,
0x72, 0x61, 0x6e, 0x73, 0x49, 0x6e, 0x58, 0x61, 0x12, 0x11, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70,
0x6c, 0x65, 0x73, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d,
0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x39, 0x0a, 0x0a, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x4f, 0x75,
0x74, 0x58, 0x61, 0x12, 0x11, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x42,
0x75, 0x73, 0x69, 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00,
0x12, 0x39, 0x0a, 0x0a, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x49, 0x6e, 0x54, 0x63, 0x63, 0x12, 0x11,
0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65,
0x71, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x3a, 0x0a, 0x0b, 0x54,
0x72, 0x61, 0x6e, 0x73, 0x4f, 0x75, 0x74, 0x54, 0x63, 0x63, 0x12, 0x11, 0x2e, 0x65, 0x78, 0x61,
0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x3f, 0x0a, 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73,
0x49, 0x6e, 0x54, 0x63, 0x63, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x12, 0x11, 0x2e, 0x65, 0x78,
0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x71, 0x1a, 0x16,
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x3b, 0x0a, 0x0c, 0x54, 0x72, 0x61, 0x6e,
0x73, 0x49, 0x6e, 0x42, 0x53, 0x61, 0x67, 0x61, 0x12, 0x11, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70,
0x6c, 0x65, 0x73, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d,
0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x3c, 0x0a, 0x0d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x4f, 0x75,
0x74, 0x42, 0x53, 0x61, 0x67, 0x61, 0x12, 0x11, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65,
0x73, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74,
0x79, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x12, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x49, 0x6e, 0x52, 0x65,
0x76, 0x65, 0x72, 0x74, 0x42, 0x53, 0x61, 0x67, 0x61, 0x12, 0x11, 0x2e, 0x65, 0x78, 0x61, 0x6d,
0x70, 0x6c, 0x65, 0x73, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x67,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45,
0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x42, 0x0a, 0x13, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x4f,
0x75, 0x74, 0x52, 0x65, 0x76, 0x65, 0x72, 0x74, 0x42, 0x53, 0x61, 0x67, 0x61, 0x12, 0x11, 0x2e,
0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x42, 0x75, 0x73, 0x69, 0x52, 0x65, 0x71,
0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x42, 0x1e, 0x5a, 0x1c, 0x67, 0x69,
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x79, 0x65, 0x64, 0x66, 0x2f, 0x64, 0x74,
0x6d, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
}
var (
file_examples_busi_proto_rawDescOnce sync.Once
file_examples_busi_proto_rawDescData = file_examples_busi_proto_rawDesc
)
func file_examples_busi_proto_rawDescGZIP() []byte {
file_examples_busi_proto_rawDescOnce.Do(func() {
file_examples_busi_proto_rawDescData = protoimpl.X.CompressGZIP(file_examples_busi_proto_rawDescData)
})
return file_examples_busi_proto_rawDescData
}
var file_examples_busi_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_examples_busi_proto_goTypes = []interface{}{
(*dtmgrpc.BusiRequest)(nil), // 0: dtmgrpc.BusiRequest
(*dtmgrpc.BusiReply)(nil), // 1: dtmgrpc.BusiReply
(*BusiReq)(nil), // 0: examples.BusiReq
(*emptypb.Empty)(nil), // 1: google.protobuf.Empty
}
var file_examples_busi_proto_depIdxs = []int32{
0, // 0: examples.Busi.CanSubmit:input_type -> dtmgrpc.BusiRequest
0, // 1: examples.Busi.TransIn:input_type -> dtmgrpc.BusiRequest
0, // 2: examples.Busi.TransOut:input_type -> dtmgrpc.BusiRequest
0, // 3: examples.Busi.TransInRevert:input_type -> dtmgrpc.BusiRequest
0, // 4: examples.Busi.TransOutRevert:input_type -> dtmgrpc.BusiRequest
0, // 5: examples.Busi.TransInConfirm:input_type -> dtmgrpc.BusiRequest
0, // 6: examples.Busi.TransOutConfirm:input_type -> dtmgrpc.BusiRequest
0, // 7: examples.Busi.XaNotify:input_type -> dtmgrpc.BusiRequest
0, // 8: examples.Busi.TransInXa:input_type -> dtmgrpc.BusiRequest
0, // 9: examples.Busi.TransOutXa:input_type -> dtmgrpc.BusiRequest
0, // 10: examples.Busi.TransInTcc:input_type -> dtmgrpc.BusiRequest
0, // 11: examples.Busi.TransOutTcc:input_type -> dtmgrpc.BusiRequest
0, // 12: examples.Busi.TransInTccNested:input_type -> dtmgrpc.BusiRequest
0, // 13: examples.Busi.TransInBSaga:input_type -> dtmgrpc.BusiRequest
0, // 14: examples.Busi.TransOutBSaga:input_type -> dtmgrpc.BusiRequest
0, // 15: examples.Busi.TransInRevertBSaga:input_type -> dtmgrpc.BusiRequest
0, // 16: examples.Busi.TransOutRevertBSaga:input_type -> dtmgrpc.BusiRequest
1, // 17: examples.Busi.CanSubmit:output_type -> dtmgrpc.BusiReply
1, // 18: examples.Busi.TransIn:output_type -> dtmgrpc.BusiReply
1, // 19: examples.Busi.TransOut:output_type -> dtmgrpc.BusiReply
1, // 20: examples.Busi.TransInRevert:output_type -> dtmgrpc.BusiReply
1, // 21: examples.Busi.TransOutRevert:output_type -> dtmgrpc.BusiReply
1, // 22: examples.Busi.TransInConfirm:output_type -> dtmgrpc.BusiReply
1, // 23: examples.Busi.TransOutConfirm:output_type -> dtmgrpc.BusiReply
1, // 24: examples.Busi.XaNotify:output_type -> dtmgrpc.BusiReply
1, // 25: examples.Busi.TransInXa:output_type -> dtmgrpc.BusiReply
1, // 26: examples.Busi.TransOutXa:output_type -> dtmgrpc.BusiReply
1, // 27: examples.Busi.TransInTcc:output_type -> dtmgrpc.BusiReply
1, // 28: examples.Busi.TransOutTcc:output_type -> dtmgrpc.BusiReply
1, // 29: examples.Busi.TransInTccNested:output_type -> dtmgrpc.BusiReply
1, // 30: examples.Busi.TransInBSaga:output_type -> dtmgrpc.BusiReply
1, // 31: examples.Busi.TransOutBSaga:output_type -> dtmgrpc.BusiReply
1, // 32: examples.Busi.TransInRevertBSaga:output_type -> dtmgrpc.BusiReply
1, // 33: examples.Busi.TransOutRevertBSaga:output_type -> dtmgrpc.BusiReply
0, // 0: examples.Busi.CanSubmit:input_type -> examples.BusiReq
0, // 1: examples.Busi.TransIn:input_type -> examples.BusiReq
0, // 2: examples.Busi.TransOut:input_type -> examples.BusiReq
0, // 3: examples.Busi.TransInRevert:input_type -> examples.BusiReq
0, // 4: examples.Busi.TransOutRevert:input_type -> examples.BusiReq
0, // 5: examples.Busi.TransInConfirm:input_type -> examples.BusiReq
0, // 6: examples.Busi.TransOutConfirm:input_type -> examples.BusiReq
1, // 7: examples.Busi.XaNotify:input_type -> google.protobuf.Empty
0, // 8: examples.Busi.TransInXa:input_type -> examples.BusiReq
0, // 9: examples.Busi.TransOutXa:input_type -> examples.BusiReq
0, // 10: examples.Busi.TransInTcc:input_type -> examples.BusiReq
0, // 11: examples.Busi.TransOutTcc:input_type -> examples.BusiReq
0, // 12: examples.Busi.TransInTccNested:input_type -> examples.BusiReq
0, // 13: examples.Busi.TransInBSaga:input_type -> examples.BusiReq
0, // 14: examples.Busi.TransOutBSaga:input_type -> examples.BusiReq
0, // 15: examples.Busi.TransInRevertBSaga:input_type -> examples.BusiReq
0, // 16: examples.Busi.TransOutRevertBSaga:input_type -> examples.BusiReq
1, // 17: examples.Busi.CanSubmit:output_type -> google.protobuf.Empty
1, // 18: examples.Busi.TransIn:output_type -> google.protobuf.Empty
1, // 19: examples.Busi.TransOut:output_type -> google.protobuf.Empty
1, // 20: examples.Busi.TransInRevert:output_type -> google.protobuf.Empty
1, // 21: examples.Busi.TransOutRevert:output_type -> google.protobuf.Empty
1, // 22: examples.Busi.TransInConfirm:output_type -> google.protobuf.Empty
1, // 23: examples.Busi.TransOutConfirm:output_type -> google.protobuf.Empty
1, // 24: examples.Busi.XaNotify:output_type -> google.protobuf.Empty
1, // 25: examples.Busi.TransInXa:output_type -> google.protobuf.Empty
1, // 26: examples.Busi.TransOutXa:output_type -> google.protobuf.Empty
1, // 27: examples.Busi.TransInTcc:output_type -> google.protobuf.Empty
1, // 28: examples.Busi.TransOutTcc:output_type -> google.protobuf.Empty
1, // 29: examples.Busi.TransInTccNested:output_type -> google.protobuf.Empty
1, // 30: examples.Busi.TransInBSaga:output_type -> google.protobuf.Empty
1, // 31: examples.Busi.TransOutBSaga:output_type -> google.protobuf.Empty
1, // 32: examples.Busi.TransInRevertBSaga:output_type -> google.protobuf.Empty
1, // 33: examples.Busi.TransOutRevertBSaga:output_type -> google.protobuf.Empty
17, // [17:34] is the sub-list for method output_type
0, // [0:17] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
@ -147,18 +234,33 @@ func file_examples_busi_proto_init() {
if File_examples_busi_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_examples_busi_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*BusiReq); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_examples_busi_proto_rawDesc,
NumEnums: 0,
NumMessages: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_examples_busi_proto_goTypes,
DependencyIndexes: file_examples_busi_proto_depIdxs,
MessageInfos: file_examples_busi_proto_msgTypes,
}.Build()
File_examples_busi_proto = out.File
file_examples_busi_proto_rawDesc = nil

43
examples/busi.proto

@ -1,30 +1,37 @@
syntax = "proto3";
package examples;
import "google/protobuf/empty.proto";
option go_package = "github.com/yedf/dtm/examples";
import "dtmgrpc/dtmgrpc.proto";
// DtmRequest request sent to dtm server
message BusiReq {
int64 Amount = 1;
string TransOutResult = 2;
string TransInResult = 3;
}
// The dtm service definition.
service Busi {
rpc CanSubmit(dtmgrpc.BusiRequest) returns (dtmgrpc.BusiReply) {}
rpc TransIn(dtmgrpc.BusiRequest) returns (dtmgrpc.BusiReply) {}
rpc TransOut(dtmgrpc.BusiRequest) returns (dtmgrpc.BusiReply) {}
rpc TransInRevert(dtmgrpc.BusiRequest) returns (dtmgrpc.BusiReply) {}
rpc TransOutRevert(dtmgrpc.BusiRequest) returns (dtmgrpc.BusiReply) {}
rpc TransInConfirm(dtmgrpc.BusiRequest) returns (dtmgrpc.BusiReply) {}
rpc TransOutConfirm(dtmgrpc.BusiRequest) returns (dtmgrpc.BusiReply) {}
rpc XaNotify(dtmgrpc.BusiRequest) returns (dtmgrpc.BusiReply) {}
rpc CanSubmit(BusiReq) returns (google.protobuf.Empty) {}
rpc TransIn(BusiReq) returns (google.protobuf.Empty) {}
rpc TransOut(BusiReq) returns (google.protobuf.Empty) {}
rpc TransInRevert(BusiReq) returns (google.protobuf.Empty) {}
rpc TransOutRevert(BusiReq) returns (google.protobuf.Empty) {}
rpc TransInConfirm(BusiReq) returns (google.protobuf.Empty) {}
rpc TransOutConfirm(BusiReq) returns (google.protobuf.Empty) {}
rpc XaNotify(google.protobuf.Empty) returns (google.protobuf.Empty) {}
rpc TransInXa(dtmgrpc.BusiRequest) returns (dtmgrpc.BusiReply) {}
rpc TransOutXa(dtmgrpc.BusiRequest) returns (dtmgrpc.BusiReply) {}
rpc TransInTcc(dtmgrpc.BusiRequest) returns (dtmgrpc.BusiReply) {}
rpc TransOutTcc(dtmgrpc.BusiRequest) returns (dtmgrpc.BusiReply) {}
rpc TransInTccNested(dtmgrpc.BusiRequest) returns (dtmgrpc.BusiReply) {}
rpc TransInXa(BusiReq) returns (google.protobuf.Empty) {}
rpc TransOutXa(BusiReq) returns (google.protobuf.Empty) {}
rpc TransInTcc(BusiReq) returns (google.protobuf.Empty) {}
rpc TransOutTcc(BusiReq) returns (google.protobuf.Empty) {}
rpc TransInTccNested(BusiReq) returns (google.protobuf.Empty) {}
rpc TransInBSaga(dtmgrpc.BusiRequest) returns (dtmgrpc.BusiReply) {}
rpc TransOutBSaga(dtmgrpc.BusiRequest) returns (dtmgrpc.BusiReply) {}
rpc TransInRevertBSaga(dtmgrpc.BusiRequest) returns (dtmgrpc.BusiReply) {}
rpc TransOutRevertBSaga(dtmgrpc.BusiRequest) returns (dtmgrpc.BusiReply) {}
rpc TransInBSaga(BusiReq) returns (google.protobuf.Empty) {}
rpc TransOutBSaga(BusiReq) returns (google.protobuf.Empty) {}
rpc TransInRevertBSaga(BusiReq) returns (google.protobuf.Empty) {}
rpc TransOutRevertBSaga(BusiReq) returns (google.protobuf.Empty) {}
}

240
examples/busi_grpc.pb.go

@ -4,10 +4,10 @@ package examples
import (
context "context"
dtmgrpc "github.com/yedf/dtm/dtmgrpc"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
emptypb "google.golang.org/protobuf/types/known/emptypb"
)
// This is a compile-time assertion to ensure that this generated file
@ -19,23 +19,23 @@ const _ = grpc.SupportPackageIsVersion7
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type BusiClient interface {
CanSubmit(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error)
TransIn(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error)
TransOut(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error)
TransInRevert(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error)
TransOutRevert(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error)
TransInConfirm(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error)
TransOutConfirm(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error)
XaNotify(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error)
TransInXa(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error)
TransOutXa(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error)
TransInTcc(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error)
TransOutTcc(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error)
TransInTccNested(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error)
TransInBSaga(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error)
TransOutBSaga(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error)
TransInRevertBSaga(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error)
TransOutRevertBSaga(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error)
CanSubmit(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error)
TransIn(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error)
TransOut(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error)
TransInRevert(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error)
TransOutRevert(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error)
TransInConfirm(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error)
TransOutConfirm(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error)
XaNotify(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*emptypb.Empty, error)
TransInXa(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error)
TransOutXa(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error)
TransInTcc(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error)
TransOutTcc(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error)
TransInTccNested(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error)
TransInBSaga(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error)
TransOutBSaga(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error)
TransInRevertBSaga(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error)
TransOutRevertBSaga(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error)
}
type busiClient struct {
@ -46,8 +46,8 @@ func NewBusiClient(cc grpc.ClientConnInterface) BusiClient {
return &busiClient{cc}
}
func (c *busiClient) CanSubmit(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error) {
out := new(dtmgrpc.BusiReply)
func (c *busiClient) CanSubmit(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/examples.Busi/CanSubmit", in, out, opts...)
if err != nil {
return nil, err
@ -55,8 +55,8 @@ func (c *busiClient) CanSubmit(ctx context.Context, in *dtmgrpc.BusiRequest, opt
return out, nil
}
func (c *busiClient) TransIn(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error) {
out := new(dtmgrpc.BusiReply)
func (c *busiClient) TransIn(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/examples.Busi/TransIn", in, out, opts...)
if err != nil {
return nil, err
@ -64,8 +64,8 @@ func (c *busiClient) TransIn(ctx context.Context, in *dtmgrpc.BusiRequest, opts
return out, nil
}
func (c *busiClient) TransOut(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error) {
out := new(dtmgrpc.BusiReply)
func (c *busiClient) TransOut(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/examples.Busi/TransOut", in, out, opts...)
if err != nil {
return nil, err
@ -73,8 +73,8 @@ func (c *busiClient) TransOut(ctx context.Context, in *dtmgrpc.BusiRequest, opts
return out, nil
}
func (c *busiClient) TransInRevert(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error) {
out := new(dtmgrpc.BusiReply)
func (c *busiClient) TransInRevert(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/examples.Busi/TransInRevert", in, out, opts...)
if err != nil {
return nil, err
@ -82,8 +82,8 @@ func (c *busiClient) TransInRevert(ctx context.Context, in *dtmgrpc.BusiRequest,
return out, nil
}
func (c *busiClient) TransOutRevert(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error) {
out := new(dtmgrpc.BusiReply)
func (c *busiClient) TransOutRevert(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/examples.Busi/TransOutRevert", in, out, opts...)
if err != nil {
return nil, err
@ -91,8 +91,8 @@ func (c *busiClient) TransOutRevert(ctx context.Context, in *dtmgrpc.BusiRequest
return out, nil
}
func (c *busiClient) TransInConfirm(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error) {
out := new(dtmgrpc.BusiReply)
func (c *busiClient) TransInConfirm(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/examples.Busi/TransInConfirm", in, out, opts...)
if err != nil {
return nil, err
@ -100,8 +100,8 @@ func (c *busiClient) TransInConfirm(ctx context.Context, in *dtmgrpc.BusiRequest
return out, nil
}
func (c *busiClient) TransOutConfirm(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error) {
out := new(dtmgrpc.BusiReply)
func (c *busiClient) TransOutConfirm(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/examples.Busi/TransOutConfirm", in, out, opts...)
if err != nil {
return nil, err
@ -109,8 +109,8 @@ func (c *busiClient) TransOutConfirm(ctx context.Context, in *dtmgrpc.BusiReques
return out, nil
}
func (c *busiClient) XaNotify(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error) {
out := new(dtmgrpc.BusiReply)
func (c *busiClient) XaNotify(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/examples.Busi/XaNotify", in, out, opts...)
if err != nil {
return nil, err
@ -118,8 +118,8 @@ func (c *busiClient) XaNotify(ctx context.Context, in *dtmgrpc.BusiRequest, opts
return out, nil
}
func (c *busiClient) TransInXa(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error) {
out := new(dtmgrpc.BusiReply)
func (c *busiClient) TransInXa(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/examples.Busi/TransInXa", in, out, opts...)
if err != nil {
return nil, err
@ -127,8 +127,8 @@ func (c *busiClient) TransInXa(ctx context.Context, in *dtmgrpc.BusiRequest, opt
return out, nil
}
func (c *busiClient) TransOutXa(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error) {
out := new(dtmgrpc.BusiReply)
func (c *busiClient) TransOutXa(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/examples.Busi/TransOutXa", in, out, opts...)
if err != nil {
return nil, err
@ -136,8 +136,8 @@ func (c *busiClient) TransOutXa(ctx context.Context, in *dtmgrpc.BusiRequest, op
return out, nil
}
func (c *busiClient) TransInTcc(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error) {
out := new(dtmgrpc.BusiReply)
func (c *busiClient) TransInTcc(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/examples.Busi/TransInTcc", in, out, opts...)
if err != nil {
return nil, err
@ -145,8 +145,8 @@ func (c *busiClient) TransInTcc(ctx context.Context, in *dtmgrpc.BusiRequest, op
return out, nil
}
func (c *busiClient) TransOutTcc(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error) {
out := new(dtmgrpc.BusiReply)
func (c *busiClient) TransOutTcc(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/examples.Busi/TransOutTcc", in, out, opts...)
if err != nil {
return nil, err
@ -154,8 +154,8 @@ func (c *busiClient) TransOutTcc(ctx context.Context, in *dtmgrpc.BusiRequest, o
return out, nil
}
func (c *busiClient) TransInTccNested(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error) {
out := new(dtmgrpc.BusiReply)
func (c *busiClient) TransInTccNested(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/examples.Busi/TransInTccNested", in, out, opts...)
if err != nil {
return nil, err
@ -163,8 +163,8 @@ func (c *busiClient) TransInTccNested(ctx context.Context, in *dtmgrpc.BusiReque
return out, nil
}
func (c *busiClient) TransInBSaga(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error) {
out := new(dtmgrpc.BusiReply)
func (c *busiClient) TransInBSaga(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/examples.Busi/TransInBSaga", in, out, opts...)
if err != nil {
return nil, err
@ -172,8 +172,8 @@ func (c *busiClient) TransInBSaga(ctx context.Context, in *dtmgrpc.BusiRequest,
return out, nil
}
func (c *busiClient) TransOutBSaga(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error) {
out := new(dtmgrpc.BusiReply)
func (c *busiClient) TransOutBSaga(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/examples.Busi/TransOutBSaga", in, out, opts...)
if err != nil {
return nil, err
@ -181,8 +181,8 @@ func (c *busiClient) TransOutBSaga(ctx context.Context, in *dtmgrpc.BusiRequest,
return out, nil
}
func (c *busiClient) TransInRevertBSaga(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error) {
out := new(dtmgrpc.BusiReply)
func (c *busiClient) TransInRevertBSaga(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/examples.Busi/TransInRevertBSaga", in, out, opts...)
if err != nil {
return nil, err
@ -190,8 +190,8 @@ func (c *busiClient) TransInRevertBSaga(ctx context.Context, in *dtmgrpc.BusiReq
return out, nil
}
func (c *busiClient) TransOutRevertBSaga(ctx context.Context, in *dtmgrpc.BusiRequest, opts ...grpc.CallOption) (*dtmgrpc.BusiReply, error) {
out := new(dtmgrpc.BusiReply)
func (c *busiClient) TransOutRevertBSaga(ctx context.Context, in *BusiReq, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/examples.Busi/TransOutRevertBSaga", in, out, opts...)
if err != nil {
return nil, err
@ -203,23 +203,23 @@ func (c *busiClient) TransOutRevertBSaga(ctx context.Context, in *dtmgrpc.BusiRe
// All implementations must embed UnimplementedBusiServer
// for forward compatibility
type BusiServer interface {
CanSubmit(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error)
TransIn(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error)
TransOut(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error)
TransInRevert(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error)
TransOutRevert(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error)
TransInConfirm(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error)
TransOutConfirm(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error)
XaNotify(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error)
TransInXa(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error)
TransOutXa(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error)
TransInTcc(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error)
TransOutTcc(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error)
TransInTccNested(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error)
TransInBSaga(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error)
TransOutBSaga(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error)
TransInRevertBSaga(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error)
TransOutRevertBSaga(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error)
CanSubmit(context.Context, *BusiReq) (*emptypb.Empty, error)
TransIn(context.Context, *BusiReq) (*emptypb.Empty, error)
TransOut(context.Context, *BusiReq) (*emptypb.Empty, error)
TransInRevert(context.Context, *BusiReq) (*emptypb.Empty, error)
TransOutRevert(context.Context, *BusiReq) (*emptypb.Empty, error)
TransInConfirm(context.Context, *BusiReq) (*emptypb.Empty, error)
TransOutConfirm(context.Context, *BusiReq) (*emptypb.Empty, error)
XaNotify(context.Context, *emptypb.Empty) (*emptypb.Empty, error)
TransInXa(context.Context, *BusiReq) (*emptypb.Empty, error)
TransOutXa(context.Context, *BusiReq) (*emptypb.Empty, error)
TransInTcc(context.Context, *BusiReq) (*emptypb.Empty, error)
TransOutTcc(context.Context, *BusiReq) (*emptypb.Empty, error)
TransInTccNested(context.Context, *BusiReq) (*emptypb.Empty, error)
TransInBSaga(context.Context, *BusiReq) (*emptypb.Empty, error)
TransOutBSaga(context.Context, *BusiReq) (*emptypb.Empty, error)
TransInRevertBSaga(context.Context, *BusiReq) (*emptypb.Empty, error)
TransOutRevertBSaga(context.Context, *BusiReq) (*emptypb.Empty, error)
mustEmbedUnimplementedBusiServer()
}
@ -227,55 +227,55 @@ type BusiServer interface {
type UnimplementedBusiServer struct {
}
func (UnimplementedBusiServer) CanSubmit(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
func (UnimplementedBusiServer) CanSubmit(context.Context, *BusiReq) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method CanSubmit not implemented")
}
func (UnimplementedBusiServer) TransIn(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
func (UnimplementedBusiServer) TransIn(context.Context, *BusiReq) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method TransIn not implemented")
}
func (UnimplementedBusiServer) TransOut(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
func (UnimplementedBusiServer) TransOut(context.Context, *BusiReq) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method TransOut not implemented")
}
func (UnimplementedBusiServer) TransInRevert(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
func (UnimplementedBusiServer) TransInRevert(context.Context, *BusiReq) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method TransInRevert not implemented")
}
func (UnimplementedBusiServer) TransOutRevert(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
func (UnimplementedBusiServer) TransOutRevert(context.Context, *BusiReq) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method TransOutRevert not implemented")
}
func (UnimplementedBusiServer) TransInConfirm(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
func (UnimplementedBusiServer) TransInConfirm(context.Context, *BusiReq) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method TransInConfirm not implemented")
}
func (UnimplementedBusiServer) TransOutConfirm(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
func (UnimplementedBusiServer) TransOutConfirm(context.Context, *BusiReq) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method TransOutConfirm not implemented")
}
func (UnimplementedBusiServer) XaNotify(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
func (UnimplementedBusiServer) XaNotify(context.Context, *emptypb.Empty) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method XaNotify not implemented")
}
func (UnimplementedBusiServer) TransInXa(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
func (UnimplementedBusiServer) TransInXa(context.Context, *BusiReq) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method TransInXa not implemented")
}
func (UnimplementedBusiServer) TransOutXa(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
func (UnimplementedBusiServer) TransOutXa(context.Context, *BusiReq) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method TransOutXa not implemented")
}
func (UnimplementedBusiServer) TransInTcc(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
func (UnimplementedBusiServer) TransInTcc(context.Context, *BusiReq) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method TransInTcc not implemented")
}
func (UnimplementedBusiServer) TransOutTcc(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
func (UnimplementedBusiServer) TransOutTcc(context.Context, *BusiReq) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method TransOutTcc not implemented")
}
func (UnimplementedBusiServer) TransInTccNested(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
func (UnimplementedBusiServer) TransInTccNested(context.Context, *BusiReq) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method TransInTccNested not implemented")
}
func (UnimplementedBusiServer) TransInBSaga(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
func (UnimplementedBusiServer) TransInBSaga(context.Context, *BusiReq) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method TransInBSaga not implemented")
}
func (UnimplementedBusiServer) TransOutBSaga(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
func (UnimplementedBusiServer) TransOutBSaga(context.Context, *BusiReq) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method TransOutBSaga not implemented")
}
func (UnimplementedBusiServer) TransInRevertBSaga(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
func (UnimplementedBusiServer) TransInRevertBSaga(context.Context, *BusiReq) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method TransInRevertBSaga not implemented")
}
func (UnimplementedBusiServer) TransOutRevertBSaga(context.Context, *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
func (UnimplementedBusiServer) TransOutRevertBSaga(context.Context, *BusiReq) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method TransOutRevertBSaga not implemented")
}
func (UnimplementedBusiServer) mustEmbedUnimplementedBusiServer() {}
@ -292,7 +292,7 @@ func RegisterBusiServer(s grpc.ServiceRegistrar, srv BusiServer) {
}
func _Busi_CanSubmit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(dtmgrpc.BusiRequest)
in := new(BusiReq)
if err := dec(in); err != nil {
return nil, err
}
@ -304,13 +304,13 @@ func _Busi_CanSubmit_Handler(srv interface{}, ctx context.Context, dec func(inte
FullMethod: "/examples.Busi/CanSubmit",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BusiServer).CanSubmit(ctx, req.(*dtmgrpc.BusiRequest))
return srv.(BusiServer).CanSubmit(ctx, req.(*BusiReq))
}
return interceptor(ctx, in, info, handler)
}
func _Busi_TransIn_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(dtmgrpc.BusiRequest)
in := new(BusiReq)
if err := dec(in); err != nil {
return nil, err
}
@ -322,13 +322,13 @@ func _Busi_TransIn_Handler(srv interface{}, ctx context.Context, dec func(interf
FullMethod: "/examples.Busi/TransIn",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BusiServer).TransIn(ctx, req.(*dtmgrpc.BusiRequest))
return srv.(BusiServer).TransIn(ctx, req.(*BusiReq))
}
return interceptor(ctx, in, info, handler)
}
func _Busi_TransOut_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(dtmgrpc.BusiRequest)
in := new(BusiReq)
if err := dec(in); err != nil {
return nil, err
}
@ -340,13 +340,13 @@ func _Busi_TransOut_Handler(srv interface{}, ctx context.Context, dec func(inter
FullMethod: "/examples.Busi/TransOut",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BusiServer).TransOut(ctx, req.(*dtmgrpc.BusiRequest))
return srv.(BusiServer).TransOut(ctx, req.(*BusiReq))
}
return interceptor(ctx, in, info, handler)
}
func _Busi_TransInRevert_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(dtmgrpc.BusiRequest)
in := new(BusiReq)
if err := dec(in); err != nil {
return nil, err
}
@ -358,13 +358,13 @@ func _Busi_TransInRevert_Handler(srv interface{}, ctx context.Context, dec func(
FullMethod: "/examples.Busi/TransInRevert",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BusiServer).TransInRevert(ctx, req.(*dtmgrpc.BusiRequest))
return srv.(BusiServer).TransInRevert(ctx, req.(*BusiReq))
}
return interceptor(ctx, in, info, handler)
}
func _Busi_TransOutRevert_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(dtmgrpc.BusiRequest)
in := new(BusiReq)
if err := dec(in); err != nil {
return nil, err
}
@ -376,13 +376,13 @@ func _Busi_TransOutRevert_Handler(srv interface{}, ctx context.Context, dec func
FullMethod: "/examples.Busi/TransOutRevert",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BusiServer).TransOutRevert(ctx, req.(*dtmgrpc.BusiRequest))
return srv.(BusiServer).TransOutRevert(ctx, req.(*BusiReq))
}
return interceptor(ctx, in, info, handler)
}
func _Busi_TransInConfirm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(dtmgrpc.BusiRequest)
in := new(BusiReq)
if err := dec(in); err != nil {
return nil, err
}
@ -394,13 +394,13 @@ func _Busi_TransInConfirm_Handler(srv interface{}, ctx context.Context, dec func
FullMethod: "/examples.Busi/TransInConfirm",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BusiServer).TransInConfirm(ctx, req.(*dtmgrpc.BusiRequest))
return srv.(BusiServer).TransInConfirm(ctx, req.(*BusiReq))
}
return interceptor(ctx, in, info, handler)
}
func _Busi_TransOutConfirm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(dtmgrpc.BusiRequest)
in := new(BusiReq)
if err := dec(in); err != nil {
return nil, err
}
@ -412,13 +412,13 @@ func _Busi_TransOutConfirm_Handler(srv interface{}, ctx context.Context, dec fun
FullMethod: "/examples.Busi/TransOutConfirm",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BusiServer).TransOutConfirm(ctx, req.(*dtmgrpc.BusiRequest))
return srv.(BusiServer).TransOutConfirm(ctx, req.(*BusiReq))
}
return interceptor(ctx, in, info, handler)
}
func _Busi_XaNotify_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(dtmgrpc.BusiRequest)
in := new(emptypb.Empty)
if err := dec(in); err != nil {
return nil, err
}
@ -430,13 +430,13 @@ func _Busi_XaNotify_Handler(srv interface{}, ctx context.Context, dec func(inter
FullMethod: "/examples.Busi/XaNotify",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BusiServer).XaNotify(ctx, req.(*dtmgrpc.BusiRequest))
return srv.(BusiServer).XaNotify(ctx, req.(*emptypb.Empty))
}
return interceptor(ctx, in, info, handler)
}
func _Busi_TransInXa_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(dtmgrpc.BusiRequest)
in := new(BusiReq)
if err := dec(in); err != nil {
return nil, err
}
@ -448,13 +448,13 @@ func _Busi_TransInXa_Handler(srv interface{}, ctx context.Context, dec func(inte
FullMethod: "/examples.Busi/TransInXa",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BusiServer).TransInXa(ctx, req.(*dtmgrpc.BusiRequest))
return srv.(BusiServer).TransInXa(ctx, req.(*BusiReq))
}
return interceptor(ctx, in, info, handler)
}
func _Busi_TransOutXa_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(dtmgrpc.BusiRequest)
in := new(BusiReq)
if err := dec(in); err != nil {
return nil, err
}
@ -466,13 +466,13 @@ func _Busi_TransOutXa_Handler(srv interface{}, ctx context.Context, dec func(int
FullMethod: "/examples.Busi/TransOutXa",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BusiServer).TransOutXa(ctx, req.(*dtmgrpc.BusiRequest))
return srv.(BusiServer).TransOutXa(ctx, req.(*BusiReq))
}
return interceptor(ctx, in, info, handler)
}
func _Busi_TransInTcc_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(dtmgrpc.BusiRequest)
in := new(BusiReq)
if err := dec(in); err != nil {
return nil, err
}
@ -484,13 +484,13 @@ func _Busi_TransInTcc_Handler(srv interface{}, ctx context.Context, dec func(int
FullMethod: "/examples.Busi/TransInTcc",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BusiServer).TransInTcc(ctx, req.(*dtmgrpc.BusiRequest))
return srv.(BusiServer).TransInTcc(ctx, req.(*BusiReq))
}
return interceptor(ctx, in, info, handler)
}
func _Busi_TransOutTcc_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(dtmgrpc.BusiRequest)
in := new(BusiReq)
if err := dec(in); err != nil {
return nil, err
}
@ -502,13 +502,13 @@ func _Busi_TransOutTcc_Handler(srv interface{}, ctx context.Context, dec func(in
FullMethod: "/examples.Busi/TransOutTcc",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BusiServer).TransOutTcc(ctx, req.(*dtmgrpc.BusiRequest))
return srv.(BusiServer).TransOutTcc(ctx, req.(*BusiReq))
}
return interceptor(ctx, in, info, handler)
}
func _Busi_TransInTccNested_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(dtmgrpc.BusiRequest)
in := new(BusiReq)
if err := dec(in); err != nil {
return nil, err
}
@ -520,13 +520,13 @@ func _Busi_TransInTccNested_Handler(srv interface{}, ctx context.Context, dec fu
FullMethod: "/examples.Busi/TransInTccNested",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BusiServer).TransInTccNested(ctx, req.(*dtmgrpc.BusiRequest))
return srv.(BusiServer).TransInTccNested(ctx, req.(*BusiReq))
}
return interceptor(ctx, in, info, handler)
}
func _Busi_TransInBSaga_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(dtmgrpc.BusiRequest)
in := new(BusiReq)
if err := dec(in); err != nil {
return nil, err
}
@ -538,13 +538,13 @@ func _Busi_TransInBSaga_Handler(srv interface{}, ctx context.Context, dec func(i
FullMethod: "/examples.Busi/TransInBSaga",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BusiServer).TransInBSaga(ctx, req.(*dtmgrpc.BusiRequest))
return srv.(BusiServer).TransInBSaga(ctx, req.(*BusiReq))
}
return interceptor(ctx, in, info, handler)
}
func _Busi_TransOutBSaga_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(dtmgrpc.BusiRequest)
in := new(BusiReq)
if err := dec(in); err != nil {
return nil, err
}
@ -556,13 +556,13 @@ func _Busi_TransOutBSaga_Handler(srv interface{}, ctx context.Context, dec func(
FullMethod: "/examples.Busi/TransOutBSaga",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BusiServer).TransOutBSaga(ctx, req.(*dtmgrpc.BusiRequest))
return srv.(BusiServer).TransOutBSaga(ctx, req.(*BusiReq))
}
return interceptor(ctx, in, info, handler)
}
func _Busi_TransInRevertBSaga_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(dtmgrpc.BusiRequest)
in := new(BusiReq)
if err := dec(in); err != nil {
return nil, err
}
@ -574,13 +574,13 @@ func _Busi_TransInRevertBSaga_Handler(srv interface{}, ctx context.Context, dec
FullMethod: "/examples.Busi/TransInRevertBSaga",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BusiServer).TransInRevertBSaga(ctx, req.(*dtmgrpc.BusiRequest))
return srv.(BusiServer).TransInRevertBSaga(ctx, req.(*BusiReq))
}
return interceptor(ctx, in, info, handler)
}
func _Busi_TransOutRevertBSaga_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(dtmgrpc.BusiRequest)
in := new(BusiReq)
if err := dec(in); err != nil {
return nil, err
}
@ -592,7 +592,7 @@ func _Busi_TransOutRevertBSaga_Handler(srv interface{}, ctx context.Context, dec
FullMethod: "/examples.Busi/TransOutRevertBSaga",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BusiServer).TransOutRevertBSaga(ctx, req.(*dtmgrpc.BusiRequest))
return srv.(BusiServer).TransOutRevertBSaga(ctx, req.(*BusiReq))
}
return interceptor(ctx, in, info, handler)
}

40
examples/data.go

@ -7,34 +7,54 @@ import (
"time"
"github.com/yedf/dtm/common"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
)
var config = common.DtmConfig
// RunSQLScript 1
func RunSQLScript(conf map[string]string, script string, skipDrop bool) {
con, err := dtmcli.StandaloneDB(conf)
dtmcli.FatalIfError(err)
con, err := dtmimp.StandaloneDB(conf)
dtmimp.FatalIfError(err)
defer func() { con.Close() }()
content, err := ioutil.ReadFile(script)
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
sqls := strings.Split(string(content), ";")
for _, sql := range sqls {
s := strings.TrimSpace(sql)
if s == "" || (skipDrop && strings.Contains(s, "drop")) {
continue
}
for _, err = dtmcli.DBExec(con, s); err != nil; { // wait for mysql to start
time.Sleep(3 * time.Second)
_, err = dtmcli.DBExec(con, s)
}
dtmcli.FatalIfError(err)
_, err = dtmimp.DBExec(con, s)
dtmimp.FatalIfError(err)
}
}
func resetXaData() {
if config.DB["driver"] != "mysql" {
return
}
db := dbGet()
type XaRow struct {
Data string
}
xas := []XaRow{}
db.Must().Raw("xa recover").Scan(&xas)
for _, xa := range xas {
db.Must().Exec(fmt.Sprintf("xa rollback '%s'", xa.Data))
}
}
// PopulateDB populate example mysql data
func PopulateDB(skipDrop bool) {
sdb := sdbGet()
for _, err := dtmimp.DBExec(sdb, "select 1"); err != nil; { // wait for mysql to start
time.Sleep(3 * time.Second)
_, err = dtmimp.DBExec(sdb, "select 1")
}
resetXaData()
file := fmt.Sprintf("%s/examples.%s.sql", common.GetCallerCodeDir(), config.DB["driver"])
RunSQLScript(config.DB, file, skipDrop)
file = fmt.Sprintf("%s/../dtmcli/barrier.%s.sql", common.GetCallerCodeDir(), config.DB["driver"])
@ -51,6 +71,6 @@ type sampleInfo struct {
var Samples = map[string]*sampleInfo{}
func addSample(name string, fn func() string) {
dtmcli.LogIfFatalf(Samples[name] != nil, "%s already exists", name)
dtmimp.LogIfFatalf(Samples[name] != nil, "%s already exists", name)
Samples[name] = &sampleInfo{Arg: name, Action: fn}
}

6
examples/grpc_msg.go

@ -1,19 +1,19 @@
package examples
import (
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
dtmgrpc "github.com/yedf/dtm/dtmgrpc"
)
func init() {
addSample("grpc_msg", func() string {
req := dtmcli.MustMarshal(&TransReq{Amount: 30})
req := &BusiReq{Amount: 30}
gid := dtmgrpc.MustGenGid(DtmGrpcServer)
msg := dtmgrpc.NewMsgGrpc(DtmGrpcServer, gid).
Add(BusiGrpc+"/examples.Busi/TransOut", req).
Add(BusiGrpc+"/examples.Busi/TransIn", req)
err := msg.Submit()
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
return msg.Gid
})
}

14
examples/grpc_saga.go

@ -1,30 +1,30 @@
package examples
import (
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
dtmgrpc "github.com/yedf/dtm/dtmgrpc"
)
func init() {
addSample("grpc_saga", func() string {
req := dtmcli.MustMarshal(&TransReq{Amount: 30})
req := &BusiReq{Amount: 30}
gid := dtmgrpc.MustGenGid(DtmGrpcServer)
saga := dtmgrpc.NewSaga(DtmGrpcServer, gid).
saga := dtmgrpc.NewSagaGrpc(DtmGrpcServer, gid).
Add(BusiGrpc+"/examples.Busi/TransOut", BusiGrpc+"/examples.Busi/TransOutRevert", req).
Add(BusiGrpc+"/examples.Busi/TransIn", BusiGrpc+"/examples.Busi/TransOutRevert", req)
err := saga.Submit()
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
return saga.Gid
})
addSample("grpc_saga_wait", func() string {
req := dtmcli.MustMarshal(&TransReq{Amount: 30})
req := &BusiReq{Amount: 30}
gid := dtmgrpc.MustGenGid(DtmGrpcServer)
saga := dtmgrpc.NewSaga(DtmGrpcServer, gid).
saga := dtmgrpc.NewSagaGrpc(DtmGrpcServer, gid).
Add(BusiGrpc+"/examples.Busi/TransOut", BusiGrpc+"/examples.Busi/TransOutRevert", req).
Add(BusiGrpc+"/examples.Busi/TransIn", BusiGrpc+"/examples.Busi/TransOutRevert", req)
saga.WaitResult = true
err := saga.Submit()
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
return saga.Gid
})
}

52
examples/grpc_saga_barrier.go

@ -4,65 +4,59 @@ import (
"context"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/dtmgrpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
emptypb "google.golang.org/protobuf/types/known/emptypb"
)
func init() {
addSample("grpc_saga_barrier", func() string {
req := dtmcli.MustMarshal(&TransReq{Amount: 30})
req := &BusiReq{Amount: 30}
gid := dtmgrpc.MustGenGid(DtmGrpcServer)
saga := dtmgrpc.NewSaga(DtmGrpcServer, gid).
saga := dtmgrpc.NewSagaGrpc(DtmGrpcServer, gid).
Add(BusiGrpc+"/examples.Busi/TransOutBSaga", BusiGrpc+"/examples.Busi/TransOutRevertBSaga", req).
Add(BusiGrpc+"/examples.Busi/TransInBSaga", BusiGrpc+"/examples.Busi/TransInRevertBSaga", req)
err := saga.Submit()
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
return saga.Gid
})
}
func sagaGrpcBarrierAdjustBalance(db dtmcli.DB, uid int, amount int, result string) error {
func sagaGrpcBarrierAdjustBalance(db dtmcli.DB, uid int, amount int64, result string) error {
if result == dtmcli.ResultFailure {
return status.New(codes.Aborted, dtmcli.ResultFailure).Err()
}
_, err := dtmcli.DBExec(db, "update dtm_busi.user_account set balance = balance + ? where user_id = ?", amount, uid)
_, err := dtmimp.DBExec(db, "update dtm_busi.user_account set balance = balance + ? where user_id = ?", amount, uid)
return err
}
func (s *busiServer) TransInBSaga(ctx context.Context, in *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
req := TransReq{}
dtmcli.MustUnmarshal(in.BusiData, &req)
barrier := MustBarrierFromGrpc(in)
return &dtmgrpc.BusiReply{}, barrier.Call(txGet(), func(tx dtmcli.DB) error {
return sagaGrpcBarrierAdjustBalance(tx, 2, req.Amount, req.TransInResult)
func (s *busiServer) TransInBSaga(ctx context.Context, in *BusiReq) (*emptypb.Empty, error) {
barrier := MustBarrierFromGrpc(ctx)
return &emptypb.Empty{}, barrier.Call(txGet(), func(tx dtmcli.DB) error {
return sagaGrpcBarrierAdjustBalance(tx, 2, in.Amount, in.TransInResult)
})
}
func (s *busiServer) TransOutBSaga(ctx context.Context, in *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
req := TransReq{}
dtmcli.MustUnmarshal(in.BusiData, &req)
barrier := MustBarrierFromGrpc(in)
return &dtmgrpc.BusiReply{}, barrier.Call(txGet(), func(db dtmcli.DB) error {
return sagaGrpcBarrierAdjustBalance(db, 1, -req.Amount, req.TransOutResult)
func (s *busiServer) TransOutBSaga(ctx context.Context, in *BusiReq) (*emptypb.Empty, error) {
barrier := MustBarrierFromGrpc(ctx)
return &emptypb.Empty{}, barrier.Call(txGet(), func(db dtmcli.DB) error {
return sagaGrpcBarrierAdjustBalance(db, 1, -in.Amount, in.TransOutResult)
})
}
func (s *busiServer) TransInRevertBSaga(ctx context.Context, in *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
req := TransReq{}
dtmcli.MustUnmarshal(in.BusiData, &req)
barrier := MustBarrierFromGrpc(in)
return &dtmgrpc.BusiReply{}, barrier.Call(txGet(), func(db dtmcli.DB) error {
return sagaGrpcBarrierAdjustBalance(db, 2, -req.Amount, "")
func (s *busiServer) TransInRevertBSaga(ctx context.Context, in *BusiReq) (*emptypb.Empty, error) {
barrier := MustBarrierFromGrpc(ctx)
return &emptypb.Empty{}, barrier.Call(txGet(), func(db dtmcli.DB) error {
return sagaGrpcBarrierAdjustBalance(db, 2, -in.Amount, "")
})
}
func (s *busiServer) TransOutRevertBSaga(ctx context.Context, in *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
req := TransReq{}
dtmcli.MustUnmarshal(in.BusiData, &req)
barrier := MustBarrierFromGrpc(in)
return &dtmgrpc.BusiReply{}, barrier.Call(txGet(), func(db dtmcli.DB) error {
return sagaGrpcBarrierAdjustBalance(db, 1, req.Amount, "")
func (s *busiServer) TransOutRevertBSaga(ctx context.Context, in *BusiReq) (*emptypb.Empty, error) {
barrier := MustBarrierFromGrpc(ctx)
return &emptypb.Empty{}, barrier.Call(txGet(), func(db dtmcli.DB) error {
return sagaGrpcBarrierAdjustBalance(db, 1, in.Amount, "")
})
}

14
examples/grpc_tcc.go

@ -1,24 +1,26 @@
package examples
import (
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
dtmgrpc "github.com/yedf/dtm/dtmgrpc"
emptypb "google.golang.org/protobuf/types/known/emptypb"
)
func init() {
addSample("grpc_tcc", func() string {
dtmcli.Logf("tcc simple transaction begin")
dtmimp.Logf("tcc simple transaction begin")
gid := dtmgrpc.MustGenGid(DtmGrpcServer)
err := dtmgrpc.TccGlobalTransaction(DtmGrpcServer, gid, func(tcc *dtmgrpc.TccGrpc) error {
data := dtmcli.MustMarshal(&TransReq{Amount: 30})
_, err := tcc.CallBranch(data, BusiGrpc+"/examples.Busi/TransOutTcc", BusiGrpc+"/examples.Busi/TransOutConfirm", BusiGrpc+"/examples.Busi/TransOutRevert")
data := &BusiReq{Amount: 30}
r := &emptypb.Empty{}
err := tcc.CallBranch(data, BusiGrpc+"/examples.Busi/TransOutTcc", BusiGrpc+"/examples.Busi/TransOutConfirm", BusiGrpc+"/examples.Busi/TransOutRevert", r)
if err != nil {
return err
}
_, err = tcc.CallBranch(data, BusiGrpc+"/examples.Busi/TransInTcc", BusiGrpc+"/examples.Busi/TransInConfirm", BusiGrpc+"/examples.Busi/TransInRevert")
err = tcc.CallBranch(data, BusiGrpc+"/examples.Busi/TransInTcc", BusiGrpc+"/examples.Busi/TransInConfirm", BusiGrpc+"/examples.Busi/TransInRevert", r)
return err
})
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
return gid
})
}

24
examples/grpc_xa.go

@ -3,35 +3,29 @@ package examples
import (
context "context"
"github.com/gin-gonic/gin"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/dtmgrpc"
"google.golang.org/protobuf/types/known/emptypb"
)
// XaGrpcClient XA client connection
var XaGrpcClient *dtmgrpc.XaGrpcClient = nil
func init() {
setupFuncs["XaGrpcSetup"] = func(app *gin.Engine) {
XaGrpcClient = dtmgrpc.NewXaGrpcClient(DtmGrpcServer, config.DB, BusiGrpc+"/examples.Busi/XaNotify")
}
addSample("grpc_xa", func() string {
gid := dtmgrpc.MustGenGid(DtmGrpcServer)
busiData := dtmcli.MustMarshal(&TransReq{Amount: 30})
req := &BusiReq{Amount: 30}
err := XaGrpcClient.XaGlobalTransaction(gid, func(xa *dtmgrpc.XaGrpc) error {
_, err := xa.CallBranch(busiData, BusiGrpc+"/examples.Busi/TransOutXa")
r := &emptypb.Empty{}
err := xa.CallBranch(req, BusiGrpc+"/examples.Busi/TransOutXa", r)
if err != nil {
return err
}
_, err = xa.CallBranch(busiData, BusiGrpc+"/examples.Busi/TransInXa")
err = xa.CallBranch(req, BusiGrpc+"/examples.Busi/TransInXa", r)
return err
})
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
return gid
})
}
func (s *busiServer) XaNotify(ctx context.Context, in *dtmgrpc.BusiRequest) (*dtmgrpc.BusiReply, error) {
err := XaGrpcClient.HandleCallback(in.Info.Gid, in.Info.BranchID, in.Info.BranchType)
return &dtmgrpc.BusiReply{}, dtmgrpc.Result2Error(nil, err)
func (s *busiServer) XaNotify(ctx context.Context, in *emptypb.Empty) (*emptypb.Empty, error) {
return XaGrpcClient.HandleCallback(ctx)
}

3
examples/http_gorm_xa.go

@ -3,6 +3,7 @@ package examples
import (
"github.com/go-resty/resty/v2"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
)
func init() {
@ -15,7 +16,7 @@ func init() {
}
return xa.CallBranch(&TransReq{Amount: 30}, Busi+"/TransInXa")
})
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
return gid
})

9
examples/http_msg.go

@ -2,20 +2,21 @@ package examples
import (
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
)
func init() {
addSample("msg", func() string {
dtmcli.Logf("a busi transaction begin")
dtmimp.Logf("a busi transaction begin")
req := &TransReq{Amount: 30}
msg := dtmcli.NewMsg(DtmServer, dtmcli.MustGenGid(DtmServer)).
Add(Busi+"/TransOut", req).
Add(Busi+"/TransIn", req)
err := msg.Prepare(Busi + "/query")
dtmcli.FatalIfError(err)
dtmcli.Logf("busi trans submit")
dtmimp.FatalIfError(err)
dtmimp.Logf("busi trans submit")
err = msg.Submit()
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
return msg.Gid
})
}

25
examples/http_saga.go

@ -2,35 +2,36 @@ package examples
import (
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
)
func init() {
addSample("saga", func() string {
dtmcli.Logf("a saga busi transaction begin")
dtmimp.Logf("a saga busi transaction begin")
req := &TransReq{Amount: 30}
saga := dtmcli.NewSaga(DtmServer, dtmcli.MustGenGid(DtmServer)).
Add(Busi+"/TransOut", Busi+"/TransOutRevert", req).
Add(Busi+"/TransIn", Busi+"/TransInRevert", req)
dtmcli.Logf("saga busi trans submit")
dtmimp.Logf("saga busi trans submit")
err := saga.Submit()
dtmcli.Logf("result gid is: %s", saga.Gid)
dtmcli.FatalIfError(err)
dtmimp.Logf("result gid is: %s", saga.Gid)
dtmimp.FatalIfError(err)
return saga.Gid
})
addSample("saga_wait", func() string {
dtmcli.Logf("a saga busi transaction begin")
dtmimp.Logf("a saga busi transaction begin")
req := &TransReq{Amount: 30}
saga := dtmcli.NewSaga(DtmServer, dtmcli.MustGenGid(DtmServer)).
Add(Busi+"/TransOut", Busi+"/TransOutRevert", req).
Add(Busi+"/TransIn", Busi+"/TransInRevert", req)
saga.SetOptions(&dtmcli.TransOptions{WaitResult: true})
saga.SetOptions(&dtmimp.TransOptions{WaitResult: true})
err := saga.Submit()
dtmcli.Logf("result gid is: %s", saga.Gid)
dtmcli.FatalIfError(err)
dtmimp.Logf("result gid is: %s", saga.Gid)
dtmimp.FatalIfError(err)
return saga.Gid
})
addSample("concurrent_saga", func() string {
dtmcli.Logf("a concurrent saga busi transaction begin")
dtmimp.Logf("a concurrent saga busi transaction begin")
req := &TransReq{Amount: 30}
csaga := dtmcli.NewSaga(DtmServer, dtmcli.MustGenGid(DtmServer)).
Add(Busi+"/TransOut", Busi+"/TransOutRevert", req).
@ -40,10 +41,10 @@ func init() {
EnableConcurrent().
AddBranchOrder(2, []int{0, 1}).
AddBranchOrder(3, []int{0, 1})
dtmcli.Logf("concurrent saga busi trans submit")
dtmimp.Logf("concurrent saga busi trans submit")
err := csaga.Submit()
dtmcli.Logf("result gid is: %s", csaga.Gid)
dtmcli.FatalIfError(err)
dtmimp.Logf("result gid is: %s", csaga.Gid)
dtmimp.FatalIfError(err)
return csaga.Gid
})
}

9
examples/http_saga_barrier.go

@ -4,6 +4,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/yedf/dtm/common"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
)
func init() {
@ -14,20 +15,20 @@ func init() {
app.POST(BusiAPI+"/SagaBTransOutCompensate", common.WrapHandler(sagaBarrierTransOutCompensate))
}
addSample("saga_barrier", func() string {
dtmcli.Logf("a busi transaction begin")
dtmimp.Logf("a busi transaction begin")
req := &TransReq{Amount: 30}
saga := dtmcli.NewSaga(DtmServer, dtmcli.MustGenGid(DtmServer)).
Add(Busi+"/SagaBTransOut", Busi+"/SagaBTransOutCompensate", req).
Add(Busi+"/SagaBTransIn", Busi+"/SagaBTransInCompensate", req)
dtmcli.Logf("busi trans submit")
dtmimp.Logf("busi trans submit")
err := saga.Submit()
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
return saga.Gid
})
}
func sagaBarrierAdjustBalance(db dtmcli.DB, uid int, amount int) error {
_, err := dtmcli.DBExec(db, "update dtm_busi.user_account set balance = balance + ? where user_id = ?", amount, uid)
_, err := dtmimp.DBExec(db, "update dtm_busi.user_account set balance = balance + ? where user_id = ?", amount, uid)
return err
}

7
examples/http_saga_gorm_barrier.go

@ -6,6 +6,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/yedf/dtm/common"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
)
func init() {
@ -13,14 +14,14 @@ func init() {
app.POST(BusiAPI+"/SagaBTransOutGorm", common.WrapHandler(sagaGormBarrierTransOut))
}
addSample("saga_gorm_barrier", func() string {
dtmcli.Logf("a busi transaction begin")
dtmimp.Logf("a busi transaction begin")
req := &TransReq{Amount: 30}
saga := dtmcli.NewSaga(DtmServer, dtmcli.MustGenGid(DtmServer)).
Add(Busi+"/SagaBTransOutGorm", Busi+"/SagaBTransOutCompensate", req).
Add(Busi+"/SagaBTransIn", Busi+"/SagaBTransInCompensate", req)
dtmcli.Logf("busi trans submit")
dtmimp.Logf("busi trans submit")
err := saga.Submit()
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
return saga.Gid
})

11
examples/http_tcc.go

@ -5,14 +5,15 @@ import (
"github.com/go-resty/resty/v2"
"github.com/yedf/dtm/common"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
)
func init() {
setupFuncs["TccSetupSetup"] = func(app *gin.Engine) {
app.POST(BusiAPI+"/TransInTccParent", common.WrapHandler(func(c *gin.Context) (interface{}, error) {
tcc, err := dtmcli.TccFromQuery(c.Request.URL.Query())
dtmcli.FatalIfError(err)
dtmcli.Logf("TransInTccParent ")
dtmimp.FatalIfError(err)
dtmimp.Logf("TransInTccParent ")
return tcc.CallBranch(&TransReq{Amount: reqFrom(c).Amount}, Busi+"/TransIn", Busi+"/TransInConfirm", Busi+"/TransInRevert")
}))
}
@ -25,11 +26,11 @@ func init() {
}
return tcc.CallBranch(&TransReq{Amount: 30}, Busi+"/TransInTccParent", Busi+"/TransInConfirm", Busi+"/TransInRevert")
})
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
return gid
})
addSample("tcc", func() string {
dtmcli.Logf("tcc simple transaction begin")
dtmimp.Logf("tcc simple transaction begin")
gid := dtmcli.MustGenGid(DtmServer)
err := dtmcli.TccGlobalTransaction(DtmServer, gid, func(tcc *dtmcli.Tcc) (*resty.Response, error) {
resp, err := tcc.CallBranch(&TransReq{Amount: 30}, Busi+"/TransOut", Busi+"/TransOutConfirm", Busi+"/TransOutRevert")
@ -38,7 +39,7 @@ func init() {
}
return tcc.CallBranch(&TransReq{Amount: 30}, Busi+"/TransIn", Busi+"/TransInConfirm", Busi+"/TransInRevert")
})
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
return gid
})
}

9
examples/http_tcc_barrier.go

@ -7,6 +7,7 @@ import (
"github.com/go-resty/resty/v2"
"github.com/yedf/dtm/common"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
)
func init() {
@ -19,7 +20,7 @@ func init() {
app.POST(BusiAPI+"/TccBTransOutCancel", common.WrapHandler(TccBarrierTransOutCancel))
}
addSample("tcc_barrier", func() string {
dtmcli.Logf("tcc transaction begin")
dtmimp.Logf("tcc transaction begin")
gid := dtmcli.MustGenGid(DtmServer)
err := dtmcli.TccGlobalTransaction(DtmServer, gid, func(tcc *dtmcli.Tcc) (*resty.Response, error) {
resp, err := tcc.CallBranch(&TransReq{Amount: 30}, Busi+"/TccBTransOutTry",
@ -29,7 +30,7 @@ func init() {
}
return tcc.CallBranch(&TransReq{Amount: 30}, Busi+"/TccBTransInTry", Busi+"/TccBTransInConfirm", Busi+"/TccBTransInCancel")
})
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
return gid
})
}
@ -38,7 +39,7 @@ const transInUID = 1
const transOutUID = 2
func adjustTrading(db dtmcli.DB, uid int, amount int) error {
affected, err := dtmcli.DBExec(db, `update dtm_busi.user_account set trading_balance=trading_balance+?
affected, err := dtmimp.DBExec(db, `update dtm_busi.user_account set trading_balance=trading_balance+?
where user_id=? and trading_balance + ? + balance >= 0`, amount, uid, amount)
if err == nil && affected == 0 {
return fmt.Errorf("update error, maybe balance not enough")
@ -47,7 +48,7 @@ func adjustTrading(db dtmcli.DB, uid int, amount int) error {
}
func adjustBalance(db dtmcli.DB, uid int, amount int) error {
affected, err := dtmcli.DBExec(db, `update dtm_busi.user_account set trading_balance=trading_balance-?,
affected, err := dtmimp.DBExec(db, `update dtm_busi.user_account set trading_balance=trading_balance-?,
balance=balance+? where user_id=?`, amount, amount, uid)
if err == nil && affected == 0 {
return fmt.Errorf("update user_account 0 rows")

5
examples/http_xa.go

@ -5,6 +5,7 @@ import (
"github.com/go-resty/resty/v2"
"github.com/yedf/dtm/common"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
)
// XaClient XA client connection
@ -18,7 +19,7 @@ func init() {
return xa.HandleCallback(c.Query("gid"), c.Query("branch_id"), c.Query("branch_type"))
}))
})
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
}
addSample("xa", func() string {
gid := dtmcli.MustGenGid(DtmServer)
@ -29,7 +30,7 @@ func init() {
}
return xa.CallBranch(&TransReq{Amount: 30}, Busi+"/TransInXa")
})
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
return gid
})
}

7
examples/quick_start.go

@ -7,6 +7,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/yedf/dtm/common"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
)
// 启动命令:go run app/main.go qs
@ -21,7 +22,7 @@ var qsBusi = fmt.Sprintf("http://localhost:%d%s", qsBusiPort, qsBusiAPI)
func QsStartSvr() {
app := common.GetGinApp()
qsAddRoute(app)
dtmcli.Logf("quick qs examples listening at %d", qsBusiPort)
dtmimp.Logf("quick qs examples listening at %d", qsBusiPort)
go app.Run(fmt.Sprintf(":%d", qsBusiPort))
time.Sleep(100 * time.Millisecond)
}
@ -37,12 +38,12 @@ func QsFireRequest() string {
Add(qsBusi+"/TransIn", qsBusi+"/TransInCompensate", req)
// 提交saga事务,dtm会完成所有的子事务/回滚所有的子事务
err := saga.Submit()
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
return saga.Gid
}
func qsAdjustBalance(uid int, amount int) (interface{}, error) {
_, err := dtmcli.DBExec(sdbGet(), "update dtm_busi.user_account set balance = balance + ? where user_id = ?", amount, uid)
_, err := dtmimp.DBExec(sdbGet(), "update dtm_busi.user_account set balance = balance + ? where user_id = ?", amount, uid)
return dtmcli.MapSuccess, err
}

3
go.mod

@ -9,10 +9,7 @@ require (
github.com/go-resty/resty/v2 v2.6.0
github.com/go-sql-driver/mysql v1.5.0
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
github.com/kr/pretty v0.1.0 // indirect
github.com/lib/pq v1.10.3
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/prometheus/client_golang v1.11.0
github.com/stretchr/testify v1.7.0
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d // indirect

12
go.sum

@ -1,6 +1,7 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@ -21,6 +22,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
@ -58,6 +60,7 @@ github.com/go-resty/resty/v2 v2.6.0/go.mod h1:PwvJS6hvaPkjtjNg9ph+VrSD92bi5Zq73w
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
@ -109,6 +112,7 @@ github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc=
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
@ -146,7 +150,6 @@ github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@ -191,6 +194,7 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@ -220,6 +224,7 @@ github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OK
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
@ -339,7 +344,6 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
@ -400,7 +404,6 @@ google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+Rur
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@ -421,11 +424,8 @@ gorm.io/driver/mysql v1.0.3/go.mod h1:twGxftLBlFgNVNakL7F+P/x9oYqoymG3YYT8cAfI9o
gorm.io/driver/postgres v1.1.2 h1:Amy3hCvLqM+/ICzjCnQr8wKFLVJTeOTdlMT7kCP+J1Q=
gorm.io/driver/postgres v1.1.2/go.mod h1:/AGV0zvqF3mt9ZtzLzQmXWQ/5vr+1V1TyHZGZVjzmwI=
gorm.io/gorm v1.20.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.21.12 h1:3fQM0Eiz7jcJEhPggHEpoYnsGZqynMzverL77DV40RM=
gorm.io/gorm v1.21.12/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
gorm.io/gorm v1.21.15 h1:gAyaDoPw0lCyrSFWhBlahbUA1U4P5RViC1uIqoB+1Rk=
gorm.io/gorm v1.21.15/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=

44
test/api_test.go

@ -0,0 +1,44 @@
package test
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/examples"
)
const gidTestAPI = "TestAPI"
func TestAPIQuery(t *testing.T) {
err := genMsg(gidTestAPI).Submit()
assert.Nil(t, err)
waitTransProcessed(gidTestAPI)
resp, err := dtmimp.RestyClient.R().SetQueryParam("gid", gidTestAPI).Get(examples.DtmServer + "/query")
e2p(err)
m := map[string]interface{}{}
assert.Equal(t, resp.StatusCode(), 200)
dtmimp.MustUnmarshalString(resp.String(), &m)
assert.NotEqual(t, nil, m["transaction"])
assert.Equal(t, 2, len(m["branches"].([]interface{})))
resp, err = dtmimp.RestyClient.R().SetQueryParam("gid", "").Get(examples.DtmServer + "/query")
e2p(err)
assert.Equal(t, resp.StatusCode(), 500)
resp, err = dtmimp.RestyClient.R().SetQueryParam("gid", "1").Get(examples.DtmServer + "/query")
e2p(err)
assert.Equal(t, resp.StatusCode(), 200)
dtmimp.MustUnmarshalString(resp.String(), &m)
assert.Equal(t, nil, m["transaction"])
assert.Equal(t, 0, len(m["branches"].([]interface{})))
}
func TestAPIAll(t *testing.T) {
_, err := dtmimp.RestyClient.R().Get(examples.DtmServer + "/all")
assert.Nil(t, err)
_, err = dtmimp.RestyClient.R().SetQueryParam("last_id", "10").Get(examples.DtmServer + "/all")
assert.Nil(t, err)
resp, err := dtmimp.RestyClient.R().SetQueryParam("last_id", "abc").Get(examples.DtmServer + "/all")
assert.Equal(t, resp.StatusCode(), 500)
}

22
test/base_test.go

@ -7,10 +7,20 @@ import (
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/common"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/examples"
)
func TestSqlDB(t *testing.T) {
// BarrierModel barrier model for gorm
type BarrierModel struct {
common.ModelBase
dtmcli.BranchBarrier
}
// TableName gorm table name
func (BarrierModel) TableName() string { return "dtm_barrier.barrier" }
func TestBaseSqlDB(t *testing.T) {
asserts := assert.New(t)
db := common.DbGet(config.DB)
barrier := &dtmcli.BranchBarrier{
@ -23,7 +33,7 @@ func TestSqlDB(t *testing.T) {
tx, err := db.ToSQLDB().Begin()
asserts.Nil(err)
err = barrier.Call(tx, func(db dtmcli.DB) error {
dtmcli.Logf("rollback gid2")
dtmimp.Logf("rollback gid2")
return fmt.Errorf("gid2 error")
})
asserts.Error(err, fmt.Errorf("gid2 error"))
@ -35,7 +45,7 @@ func TestSqlDB(t *testing.T) {
tx2, err := db.ToSQLDB().Begin()
asserts.Nil(err)
err = barrier.Call(tx2, func(db dtmcli.DB) error {
dtmcli.Logf("submit gid2")
dtmimp.Logf("submit gid2")
return nil
})
asserts.Nil(err)
@ -43,11 +53,11 @@ func TestSqlDB(t *testing.T) {
asserts.Equal(dbr.RowsAffected, int64(1))
}
func TestHttp(t *testing.T) {
resp, err := dtmcli.RestyClient.R().SetQueryParam("panic_string", "1").Post(examples.Busi + "/TestPanic")
func TestBaseHttp(t *testing.T) {
resp, err := dtmimp.RestyClient.R().SetQueryParam("panic_string", "1").Post(examples.Busi + "/TestPanic")
assert.Nil(t, err)
assert.Contains(t, resp.String(), "panic_string")
resp, err = dtmcli.RestyClient.R().SetQueryParam("panic_error", "1").Post(examples.Busi + "/TestPanic")
resp, err = dtmimp.RestyClient.R().SetQueryParam("panic_error", "1").Post(examples.Busi + "/TestPanic")
assert.Nil(t, err)
assert.Contains(t, resp.String(), "panic_error")
}

50
test/dtmsvr_test.go

@ -8,6 +8,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/common"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/dtmsvr"
"github.com/yedf/dtm/examples"
)
@ -16,15 +17,6 @@ var DtmServer = examples.DtmServer
var Busi = examples.Busi
var app *gin.Engine
// BarrierModel barrier model for gorm
type BarrierModel struct {
common.ModelBase
dtmcli.BranchBarrier
}
// TableName gorm table name
func (BarrierModel) TableName() string { return "dtm_barrier.barrier" }
func getTransStatus(gid string) string {
sm := TransGlobal{}
dbr := dbGet().Model(&sm).Where("gid=?", gid).First(&sm)
@ -48,49 +40,15 @@ func assertSucceed(t *testing.T, gid string) {
assert.Equal(t, dtmcli.StatusSucceed, getTransStatus(gid))
}
func genMsg(gid string) *dtmcli.Msg {
dtmcli.Logf("beginning a msg test ---------------- %s", gid)
msg := dtmcli.NewMsg(examples.DtmServer, gid)
msg.QueryPrepared = examples.Busi + "/CanSubmit"
req := examples.GenTransReq(30, false, false)
msg.Add(examples.Busi+"/TransOut", &req)
msg.Add(examples.Busi+"/TransIn", &req)
return msg
}
func transQuery(t *testing.T, gid string) {
resp, err := dtmcli.RestyClient.R().SetQueryParam("gid", gid).Get(examples.DtmServer + "/query")
e2p(err)
m := M{}
assert.Equal(t, resp.StatusCode(), 200)
dtmcli.MustUnmarshalString(resp.String(), &m)
assert.NotEqual(t, nil, m["transaction"])
assert.Equal(t, 4, len(m["branches"].([]interface{})))
resp, err = dtmcli.RestyClient.R().SetQueryParam("gid", "").Get(examples.DtmServer + "/query")
e2p(err)
assert.Equal(t, resp.StatusCode(), 500)
resp, err = dtmcli.RestyClient.R().SetQueryParam("gid", "1").Get(examples.DtmServer + "/query")
e2p(err)
assert.Equal(t, resp.StatusCode(), 200)
dtmcli.MustUnmarshalString(resp.String(), &m)
assert.Equal(t, nil, m["transaction"])
assert.Equal(t, 0, len(m["branches"].([]interface{})))
resp, err = dtmcli.RestyClient.R().Get(examples.DtmServer + "/all")
assert.Nil(t, err)
}
func TestUpdateBranchAsync(t *testing.T) {
common.DtmConfig.UpdateBranchSync = 0
saga := genSaga("gid-update-branch-async", false, false)
saga.SetOptions(&dtmcli.TransOptions{WaitResult: true})
saga := genSaga1(dtmimp.GetFuncName(), false, false)
saga.SetOptions(&dtmimp.TransOptions{WaitResult: true})
err := saga.Submit()
assert.Nil(t, err)
waitTransProcessed(saga.Gid)
time.Sleep(dtmsvr.UpdateBranchAsyncInterval)
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusSucceed, dtmcli.StatusPrepared, dtmcli.StatusSucceed}, getBranchesStatus(saga.Gid))
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusSucceed}, getBranchesStatus(saga.Gid))
assert.Equal(t, dtmcli.StatusSucceed, getTransStatus(saga.Gid))
common.DtmConfig.UpdateBranchSync = 1
}

1
test/examples_test.go

@ -7,7 +7,6 @@ import (
)
func TestExamples(t *testing.T) {
// for coverage
examples.QsStartSvr()
for _, s := range examples.Samples {
assertSucceed(t, s.Action())

36
test/grpc_msg_test.go

@ -6,26 +6,22 @@ import (
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/dtmgrpc"
"github.com/yedf/dtm/examples"
)
func TestGrpcMsg(t *testing.T) {
grpcMsgNormal(t)
grpcMsgOngoing(t)
}
func grpcMsgNormal(t *testing.T) {
msg := genGrpcMsg("grpc-msg-normal")
func TestGrpcMsgNormal(t *testing.T) {
msg := genGrpcMsg(dtmimp.GetFuncName())
err := msg.Submit()
assert.Nil(t, err)
waitTransProcessed(msg.Gid)
assert.Equal(t, dtmcli.StatusSucceed, getTransStatus(msg.Gid))
}
func grpcMsgOngoing(t *testing.T) {
msg := genGrpcMsg("grpc-msg-pending")
err := msg.Prepare(fmt.Sprintf("%s/examples.Busi/CanSubmit", examples.BusiGrpc))
func TestGrpcMsgOngoingSuccess(t *testing.T) {
msg := genGrpcMsg(dtmimp.GetFuncName())
err := msg.Prepare("")
assert.Nil(t, err)
examples.MainSwitch.CanSubmitResult.SetOnce(dtmcli.ResultOngoing)
cronTransOnceForwardNow(180)
@ -37,10 +33,24 @@ func grpcMsgOngoing(t *testing.T) {
assert.Equal(t, dtmcli.StatusSucceed, getTransStatus(msg.Gid))
}
func TestGrpcMsgOngoingFailed(t *testing.T) {
msg := genGrpcMsg(dtmimp.GetFuncName())
msg.Prepare("")
assert.Equal(t, dtmcli.StatusPrepared, getTransStatus(msg.Gid))
examples.MainSwitch.CanSubmitResult.SetOnce(dtmcli.ResultOngoing)
cronTransOnceForwardNow(180)
assert.Equal(t, dtmcli.StatusPrepared, getTransStatus(msg.Gid))
examples.MainSwitch.CanSubmitResult.SetOnce(dtmcli.ResultFailure)
cronTransOnceForwardNow(180)
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusPrepared}, getBranchesStatus(msg.Gid))
assert.Equal(t, dtmcli.StatusFailed, getTransStatus(msg.Gid))
}
func genGrpcMsg(gid string) *dtmgrpc.MsgGrpc {
req := dtmcli.MustMarshal(&examples.TransReq{Amount: 30})
return dtmgrpc.NewMsgGrpc(examples.DtmGrpcServer, gid).
req := &examples.BusiReq{Amount: 30}
msg := dtmgrpc.NewMsgGrpc(examples.DtmGrpcServer, gid).
Add(examples.BusiGrpc+"/examples.Busi/TransOut", req).
Add(examples.BusiGrpc+"/examples.Busi/TransIn", req)
msg.QueryPrepared = fmt.Sprintf("%s/examples.Busi/CanSubmit", examples.BusiGrpc)
return msg
}

19
test/grpc_barrier_saga_test.go → test/grpc_saga_barrier_test.go

@ -5,19 +5,14 @@ import (
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/dtmgrpc"
"github.com/yedf/dtm/examples"
)
func TestGrpcBarrierSaga(t *testing.T) {
grpcSagaBarrierNormal(t)
grpcSagaBarrierRollback(t)
}
func grpcSagaBarrierNormal(t *testing.T) {
req := dtmcli.MustMarshal(&examples.TransReq{Amount: 30})
saga := dtmgrpc.NewSaga(examples.DtmGrpcServer, "grpcSagaBarrierNormal").
func TestGrpcSagaBarrierNormal(t *testing.T) {
req := examples.GenBusiReq(30, false, false)
saga := dtmgrpc.NewSagaGrpc(examples.DtmGrpcServer, dtmimp.GetFuncName()).
Add(examples.BusiGrpc+"/examples.Busi/TransOutBSaga", examples.BusiGrpc+"/examples.Busi/TransOutRevertBSaga", req).
Add(examples.BusiGrpc+"/examples.Busi/TransInBSaga", examples.BusiGrpc+"/examples.Busi/TransInRevertBSaga", req)
err := saga.Submit()
@ -26,9 +21,9 @@ func grpcSagaBarrierNormal(t *testing.T) {
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusSucceed, dtmcli.StatusPrepared, dtmcli.StatusSucceed}, getBranchesStatus(saga.Gid))
}
func grpcSagaBarrierRollback(t *testing.T) {
req := dtmcli.MustMarshal(&examples.TransReq{Amount: 30, TransInResult: dtmcli.ResultFailure})
saga := dtmgrpc.NewSaga(examples.DtmGrpcServer, "grpcSagaBarrierRollback").
func TestGrpcSagaBarrierRollback(t *testing.T) {
req := examples.GenBusiReq(30, false, true)
saga := dtmgrpc.NewSagaGrpc(examples.DtmGrpcServer, dtmimp.GetFuncName()).
Add(examples.BusiGrpc+"/examples.Busi/TransOutBSaga", examples.BusiGrpc+"/examples.Busi/TransOutRevertBSaga", req).
Add(examples.BusiGrpc+"/examples.Busi/TransInBSaga", examples.BusiGrpc+"/examples.Busi/TransInRevertBSaga", req)
err := saga.Submit()

26
test/grpc_saga_test.go

@ -5,27 +5,21 @@ import (
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/dtmgrpc"
"github.com/yedf/dtm/examples"
)
func TestGrpcSaga(t *testing.T) {
sagaGrpcNormal(t)
sagaGrpcCommittedOngoing(t)
sagaGrpcRollback(t)
}
func sagaGrpcNormal(t *testing.T) {
saga := genSagaGrpc("gid-sagaGrpcNormal", false, false)
func TestGrpcSagaNormal(t *testing.T) {
saga := genSagaGrpc(dtmimp.GetFuncName(), false, false)
saga.Submit()
waitTransProcessed(saga.Gid)
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusSucceed, dtmcli.StatusPrepared, dtmcli.StatusSucceed}, getBranchesStatus(saga.Gid))
assert.Equal(t, dtmcli.StatusSucceed, getTransStatus(saga.Gid))
transQuery(t, saga.Gid)
}
func sagaGrpcCommittedOngoing(t *testing.T) {
saga := genSagaGrpc("gid-committedOngoingGrpc", false, false)
func TestGrpcSagaCommittedOngoing(t *testing.T) {
saga := genSagaGrpc(dtmimp.GetFuncName(), false, false)
examples.MainSwitch.TransOutResult.SetOnce(dtmcli.ResultOngoing)
saga.Submit()
waitTransProcessed(saga.Gid)
@ -35,8 +29,8 @@ func sagaGrpcCommittedOngoing(t *testing.T) {
assert.Equal(t, dtmcli.StatusSucceed, getTransStatus(saga.Gid))
}
func sagaGrpcRollback(t *testing.T) {
saga := genSagaGrpc("gid-rollbackSaga2Grpc", false, true)
func TestGrpcSagaRollback(t *testing.T) {
saga := genSagaGrpc(dtmimp.GetFuncName(), false, true)
examples.MainSwitch.TransOutRevertResult.SetOnce(dtmcli.ResultOngoing)
saga.Submit()
waitTransProcessed(saga.Gid)
@ -47,9 +41,9 @@ func sagaGrpcRollback(t *testing.T) {
}
func genSagaGrpc(gid string, outFailed bool, inFailed bool) *dtmgrpc.SagaGrpc {
dtmcli.Logf("beginning a grpc saga test ---------------- %s", gid)
saga := dtmgrpc.NewSaga(examples.DtmGrpcServer, gid)
req := dtmcli.MustMarshal(examples.GenTransReq(30, outFailed, inFailed))
dtmimp.Logf("beginning a grpc saga test ---------------- %s", gid)
saga := dtmgrpc.NewSagaGrpc(examples.DtmGrpcServer, gid)
req := examples.GenBusiReq(30, outFailed, inFailed)
saga.Add(examples.BusiGrpc+"/examples.Busi/TransOut", examples.BusiGrpc+"/examples.Busi/TransOutRevert", req)
saga.Add(examples.BusiGrpc+"/examples.Busi/TransIn", examples.BusiGrpc+"/examples.Busi/TransInRevert", req)
return saga

49
test/grpc_tcc_test.go

@ -1,60 +1,59 @@
package test
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/dtmgrpc"
"github.com/yedf/dtm/examples"
"google.golang.org/protobuf/types/known/emptypb"
)
func TestGrpcTcc(t *testing.T) {
tccGrpcType(t)
tccGrpcNormal(t)
tccGrpcNested(t)
tccGrpcRollback(t)
}
func tccGrpcType(t *testing.T) {
_, err := dtmgrpc.TccFromRequest(&dtmgrpc.BusiRequest{Info: &dtmgrpc.BranchInfo{}})
func TestGrpcTccType(t *testing.T) {
_, err := dtmgrpc.TccFromGrpc(context.Background())
assert.Error(t, err)
dtmcli.Logf("expecting dtmgrpcserver error")
dtmimp.Logf("expecting dtmgrpcserver error")
err = dtmgrpc.TccGlobalTransaction("-", "", func(tcc *dtmgrpc.TccGrpc) error { return nil })
assert.Error(t, err)
}
func tccGrpcNormal(t *testing.T) {
data := dtmcli.MustMarshal(&examples.TransReq{Amount: 30})
gid := "tccGrpcNormal"
func TestGrpcTccNormal(t *testing.T) {
data := &examples.BusiReq{Amount: 30}
gid := dtmimp.GetFuncName()
err := dtmgrpc.TccGlobalTransaction(examples.DtmGrpcServer, gid, func(tcc *dtmgrpc.TccGrpc) error {
_, err := tcc.CallBranch(data, examples.BusiGrpc+"/examples.Busi/TransOut", examples.BusiGrpc+"/examples.Busi/TransOutConfirm", examples.BusiGrpc+"/examples.Busi/TransOutRevert")
r := &emptypb.Empty{}
err := tcc.CallBranch(data, examples.BusiGrpc+"/examples.Busi/TransOut", examples.BusiGrpc+"/examples.Busi/TransOutConfirm", examples.BusiGrpc+"/examples.Busi/TransOutRevert", r)
assert.Nil(t, err)
_, err = tcc.CallBranch(data, examples.BusiGrpc+"/examples.Busi/TransIn", examples.BusiGrpc+"/examples.Busi/TransInConfirm", examples.BusiGrpc+"/examples.Busi/TransInRevert")
err = tcc.CallBranch(data, examples.BusiGrpc+"/examples.Busi/TransIn", examples.BusiGrpc+"/examples.Busi/TransInConfirm", examples.BusiGrpc+"/examples.Busi/TransInRevert", r)
return err
})
assert.Nil(t, err)
}
func tccGrpcNested(t *testing.T) {
data := dtmcli.MustMarshal(&examples.TransReq{Amount: 30})
gid := "tccGrpcNested"
func TestGrpcTestNested(t *testing.T) {
data := &examples.BusiReq{Amount: 30}
gid := dtmimp.GetFuncName()
err := dtmgrpc.TccGlobalTransaction(examples.DtmGrpcServer, gid, func(tcc *dtmgrpc.TccGrpc) error {
_, err := tcc.CallBranch(data, examples.BusiGrpc+"/examples.Busi/TransOutTcc", examples.BusiGrpc+"/examples.Busi/TransOutConfirm", examples.BusiGrpc+"/examples.Busi/TransOutRevert")
r := &emptypb.Empty{}
err := tcc.CallBranch(data, examples.BusiGrpc+"/examples.Busi/TransOutTcc", examples.BusiGrpc+"/examples.Busi/TransOutConfirm", examples.BusiGrpc+"/examples.Busi/TransOutRevert", r)
assert.Nil(t, err)
_, err = tcc.CallBranch(data, examples.BusiGrpc+"/examples.Busi/TransInTccNested", examples.BusiGrpc+"/examples.Busi/TransInConfirm", examples.BusiGrpc+"/examples.Busi/TransInRevert")
err = tcc.CallBranch(data, examples.BusiGrpc+"/examples.Busi/TransInTccNested", examples.BusiGrpc+"/examples.Busi/TransInConfirm", examples.BusiGrpc+"/examples.Busi/TransInRevert", r)
return err
})
assert.Nil(t, err)
}
func tccGrpcRollback(t *testing.T) {
gid := "tccGrpcRollback"
data := dtmcli.MustMarshal(&examples.TransReq{Amount: 30, TransInResult: dtmcli.ResultFailure})
func TestGrpcTccRollback(t *testing.T) {
gid := dtmimp.GetFuncName()
data := &examples.BusiReq{Amount: 30, TransInResult: dtmcli.ResultFailure}
err := dtmgrpc.TccGlobalTransaction(examples.DtmGrpcServer, gid, func(tcc *dtmgrpc.TccGrpc) error {
_, err := tcc.CallBranch(data, examples.BusiGrpc+"/examples.Busi/TransOutTcc", examples.BusiGrpc+"/examples.Busi/TransOutConfirm", examples.BusiGrpc+"/examples.Busi/TransOutRevert")
r := &emptypb.Empty{}
err := tcc.CallBranch(data, examples.BusiGrpc+"/examples.Busi/TransOutTcc", examples.BusiGrpc+"/examples.Busi/TransOutConfirm", examples.BusiGrpc+"/examples.Busi/TransOutRevert", r)
assert.Nil(t, err)
examples.MainSwitch.TransOutRevertResult.SetOnce(dtmcli.ResultOngoing)
_, err = tcc.CallBranch(data, examples.BusiGrpc+"/examples.Busi/TransInTcc", examples.BusiGrpc+"/examples.Busi/TransInConfirm", examples.BusiGrpc+"/examples.Busi/TransInRevert")
err = tcc.CallBranch(data, examples.BusiGrpc+"/examples.Busi/TransInTcc", examples.BusiGrpc+"/examples.Busi/TransInConfirm", examples.BusiGrpc+"/examples.Busi/TransInRevert", r)
return err
})
assert.Error(t, err)

44
test/grpc_xa_test.go

@ -1,53 +1,50 @@
package test
import (
"context"
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/dtmgrpc"
"github.com/yedf/dtm/examples"
"google.golang.org/protobuf/types/known/emptypb"
)
func TestGrpcXa(t *testing.T) {
xaGrpcType(t)
xaGrpcLocalError(t)
xaGrpcNormal(t)
xaGrpcRollback(t)
}
func xaGrpcType(t *testing.T) {
_, err := dtmgrpc.XaGrpcFromRequest(&dtmgrpc.BusiRequest{Info: &dtmgrpc.BranchInfo{}})
func TestGrpcXaType(t *testing.T) {
_, err := dtmgrpc.XaGrpcFromRequest(context.Background())
assert.Error(t, err)
err = examples.XaGrpcClient.XaLocalTransaction(&dtmgrpc.BusiRequest{Info: &dtmgrpc.BranchInfo{}}, nil)
err = examples.XaGrpcClient.XaLocalTransaction(context.Background(), nil, nil)
assert.Error(t, err)
err = dtmcli.CatchP(func() {
err = dtmimp.CatchP(func() {
examples.XaGrpcClient.XaGlobalTransaction("id1", func(xa *dtmgrpc.XaGrpc) error { panic(fmt.Errorf("hello")) })
})
assert.Error(t, err)
}
func xaGrpcLocalError(t *testing.T) {
func TestGrpcXaLocalError(t *testing.T) {
xc := examples.XaGrpcClient
err := xc.XaGlobalTransaction("xaGrpcLocalError", func(xa *dtmgrpc.XaGrpc) error {
err := xc.XaGlobalTransaction(dtmimp.GetFuncName(), func(xa *dtmgrpc.XaGrpc) error {
return fmt.Errorf("an error")
})
assert.Error(t, err, fmt.Errorf("an error"))
}
func xaGrpcNormal(t *testing.T) {
func TestGrpcXaNormal(t *testing.T) {
xc := examples.XaGrpcClient
gid := "xaGrpcNormal"
gid := dtmimp.GetFuncName()
err := xc.XaGlobalTransaction(gid, func(xa *dtmgrpc.XaGrpc) error {
req := dtmcli.MustMarshal(examples.GenTransReq(30, false, false))
_, err := xa.CallBranch(req, examples.BusiGrpc+"/examples.Busi/TransOutXa")
req := &examples.BusiReq{Amount: 30}
r := &emptypb.Empty{}
err := xa.CallBranch(req, examples.BusiGrpc+"/examples.Busi/TransOutXa", r)
if err != nil {
return err
}
_, err = xa.CallBranch(req, examples.BusiGrpc+"/examples.Busi/TransInXa")
err = xa.CallBranch(req, examples.BusiGrpc+"/examples.Busi/TransInXa", r)
return err
})
assert.Equal(t, nil, err)
@ -55,16 +52,17 @@ func xaGrpcNormal(t *testing.T) {
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusSucceed, dtmcli.StatusPrepared, dtmcli.StatusSucceed}, getBranchesStatus(gid))
}
func xaGrpcRollback(t *testing.T) {
func TestGrpcXaRollback(t *testing.T) {
xc := examples.XaGrpcClient
gid := "xaGrpcRollback"
gid := dtmimp.GetFuncName()
err := xc.XaGlobalTransaction(gid, func(xa *dtmgrpc.XaGrpc) error {
req := dtmcli.MustMarshal(&examples.TransReq{Amount: 30, TransInResult: dtmcli.ResultFailure})
_, err := xa.CallBranch(req, examples.BusiGrpc+"/examples.Busi/TransOutXa")
req := &examples.BusiReq{Amount: 30, TransInResult: dtmcli.ResultFailure}
r := &emptypb.Empty{}
err := xa.CallBranch(req, examples.BusiGrpc+"/examples.Busi/TransOutXa", r)
if err != nil {
return err
}
_, err = xa.CallBranch(req, examples.BusiGrpc+"/examples.Busi/TransInXa")
err = xa.CallBranch(req, examples.BusiGrpc+"/examples.Busi/TransInXa", r)
return err
})
assert.Error(t, err)

17
test/main_test.go

@ -1,7 +1,6 @@
package test
import (
"fmt"
"testing"
"time"
@ -24,21 +23,5 @@ func TestMain(m *testing.M) {
examples.GrpcStartup()
app = examples.BaseAppStartup()
resetXaData()
m.Run()
}
func resetXaData() {
if config.DB["driver"] != "mysql" {
return
}
db := dbGet()
type XaRow struct {
Data string
}
xas := []XaRow{}
db.Must().Raw("xa recover").Scan(&xas)
for _, xa := range xas {
db.Must().Exec(fmt.Sprintf("xa rollback '%s'", xa.Data))
}
}

48
test/msg_test.go

@ -5,31 +5,22 @@ import (
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/examples"
)
func TestMsg(t *testing.T) {
msgNormal(t)
msgOngoing(t)
msgOngoingFailed(t)
}
func msgNormal(t *testing.T) {
msg := genMsg("gid-msg-normal")
func TestMsgNormal(t *testing.T) {
msg := genMsg(dtmimp.GetFuncName())
msg.Submit()
assert.Equal(t, dtmcli.StatusSubmitted, getTransStatus(msg.Gid))
waitTransProcessed(msg.Gid)
assert.Equal(t, []string{dtmcli.StatusSucceed, dtmcli.StatusSucceed}, getBranchesStatus(msg.Gid))
assert.Equal(t, dtmcli.StatusSucceed, getTransStatus(msg.Gid))
cronTransOnce()
}
func msgOngoing(t *testing.T) {
msg := genMsg("gid-msg-normal-pending")
func TestMsgOngoingSuccess(t *testing.T) {
msg := genMsg(dtmimp.GetFuncName())
msg.Prepare("")
err := msg.Prepare("") // additional prepare to go conflict key path
assert.Nil(t, err)
assert.Equal(t, dtmcli.StatusPrepared, getTransStatus(msg.Gid))
examples.MainSwitch.CanSubmitResult.SetOnce(dtmcli.ResultOngoing)
cronTransOnceForwardNow(180)
@ -40,12 +31,10 @@ func msgOngoing(t *testing.T) {
cronTransOnce()
assert.Equal(t, []string{dtmcli.StatusSucceed, dtmcli.StatusSucceed}, getBranchesStatus(msg.Gid))
assert.Equal(t, dtmcli.StatusSucceed, getTransStatus(msg.Gid))
err = msg.Prepare("")
assert.Error(t, err)
}
func msgOngoingFailed(t *testing.T) {
msg := genMsg("gid-msg-pending-failed")
func TestMsgOngoingFailed(t *testing.T) {
msg := genMsg(dtmimp.GetFuncName())
msg.Prepare("")
assert.Equal(t, dtmcli.StatusPrepared, getTransStatus(msg.Gid))
examples.MainSwitch.CanSubmitResult.SetOnce(dtmcli.ResultOngoing)
@ -56,3 +45,26 @@ func msgOngoingFailed(t *testing.T) {
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusPrepared}, getBranchesStatus(msg.Gid))
assert.Equal(t, dtmcli.StatusFailed, getTransStatus(msg.Gid))
}
func TestMsgAbnormal(t *testing.T) {
msg := genMsg(dtmimp.GetFuncName())
msg.Prepare("")
err := msg.Prepare("")
assert.Nil(t, err)
err = msg.Submit()
assert.Nil(t, err)
err = msg.Submit()
assert.Nil(t, err)
err = msg.Prepare("")
assert.Error(t, err)
}
func genMsg(gid string) *dtmcli.Msg {
req := examples.GenTransReq(30, false, false)
msg := dtmcli.NewMsg(examples.DtmServer, gid).
Add(examples.Busi+"/TransOut", &req).
Add(examples.Busi+"/TransIn", &req)
msg.QueryPrepared = examples.Busi + "/CanSubmit"
return msg
}

19
test/barrier_saga_test.go → test/saga_barrier_test.go

@ -5,32 +5,27 @@ import (
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/examples"
)
func TestBarrierSaga(t *testing.T) {
sagaBarrierNormal(t)
sagaBarrierRollback(t)
}
func sagaBarrierNormal(t *testing.T) {
func TestSagaBarrierNormal(t *testing.T) {
req := &examples.TransReq{Amount: 30}
saga := dtmcli.NewSaga(DtmServer, "sagaBarrierNormal").
saga := dtmcli.NewSaga(DtmServer, dtmimp.GetFuncName()).
Add(Busi+"/SagaBTransOut", Busi+"/SagaBTransOutCompensate", req).
Add(Busi+"/SagaBTransIn", Busi+"/SagaBTransInCompensate", req)
dtmcli.Logf("busi trans submit")
dtmimp.Logf("busi trans submit")
err := saga.Submit()
e2p(err)
waitTransProcessed(saga.Gid)
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusSucceed, dtmcli.StatusPrepared, dtmcli.StatusSucceed}, getBranchesStatus(saga.Gid))
}
func sagaBarrierRollback(t *testing.T) {
saga := dtmcli.NewSaga(DtmServer, "sagaBarrierRollback").
func TestSagaBarrierRollback(t *testing.T) {
saga := dtmcli.NewSaga(DtmServer, dtmimp.GetFuncName()).
Add(Busi+"/SagaBTransOut", Busi+"/SagaBTransOutCompensate", &examples.TransReq{Amount: 30}).
Add(Busi+"/SagaBTransIn", Busi+"/SagaBTransInCompensate", &examples.TransReq{Amount: 30, TransInResult: dtmcli.ResultFailure})
dtmcli.Logf("busi trans submit")
dtmimp.Logf("busi trans submit")
err := saga.Submit()
e2p(err)
waitTransProcessed(saga.Gid)

21
test/saga_compatible_test.go

@ -0,0 +1,21 @@
package test
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/examples"
)
func TestSagaCompatibleNormal(t *testing.T) { // compatible with old http, which put payload in steps.data
gid := dtmimp.GetFuncName()
body := fmt.Sprintf(`{"gid":"%s","trans_type":"saga","steps":[{"action":"%s/TransOut","compensate":"%s/TransOutRevert","data":"{\"amount\":30,\"transInResult\":\"SUCCESS\",\"transOutResult\":\"SUCCESS\"}"},{"action":"%s/TransIn","compensate":"%s/TransInRevert","data":"{\"amount\":30,\"transInResult\":\"SUCCESS\",\"transOutResult\":\"SUCCESS\"}"}]}`,
gid, examples.Busi, examples.Busi, examples.Busi, examples.Busi)
dtmimp.RestyClient.R().SetBody(body).Post(fmt.Sprintf("%s/submit", examples.DtmServer))
waitTransProcessed(gid)
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusSucceed, dtmcli.StatusPrepared, dtmcli.StatusSucceed}, getBranchesStatus(gid))
assert.Equal(t, dtmcli.StatusSucceed, getTransStatus(gid))
}

76
test/saga_concurrent_test.go

@ -5,69 +5,63 @@ import (
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/examples"
)
func TestCSaga(t *testing.T) {
csagaNormal(t)
csagaRollback(t)
csagaRollback2(t)
csagaCommittedOngoing(t)
}
func genCSaga(gid string, outFailed bool, inFailed bool) *dtmcli.Saga {
dtmcli.Logf("beginning a concurrent saga test ---------------- %s", gid)
func genSagaCon(gid string, outFailed bool, inFailed bool) *dtmcli.Saga {
dtmimp.Logf("beginning a concurrent saga test ---------------- %s", gid)
req := examples.GenTransReq(30, outFailed, inFailed)
csaga := dtmcli.NewSaga(examples.DtmServer, gid).
sagaCon := dtmcli.NewSaga(examples.DtmServer, gid).
Add(examples.Busi+"/TransOut", examples.Busi+"/TransOutRevert", &req).
Add(examples.Busi+"/TransIn", examples.Busi+"/TransInRevert", &req).
EnableConcurrent()
return csaga
return sagaCon
}
func csagaNormal(t *testing.T) {
csaga := genCSaga("gid-noraml-csaga", false, false)
csaga.Submit()
waitTransProcessed(csaga.Gid)
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusSucceed, dtmcli.StatusPrepared, dtmcli.StatusSucceed}, getBranchesStatus(csaga.Gid))
assert.Equal(t, dtmcli.StatusSucceed, getTransStatus(csaga.Gid))
func TestSagaConNormal(t *testing.T) {
sagaCon := genSagaCon(dtmimp.GetFuncName(), false, false)
sagaCon.Submit()
waitTransProcessed(sagaCon.Gid)
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusSucceed, dtmcli.StatusPrepared, dtmcli.StatusSucceed}, getBranchesStatus(sagaCon.Gid))
assert.Equal(t, dtmcli.StatusSucceed, getTransStatus(sagaCon.Gid))
}
func csagaRollback(t *testing.T) {
csaga := genCSaga("gid-rollback-csaga", true, false)
func TestSagaConRollback(t *testing.T) {
sagaCon := genSagaCon(dtmimp.GetFuncName(), true, false)
examples.MainSwitch.TransOutRevertResult.SetOnce(dtmcli.ResultOngoing)
err := csaga.Submit()
err := sagaCon.Submit()
assert.Nil(t, err)
waitTransProcessed(csaga.Gid)
assert.Equal(t, dtmcli.StatusAborting, getTransStatus(csaga.Gid))
waitTransProcessed(sagaCon.Gid)
assert.Equal(t, dtmcli.StatusAborting, getTransStatus(sagaCon.Gid))
cronTransOnce()
assert.Equal(t, dtmcli.StatusFailed, getTransStatus(csaga.Gid))
assert.Equal(t, []string{dtmcli.StatusSucceed, dtmcli.StatusFailed, dtmcli.StatusSucceed, dtmcli.StatusSucceed}, getBranchesStatus(csaga.Gid))
err = csaga.Submit()
assert.Equal(t, dtmcli.StatusFailed, getTransStatus(sagaCon.Gid))
assert.Equal(t, []string{dtmcli.StatusSucceed, dtmcli.StatusFailed, dtmcli.StatusSucceed, dtmcli.StatusSucceed}, getBranchesStatus(sagaCon.Gid))
err = sagaCon.Submit()
assert.Error(t, err)
}
func csagaRollback2(t *testing.T) {
csaga := genCSaga("gid-rollback-csaga2", true, false)
csaga.AddBranchOrder(1, []int{0})
err := csaga.Submit()
func TestSagaConRollback2(t *testing.T) {
sagaCon := genSagaCon(dtmimp.GetFuncName(), true, false)
sagaCon.AddBranchOrder(1, []int{0})
err := sagaCon.Submit()
assert.Nil(t, err)
waitTransProcessed(csaga.Gid)
assert.Equal(t, dtmcli.StatusFailed, getTransStatus(csaga.Gid))
assert.Equal(t, []string{dtmcli.StatusSucceed, dtmcli.StatusFailed, dtmcli.StatusPrepared, dtmcli.StatusPrepared}, getBranchesStatus(csaga.Gid))
err = csaga.Submit()
waitTransProcessed(sagaCon.Gid)
assert.Equal(t, dtmcli.StatusFailed, getTransStatus(sagaCon.Gid))
assert.Equal(t, []string{dtmcli.StatusSucceed, dtmcli.StatusFailed, dtmcli.StatusPrepared, dtmcli.StatusPrepared}, getBranchesStatus(sagaCon.Gid))
err = sagaCon.Submit()
assert.Error(t, err)
}
func csagaCommittedOngoing(t *testing.T) {
csaga := genCSaga("gid-committed-ongoing-csaga", false, false)
func TestSagaConCommittedOngoing(t *testing.T) {
sagaCon := genSagaCon(dtmimp.GetFuncName(), false, false)
examples.MainSwitch.TransOutResult.SetOnce(dtmcli.ResultOngoing)
csaga.Submit()
waitTransProcessed(csaga.Gid)
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusPrepared, dtmcli.StatusPrepared, dtmcli.StatusSucceed}, getBranchesStatus(csaga.Gid))
assert.Equal(t, dtmcli.StatusSubmitted, getTransStatus(csaga.Gid))
sagaCon.Submit()
waitTransProcessed(sagaCon.Gid)
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusPrepared, dtmcli.StatusPrepared, dtmcli.StatusSucceed}, getBranchesStatus(sagaCon.Gid))
assert.Equal(t, dtmcli.StatusSubmitted, getTransStatus(sagaCon.Gid))
cronTransOnce()
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusSucceed, dtmcli.StatusPrepared, dtmcli.StatusSucceed}, getBranchesStatus(csaga.Gid))
assert.Equal(t, dtmcli.StatusSucceed, getTransStatus(csaga.Gid))
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusSucceed, dtmcli.StatusPrepared, dtmcli.StatusSucceed}, getBranchesStatus(sagaCon.Gid))
assert.Equal(t, dtmcli.StatusSucceed, getTransStatus(sagaCon.Gid))
}

82
test/saga_options_test.go

@ -0,0 +1,82 @@
package test
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/examples"
)
func TestSagaOptionsRetryOngoing(t *testing.T) {
saga := genSaga1(dtmimp.GetFuncName(), false, false)
saga.RetryInterval = 150 // CronForwardDuration is larger than RetryInterval
examples.MainSwitch.TransOutResult.SetOnce(dtmcli.ResultOngoing)
err := saga.Submit()
assert.Nil(t, err)
waitTransProcessed(saga.Gid)
cronTransOnce()
assert.Equal(t, dtmcli.StatusSucceed, getTransStatus(saga.Gid))
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusSucceed}, getBranchesStatus(saga.Gid))
}
func TestSagaOptionsRetryError(t *testing.T) {
saga := genSaga1(dtmimp.GetFuncName(), false, false)
saga.RetryInterval = 150 // CronForwardDuration is less than 2*RetryInterval
examples.MainSwitch.TransOutResult.SetOnce("ERROR")
err := saga.Submit()
assert.Nil(t, err)
waitTransProcessed(saga.Gid)
cronTransOnce()
assert.Equal(t, dtmcli.StatusSubmitted, getTransStatus(saga.Gid))
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusPrepared}, getBranchesStatus(saga.Gid))
cronTransOnceForwardCron(360)
assert.Equal(t, dtmcli.StatusSucceed, getTransStatus(saga.Gid))
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusSucceed}, getBranchesStatus(saga.Gid))
}
func TestSagaOptionsTimeout(t *testing.T) {
saga := genSaga(dtmimp.GetFuncName(), false, false)
saga.TimeoutToFail = 1800
examples.MainSwitch.TransOutResult.SetOnce(dtmcli.ResultOngoing)
saga.Submit()
waitTransProcessed(saga.Gid)
assert.Equal(t, dtmcli.StatusSubmitted, getTransStatus(saga.Gid))
cronTransOnceForwardNow(3600)
assert.Equal(t, dtmcli.StatusFailed, getTransStatus(saga.Gid))
}
func TestSagaOptionsNormalWait(t *testing.T) {
saga := genSaga(dtmimp.GetFuncName(), false, false)
saga.SetOptions(&dtmimp.TransOptions{WaitResult: true})
err := saga.Submit()
assert.Nil(t, err)
waitTransProcessed(saga.Gid)
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusSucceed, dtmcli.StatusPrepared, dtmcli.StatusSucceed}, getBranchesStatus(saga.Gid))
assert.Equal(t, dtmcli.StatusSucceed, getTransStatus(saga.Gid))
}
func TestSagaOptionsCommittedOngoingWait(t *testing.T) {
saga := genSaga(dtmimp.GetFuncName(), false, false)
examples.MainSwitch.TransOutResult.SetOnce(dtmcli.ResultOngoing)
saga.SetOptions(&dtmimp.TransOptions{WaitResult: true})
err := saga.Submit()
assert.Error(t, err)
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusPrepared, dtmcli.StatusPrepared, dtmcli.StatusPrepared}, getBranchesStatus(saga.Gid))
assert.Equal(t, dtmcli.StatusSubmitted, getTransStatus(saga.Gid))
waitTransProcessed(saga.Gid)
cronTransOnce()
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusSucceed, dtmcli.StatusPrepared, dtmcli.StatusSucceed}, getBranchesStatus(saga.Gid))
assert.Equal(t, dtmcli.StatusSucceed, getTransStatus(saga.Gid))
}
func TestSagaOptionsRollbackWait(t *testing.T) {
saga := genSaga(dtmimp.GetFuncName(), false, true)
saga.SetOptions(&dtmimp.TransOptions{WaitResult: true})
err := saga.Submit()
assert.Error(t, err)
waitTransProcessed(saga.Gid)
assert.Equal(t, dtmcli.StatusFailed, getTransStatus(saga.Gid))
assert.Equal(t, []string{dtmcli.StatusSucceed, dtmcli.StatusSucceed, dtmcli.StatusSucceed, dtmcli.StatusFailed}, getBranchesStatus(saga.Gid))
}

59
test/saga_test.go

@ -5,41 +5,32 @@ import (
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/examples"
)
func TestSaga(t *testing.T) {
sagaNormal(t)
sagaCommittedOngoing(t)
sagaRollback(t)
sagaRollback2(t)
sagaTimeout(t)
}
func sagaNormal(t *testing.T) {
saga := genSaga("gid-noramlSaga", false, false)
func TestSagaNormal(t *testing.T) {
saga := genSaga(dtmimp.GetFuncName(), false, false)
saga.Submit()
waitTransProcessed(saga.Gid)
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusSucceed, dtmcli.StatusPrepared, dtmcli.StatusSucceed}, getBranchesStatus(saga.Gid))
assert.Equal(t, dtmcli.StatusSucceed, getTransStatus(saga.Gid))
transQuery(t, saga.Gid)
err := saga.Submit() // 第二次提交
assert.Error(t, err)
}
func sagaCommittedOngoing(t *testing.T) {
saga := genSaga("gid-committedOngoing", false, false)
func TestSagaOngoingSucceed(t *testing.T) {
saga := genSaga(dtmimp.GetFuncName(), false, false)
examples.MainSwitch.TransOutResult.SetOnce(dtmcli.ResultOngoing)
saga.Submit()
waitTransProcessed(saga.Gid)
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusPrepared, dtmcli.StatusPrepared, dtmcli.StatusPrepared}, getBranchesStatus(saga.Gid))
assert.Equal(t, dtmcli.StatusSubmitted, getTransStatus(saga.Gid))
cronTransOnce()
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusSucceed, dtmcli.StatusPrepared, dtmcli.StatusSucceed}, getBranchesStatus(saga.Gid))
assert.Equal(t, dtmcli.StatusSucceed, getTransStatus(saga.Gid))
}
func sagaRollback(t *testing.T) {
saga := genSaga("gid-rollback-saga", false, true)
func TestSagaFailed(t *testing.T) {
saga := genSaga(dtmimp.GetFuncName(), false, true)
examples.MainSwitch.TransOutRevertResult.SetOnce("ERROR")
err := saga.Submit()
assert.Nil(t, err)
@ -48,38 +39,30 @@ func sagaRollback(t *testing.T) {
cronTransOnce()
assert.Equal(t, dtmcli.StatusFailed, getTransStatus(saga.Gid))
assert.Equal(t, []string{dtmcli.StatusSucceed, dtmcli.StatusSucceed, dtmcli.StatusSucceed, dtmcli.StatusFailed}, getBranchesStatus(saga.Gid))
err = saga.Submit()
assert.Error(t, err)
}
func sagaRollback2(t *testing.T) {
saga := genSaga("gid-rollback-saga2", false, false)
saga.TimeoutToFail = 1800
examples.MainSwitch.TransInResult.SetOnce(dtmcli.ResultOngoing)
func TestSagaAbnormal(t *testing.T) {
saga := genSaga(dtmimp.GetFuncName(), false, false)
err := saga.Submit()
assert.Nil(t, err)
err = saga.Submit() // submit twice, ignored
assert.Nil(t, err)
waitTransProcessed(saga.Gid)
cronTransOnceForwardNow(3600)
assert.Equal(t, dtmcli.StatusFailed, getTransStatus(saga.Gid))
assert.Equal(t, []string{dtmcli.StatusSucceed, dtmcli.StatusSucceed, dtmcli.StatusSucceed, dtmcli.StatusPrepared}, getBranchesStatus(saga.Gid))
}
func sagaTimeout(t *testing.T) {
saga := genSaga("gid-timeout-saga", false, false)
saga.TimeoutToFail = 1800
examples.MainSwitch.TransOutResult.SetOnce("UNKOWN")
saga.Submit()
waitTransProcessed(saga.Gid)
assert.Equal(t, dtmcli.StatusSubmitted, getTransStatus(saga.Gid))
cronTransOnceForwardNow(3600)
assert.Equal(t, dtmcli.StatusFailed, getTransStatus(saga.Gid))
err = saga.Submit()
assert.Error(t, err) // a succeed trans can't accept submit
}
func genSaga(gid string, outFailed bool, inFailed bool) *dtmcli.Saga {
dtmcli.Logf("beginning a saga test ---------------- %s", gid)
saga := dtmcli.NewSaga(examples.DtmServer, gid)
req := examples.GenTransReq(30, outFailed, inFailed)
saga.Add(examples.Busi+"/TransOut", examples.Busi+"/TransOutRevert", &req)
saga.Add(examples.Busi+"/TransIn", examples.Busi+"/TransInRevert", &req)
return saga
}
func genSaga1(gid string, outFailed bool, inFailed bool) *dtmcli.Saga {
saga := dtmcli.NewSaga(examples.DtmServer, gid)
req := examples.GenTransReq(30, outFailed, inFailed)
saga.Add(examples.Busi+"/TransOut", examples.Busi+"/TransOutRevert", &req)
return saga
}

44
test/barrier_tcc_test.go → test/tcc_barrier_test.go

@ -13,18 +13,12 @@ import (
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/common"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/examples"
)
func TestBarrierTcc(t *testing.T) {
tccBarrierDisorder(t)
tccBarrierNormal(t)
tccBarrierRollback(t)
barrierPanic(t)
}
func tccBarrierRollback(t *testing.T) {
gid := "tccBarrierRollback"
func TestTccBarrierRollback(t *testing.T) {
gid := dtmimp.GetFuncName()
err := dtmcli.TccGlobalTransaction(DtmServer, gid, func(tcc *dtmcli.Tcc) (*resty.Response, error) {
_, err := tcc.CallBranch(&examples.TransReq{Amount: 30}, Busi+"/TccBTransOutTry", Busi+"/TccBTransOutConfirm", Busi+"/TccBTransOutCancel")
assert.Nil(t, err)
@ -35,8 +29,8 @@ func tccBarrierRollback(t *testing.T) {
assert.Equal(t, dtmcli.StatusFailed, getTransStatus(gid))
}
func tccBarrierNormal(t *testing.T) {
gid := "tccBarrierNormal"
func TestTccBarrierNormal(t *testing.T) {
gid := dtmimp.GetFuncName()
err := dtmcli.TccGlobalTransaction(DtmServer, gid, func(tcc *dtmcli.Tcc) (*resty.Response, error) {
_, err := tcc.CallBranch(&examples.TransReq{Amount: 30}, Busi+"/TccBTransOutTry", Busi+"/TccBTransOutConfirm", Busi+"/TccBTransOutCancel")
assert.Nil(t, err)
@ -47,36 +41,36 @@ func tccBarrierNormal(t *testing.T) {
assert.Equal(t, dtmcli.StatusSucceed, getTransStatus(gid))
}
func tccBarrierDisorder(t *testing.T) {
func TestTccBarrierDisorder(t *testing.T) {
timeoutChan := make(chan string, 2)
finishedChan := make(chan string, 2)
gid := "tccBarrierDisorder"
gid := dtmimp.GetFuncName()
err := dtmcli.TccGlobalTransaction(DtmServer, gid, func(tcc *dtmcli.Tcc) (*resty.Response, error) {
body := &examples.TransReq{Amount: 30}
tryURL := Busi + "/TccBTransOutTry"
confirmURL := Busi + "/TccBTransOutConfirm"
cancelURL := Busi + "/TccBSleepCancel"
// 请参见子事务屏障里的时序图,这里为了模拟该时序图,手动拆解了callbranch
branchID := tcc.NewBranchID()
branchID := tcc.NewSubBranchID()
sleeped := false
app.POST(examples.BusiAPI+"/TccBSleepCancel", common.WrapHandler(func(c *gin.Context) (interface{}, error) {
res, err := examples.TccBarrierTransOutCancel(c)
if !sleeped {
sleeped = true
dtmcli.Logf("sleep before cancel return")
dtmimp.Logf("sleep before cancel return")
<-timeoutChan
finishedChan <- "1"
}
return res, err
}))
// 注册子事务
resp, err := dtmcli.RestyClient.R().
SetBody(M{
resp, err := dtmimp.RestyClient.R().
SetBody(map[string]interface{}{
"gid": tcc.Gid,
"branch_id": branchID,
"trans_type": "tcc",
"status": dtmcli.StatusPrepared,
"data": string(dtmcli.MustMarshal(body)),
"data": string(dtmimp.MustMarshal(body)),
dtmcli.BranchTry: tryURL,
dtmcli.BranchConfirm: confirmURL,
dtmcli.BranchCancel: cancelURL,
@ -85,11 +79,11 @@ func tccBarrierDisorder(t *testing.T) {
assert.Contains(t, resp.String(), dtmcli.ResultSuccess)
go func() {
dtmcli.Logf("sleeping to wait for tcc try timeout")
dtmimp.Logf("sleeping to wait for tcc try timeout")
<-timeoutChan
r, _ := dtmcli.RestyClient.R().
r, _ := dtmimp.RestyClient.R().
SetBody(body).
SetQueryParams(dtmcli.MS{
SetQueryParams(map[string]string{
"dtm": tcc.Dtm,
"gid": tcc.Gid,
"branch_id": branchID,
@ -100,10 +94,10 @@ func tccBarrierDisorder(t *testing.T) {
assert.True(t, strings.Contains(r.String(), dtmcli.ResultSuccess)) // 这个是悬挂操作,为了简单起见,依旧让他返回成功
finishedChan <- "1"
}()
dtmcli.Logf("cron to timeout and then call cancel")
dtmimp.Logf("cron to timeout and then call cancel")
go cronTransOnceForwardNow(300)
time.Sleep(100 * time.Millisecond)
dtmcli.Logf("cron to timeout and then call cancelled twice")
dtmimp.Logf("cron to timeout and then call cancelled twice")
cronTransOnceForwardNow(300)
timeoutChan <- "wake"
timeoutChan <- "wake"
@ -117,11 +111,11 @@ func tccBarrierDisorder(t *testing.T) {
assert.Equal(t, dtmcli.StatusFailed, getTransStatus(gid))
}
func barrierPanic(t *testing.T) {
func TestTccBarrierPanic(t *testing.T) {
bb := &dtmcli.BranchBarrier{TransType: "saga", Gid: "gid1", BranchID: "bid1", BranchType: "action", BarrierID: 1}
var err error
func() {
defer dtmcli.P2E(&err)
defer dtmimp.P2E(&err)
tx, _ := dbGet().ToSQLDB().BeginTx(context.Background(), &sql.TxOptions{})
bb.Call(tx, func(db dtmcli.DB) error {
panic(fmt.Errorf("an error"))

15
test/tcc_test.go

@ -6,18 +6,13 @@ import (
"github.com/go-resty/resty/v2"
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/examples"
)
func TestTcc(t *testing.T) {
tccNormal(t)
tccRollback(t)
}
func tccNormal(t *testing.T) {
func TestTccNormal(t *testing.T) {
data := &examples.TransReq{Amount: 30}
gid := "tccNormal"
gid := dtmimp.GetFuncName()
err := dtmcli.TccGlobalTransaction(examples.DtmServer, gid, func(tcc *dtmcli.Tcc) (*resty.Response, error) {
_, err := tcc.CallBranch(data, Busi+"/TransOut", Busi+"/TransOutConfirm", Busi+"/TransOutRevert")
assert.Nil(t, err)
@ -26,8 +21,8 @@ func tccNormal(t *testing.T) {
assert.Nil(t, err)
}
func tccRollback(t *testing.T) {
gid := "tccRollback"
func TestTccRollback(t *testing.T) {
gid := dtmimp.GetFuncName()
data := &examples.TransReq{Amount: 30, TransInResult: dtmcli.ResultFailure}
err := dtmcli.TccGlobalTransaction(examples.DtmServer, gid, func(tcc *dtmcli.Tcc) (*resty.Response, error) {
_, rerr := tcc.CallBranch(data, Busi+"/TransOut", Busi+"/TransOutConfirm", Busi+"/TransOutRevert")

22
test/types.go

@ -4,7 +4,7 @@ import (
"time"
"github.com/yedf/dtm/common"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/dtmsvr"
)
@ -16,16 +16,16 @@ func dbGet() *common.DB {
// waitTransProcessed only for test usage. wait for transaction processed once
func waitTransProcessed(gid string) {
dtmcli.Logf("waiting for gid %s", gid)
dtmimp.Logf("waiting for gid %s", gid)
select {
case id := <-dtmsvr.TransProcessedTestChan:
for id != gid {
dtmcli.LogRedf("-------id %s not match gid %s", id, gid)
dtmimp.LogRedf("-------id %s not match gid %s", id, gid)
id = <-dtmsvr.TransProcessedTestChan
}
dtmcli.Logf("finish for gid %s", gid)
dtmimp.Logf("finish for gid %s", gid)
case <-time.After(time.Duration(time.Second * 3)):
dtmcli.LogFatalf("Wait Trans timeout")
dtmimp.LogFatalf("Wait Trans timeout")
}
}
@ -36,7 +36,7 @@ func cronTransOnce() {
}
}
var e2p = dtmcli.E2P
var e2p = dtmimp.E2P
// TransGlobal alias
type TransGlobal = dtmsvr.TransGlobal
@ -44,12 +44,16 @@ type TransGlobal = dtmsvr.TransGlobal
// TransBranch alias
type TransBranch = dtmsvr.TransBranch
// M alias
type M = dtmcli.M
func cronTransOnceForwardNow(seconds int) {
old := dtmsvr.NowForwardDuration
dtmsvr.NowForwardDuration = time.Duration(seconds) * time.Second
cronTransOnce()
dtmsvr.NowForwardDuration = old
}
func cronTransOnceForwardCron(seconds int) {
old := dtmsvr.CronForwardDuration
dtmsvr.CronForwardDuration = time.Duration(seconds) * time.Second
cronTransOnce()
dtmsvr.CronForwardDuration = old
}

50
test/wait_saga_test.go

@ -1,50 +0,0 @@
package test
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/examples"
)
func TestWaitSaga(t *testing.T) {
sagaNormalWait(t)
sagaCommittedOngoingWait(t)
sagaRollbackWait(t)
}
func sagaNormalWait(t *testing.T) {
saga := genSaga("gid-noramlSagaWait", false, false)
saga.SetOptions(&dtmcli.TransOptions{WaitResult: true})
err := saga.Submit()
assert.Nil(t, err)
waitTransProcessed(saga.Gid)
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusSucceed, dtmcli.StatusPrepared, dtmcli.StatusSucceed}, getBranchesStatus(saga.Gid))
assert.Equal(t, dtmcli.StatusSucceed, getTransStatus(saga.Gid))
transQuery(t, saga.Gid)
}
func sagaCommittedOngoingWait(t *testing.T) {
saga := genSaga("gid-committedOngoingWait", false, false)
examples.MainSwitch.TransOutResult.SetOnce(dtmcli.ResultOngoing)
saga.SetOptions(&dtmcli.TransOptions{WaitResult: true})
err := saga.Submit()
assert.Error(t, err)
waitTransProcessed(saga.Gid)
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusPrepared, dtmcli.StatusPrepared, dtmcli.StatusPrepared}, getBranchesStatus(saga.Gid))
cronTransOnce()
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusSucceed, dtmcli.StatusPrepared, dtmcli.StatusSucceed}, getBranchesStatus(saga.Gid))
assert.Equal(t, dtmcli.StatusSucceed, getTransStatus(saga.Gid))
}
func sagaRollbackWait(t *testing.T) {
saga := genSaga("gid-rollbackSaga2Wait", false, true)
saga.SetOptions(&dtmcli.TransOptions{WaitResult: true})
err := saga.Submit()
assert.Error(t, err)
waitTransProcessed(saga.Gid)
assert.Equal(t, dtmcli.StatusFailed, getTransStatus(saga.Gid))
assert.Equal(t, []string{dtmcli.StatusSucceed, dtmcli.StatusSucceed, dtmcli.StatusSucceed, dtmcli.StatusFailed}, getBranchesStatus(saga.Gid))
}

33
test/xa_test.go

@ -8,18 +8,11 @@ import (
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/common"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/examples"
)
func TestXa(t *testing.T) {
xaLocalError(t)
xaNormal(t)
xaDuplicate(t)
xaRollback(t)
xaTimeout(t)
}
func xaLocalError(t *testing.T) {
func TestXaLocalError(t *testing.T) {
xc := examples.XaClient
err := xc.XaGlobalTransaction("xaLocalError", func(xa *dtmcli.Xa) (*resty.Response, error) {
return nil, fmt.Errorf("an error")
@ -27,9 +20,9 @@ func xaLocalError(t *testing.T) {
assert.Error(t, err, fmt.Errorf("an error"))
}
func xaNormal(t *testing.T) {
func TestXaNormal(t *testing.T) {
xc := examples.XaClient
gid := "xaNormal"
gid := dtmimp.GetFuncName()
err := xc.XaGlobalTransaction(gid, func(xa *dtmcli.Xa) (*resty.Response, error) {
req := examples.GenTransReq(30, false, false)
resp, err := xa.CallBranch(req, examples.Busi+"/TransOutXa")
@ -43,26 +36,26 @@ func xaNormal(t *testing.T) {
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusSucceed, dtmcli.StatusPrepared, dtmcli.StatusSucceed}, getBranchesStatus(gid))
}
func xaDuplicate(t *testing.T) {
func TestXaDuplicate(t *testing.T) {
xc := examples.XaClient
gid := "xaDuplicate"
gid := dtmimp.GetFuncName()
err := xc.XaGlobalTransaction(gid, func(xa *dtmcli.Xa) (*resty.Response, error) {
req := examples.GenTransReq(30, false, false)
_, err := xa.CallBranch(req, examples.Busi+"/TransOutXa")
assert.Nil(t, err)
sdb, err := dtmcli.StandaloneDB(common.DtmConfig.DB)
sdb, err := dtmimp.StandaloneDB(common.DtmConfig.DB)
assert.Nil(t, err)
dtmcli.DBExec(sdb, "xa recover")
dtmcli.DBExec(sdb, "xa commit 'xaDuplicate-0101'") // 先把某一个事务提交,模拟重复请求
dtmimp.DBExec(sdb, "xa recover")
dtmimp.DBExec(sdb, "xa commit 'xaDuplicate-0101'") // 先把某一个事务提交,模拟重复请求
return xa.CallBranch(req, examples.Busi+"/TransInXa")
})
assert.Equal(t, nil, err)
waitTransProcessed(gid)
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusSucceed, dtmcli.StatusPrepared, dtmcli.StatusSucceed}, getBranchesStatus(gid))
}
func xaRollback(t *testing.T) {
func TestXaRollback(t *testing.T) {
xc := examples.XaClient
gid := "xaRollback"
gid := dtmimp.GetFuncName()
err := xc.XaGlobalTransaction(gid, func(xa *dtmcli.Xa) (*resty.Response, error) {
req := &examples.TransReq{Amount: 30, TransInResult: dtmcli.ResultFailure}
resp, err := xa.CallBranch(req, examples.Busi+"/TransOutXa")
@ -77,9 +70,9 @@ func xaRollback(t *testing.T) {
assert.Equal(t, dtmcli.StatusFailed, getTransStatus(gid))
}
func xaTimeout(t *testing.T) {
func TestXaTimeout(t *testing.T) {
xc := examples.XaClient
gid := "xaTimeout"
gid := dtmimp.GetFuncName()
timeoutChan := make(chan int, 1)
err := xc.XaGlobalTransaction(gid, func(xa *dtmcli.Xa) (*resty.Response, error) {
go func() {

Loading…
Cancel
Save