Browse Source

Merge pull request #52 from yedf/alpha

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

2
.travis.yml

@ -14,4 +14,4 @@ before_install:
- go get -t -v ./...
- go get github.com/mattn/goveralls
script:
- $GOPATH/bin/goveralls -service=travis-ci -ignore="examples/*,dtmgrpc/*.pb.go,bench/*"
- $GOPATH/bin/goveralls -service=travis-ci -ignore="examples/*,dtmgrpc/dtmgimp/*.pb.go,bench/*,test/*"

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 {}

67
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
}
@ -40,19 +41,19 @@ func reloadData() {
time.Sleep(dtmsvr.UpdateBranchAsyncInterval * 2)
began := time.Now()
db := sdbGet()
tables := []string{"dtm_busi.user_account", "dtm_busi.user_account_log", "dtm.trans_global", "dtm.trans_branch", "dtm_barrier.barrier"}
tables := []string{"dtm_busi.user_account", "dtm_busi.user_account_log", "dtm.trans_global", "dtm.trans_branch_op", "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,18 +64,18 @@ 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,
gid varchar(45) not null,
branch_id varchar(45) not null,
branch_type varchar(45) not null,
op varchar(45) not null,
reason varchar(45),
create_time datetime not null default now(),
update_time datetime not null default now(),
@ -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, op, 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 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)
}

22
common/utils.go

@ -13,7 +13,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/go-resty/resty/v2"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmcli/dtmimp"
)
// GetGinApp init and return gin
@ -24,19 +24,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,7 +44,7 @@ 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{}
@ -54,14 +54,14 @@ func WrapHandler(fn func(*gin.Context) (interface{}, error)) gin.HandlerFunc {
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 +69,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
}

52
dtmcli/barrier.go

@ -3,55 +3,57 @@ 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 {
TransType string
Gid string
BranchID string
BranchType string
BarrierID int
TransType string
Gid string
BranchID string
Op string
BarrierID int
}
func (bb *BranchBarrier) String() string {
return fmt.Sprintf("transInfo: %s %s %s %s", bb.TransType, bb.Gid, bb.BranchID, bb.BranchType)
return fmt.Sprintf("transInfo: %s %s %s %s", bb.TransType, bb.Gid, bb.BranchID, bb.Op)
}
// BarrierFromQuery construct transaction info from request
func BarrierFromQuery(qs url.Values) (*BranchBarrier, error) {
return BarrierFrom(qs.Get("trans_type"), qs.Get("gid"), qs.Get("branch_id"), qs.Get("branch_type"))
return BarrierFrom(qs.Get("trans_type"), qs.Get("gid"), qs.Get("branch_id"), qs.Get("op"))
}
// BarrierFrom construct transaction info from request
func BarrierFrom(transType, gid, branchID, branchType string) (*BranchBarrier, error) {
func BarrierFrom(transType, gid, branchID, op string) (*BranchBarrier, error) {
ti := &BranchBarrier{
TransType: transType,
Gid: gid,
BranchID: branchID,
BranchType: branchType,
TransType: transType,
Gid: gid,
BranchID: branchID,
Op: op,
}
if ti.TransType == "" || ti.Gid == "" || ti.BranchID == "" || ti.BranchType == "" {
if ti.TransType == "" || ti.Gid == "" || ti.BranchID == "" || ti.Op == "" {
return nil, fmt.Errorf("invlid trans info: %v", ti)
}
return ti, nil
}
func insertBarrier(tx Tx, transType string, gid string, branchID string, branchType string, barrierID string, reason string) (int64, error) {
if branchType == "" {
func insertBarrier(tx Tx, transType string, gid string, branchID string, op string, barrierID string, reason string) (int64, error) {
if op == "" {
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, op, barrier_id, reason) values(?,?,?,?,?,?)", "uniq_barrier")
return dtmimp.DBExec(tx, sql, transType, gid, branchID, op, 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() {
@ -69,12 +71,12 @@ func (bb *BranchBarrier) Call(tx Tx, busiCall BusiFunc) (rerr error) {
originType := map[string]string{
BranchCancel: BranchTry,
BranchCompensate: BranchAction,
}[ti.BranchType]
}[ti.Op]
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)
if (ti.BranchType == BranchCancel || ti.BranchType == BranchCompensate) && originAffected > 0 || // 这个是空补偿
originAffected, _ := insertBarrier(tx, ti.TransType, ti.Gid, ti.BranchID, originType, bid, ti.Op)
currentAffected, rerr := insertBarrier(tx, ti.TransType, ti.Gid, ti.BranchID, ti.Op, bid, ti.Op)
dtmimp.Logf("originAffected: %d currentAffected: %d", originAffected, currentAffected)
if (ti.Op == BranchCancel || ti.Op == BranchCompensate) && originAffected > 0 || // 这个是空补偿
currentAffected == 0 { // 这个是重复请求或者悬挂
return
}

4
dtmcli/barrier.mysql.sql

@ -7,12 +7,12 @@ create table if not exists dtm_barrier.barrier(
trans_type varchar(45) default '',
gid varchar(128) default '',
branch_id varchar(128) default '',
branch_type varchar(45) default '',
op varchar(45) default '',
barrier_id varchar(45) default '',
reason varchar(45) default '' comment 'the branch type who insert this record',
create_time datetime DEFAULT now(),
update_time datetime DEFAULT now(),
key(create_time),
key(update_time),
UNIQUE key(gid, branch_id, branch_type, barrier_id)
UNIQUE key(gid, branch_id, op, barrier_id)
);

4
dtmcli/barrier.postgres.sql

@ -6,11 +6,11 @@ create table if not exists dtm_barrier.barrier(
trans_type varchar(45) default '',
gid varchar(128) default '',
branch_id varchar(128) default '',
branch_type varchar(45) default '',
op varchar(45) default '',
barrier_id varchar(45) default '',
reason varchar(45) default '',
create_time timestamp(0) DEFAULT NULL,
update_time timestamp(0) DEFAULT NULL,
PRIMARY KEY(id),
CONSTRAINT uniq_barrier unique(gid, branch_id, branch_type, barrier_id)
CONSTRAINT uniq_barrier unique(gid, branch_id, op, barrier_id)
);

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
Op string `json:"-"` // used in XA/TCC
QueryPrepared string `json:"query_prepared,omitempty"` // 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, op 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,
"op": op,
}).
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")
}

42
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,45 +38,30 @@ 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
}
// 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)
}

110
dtmcli/types.go

@ -1,115 +1,33 @@
package dtmcli
import (
"errors"
"fmt"
"net/url"
)
// 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)
}
// TransResult dtm 返回的结果
type TransResult struct {
DtmResult string `json:"dtm_result"`
Message string
}
// 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
}
// DB interface
type DB = dtmimp.DB
// TransBase 事务的基础类
type TransBase struct {
Gid string `json:"gid"`
TransType string `json:"trans_type"`
Dtm string `json:"-"`
CustomData string `json:"custom_data,omitempty"`
IDGenerator
TransOptions
}
// Tx interface
type Tx = dtmimp.Tx
// SetOptions set options
func (tb *TransBase) SetOptions(options *TransOptions) {
tb.TransOptions = *options
// SetCurrentDBType set currentDBType
func SetCurrentDBType(dbType string) {
dtmimp.SetCurrentDBType(dbType)
}
// 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,
}
// GetCurrentDBType get currentDBType
func GetCurrentDBType() string {
return dtmimp.GetCurrentDBType()
}
// 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"))
}
// callDtm 调用dtm服务器,返回事务的状态
func (tb *TransBase) callDtm(body interface{}, operation string) error {
resp, err := RestyClient.R().
SetResult(&TransResult{}).SetBody(body).Post(fmt.Sprintf("%s/%s", tb.Dtm, operation))
if err != nil {
return err
}
tr := resp.Result().(*TransResult)
if tr.DtmResult == ResultFailure {
return errors.New("FAILURE: " + tr.Message)
}
return nil
}
// 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.Op)
}

558
dtmgrpc/dtmgimp/dtmgimp.pb.go

@ -0,0 +1,558 @@
// 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
}
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}
}
type DtmBranchRequest 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"`
Op string `protobuf:"bytes,4,opt,name=Op,proto3" json:"Op,omitempty"`
Data map[string]string `protobuf:"bytes,5,rep,name=Data,proto3" json:"Data,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
BusiPayload []byte `protobuf:"bytes,6,opt,name=BusiPayload,proto3" json:"BusiPayload,omitempty"`
}
func (x *DtmBranchRequest) Reset() {
*x = DtmBranchRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_dtmgrpc_dtmgimp_dtmgimp_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DtmBranchRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DtmBranchRequest) ProtoMessage() {}
func (x *DtmBranchRequest) 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 DtmBranchRequest.ProtoReflect.Descriptor instead.
func (*DtmBranchRequest) Descriptor() ([]byte, []int) {
return file_dtmgrpc_dtmgimp_dtmgimp_proto_rawDescGZIP(), []int{4}
}
func (x *DtmBranchRequest) GetGid() string {
if x != nil {
return x.Gid
}
return ""
}
func (x *DtmBranchRequest) GetTransType() string {
if x != nil {
return x.TransType
}
return ""
}
func (x *DtmBranchRequest) GetBranchID() string {
if x != nil {
return x.BranchID
}
return ""
}
func (x *DtmBranchRequest) GetBranchType() string {
if x != nil {
return x.Op
}
return ""
}
func (x *DtmBranchRequest) GetData() map[string]string {
if x != nil {
return x.Data
}
return nil
}
func (x *DtmBranchRequest) GetBusiPayload() []byte {
if x != nil {
return x.BusiPayload
}
return nil
}
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, 0x0f, 0x0a, 0x0d, 0x44, 0x74, 0x6d, 0x42, 0x72, 0x61, 0x6e, 0x63,
0x68, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x92, 0x02, 0x0a, 0x10, 0x44, 0x74, 0x6d, 0x42, 0x72, 0x61,
0x6e, 0x63, 0x68, 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, 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, 0x12, 0x37, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, 0x05,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x64, 0x74, 0x6d, 0x67, 0x69, 0x6d, 0x70, 0x2e, 0x44,
0x74, 0x6d, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e,
0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x12,
0x20, 0x0a, 0x0b, 0x42, 0x75, 0x73, 0x69, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x06,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x42, 0x75, 0x73, 0x69, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61,
0x64, 0x1a, 0x37, 0x0a, 0x09, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x32, 0xb1, 0x02, 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, 0x45, 0x0a, 0x0e, 0x52, 0x65, 0x67, 0x69, 0x73,
0x74, 0x65, 0x72, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x12, 0x19, 0x2e, 0x64, 0x74, 0x6d, 0x67,
0x69, 0x6d, 0x70, 0x2e, 0x44, 0x74, 0x6d, 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
(*DtmBranchRequest)(nil), // 4: dtmgimp.DtmBranchRequest
nil, // 5: dtmgimp.DtmBranchRequest.DataEntry
(*emptypb.Empty)(nil), // 6: google.protobuf.Empty
}
var file_dtmgrpc_dtmgimp_dtmgimp_proto_depIdxs = []int32{
0, // 0: dtmgimp.DtmRequest.TransOptions:type_name -> dtmgimp.DtmTransOptions
5, // 1: dtmgimp.DtmBranchRequest.Data:type_name -> dtmgimp.DtmBranchRequest.DataEntry
6, // 2: dtmgimp.Dtm.NewGid:input_type -> google.protobuf.Empty
1, // 3: dtmgimp.Dtm.Submit:input_type -> dtmgimp.DtmRequest
1, // 4: dtmgimp.Dtm.Prepare:input_type -> dtmgimp.DtmRequest
1, // 5: dtmgimp.Dtm.Abort:input_type -> dtmgimp.DtmRequest
4, // 6: dtmgimp.Dtm.RegisterBranch:input_type -> dtmgimp.DtmBranchRequest
2, // 7: dtmgimp.Dtm.NewGid:output_type -> dtmgimp.DtmGidReply
6, // 8: dtmgimp.Dtm.Submit:output_type -> google.protobuf.Empty
6, // 9: dtmgimp.Dtm.Prepare:output_type -> google.protobuf.Empty
6, // 10: dtmgimp.Dtm.Abort:output_type -> google.protobuf.Empty
6, // 11: dtmgimp.Dtm.RegisterBranch:output_type -> google.protobuf.Empty
7, // [7:12] is the sub-list for method output_type
2, // [2:7] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] 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.(*DtmBranchRequest); 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
}

46
dtmgrpc/dtmgimp/dtmgimp.proto

@ -0,0 +1,46 @@
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 RegisterBranch(DtmBranchRequest) 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 DtmBranchRequest {
string Gid = 1;
string TransType = 2;
string BranchID = 3;
string Op = 4;
map<string, string> Data = 5;
bytes BusiPayload = 6;
}

84
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"
@ -23,8 +23,7 @@ type DtmClient interface {
Submit(ctx context.Context, in *DtmRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
Prepare(ctx context.Context, in *DtmRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
Abort(ctx context.Context, in *DtmRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
RegisterTccBranch(ctx context.Context, in *DtmTccBranchRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
RegisterXaBranch(ctx context.Context, in *DtmXaBranchRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
RegisterBranch(ctx context.Context, in *DtmBranchRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
}
type dtmClient struct {
@ -37,7 +36,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 +45,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 +54,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,25 +63,16 @@ 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
}
return out, nil
}
func (c *dtmClient) RegisterTccBranch(ctx context.Context, in *DtmTccBranchRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
func (c *dtmClient) RegisterBranch(ctx context.Context, in *DtmBranchRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/dtmgrpc.Dtm/RegisterTccBranch", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
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/RegisterBranch", in, out, opts...)
if err != nil {
return nil, err
}
@ -97,8 +87,7 @@ type DtmServer interface {
Submit(context.Context, *DtmRequest) (*emptypb.Empty, error)
Prepare(context.Context, *DtmRequest) (*emptypb.Empty, error)
Abort(context.Context, *DtmRequest) (*emptypb.Empty, error)
RegisterTccBranch(context.Context, *DtmTccBranchRequest) (*emptypb.Empty, error)
RegisterXaBranch(context.Context, *DtmXaBranchRequest) (*emptypb.Empty, error)
RegisterBranch(context.Context, *DtmBranchRequest) (*emptypb.Empty, error)
mustEmbedUnimplementedDtmServer()
}
@ -118,11 +107,8 @@ func (UnimplementedDtmServer) Prepare(context.Context, *DtmRequest) (*emptypb.Em
func (UnimplementedDtmServer) Abort(context.Context, *DtmRequest) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method Abort not implemented")
}
func (UnimplementedDtmServer) RegisterTccBranch(context.Context, *DtmTccBranchRequest) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method RegisterTccBranch not implemented")
}
func (UnimplementedDtmServer) RegisterXaBranch(context.Context, *DtmXaBranchRequest) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method RegisterXaBranch not implemented")
func (UnimplementedDtmServer) RegisterBranch(context.Context, *DtmBranchRequest) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method RegisterBranch not implemented")
}
func (UnimplementedDtmServer) mustEmbedUnimplementedDtmServer() {}
@ -147,7 +133,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 +151,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 +169,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 +187,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))
@ -209,38 +195,20 @@ func _Dtm_Abort_Handler(srv interface{}, ctx context.Context, dec func(interface
return interceptor(ctx, in, info, handler)
}
func _Dtm_RegisterTccBranch_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DtmTccBranchRequest)
func _Dtm_RegisterBranch_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DtmBranchRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DtmServer).RegisterTccBranch(ctx, in)
return srv.(DtmServer).RegisterBranch(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/dtmgrpc.Dtm/RegisterTccBranch",
FullMethod: "/dtmgimp.Dtm/RegisterBranch",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DtmServer).RegisterTccBranch(ctx, req.(*DtmTccBranchRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Dtm_RegisterXaBranch_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DtmXaBranchRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DtmServer).RegisterXaBranch(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/dtmgrpc.Dtm/RegisterXaBranch",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DtmServer).RegisterXaBranch(ctx, req.(*DtmXaBranchRequest))
return srv.(DtmServer).RegisterBranch(ctx, req.(*DtmBranchRequest))
}
return interceptor(ctx, in, info, handler)
}
@ -249,7 +217,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{
{
@ -269,14 +237,10 @@ var Dtm_ServiceDesc = grpc.ServiceDesc{
Handler: _Dtm_Abort_Handler,
},
{
MethodName: "RegisterTccBranch",
Handler: _Dtm_RegisterTccBranch_Handler,
},
{
MethodName: "RegisterXaBranch",
Handler: _Dtm_RegisterXaBranch_Handler,
MethodName: "RegisterBranch",
Handler: _Dtm_RegisterBranch_Handler,
},
},
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, op, dtm string) context.Context {
md := metadata.Pairs(
mdpre+"gid", gid,
mdpre+"trans_type", transType,
mdpre+"branch_id", branchID,
mdpre+"op", op,
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 op: %s dtm: %s", tb.Gid, tb.TransType, tb.BranchID, tb.Op, 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.Op = mdGet(md, "op")
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服务器的消息Emptyerror == 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")
}

60
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,32 @@ 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{
Gid: t.Gid,
TransType: t.TransType,
BranchID: branchID,
},
BusiData: string(busiData),
Try: tryURL,
Confirm: confirmURL,
Cancel: cancelURL,
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).RegisterBranch(context.Background(), &dtmgimp.DtmBranchRequest{
Gid: t.Gid,
TransType: t.TransType,
BranchID: branchID,
BusiPayload: bd,
Data: map[string]string{"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)
}

97
dtmgrpc/type.go

@ -2,102 +2,27 @@ 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)
}
// GetCurrentDBType set the current db type
func GetCurrentDBType() string {
return dtmcli.GetCurrentDBType()
}

10
dtmgrpc/type_test.go

@ -1,15 +1,21 @@
package dtmgrpc
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/dtmcli"
)
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)
old := GetCurrentDBType()
SetCurrentDBType(dtmcli.DBTypeMysql)
SetCurrentDBType(old)
}

90
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,47 @@ 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.Op)
}
// 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{
Gid: xa.Gid,
BranchID: xa.CurrentBranchID(),
TransType: xa.TransType,
},
BusiData: "",
Notify: xc.NotifyURL,
_, err = dtmgimp.MustGetDtmClient(xa.Dtm).RegisterBranch(context.Background(), &dtmgimp.DtmBranchRequest{
Gid: xa.Gid,
BranchID: xa.BranchID,
TransType: xa.TransType,
BusiPayload: data,
Data: map[string]string{"url": 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 +103,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
}

45
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,23 +40,32 @@ 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 svcRegisterBranch(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}
for i, b := range []string{dtmcli.BranchCancel, dtmcli.BranchConfirm, dtmcli.BranchTry} {
branches[i].BranchType = b
branches[i].URL = data[b]
branches := []TransBranch{*branch, *branch}
if dbt.TransType == "tcc" {
for i, b := range []string{dtmcli.BranchCancel, dtmcli.BranchConfirm} {
branches[i].Op = b
branches[i].URL = data[b]
}
} else if dbt.TransType == "xa" {
branches[0].Op = dtmcli.BranchRollback
branches[0].URL = data["url"]
branches[1].Op = dtmcli.BranchCommit
branches[1].URL = data["url"]
} else {
return nil, fmt.Errorf("unknow trans type: %s", dbt.TransType)
}
db.Must().Clauses(clause.OnConflict{
@ -66,21 +75,3 @@ func svcRegisterTccBranch(branch *TransBranch, data dtmcli.MS) (interface{}, err
global.touch(dbGet(), cronKeep)
return dtmcli.MapSuccess, nil
}
func svcRegisterXaBranch(branch *TransBranch) (interface{}, error) {
branch.Status = dtmcli.StatusPrepared
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
}
branches := []TransBranch{*branch, *branch}
branches[0].BranchType = dtmcli.BranchRollback
branches[1].BranchType = dtmcli.BranchCommit
db.Must().Clauses(clause.OnConflict{
DoNothing: true,
}).Create(branches)
global := TransGlobal{Gid: branch.Gid}
global.touch(db, cronKeep)
return dtmcli.MapSuccess, nil
}

45
dtmsvr/api_grpc.go

@ -4,56 +4,41 @@ 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) {
r, err := svcRegisterTccBranch(&TransBranch{
Gid: in.Info.Gid,
BranchID: in.Info.BranchID,
func (s *dtmServer) RegisterBranch(ctx context.Context, in *pb.DtmBranchRequest) (*emptypb.Empty, error) {
r, err := svcRegisterBranch(&TransBranch{
Gid: in.Gid,
BranchID: in.BranchID,
Status: dtmcli.StatusPrepared,
Data: in.BusiData,
}, dtmcli.MS{
dtmcli.BranchCancel: in.Cancel,
dtmcli.BranchConfirm: in.Confirm,
dtmcli.BranchTry: in.Try,
})
return &emptypb.Empty{}, dtmgrpc.Result2Error(r, err)
}
func (s *dtmServer) RegisterXaBranch(ctx context.Context, in *pb.DtmXaBranchRequest) (*emptypb.Empty, error) {
r, err := svcRegisterXaBranch(&TransBranch{
Gid: in.Info.Gid,
BranchID: in.Info.BranchID,
Status: dtmcli.StatusPrepared,
Data: in.BusiData,
URL: in.Notify,
})
return &emptypb.Empty{}, dtmgrpc.Result2Error(r, err)
BinData: in.BusiPayload,
}, in.Data)
return &emptypb.Empty{}, dtmgimp.Result2Error(r, err)
}

29
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) {
@ -14,14 +15,15 @@ func addRoute(engine *gin.Engine) {
engine.POST("/api/dtmsvr/prepare", common.WrapHandler(prepare))
engine.POST("/api/dtmsvr/submit", common.WrapHandler(submit))
engine.POST("/api/dtmsvr/abort", common.WrapHandler(abort))
engine.POST("/api/dtmsvr/registerXaBranch", common.WrapHandler(registerXaBranch))
engine.POST("/api/dtmsvr/registerTccBranch", common.WrapHandler(registerTccBranch))
engine.POST("/api/dtmsvr/registerBranch", common.WrapHandler(registerBranch))
engine.POST("/api/dtmsvr/registerXaBranch", common.WrapHandler(registerBranch)) // compatible for old sdk
engine.POST("/api/dtmsvr/registerTccBranch", common.WrapHandler(registerBranch)) // compatible for old sdk
engine.GET("/api/dtmsvr/query", common.WrapHandler(query))
engine.GET("/api/dtmsvr/all", common.WrapHandler(all))
}
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) {
@ -36,24 +38,17 @@ func abort(c *gin.Context) (interface{}, error) {
return svcAbort(TransFromContext(c))
}
func registerXaBranch(c *gin.Context) (interface{}, error) {
branch := TransBranch{}
err := c.BindJSON(&branch)
e2p(err)
return svcRegisterXaBranch(&branch)
}
func registerTccBranch(c *gin.Context) (interface{}, error) {
data := dtmcli.MS{}
func registerBranch(c *gin.Context) (interface{}, error) {
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)
return svcRegisterBranch(&branch, data)
}
func query(c *gin.Context) (interface{}, error) {
@ -65,16 +60,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)
}

26
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)
}
@ -77,12 +77,12 @@ func updateBranchAsync() {
}
for len(updates) > 0 {
dbr := dbGet().Clauses(clause.OnConflict{
OnConstraint: "trans_branch_pkey",
OnConstraint: "trans_branch_op_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{}

29
dtmsvr/dtmsvr.mysql.sql

@ -23,39 +23,22 @@ CREATE TABLE if not EXISTS dtm.trans_global (
PRIMARY KEY (`id`),
UNIQUE KEY `gid` (`gid`),
key `owner`(`owner`),
KEY `create_time` (`create_time`),
KEY `update_time` (`update_time`),
key `status_next_cron_time` (`status`, `next_cron_time`) comment '这个索引用于查询超时的全局事务,能够合理的走索引'
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
drop table IF EXISTS dtm.trans_branch;
CREATE TABLE IF NOT EXISTS dtm.trans_branch (
drop table IF EXISTS dtm.trans_branch_op;
CREATE TABLE IF NOT EXISTS dtm.trans_branch_op (
`id` bigint(22) NOT NULL AUTO_INCREMENT,
`gid` varchar(128) NOT NULL COMMENT '事务全局id',
`url` varchar(128) NOT NULL COMMENT '动作关联的url',
`data` TEXT COMMENT '请求所携带的数据',
`branch_id` VARCHAR(128) NOT NULL COMMENT '事务分支名称',
`branch_type` varchar(45) NOT NULL COMMENT '事务分支类型 saga_action | saga_compensate | xa',
`bin_data` BLOB COMMENT 'grpc的二进制数据',
`branch_id` VARCHAR(128) NOT NULL COMMENT '事务分支ID',
`op` varchar(45) NOT NULL COMMENT '事务分支类型 saga_action | saga_compensate | xa',
`status` varchar(45) NOT NULL COMMENT '步骤的状态 submitted | finished | rollbacked',
`finish_time` datetime DEFAULT NULL,
`rollback_time` datetime DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `gid_uniq` (`gid`, `branch_id`, `branch_type`),
KEY `create_time` (`create_time`),
KEY `update_time` (`update_time`)
UNIQUE KEY `gid_uniq` (`gid`, `branch_id`, `op`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
drop table IF EXISTS dtm.trans_log;
CREATE TABLE IF NOT EXISTS dtm.trans_log (
`id` bigint(22) NOT NULL AUTO_INCREMENT,
`gid` varchar(128) NOT NULL COMMENT '事务全局id',
`branch_id` varchar(128) DEFAULT NULL COMMENT '事务分支',
`action` varchar(45) DEFAULT NULL COMMENT '行为',
`old_status` varchar(45) NOT NULL DEFAULT '' COMMENT '旧状态',
`new_status` varchar(45) NOT NULL COMMENT '新状态',
`detail` TEXT NOT NULL COMMENT '行为记录的数据',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `gid` (`gid`),
KEY `create_time` (`create_time`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;

35
dtmsvr/dtmsvr.postgres.sql

@ -25,42 +25,23 @@ CREATE TABLE if not EXISTS dtm.trans_global (
CONSTRAINT gid UNIQUE (gid)
);
create index if not EXISTS owner on dtm.trans_global(owner);
CREATE INDEX if not EXISTS create_time ON dtm.trans_global (create_time);
CREATE INDEX if not EXISTS update_time ON dtm.trans_global (update_time);
create index if not EXISTS status_next_cron_time on dtm.trans_global (status, next_cron_time);
drop table IF EXISTS dtm.trans_branch;
drop table IF EXISTS dtm.trans_branch_op;
-- SQLINES LICENSE FOR EVALUATION USE ONLY
CREATE SEQUENCE if not EXISTS dtm.trans_branch_seq;
CREATE TABLE IF NOT EXISTS dtm.trans_branch (
id bigint NOT NULL DEFAULT NEXTVAL ('dtm.trans_branch_seq'),
CREATE SEQUENCE if not EXISTS dtm.trans_branch_op_seq;
CREATE TABLE IF NOT EXISTS dtm.trans_branch_op (
id bigint NOT NULL DEFAULT NEXTVAL ('dtm.trans_branch_op_seq'),
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,
op varchar(45) NOT NULL,
status varchar(45) NOT NULL,
finish_time timestamp(0) DEFAULT NULL,
rollback_time timestamp(0) DEFAULT NULL,
create_time timestamp(0) DEFAULT NULL,
update_time timestamp(0) DEFAULT NULL,
PRIMARY KEY (id),
CONSTRAINT gid_uniq UNIQUE (gid, branch_id, branch_type)
);
CREATE INDEX if not EXISTS create_time ON dtm.trans_branch (create_time);
CREATE INDEX if not EXISTS update_time ON dtm.trans_branch (update_time);
drop table IF EXISTS dtm.trans_log;
-- SQLINES LICENSE FOR EVALUATION USE ONLY
CREATE SEQUENCE if not EXISTS dtm.trans_log_seq;
CREATE TABLE IF NOT EXISTS dtm.trans_log (
id bigint NOT NULL DEFAULT NEXTVAL ('dtm.trans_log_seq'),
gid varchar(128) NOT NULL,
branch_id varchar(128) DEFAULT NULL,
action varchar(45) DEFAULT NULL,
old_status varchar(45) NOT NULL DEFAULT '',
new_status varchar(45) NOT NULL,
detail TEXT NOT NULL,
create_time timestamp(0) DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
CREATE INDEX if not EXISTS gid ON dtm.trans_log (gid);
CREATE INDEX if not EXISTS create_time ON dtm.trans_log (create_time);
CONSTRAINT gid_uniq UNIQUE (gid, branch_id, op)
);

9
dtmsvr/metrics.go

@ -2,13 +2,14 @@ package dtmsvr
import (
"context"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prometheus/client_golang/prometheus/promhttp"
"google.golang.org/grpc"
"net/http"
"strings"
)
var (
@ -87,9 +88,9 @@ func transactionMetrics(global *TransGlobal, status bool) {
func branchMetrics(global *TransGlobal, branch *TransBranch, status bool) {
if status {
branchTotal.WithLabelValues(global.TransType, global.Gid, branch.BranchID, branch.BranchType, "ok").Inc()
branchTotal.WithLabelValues(global.TransType, global.Gid, branch.BranchID, branch.Op, "ok").Inc()
} else {
branchTotal.WithLabelValues(global.TransType, global.Gid, branch.BranchID, branch.BranchType, "fail").Inc()
branchTotal.WithLabelValues(global.TransType, global.Gid, branch.BranchID, branch.Op, "fail").Inc()
}
}

127
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,9 +95,9 @@ type TransBranch struct {
common.ModelBase
Gid string
URL string `json:"url"`
Data string
BinData []byte
BranchID string `json:"branch_id"`
BranchType string
Op string
Status string
FinishTime *time.Time
RollbackTime *time.Time
@ -106,13 +105,12 @@ type TransBranch struct {
// TableName TableName
func (*TransBranch) TableName() string {
return "dtm.trans_branch"
return "dtm.trans_branch_op"
}
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, op 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, op, "")
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{
"gid": t.Gid,
"trans_type": t.TransType,
"branch_id": branchID,
"branch_type": branchType,
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,
"op": op,
}).
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,16 +248,16 @@ 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.Op, branch.BinData)
if err != nil {
return "", err
}
if strings.Contains(body, dtmcli.ResultSuccess) {
return dtmcli.StatusSucceed, nil
} else if strings.HasSuffix(t.TransType, "saga") && branch.BranchType == dtmcli.BranchAction && strings.Contains(body, dtmcli.ResultFailure) {
} else if strings.HasSuffix(t.TransType, "saga") && branch.Op == 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
}

27
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{
Gid: t.Gid,
BranchID: GenGid(),
Data: step["data"].(string),
URL: step[dtmcli.BranchAction].(string),
BranchType: dtmcli.BranchAction,
Status: dtmcli.StatusPrepared,
})
for i, step := range t.Steps {
b := &TransBranch{
Gid: t.Gid,
BranchID: fmt.Sprintf("%02d", i+1),
BinData: t.BinPayloads[i],
URL: step[dtmcli.BranchAction],
Op: 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)
}
}
@ -57,7 +58,7 @@ func (t *transMsgProcessor) ProcessOnce(db *common.DB, branches []TransBranch) e
current := 0 // 当前正在处理的步骤
for ; current < len(branches); current++ {
branch := &branches[current]
if branch.BranchType != dtmcli.BranchAction || branch.Status != dtmcli.StatusPrepared {
if branch.Op != dtmcli.BranchAction || branch.Status != dtmcli.StatusPrepared {
continue
}
err := t.execBranch(db, branch)

55
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,18 +19,16 @@ 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} {
for _, op := range []string{dtmcli.BranchCompensate, dtmcli.BranchAction} {
branches = append(branches, TransBranch{
Gid: t.Gid,
BranchID: branch,
Data: step["data"].(string),
URL: step[branchType].(string),
BranchType: branchType,
Status: dtmcli.StatusPrepared,
Gid: t.Gid,
BranchID: branch,
BinData: t.BinPayloads[i],
URL: step[op],
Op: op,
Status: dtmcli.StatusPrepared,
})
}
}
@ -42,15 +41,15 @@ type cSagaCustom struct {
}
type branchResult struct {
index int
status string
started bool
branchType string
index int
status string
started bool
op string
}
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,21 +57,21 @@ 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
branchResults := make([]branchResult, n) // save the branch result
for i := 0; i < n; i++ {
b := branches[i]
if b.BranchType == dtmcli.BranchAction {
if b.Op == dtmcli.BranchAction {
if b.Status == dtmcli.StatusPrepared {
rsAToStart++
} else if b.Status == dtmcli.StatusFailed {
rsAFailed++
}
}
branchResults[i] = branchResult{status: branches[i].Status, branchType: branches[i].BranchType}
branchResults[i] = branchResult{status: branches[i].Status, op: branches[i].Op}
}
isPreconditionsSucceed := func(current int) bool {
// if !csc.Concurrent,then check the branch in previous step is succeed
@ -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}
resultChan <- branchResult{index: i, status: branches[i].Status, op: branches[i].Op}
if err != nil {
dtmcli.LogRedf("exec branch error: %v", err)
dtmimp.LogRedf("exec branch error: %v", err)
}
}()
err = t.execBranch(db, &branches[i])
@ -106,17 +105,17 @@ func (t *transSagaProcessor) ProcessOnce(db *common.DB, branches []TransBranch)
toRun := []int{}
for current := 0; current < n; current++ {
br := &branchResults[current]
if br.branchType == dtmcli.BranchAction && !br.started && isPreconditionsSucceed(current) && br.status == dtmcli.StatusPrepared {
if br.op == dtmcli.BranchAction && !br.started && isPreconditionsSucceed(current) && br.status == dtmcli.StatusPrepared {
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) {
for _, b := range toRun {
branchResults[b].started = true
if branchResults[b].branchType == dtmcli.BranchAction {
if branchResults[b].op == dtmcli.BranchAction {
rsAStarted++
}
go asyncExecBranch(b)
@ -128,7 +127,7 @@ func (t *transSagaProcessor) ProcessOnce(db *common.DB, branches []TransBranch)
branchResults[b].status = dtmcli.StatusSucceed
}
for i, b := range branchResults {
if b.branchType == dtmcli.BranchCompensate && b.status != dtmcli.StatusSucceed && branchResults[i+1].status != dtmcli.StatusPrepared {
if b.op == dtmcli.BranchCompensate && b.status != dtmcli.StatusSucceed && branchResults[i+1].status != dtmcli.StatusPrepared {
rsCToStart++
go asyncExecBranch(i)
}
@ -139,7 +138,7 @@ func (t *transSagaProcessor) ProcessOnce(db *common.DB, branches []TransBranch)
case r := <-resultChan:
br := &branchResults[r.index]
br.status = r.status
if r.branchType == dtmcli.BranchAction {
if r.op == dtmcli.BranchAction {
rsADone++
if r.status == dtmcli.StatusFailed {
rsAFailed++
@ -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")
}
}

8
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,15 +25,16 @@ 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)
op := 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 {
if branches[current].Op == op && branches[current].Status == dtmcli.StatusPrepared {
dtmimp.Logf("branch info: current: %d ID: %d", current, branches[current].ID)
err := t.execBranch(db, &branches[current])
if err != nil {
return err
}
}
}
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
}

7
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,15 +25,15 @@ 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 {
if branch.Op == currentType && branch.Status != dtmcli.StatusSucceed {
err := t.execBranch(db, &branch)
if err != nil {
return err
}
}
}
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())
}

67
examples/base_http.go

@ -4,11 +4,13 @@ import (
"database/sql"
"errors"
"fmt"
"strings"
"time"
"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 +34,24 @@ 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()
app.Use(func(c *gin.Context) {
v := MainSwitch.NextResult.Fetch()
if v != "" {
c.JSON(200, gin.H{"dtm_result": v})
c.Abort()
return
}
c.Next()
})
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 +70,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
@ -71,6 +84,7 @@ type mainSwitchType struct {
TransInRevertResult AutoEmptyString
TransOutRevertResult AutoEmptyString
CanSubmitResult AutoEmptyString
NextResult AutoEmptyString
}
// MainSwitch controls busi success or fail
@ -78,12 +92,22 @@ 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
}
func error2Resp(err error) (interface{}, error) {
if err != nil {
s := err.Error()
if strings.Contains(s, dtmcli.ResultFailure) || strings.Contains(s, dtmcli.ResultOngoing) {
return gin.H{"dtm_result": s}, nil
}
}
return nil, nil
}
// BaseAddRoute add base route handler
@ -107,32 +131,34 @@ 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) {
err := 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
})
return error2Resp(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) {
err := 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
})
return error2Resp(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) {
err := 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,11 +168,12 @@ 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
})
return error2Resp(err)
}))
app.POST(BusiAPI+"/TestPanic", common.WrapHandler(func(c *gin.Context) (interface{}, error) {

42
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
}
@ -53,10 +61,10 @@ func reqFrom(c *gin.Context) *TransReq {
func infoFromContext(c *gin.Context) *dtmcli.BranchBarrier {
info := dtmcli.BranchBarrier{
TransType: c.Query("trans_type"),
Gid: c.Query("gid"),
BranchID: c.Query("branch_id"),
BranchType: c.Query("branch_type"),
TransType: c.Query("trans_type"),
Gid: c.Query("gid"),
BranchID: c.Query("branch_id"),
Op: c.Query("op"),
}
return &info
}
@ -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
})
}

13
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
}
@ -52,8 +53,8 @@ func sagaBarrierTransInCompensate(c *gin.Context) (interface{}, error) {
func sagaBarrierTransOut(c *gin.Context) (interface{}, error) {
req := reqFrom(c)
if req.TransInResult != "" {
return req.TransInResult, nil
if req.TransOutResult != "" {
return req.TransOutResult, nil
}
barrier := MustBarrierFromGin(c)
return dtmcli.MapSuccess, barrier.Call(txGet(), func(db dtmcli.DB) error {

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
})
}

18
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,16 +20,17 @@ 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", Busi+"/TccBTransOutConfirm", Busi+"/TccBTransOutCancel")
resp, err := tcc.CallBranch(&TransReq{Amount: 30}, Busi+"/TccBTransOutTry",
Busi+"/TccBTransOutConfirm", Busi+"/TccBTransOutCancel")
if err != nil {
return resp, err
}
return tcc.CallBranch(&TransReq{Amount: 30}, Busi+"/TccBTransInTry", Busi+"/TccBTransInConfirm", Busi+"/TccBTransInCancel")
})
dtmcli.FatalIfError(err)
dtmimp.FatalIfError(err)
return gid
})
}
@ -37,7 +39,8 @@ 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+? where user_id=? and trading_balance + ? + balance >= 0", amount, uid, amount)
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")
}
@ -45,7 +48,8 @@ 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-?, balance=balance+? where user_id=?;", amount, amount, uid)
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")
}
@ -77,8 +81,8 @@ func tccBarrierTransInCancel(c *gin.Context) (interface{}, error) {
func tccBarrierTransOutTry(c *gin.Context) (interface{}, error) {
req := reqFrom(c)
if req.TransInResult != "" {
return req.TransInResult, nil
if req.TransOutResult != "" {
return req.TransOutResult, nil
}
return dtmcli.MapSuccess, MustBarrierFromGin(c).Call(txGet(), func(db dtmcli.DB) error {
return adjustTrading(db, transOutUID, -req.Amount)

7
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
@ -15,10 +16,10 @@ func init() {
var err error
XaClient, err = dtmcli.NewXaClient(DtmServer, config.DB, Busi+"/xa", func(path string, xa *dtmcli.XaClient) {
app.POST(path, common.WrapHandler(func(c *gin.Context) (interface{}, error) {
return xa.HandleCallback(c.Query("gid"), c.Query("branch_id"), c.Query("branch_type"))
return xa.HandleCallback(c.Query("gid"), c.Query("branch_id"), c.Query("op"))
}))
})
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)
}

38
test/barrier_saga_test.go

@ -1,38 +0,0 @@
package test
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/examples"
)
func TestBarrierSaga(t *testing.T) {
sagaBarrierNormal(t)
sagaBarrierRollback(t)
}
func sagaBarrierNormal(t *testing.T) {
req := &examples.TransReq{Amount: 30}
saga := dtmcli.NewSaga(DtmServer, "sagaBarrierNormal").
Add(Busi+"/SagaBTransOut", Busi+"/SagaBTransOutCompensate", req).
Add(Busi+"/SagaBTransIn", Busi+"/SagaBTransInCompensate", req)
dtmcli.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").
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")
err := saga.Submit()
e2p(err)
waitTransProcessed(saga.Gid)
assert.Equal(t, dtmcli.StatusFailed, getTransStatus(saga.Gid))
}

32
test/base_test.go

@ -7,23 +7,33 @@ 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{
TransType: "saga",
Gid: "gid2",
BranchID: "branch_id2",
BranchType: dtmcli.BranchAction,
TransType: "saga",
Gid: "gid2",
BranchID: "branch_id2",
Op: dtmcli.BranchAction,
}
db.Must().Exec("insert into dtm_barrier.barrier(trans_type, gid, branch_id, branch_type, reason) values('saga', 'gid1', 'branch_id1', 'action', 'saga')")
db.Must().Exec("insert into dtm_barrier.barrier(trans_type, gid, branch_id, op, reason) values('saga', 'gid1', 'branch_id1', 'action', 'saga')")
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")
}

55
test/dtmsvr_test.go

@ -7,7 +7,7 @@ import (
"github.com/gin-gonic/gin"
"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 +16,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)
@ -45,52 +36,18 @@ func getBranchesStatus(gid string) []string {
func assertSucceed(t *testing.T, gid string) {
waitTransProcessed(gid)
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)
assert.Equal(t, StatusSucceed, getTransStatus(gid))
}
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, dtmcli.StatusSucceed, getTransStatus(saga.Gid))
assert.Equal(t, []string{StatusPrepared, StatusSucceed}, getBranchesStatus(saga.Gid))
assert.Equal(t, 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())

39
test/grpc_barrier_saga_test.go

@ -1,39 +0,0 @@
package test
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/dtmcli"
"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").
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()
e2p(err)
waitTransProcessed(saga.Gid)
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").
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()
e2p(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))
}

46
test/grpc_msg_test.go

@ -1,46 +0,0 @@
package test
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/dtmcli"
"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")
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))
assert.Nil(t, err)
examples.MainSwitch.CanSubmitResult.SetOnce(dtmcli.ResultOngoing)
cronTransOnceForwardNow(180)
assert.Equal(t, dtmcli.StatusPrepared, getTransStatus(msg.Gid))
examples.MainSwitch.TransInResult.SetOnce(dtmcli.ResultOngoing)
cronTransOnceForwardNow(180)
assert.Equal(t, dtmcli.StatusSubmitted, getTransStatus(msg.Gid))
cronTransOnce()
assert.Equal(t, dtmcli.StatusSucceed, getTransStatus(msg.Gid))
}
func genGrpcMsg(gid string) *dtmgrpc.MsgGrpc {
req := dtmcli.MustMarshal(&examples.TransReq{Amount: 30})
return dtmgrpc.NewMsgGrpc(examples.DtmGrpcServer, gid).
Add(examples.BusiGrpc+"/examples.Busi/TransOut", req).
Add(examples.BusiGrpc+"/examples.Busi/TransIn", req)
}

56
test/grpc_saga_test.go

@ -1,56 +0,0 @@
package test
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/dtmcli"
"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)
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)
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))
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 sagaGrpcRollback(t *testing.T) {
saga := genSagaGrpc("gid-rollbackSaga2Grpc", false, true)
examples.MainSwitch.TransOutRevertResult.SetOnce(dtmcli.ResultOngoing)
saga.Submit()
waitTransProcessed(saga.Gid)
assert.Equal(t, dtmcli.StatusAborting, getTransStatus(saga.Gid))
cronTransOnce()
assert.Equal(t, dtmcli.StatusFailed, getTransStatus(saga.Gid))
assert.Equal(t, []string{dtmcli.StatusSucceed, dtmcli.StatusSucceed, dtmcli.StatusSucceed, dtmcli.StatusFailed}, getBranchesStatus(saga.Gid))
}
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))
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
}

65
test/grpc_tcc_test.go

@ -1,65 +0,0 @@
package test
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmgrpc"
"github.com/yedf/dtm/examples"
)
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{}})
assert.Error(t, err)
dtmcli.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"
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")
assert.Nil(t, err)
_, err = tcc.CallBranch(data, examples.BusiGrpc+"/examples.Busi/TransIn", examples.BusiGrpc+"/examples.Busi/TransInConfirm", examples.BusiGrpc+"/examples.Busi/TransInRevert")
return err
})
assert.Nil(t, err)
}
func tccGrpcNested(t *testing.T) {
data := dtmcli.MustMarshal(&examples.TransReq{Amount: 30})
gid := "tccGrpcNested"
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")
assert.Nil(t, err)
_, err = tcc.CallBranch(data, examples.BusiGrpc+"/examples.Busi/TransInTccNested", examples.BusiGrpc+"/examples.Busi/TransInConfirm", examples.BusiGrpc+"/examples.Busi/TransInRevert")
return err
})
assert.Nil(t, err)
}
func tccGrpcRollback(t *testing.T) {
gid := "tccGrpcRollback"
data := dtmcli.MustMarshal(&examples.TransReq{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")
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")
return err
})
assert.Error(t, err)
waitTransProcessed(gid)
assert.Equal(t, dtmcli.StatusAborting, getTransStatus(gid))
cronTransOnce()
assert.Equal(t, dtmcli.StatusFailed, getTransStatus(gid))
}

74
test/grpc_xa_test.go

@ -1,74 +0,0 @@
package test
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/dtmcli"
"github.com/yedf/dtm/dtmgrpc"
"github.com/yedf/dtm/examples"
)
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{}})
assert.Error(t, err)
err = examples.XaGrpcClient.XaLocalTransaction(&dtmgrpc.BusiRequest{Info: &dtmgrpc.BranchInfo{}}, nil)
assert.Error(t, err)
err = dtmcli.CatchP(func() {
examples.XaGrpcClient.XaGlobalTransaction("id1", func(xa *dtmgrpc.XaGrpc) error { panic(fmt.Errorf("hello")) })
})
assert.Error(t, err)
}
func xaGrpcLocalError(t *testing.T) {
xc := examples.XaGrpcClient
err := xc.XaGlobalTransaction("xaGrpcLocalError", func(xa *dtmgrpc.XaGrpc) error {
return fmt.Errorf("an error")
})
assert.Error(t, err, fmt.Errorf("an error"))
}
func xaGrpcNormal(t *testing.T) {
xc := examples.XaGrpcClient
gid := "xaGrpcNormal"
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")
if err != nil {
return err
}
_, err = xa.CallBranch(req, examples.BusiGrpc+"/examples.Busi/TransInXa")
return err
})
assert.Equal(t, nil, err)
waitTransProcessed(gid)
assert.Equal(t, []string{dtmcli.StatusPrepared, dtmcli.StatusSucceed, dtmcli.StatusPrepared, dtmcli.StatusSucceed}, getBranchesStatus(gid))
}
func xaGrpcRollback(t *testing.T) {
xc := examples.XaGrpcClient
gid := "xaGrpcRollback"
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")
if err != nil {
return err
}
_, err = xa.CallBranch(req, examples.BusiGrpc+"/examples.Busi/TransInXa")
return err
})
assert.Error(t, err)
waitTransProcessed(gid)
assert.Equal(t, []string{dtmcli.StatusSucceed, dtmcli.StatusPrepared}, getBranchesStatus(gid))
assert.Equal(t, dtmcli.StatusFailed, getTransStatus(gid))
}

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))
}
}

59
test/msg_grpc_test.go

@ -0,0 +1,59 @@
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/dtmgrpc"
"github.com/yedf/dtm/examples"
)
func TestMsgGrpcNormal(t *testing.T) {
msg := genGrpcMsg(dtmimp.GetFuncName())
err := msg.Submit()
assert.Nil(t, err)
waitTransProcessed(msg.Gid)
assert.Equal(t, StatusSucceed, getTransStatus(msg.Gid))
assert.Equal(t, []string{StatusSucceed, StatusSucceed}, getBranchesStatus(msg.Gid))
}
func TestMsgGrpcTimeoutSuccess(t *testing.T) {
msg := genGrpcMsg(dtmimp.GetFuncName())
err := msg.Prepare("")
assert.Nil(t, err)
examples.MainSwitch.CanSubmitResult.SetOnce(dtmcli.ResultOngoing)
cronTransOnceForwardNow(180)
assert.Equal(t, StatusPrepared, getTransStatus(msg.Gid))
examples.MainSwitch.TransOutResult.SetOnce(dtmcli.ResultOngoing)
cronTransOnceForwardNow(180)
assert.Equal(t, StatusSubmitted, getTransStatus(msg.Gid))
assert.Equal(t, []string{StatusPrepared, StatusPrepared}, getBranchesStatus(msg.Gid))
cronTransOnce()
assert.Equal(t, StatusSucceed, getTransStatus(msg.Gid))
assert.Equal(t, []string{StatusSucceed, StatusSucceed}, getBranchesStatus(msg.Gid))
}
func TestMsgGrpcTimeoutFailed(t *testing.T) {
msg := genGrpcMsg(dtmimp.GetFuncName())
msg.Prepare("")
assert.Equal(t, StatusPrepared, getTransStatus(msg.Gid))
examples.MainSwitch.CanSubmitResult.SetOnce(dtmcli.ResultOngoing)
cronTransOnceForwardNow(180)
assert.Equal(t, StatusPrepared, getTransStatus(msg.Gid))
examples.MainSwitch.CanSubmitResult.SetOnce(dtmcli.ResultFailure)
cronTransOnceForwardNow(180)
assert.Equal(t, StatusFailed, getTransStatus(msg.Gid))
assert.Equal(t, []string{StatusPrepared, StatusPrepared}, getBranchesStatus(msg.Gid))
}
func genGrpcMsg(gid string) *dtmgrpc.MsgGrpc {
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
}

44
test/msg_options_test.go

@ -0,0 +1,44 @@
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 TestMsgOptionsTimeout(t *testing.T) {
msg := genMsg(dtmimp.GetFuncName())
msg.Prepare("")
cronTransOnce()
assert.Equal(t, StatusPrepared, getTransStatus(msg.Gid))
cronTransOnceForwardNow(60)
assert.Equal(t, StatusSucceed, getTransStatus(msg.Gid))
}
func TestMsgOptionsTimeoutCustom(t *testing.T) {
msg := genMsg(dtmimp.GetFuncName())
msg.TimeoutToFail = 120
msg.Prepare("")
cronTransOnce()
assert.Equal(t, StatusPrepared, getTransStatus(msg.Gid))
cronTransOnceForwardNow(60)
assert.Equal(t, StatusPrepared, getTransStatus(msg.Gid))
cronTransOnceForwardNow(180)
assert.Equal(t, StatusSucceed, getTransStatus(msg.Gid))
}
func TestMsgOptionsTimeoutFailed(t *testing.T) {
msg := genMsg(dtmimp.GetFuncName())
msg.TimeoutToFail = 120
msg.Prepare("")
cronTransOnce()
assert.Equal(t, StatusPrepared, getTransStatus(msg.Gid))
cronTransOnceForwardNow(60)
assert.Equal(t, StatusPrepared, getTransStatus(msg.Gid))
examples.MainSwitch.CanSubmitResult.SetOnce(dtmcli.ResultFailure)
cronTransOnceForwardNow(180)
assert.Equal(t, StatusFailed, getTransStatus(msg.Gid))
}

72
test/msg_test.go

@ -5,54 +5,66 @@ 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))
assert.Equal(t, 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()
assert.Equal(t, []string{StatusSucceed, StatusSucceed}, getBranchesStatus(msg.Gid))
assert.Equal(t, StatusSucceed, getTransStatus(msg.Gid))
}
func msgOngoing(t *testing.T) {
msg := genMsg("gid-msg-normal-pending")
func TestMsgTimeoutSuccess(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))
assert.Equal(t, StatusPrepared, getTransStatus(msg.Gid))
examples.MainSwitch.CanSubmitResult.SetOnce(dtmcli.ResultOngoing)
cronTransOnceForwardNow(180)
assert.Equal(t, dtmcli.StatusPrepared, getTransStatus(msg.Gid))
assert.Equal(t, StatusPrepared, getTransStatus(msg.Gid))
examples.MainSwitch.TransInResult.SetOnce(dtmcli.ResultOngoing)
cronTransOnceForwardNow(180)
assert.Equal(t, dtmcli.StatusSubmitted, getTransStatus(msg.Gid))
assert.Equal(t, StatusSubmitted, getTransStatus(msg.Gid))
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)
assert.Equal(t, []string{StatusSucceed, StatusSucceed}, getBranchesStatus(msg.Gid))
assert.Equal(t, StatusSucceed, getTransStatus(msg.Gid))
}
func msgOngoingFailed(t *testing.T) {
msg := genMsg("gid-msg-pending-failed")
func TestMsgTimeoutFailed(t *testing.T) {
msg := genMsg(dtmimp.GetFuncName())
msg.Prepare("")
assert.Equal(t, dtmcli.StatusPrepared, getTransStatus(msg.Gid))
assert.Equal(t, StatusPrepared, getTransStatus(msg.Gid))
examples.MainSwitch.CanSubmitResult.SetOnce(dtmcli.ResultOngoing)
cronTransOnceForwardNow(180)
assert.Equal(t, dtmcli.StatusPrepared, getTransStatus(msg.Gid))
assert.Equal(t, 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))
assert.Equal(t, []string{StatusPrepared, StatusPrepared}, getBranchesStatus(msg.Gid))
assert.Equal(t, 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
}

35
test/saga_barrier_test.go

@ -0,0 +1,35 @@
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 TestSagaBarrierNormal(t *testing.T) {
saga := genSagaBarrier(dtmimp.GetFuncName(), false, false)
err := saga.Submit()
assert.Nil(t, err)
waitTransProcessed(saga.Gid)
assert.Equal(t, []string{StatusPrepared, StatusSucceed, StatusPrepared, StatusSucceed}, getBranchesStatus(saga.Gid))
assert.Equal(t, StatusSucceed, getTransStatus(saga.Gid))
}
func TestSagaBarrierRollback(t *testing.T) {
saga := genSagaBarrier(dtmimp.GetFuncName(), false, true)
err := saga.Submit()
assert.Nil(t, err)
waitTransProcessed(saga.Gid)
assert.Equal(t, StatusFailed, getTransStatus(saga.Gid))
assert.Equal(t, []string{StatusSucceed, StatusSucceed, StatusSucceed, StatusFailed}, getBranchesStatus(saga.Gid))
}
func genSagaBarrier(gid string, outFailed, inFailed bool) *dtmcli.Saga {
req := examples.GenTransReq(30, outFailed, inFailed)
return dtmcli.NewSaga(DtmServer, gid).
Add(Busi+"/SagaBTransOut", Busi+"/SagaBTransOutCompensate", req).
Add(Busi+"/SagaBTransIn", Busi+"/SagaBTransInCompensate", req)
}

20
test/saga_compatible_test.go

@ -0,0 +1,20 @@
package test
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"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{StatusPrepared, StatusSucceed, StatusPrepared, StatusSucceed}, getBranchesStatus(gid))
assert.Equal(t, StatusSucceed, getTransStatus(gid))
}

78
test/saga_concurrent_test.go

@ -5,69 +5,53 @@ 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 genSagaCon(gid string, outFailed bool, inFailed bool) *dtmcli.Saga {
return genSaga(gid, outFailed, inFailed).EnableConcurrent()
}
func genCSaga(gid string, outFailed bool, inFailed bool) *dtmcli.Saga {
dtmcli.Logf("beginning a concurrent saga test ---------------- %s", gid)
req := examples.GenTransReq(30, outFailed, inFailed)
csaga := dtmcli.NewSaga(examples.DtmServer, gid).
Add(examples.Busi+"/TransOut", examples.Busi+"/TransOutRevert", &req).
Add(examples.Busi+"/TransIn", examples.Busi+"/TransInRevert", &req).
EnableConcurrent()
return csaga
func TestSagaConNormal(t *testing.T) {
sagaCon := genSagaCon(dtmimp.GetFuncName(), false, false)
sagaCon.Submit()
waitTransProcessed(sagaCon.Gid)
assert.Equal(t, []string{StatusPrepared, StatusSucceed, StatusPrepared, StatusSucceed}, getBranchesStatus(sagaCon.Gid))
assert.Equal(t, StatusSucceed, getTransStatus(sagaCon.Gid))
}
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 csagaRollback(t *testing.T) {
csaga := genCSaga("gid-rollback-csaga", true, false)
func TestSagaConRollbackNormal(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, 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.Error(t, err)
assert.Equal(t, StatusFailed, getTransStatus(sagaCon.Gid))
assert.Equal(t, []string{StatusSucceed, StatusFailed, StatusSucceed, StatusSucceed}, getBranchesStatus(sagaCon.Gid))
}
func csagaRollback2(t *testing.T) {
csaga := genCSaga("gid-rollback-csaga2", true, false)
csaga.AddBranchOrder(1, []int{0})
err := csaga.Submit()
func TestSagaConRollbackOrder(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()
assert.Error(t, err)
waitTransProcessed(sagaCon.Gid)
assert.Equal(t, StatusFailed, getTransStatus(sagaCon.Gid))
assert.Equal(t, []string{StatusSucceed, StatusFailed, StatusPrepared, StatusPrepared}, getBranchesStatus(sagaCon.Gid))
}
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{StatusPrepared, StatusPrepared, StatusPrepared, StatusSucceed}, getBranchesStatus(sagaCon.Gid))
assert.Equal(t, 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{StatusPrepared, StatusSucceed, StatusPrepared, StatusSucceed}, getBranchesStatus(sagaCon.Gid))
assert.Equal(t, StatusSucceed, getTransStatus(sagaCon.Gid))
}

36
test/saga_grpc_barrier_test.go

@ -0,0 +1,36 @@
package test
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/yedf/dtm/dtmcli/dtmimp"
"github.com/yedf/dtm/dtmgrpc"
"github.com/yedf/dtm/examples"
)
func TestSagaGrpcBarrierNormal(t *testing.T) {
saga := genSagaGrpcBarrier(dtmimp.GetFuncName(), false, false)
err := saga.Submit()
assert.Nil(t, err)
waitTransProcessed(saga.Gid)
assert.Equal(t, StatusSucceed, getTransStatus(saga.Gid))
assert.Equal(t, []string{StatusPrepared, StatusSucceed, StatusPrepared, StatusSucceed}, getBranchesStatus(saga.Gid))
}
func TestSagaGrpcBarrierRollback(t *testing.T) {
saga := genSagaGrpcBarrier(dtmimp.GetFuncName(), false, true)
err := saga.Submit()
assert.Nil(t, err)
waitTransProcessed(saga.Gid)
assert.Equal(t, StatusFailed, getTransStatus(saga.Gid))
assert.Equal(t, []string{StatusSucceed, StatusSucceed, StatusSucceed, StatusFailed}, getBranchesStatus(saga.Gid))
}
func genSagaGrpcBarrier(gid string, outFailed bool, inFailed bool) *dtmgrpc.SagaGrpc {
saga := dtmgrpc.NewSagaGrpc(examples.DtmGrpcServer, gid)
req := examples.GenBusiReq(30, outFailed, inFailed)
saga.Add(examples.BusiGrpc+"/examples.Busi/TransOutBSaga", examples.BusiGrpc+"/examples.Busi/TransOutRevertBSaga", req)
saga.Add(examples.BusiGrpc+"/examples.Busi/TransInBSaga", examples.BusiGrpc+"/examples.Busi/TransInRevertBSaga", req)
return saga
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save