* feat: add sync worker and fmt * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update * feat: fix spell * feat: fix conflict Co-authored-by: Xin.Zh <dragoncharlie@foxmail.com> Co-authored-by: haohongfan1 <haohongfan1@jd.com>tags/1.0.2-RC1
@@ -16,11 +16,14 @@ require ( | |||
github.com/natefinch/lumberjack v2.0.0+incompatible | |||
github.com/parnurzeal/gorequest v0.2.16 | |||
github.com/pkg/errors v0.9.1 | |||
github.com/prometheus/client_golang v1.12.2 | |||
github.com/prometheus/common v0.32.1 | |||
github.com/stretchr/testify v1.8.0 | |||
go.uber.org/atomic v1.9.0 | |||
go.uber.org/zap v1.21.0 | |||
google.golang.org/grpc v1.49.0 | |||
google.golang.org/protobuf v1.28.1 | |||
gopkg.in/yaml.v2 v2.4.0 | |||
vimagination.zapto.org/byteio v0.0.0-20200222190125-d27cba0f0b10 | |||
) | |||
@@ -105,9 +108,7 @@ require ( | |||
github.com/pmezard/go-difflib v1.0.0 // indirect | |||
github.com/polarismesh/polaris-go v1.1.0 // indirect | |||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect | |||
github.com/prometheus/client_golang v1.12.2 // indirect | |||
github.com/prometheus/client_model v0.2.0 // indirect | |||
github.com/prometheus/common v0.32.1 // indirect | |||
github.com/prometheus/procfs v0.7.3 // indirect | |||
github.com/prometheus/statsd_exporter v0.21.0 // indirect | |||
github.com/robfig/cron/v3 v3.0.1 // indirect | |||
@@ -134,11 +135,10 @@ require ( | |||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect | |||
golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 // indirect | |||
golang.org/x/text v0.3.7 // indirect | |||
golang.org/x/tools v0.1.12 // indirect | |||
google.golang.org/appengine v1.6.7 // indirect | |||
google.golang.org/genproto v0.0.0-20220630174209-ad1d48641aa7 // indirect | |||
gopkg.in/ini.v1 v1.62.0 // indirect | |||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect | |||
gopkg.in/yaml.v2 v2.4.0 // indirect | |||
gopkg.in/yaml.v3 v3.0.1 // indirect | |||
moul.io/http2curl v1.0.0 // indirect | |||
vimagination.zapto.org/memio v0.0.0-20200222190306-588ebc67b97d // indirect | |||
@@ -22,7 +22,7 @@ import ( | |||
) | |||
// GettyConfig | |||
//Config holds supported types by the multiconfig package | |||
// Config holds supported types by the multiconfig package | |||
type GettyConfig struct { | |||
ReconnectInterval int `default:"0" yaml:"reconnect_interval" json:"reconnect_interval,omitempty"` | |||
// getty_session pool | |||
@@ -15,7 +15,7 @@ | |||
* limitations under the License. | |||
*/ | |||
package common | |||
package constant | |||
const ( | |||
ActionStartTime = "action-start-time" |
@@ -0,0 +1,191 @@ | |||
package sql | |||
import ( | |||
"context" | |||
"flag" | |||
"time" | |||
"github.com/prometheus/client_golang/prometheus" | |||
"github.com/prometheus/client_golang/prometheus/promauto" | |||
"github.com/seata/seata-go/pkg/datasource/sql/datasource" | |||
"github.com/seata/seata-go/pkg/datasource/sql/undo" | |||
"github.com/seata/seata-go/pkg/protocol/branch" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/seata/seata-go/pkg/util/fanout" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
) | |||
type phaseTwoContext struct { | |||
Xid string | |||
BranchID int64 | |||
ResourceID string | |||
} | |||
type AsyncWorkerConfig struct { | |||
BufferLimit int `yaml:"buffer_limit" json:"buffer_limit"` | |||
BufferCleanInterval time.Duration `yaml:"buffer_clean_interval" json:"buffer_clean_interval"` | |||
ReceiveChanSize int `yaml:"receive_chan_size" json:"receive_chan_size"` | |||
CommitWorkerCount int `yaml:"commit_worker_count" json:"commit_worker_count"` | |||
CommitWorkerBufferSize int `yaml:"commit_worker_buffer_size" json:"commit_worker_buffer_size"` | |||
} | |||
func (cfg *AsyncWorkerConfig) RegisterFlags(f *flag.FlagSet) { | |||
f.IntVar(&cfg.BufferLimit, "async-worker.commit.buffer_size", 10000, "async worker commit buffer limit.") | |||
f.DurationVar(&cfg.BufferCleanInterval, "async-worker.commit.buffer.clean_interval", time.Second, "async worker commit buffer interval") | |||
f.IntVar(&cfg.ReceiveChanSize, "async-worker.commit.channel_size", 10000, "async worker commit channel size") | |||
f.IntVar(&cfg.CommitWorkerCount, "async-worker.commit.worker_count", 10, "async worker commit worker count") | |||
f.IntVar(&cfg.CommitWorkerBufferSize, "async-worker.commit.worker_buffer_size", 1000, "async worker commit worker buffer size") | |||
} | |||
// AsyncWorker executor for branch transaction commit and undo log | |||
type AsyncWorker struct { | |||
conf AsyncWorkerConfig | |||
commitQueue chan phaseTwoContext | |||
resourceMgr datasource.DataSourceManager | |||
commitWorker *fanout.Fanout | |||
branchCommitTotal prometheus.Counter | |||
doBranchCommitFailureTotal prometheus.Counter | |||
receiveChanLength prometheus.Gauge | |||
rePutBackToQueue prometheus.Counter | |||
} | |||
func NewAsyncWorker(prom prometheus.Registerer, conf AsyncWorkerConfig, sourceManager datasource.DataSourceManager) *AsyncWorker { | |||
var asyncWorker AsyncWorker | |||
asyncWorker.conf = conf | |||
asyncWorker.commitQueue = make(chan phaseTwoContext, asyncWorker.conf.ReceiveChanSize) | |||
asyncWorker.resourceMgr = sourceManager | |||
asyncWorker.commitWorker = fanout.New("asyncWorker", | |||
fanout.WithWorker(asyncWorker.conf.CommitWorkerCount), | |||
fanout.WithBuffer(asyncWorker.conf.CommitWorkerBufferSize), | |||
) | |||
asyncWorker.branchCommitTotal = promauto.With(prom).NewCounter(prometheus.CounterOpts{ | |||
Name: "async_worker_branch_commit_total", | |||
Help: "the total count of branch commit total count", | |||
}) | |||
asyncWorker.doBranchCommitFailureTotal = promauto.With(prom).NewCounter(prometheus.CounterOpts{ | |||
Name: "async_worker_branch_commit_failure_total", | |||
Help: "the total count of branch commit failure count", | |||
}) | |||
asyncWorker.receiveChanLength = promauto.With(prom).NewGauge(prometheus.GaugeOpts{ | |||
Name: "async_worker_receive_channel_length", | |||
Help: "the current length of the receive channel size", | |||
}) | |||
asyncWorker.rePutBackToQueue = promauto.With(prom).NewCounter(prometheus.CounterOpts{ | |||
Name: "async_worker_commit_failure_retry_counter", | |||
Help: "the counter of commit failure retry counter", | |||
}) | |||
go asyncWorker.run() | |||
return &asyncWorker | |||
} | |||
// BranchCommit commit branch transaction | |||
func (aw *AsyncWorker) BranchCommit(ctx context.Context, req message.BranchCommitRequest) (branch.BranchStatus, error) { | |||
phaseCtx := phaseTwoContext{ | |||
Xid: req.Xid, | |||
BranchID: req.BranchId, | |||
ResourceID: req.ResourceId, | |||
} | |||
aw.branchCommitTotal.Add(1) | |||
select { | |||
case aw.commitQueue <- phaseCtx: | |||
case <-ctx.Done(): | |||
} | |||
aw.receiveChanLength.Add(float64(len(aw.commitQueue))) | |||
return branch.BranchStatusPhasetwoCommitted, nil | |||
} | |||
func (aw *AsyncWorker) run() { | |||
ticker := time.NewTicker(aw.conf.BufferCleanInterval) | |||
phaseCtxs := make([]phaseTwoContext, 0, aw.conf.BufferLimit) | |||
for { | |||
select { | |||
case phaseCtx := <-aw.commitQueue: | |||
phaseCtxs = append(phaseCtxs, phaseCtx) | |||
if len(phaseCtxs) >= aw.conf.BufferLimit*2/3 { | |||
aw.doBranchCommit(&phaseCtxs) | |||
} | |||
case <-ticker.C: | |||
aw.doBranchCommit(&phaseCtxs) | |||
} | |||
} | |||
} | |||
func (aw *AsyncWorker) doBranchCommit(phaseCtxs *[]phaseTwoContext) { | |||
copyPhaseCtxs := make([]phaseTwoContext, len(*phaseCtxs)) | |||
copy(copyPhaseCtxs, *phaseCtxs) | |||
*phaseCtxs = (*phaseCtxs)[:0] | |||
doBranchCommit := func(ctx context.Context) { | |||
groupCtxs := make(map[string][]phaseTwoContext, 16) | |||
for i := range copyPhaseCtxs { | |||
if copyPhaseCtxs[i].ResourceID == "" { | |||
continue | |||
} | |||
if _, ok := groupCtxs[copyPhaseCtxs[i].ResourceID]; !ok { | |||
groupCtxs[copyPhaseCtxs[i].ResourceID] = make([]phaseTwoContext, 0, 4) | |||
} | |||
ctxs := groupCtxs[copyPhaseCtxs[i].ResourceID] | |||
ctxs = append(ctxs, copyPhaseCtxs[i]) | |||
groupCtxs[copyPhaseCtxs[i].ResourceID] = ctxs | |||
} | |||
for k := range groupCtxs { | |||
aw.dealWithGroupedContexts(k, groupCtxs[k]) | |||
} | |||
} | |||
if err := aw.commitWorker.Do(context.Background(), doBranchCommit); err != nil { | |||
aw.doBranchCommitFailureTotal.Add(1) | |||
log.Errorf("do branch commit err:%v", err) | |||
} | |||
} | |||
func (aw *AsyncWorker) dealWithGroupedContexts(resID string, phaseCtxs []phaseTwoContext) { | |||
val, ok := aw.resourceMgr.GetManagedResources()[resID] | |||
if !ok { | |||
for i := range phaseCtxs { | |||
aw.rePutBackToQueue.Add(1) | |||
aw.commitQueue <- phaseCtxs[i] | |||
} | |||
return | |||
} | |||
res := val.(*DBResource) | |||
conn, err := res.target.Conn(context.Background()) | |||
if err != nil { | |||
for i := range phaseCtxs { | |||
aw.commitQueue <- phaseCtxs[i] | |||
} | |||
} | |||
defer conn.Close() | |||
undoMgr, err := undo.GetUndoLogManager(res.dbType) | |||
if err != nil { | |||
for i := range phaseCtxs { | |||
aw.rePutBackToQueue.Add(1) | |||
aw.commitQueue <- phaseCtxs[i] | |||
} | |||
return | |||
} | |||
for i := range phaseCtxs { | |||
phaseCtx := phaseCtxs[i] | |||
if err := undoMgr.BatchDeleteUndoLog([]string{phaseCtx.Xid}, []int64{phaseCtx.BranchID}, conn); err != nil { | |||
aw.rePutBackToQueue.Add(1) | |||
aw.commitQueue <- phaseCtx | |||
} | |||
} | |||
} |
@@ -20,16 +20,15 @@ package sql | |||
import ( | |||
"context" | |||
"database/sql" | |||
"flag" | |||
"fmt" | |||
"os" | |||
"strconv" | |||
"sync" | |||
"time" | |||
"github.com/seata/seata-go/pkg/datasource/sql/undo" | |||
"github.com/prometheus/client_golang/prometheus" | |||
"github.com/seata/seata-go/pkg/datasource/sql/datasource" | |||
"github.com/seata/seata-go/pkg/datasource/sql/types" | |||
"github.com/seata/seata-go/pkg/datasource/sql/undo" | |||
"github.com/seata/seata-go/pkg/protocol/branch" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/seata/seata-go/pkg/rm" | |||
@@ -41,16 +40,23 @@ const ( | |||
) | |||
func init() { | |||
datasource.RegisterResourceManager(branch.BranchTypeAT, | |||
&ATSourceManager{ | |||
resourceCache: sync.Map{}, | |||
basic: datasource.NewBasicSourceManager(), | |||
}) | |||
atSourceManager := &ATSourceManager{ | |||
resourceCache: sync.Map{}, | |||
basic: datasource.NewBasicSourceManager(), | |||
} | |||
fs := flag.NewFlagSet("", flag.PanicOnError) | |||
asyncWorkerConf := AsyncWorkerConfig{} | |||
asyncWorkerConf.RegisterFlags(fs) | |||
_ = fs.Parse([]string{}) | |||
atSourceManager.worker = NewAsyncWorker(prometheus.DefaultRegisterer, asyncWorkerConf, atSourceManager) | |||
datasource.RegisterResourceManager(branch.BranchTypeAT, atSourceManager) | |||
} | |||
type ATSourceManager struct { | |||
resourceCache sync.Map | |||
worker *asyncATWorker | |||
worker *AsyncWorker | |||
basic *datasource.BasicSourceManager | |||
} | |||
@@ -61,7 +67,7 @@ func (mgr *ATSourceManager) RegisterResource(res rm.Resource) error { | |||
return mgr.basic.RegisterResource(res) | |||
} | |||
// Unregister a Resource from the Resource Manager | |||
// Unregister a Resource from the Resource Manager | |||
func (mgr *ATSourceManager) UnregisterResource(res rm.Resource) error { | |||
return mgr.basic.UnregisterResource(res) | |||
} | |||
@@ -116,7 +122,7 @@ func (mgr *ATSourceManager) BranchRollback(ctx context.Context, req message.Bran | |||
// BranchCommit | |||
func (mgr *ATSourceManager) BranchCommit(ctx context.Context, req message.BranchCommitRequest) (branch.BranchStatus, error) { | |||
mgr.worker.branchCommit(ctx, req) | |||
mgr.worker.BranchCommit(ctx, req) | |||
return branch.BranchStatusPhaseoneDone, nil | |||
} | |||
@@ -140,132 +146,3 @@ func (mgr *ATSourceManager) CreateTableMetaCache(ctx context.Context, resID stri | |||
db *sql.DB) (datasource.TableMetaCache, error) { | |||
return mgr.basic.CreateTableMetaCache(ctx, resID, dbType, db) | |||
} | |||
type asyncATWorker struct { | |||
asyncCommitBufferLimit int64 | |||
commitQueue chan phaseTwoContext | |||
resourceMgr datasource.DataSourceManager | |||
} | |||
func newAsyncATWorker() *asyncATWorker { | |||
asyncCommitBufferLimit := int64(10000) | |||
val := os.Getenv("CLIENT_RM_ASYNC_COMMIT_BUFFER_LIMIT") | |||
if val != "" { | |||
limit, _ := strconv.ParseInt(val, 10, 64) | |||
if limit != 0 { | |||
asyncCommitBufferLimit = limit | |||
} | |||
} | |||
worker := &asyncATWorker{ | |||
commitQueue: make(chan phaseTwoContext, asyncCommitBufferLimit), | |||
} | |||
return worker | |||
} | |||
func (w *asyncATWorker) doBranchCommitSafely() { | |||
batchSize := 64 | |||
ticker := time.NewTicker(1 * time.Second) | |||
phaseCtxs := make([]phaseTwoContext, 0, batchSize) | |||
for { | |||
select { | |||
case phaseCtx := <-w.commitQueue: | |||
phaseCtxs = append(phaseCtxs, phaseCtx) | |||
if len(phaseCtxs) == batchSize { | |||
tmp := phaseCtxs | |||
w.doBranchCommit(tmp) | |||
phaseCtxs = make([]phaseTwoContext, 0, batchSize) | |||
} | |||
case <-ticker.C: | |||
tmp := phaseCtxs | |||
w.doBranchCommit(tmp) | |||
phaseCtxs = make([]phaseTwoContext, 0, batchSize) | |||
} | |||
} | |||
} | |||
func (w *asyncATWorker) doBranchCommit(phaseCtxs []phaseTwoContext) { | |||
groupCtxs := make(map[string][]phaseTwoContext, _defaultResourceSize) | |||
for i := range phaseCtxs { | |||
if phaseCtxs[i].ResourceID == "" { | |||
continue | |||
} | |||
if _, ok := groupCtxs[phaseCtxs[i].ResourceID]; !ok { | |||
groupCtxs[phaseCtxs[i].ResourceID] = make([]phaseTwoContext, 0, 4) | |||
} | |||
ctxs := groupCtxs[phaseCtxs[i].ResourceID] | |||
ctxs = append(ctxs, phaseCtxs[i]) | |||
groupCtxs[phaseCtxs[i].ResourceID] = ctxs | |||
} | |||
for k := range groupCtxs { | |||
w.dealWithGroupedContexts(k, groupCtxs[k]) | |||
} | |||
} | |||
func (w *asyncATWorker) dealWithGroupedContexts(resID string, phaseCtxs []phaseTwoContext) { | |||
val, ok := w.resourceMgr.GetManagedResources()[resID] | |||
if !ok { | |||
for i := range phaseCtxs { | |||
w.commitQueue <- phaseCtxs[i] | |||
} | |||
return | |||
} | |||
res := val.(*DBResource) | |||
conn, err := res.target.Conn(context.Background()) | |||
if err != nil { | |||
for i := range phaseCtxs { | |||
w.commitQueue <- phaseCtxs[i] | |||
} | |||
} | |||
defer conn.Close() | |||
undoMgr, err := undo.GetUndoLogManager(res.dbType) | |||
if err != nil { | |||
for i := range phaseCtxs { | |||
w.commitQueue <- phaseCtxs[i] | |||
} | |||
return | |||
} | |||
for i := range phaseCtxs { | |||
phaseCtx := phaseCtxs[i] | |||
if err := undoMgr.BatchDeleteUndoLog([]string{phaseCtx.Xid}, []int64{phaseCtx.BranchID}, conn); err != nil { | |||
w.commitQueue <- phaseCtx | |||
} | |||
} | |||
} | |||
func (w *asyncATWorker) branchCommit(ctx context.Context, req message.BranchCommitRequest) { | |||
phaseCtx := phaseTwoContext{ | |||
Xid: req.Xid, | |||
BranchID: req.BranchId, | |||
ResourceID: req.ResourceId, | |||
} | |||
select { | |||
case w.commitQueue <- phaseCtx: | |||
case <-ctx.Done(): | |||
} | |||
return | |||
} | |||
type phaseTwoContext struct { | |||
Xid string | |||
BranchID int64 | |||
ResourceID string | |||
} |
@@ -124,7 +124,6 @@ func (c *Conn) Exec(query string, args []driver.Value) (driver.Result, error) { | |||
return types.NewResult(types.WithResult(ret)), nil | |||
}) | |||
}) | |||
if err != nil { | |||
return nil, err | |||
} | |||
@@ -169,7 +168,6 @@ func (c *Conn) ExecContext(ctx context.Context, query string, args []driver.Name | |||
return ret, err | |||
}) | |||
if err != nil { | |||
return nil, err | |||
} | |||
@@ -335,7 +333,6 @@ func (c *Conn) createNewTxOnExecIfNeed(f func() (types.ExecResult, error)) (type | |||
}() | |||
ret, err := f() | |||
if err != nil { | |||
return nil, err | |||
} | |||
@@ -85,7 +85,6 @@ func baseMoclConn(mockConn *mock.MockTestDriverConn) { | |||
} | |||
func TestXAConn_ExecContext(t *testing.T) { | |||
ctrl := gomock.NewController(t) | |||
defer ctrl.Finish() | |||
@@ -25,9 +25,9 @@ import ( | |||
"testing" | |||
"github.com/golang/mock/gomock" | |||
"github.com/seata/seata-go/pkg/common/reflectx" | |||
"github.com/seata/seata-go/pkg/datasource/sql/mock" | |||
"github.com/seata/seata-go/pkg/datasource/sql/types" | |||
"github.com/seata/seata-go/pkg/util/reflectx" | |||
"github.com/stretchr/testify/assert" | |||
) | |||
@@ -26,11 +26,11 @@ import ( | |||
"strings" | |||
"github.com/go-sql-driver/mysql" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/common/reflectx" | |||
"github.com/seata/seata-go/pkg/datasource/sql/datasource" | |||
"github.com/seata/seata-go/pkg/datasource/sql/types" | |||
"github.com/seata/seata-go/pkg/protocol/branch" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
"github.com/seata/seata-go/pkg/util/reflectx" | |||
) | |||
const ( | |||
@@ -23,10 +23,10 @@ import ( | |||
"testing" | |||
"github.com/golang/mock/gomock" | |||
"github.com/seata/seata-go/pkg/common/reflectx" | |||
"github.com/seata/seata-go/pkg/datasource/sql/datasource" | |||
"github.com/seata/seata-go/pkg/datasource/sql/mock" | |||
"github.com/seata/seata-go/pkg/protocol/branch" | |||
"github.com/seata/seata-go/pkg/util/reflectx" | |||
"github.com/stretchr/testify/assert" | |||
) | |||
@@ -21,9 +21,9 @@ import ( | |||
"context" | |||
"database/sql/driver" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/datasource/sql/parser" | |||
"github.com/seata/seata-go/pkg/datasource/sql/types" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
) | |||
// executorSolts | |||
@@ -23,17 +23,16 @@ import ( | |||
"github.com/arana-db/parser/ast" | |||
"github.com/arana-db/parser/format" | |||
"github.com/seata/seata-go/pkg/common/bytes" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/datasource/sql/exec" | |||
"github.com/seata/seata-go/pkg/datasource/sql/parser" | |||
"github.com/seata/seata-go/pkg/datasource/sql/types" | |||
"github.com/seata/seata-go/pkg/util/bytes" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
_ "github.com/arana-db/parser/test_driver" | |||
) | |||
type BasicUndoBuilder struct { | |||
} | |||
type BasicUndoBuilder struct{} | |||
// buildRowImages build row iamge by exec condition | |||
func (u *BasicUndoBuilder) buildRowImages(ctx context.Context, execCtx *exec.ExecContext) ([]*types.RowImage, error) { | |||
@@ -20,9 +20,9 @@ package hook | |||
import ( | |||
"context" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/datasource/sql/exec" | |||
"github.com/seata/seata-go/pkg/datasource/sql/types" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
"go.uber.org/zap" | |||
) | |||
@@ -33,8 +33,7 @@ func init() { | |||
exec.RegisCommonHook(&undoLogSQLHook{}) | |||
} | |||
type undoLogSQLHook struct { | |||
} | |||
type undoLogSQLHook struct{} | |||
func (h *undoLogSQLHook) Type() types.SQLType { | |||
return types.SQLTypeUnknown | |||
@@ -20,9 +20,9 @@ package hook | |||
import ( | |||
"context" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/datasource/sql/exec" | |||
"github.com/seata/seata-go/pkg/datasource/sql/types" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
) | |||
// UpdateUndoHook build image when update executed | |||
@@ -26,7 +26,7 @@ import ( | |||
_ "github.com/go-sql-driver/mysql" | |||
"github.com/seata/seata-go/pkg/client" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
) | |||
var db *sql.DB | |||
@@ -24,10 +24,10 @@ import ( | |||
"github.com/seata/seata-go/pkg/datasource/sql/undo" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/datasource/sql/datasource" | |||
"github.com/seata/seata-go/pkg/protocol/branch" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
"github.com/pkg/errors" | |||
"github.com/seata/seata-go/pkg/datasource/sql/types" | |||
@@ -145,67 +145,67 @@ func GetJDBCTypeByTypeName(typeName string) JDBCType { | |||
case "ENUM": | |||
return JDBCTypeTinyInt | |||
// todo 待完善 | |||
//case fieldTypeEnum: | |||
// case fieldTypeEnum: | |||
// return "ENUM" | |||
//case fieldTypeFloat: | |||
// case fieldTypeFloat: | |||
// return "FLOAT" | |||
//case fieldTypeGeometry: | |||
// case fieldTypeGeometry: | |||
// return "GEOMETRY" | |||
//case fieldTypeInt24: | |||
// case fieldTypeInt24: | |||
// return "MEDIUMINT" | |||
//case fieldTypeJSON: | |||
// case fieldTypeJSON: | |||
// return "JSON" | |||
//case fieldTypeLong: | |||
// case fieldTypeLong: | |||
// return "INT" | |||
//case fieldTypeLongBLOB: | |||
// case fieldTypeLongBLOB: | |||
// if mf.charSet != collations[binaryCollation] { | |||
// return "LONGTEXT" | |||
// } | |||
// return "LONGBLOB" | |||
//case fieldTypeLongLong: | |||
// case fieldTypeLongLong: | |||
// return "BIGINT" | |||
//case fieldTypeMediumBLOB: | |||
// case fieldTypeMediumBLOB: | |||
// if mf.charSet != collations[binaryCollation] { | |||
// return "MEDIUMTEXT" | |||
// } | |||
// return "MEDIUMBLOB" | |||
//case fieldTypeNewDate: | |||
// case fieldTypeNewDate: | |||
// return "DATE" | |||
//case fieldTypeNewDecimal: | |||
// case fieldTypeNewDecimal: | |||
// return "DECIMAL" | |||
//case fieldTypeNULL: | |||
// case fieldTypeNULL: | |||
// return "NULL" | |||
//case fieldTypeSet: | |||
// case fieldTypeSet: | |||
// return "SET" | |||
//case fieldTypeShort: | |||
// case fieldTypeShort: | |||
// return "SMALLINT" | |||
//case fieldTypeString: | |||
// case fieldTypeString: | |||
// if mf.charSet == collations[binaryCollation] { | |||
// return "BINARY" | |||
// } | |||
// return "CHAR" | |||
//case fieldTypeTime: | |||
// case fieldTypeTime: | |||
// return "TIME" | |||
//case fieldTypeTimestamp: | |||
// case fieldTypeTimestamp: | |||
// return "TIMESTAMP" | |||
//case fieldTypeTiny: | |||
// case fieldTypeTiny: | |||
// return "TINYINT" | |||
//case fieldTypeTinyBLOB: | |||
// case fieldTypeTinyBLOB: | |||
// if mf.charSet != collations[binaryCollation] { | |||
// return "TINYTEXT" | |||
// } | |||
// return "TINYBLOB" | |||
//case fieldTypeVarChar: | |||
// case fieldTypeVarChar: | |||
// if mf.charSet == collations[binaryCollation] { | |||
// return "VARBINARY" | |||
// } | |||
// return "VARCHAR" | |||
//case fieldTypeVarString: | |||
// case fieldTypeVarString: | |||
// if mf.charSet == collations[binaryCollation] { | |||
// return "VARBINARY" | |||
// } | |||
// return "VARCHAR" | |||
//case fieldTypeYear: | |||
// case fieldTypeYear: | |||
// return "YEAR" | |||
default: | |||
return -1 | |||
@@ -21,15 +21,15 @@ import ( | |||
"context" | |||
"database/sql" | |||
"database/sql/driver" | |||
"strconv" | |||
"strings" | |||
"github.com/arana-db/parser/mysql" | |||
"github.com/pkg/errors" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/common/util" | |||
"github.com/seata/seata-go/pkg/constant" | |||
"github.com/seata/seata-go/pkg/datasource/sql/undo" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
"github.com/seata/seata-go/pkg/datasource/sql/types" | |||
) | |||
@@ -87,7 +87,7 @@ func (m *BaseUndoLogManager) BatchDeleteUndoLog(xid []string, branchID []int64, | |||
return err | |||
} | |||
branchIDStr, err := util.Int64Slice2Str(branchID, ",") | |||
branchIDStr, err := Int64Slice2Str(branchID, ",") | |||
if err != nil { | |||
log.Errorf("slice to string transfer fail, err: %v", err) | |||
return err | |||
@@ -168,3 +168,20 @@ func (m *BaseUndoLogManager) appendInParam(size int, str *strings.Builder) { | |||
str.WriteString(") ") | |||
} | |||
// Int64Slice2Str | |||
func Int64Slice2Str(values interface{}, sep string) (string, error) { | |||
v, ok := values.([]int64) | |||
if !ok { | |||
return "", errors.New("param type is fault") | |||
} | |||
var valuesText []string | |||
for i := range v { | |||
text := strconv.FormatInt(v[i], 10) | |||
valuesText = append(valuesText, text) | |||
} | |||
return strings.Join(valuesText, sep), nil | |||
} |
@@ -28,8 +28,7 @@ import ( | |||
"github.com/seata/seata-go/pkg/datasource/sql/types" | |||
) | |||
type BasicUndoLogBuilder struct { | |||
} | |||
type BasicUndoLogBuilder struct{} | |||
// getScanSlice get the column type for scann | |||
func (*BasicUndoLogBuilder) getScanSlice(columnNames []string, tableMeta types.TableMeta) []driver.Value { | |||
@@ -7,11 +7,11 @@ import ( | |||
"github.com/arana-db/parser/ast" | |||
"github.com/arana-db/parser/format" | |||
"github.com/seata/seata-go/pkg/common/bytes" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/datasource/sql/exec" | |||
"github.com/seata/seata-go/pkg/datasource/sql/parser" | |||
"github.com/seata/seata-go/pkg/datasource/sql/types" | |||
"github.com/seata/seata-go/pkg/util/bytes" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
) | |||
type MySQLDeleteUndoLogBuilder struct { | |||
@@ -26,10 +26,10 @@ import ( | |||
"github.com/arana-db/parser/ast" | |||
"github.com/arana-db/parser/format" | |||
"github.com/seata/seata-go/pkg/common/bytes" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/datasource/sql/parser" | |||
"github.com/seata/seata-go/pkg/datasource/sql/types" | |||
"github.com/seata/seata-go/pkg/util/bytes" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
) | |||
type MySQLUpdateUndoLogBuilder struct { | |||
@@ -22,14 +22,12 @@ import ( | |||
"testing" | |||
_ "github.com/arana-db/parser/test_driver" | |||
_ "github.com/seata/seata-go/pkg/common/log" | |||
_ "github.com/seata/seata-go/pkg/util/log" | |||
"github.com/stretchr/testify/assert" | |||
) | |||
func TestBuildBeforeImageSQL(t *testing.T) { | |||
var ( | |||
builder = MySQLUpdateUndoLogBuilder{} | |||
) | |||
builder := MySQLUpdateUndoLogBuilder{} | |||
tests := []struct { | |||
name string | |||
@@ -33,8 +33,10 @@ func init() { | |||
RegistrUndoLogBuilder(&builder.MySQLUpdateUndoLogBuilder{}) | |||
} | |||
var solts = map[types.DBType]*undoLogMgrHolder{} | |||
var builders = map[types.SQLType]UndoLogBuilder{} | |||
var ( | |||
solts = map[types.DBType]*undoLogMgrHolder{} | |||
builders = map[types.SQLType]UndoLogBuilder{} | |||
) | |||
type undoLogMgrHolder struct { | |||
once sync.Once | |||
@@ -25,9 +25,9 @@ import ( | |||
"dubbo.apache.org/dubbo-go/v3/common/extension" | |||
"dubbo.apache.org/dubbo-go/v3/filter" | |||
"dubbo.apache.org/dubbo-go/v3/protocol" | |||
"github.com/seata/seata-go/pkg/common" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/constant" | |||
"github.com/seata/seata-go/pkg/tm" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
) | |||
var ( | |||
@@ -36,14 +36,12 @@ var ( | |||
) | |||
func InitSeataDubbo() { | |||
extension.SetFilter(common.SeataFilterKey, GetDubboTransactionFilter) | |||
extension.SetFilter(constant.SeataFilterKey, GetDubboTransactionFilter) | |||
} | |||
type Filter interface { | |||
} | |||
type Filter interface{} | |||
type dubboTransactionFilter struct { | |||
} | |||
type dubboTransactionFilter struct{} | |||
func GetDubboTransactionFilter() filter.Filter { | |||
if seataFilter == nil { | |||
@@ -61,9 +59,9 @@ func (d *dubboTransactionFilter) Invoke(ctx context.Context, invoker protocol.In | |||
if xid != "" { | |||
// dubbo go | |||
invocation.SetAttachment(common.SeataXidKey, xid) | |||
invocation.SetAttachment(constant.SeataXidKey, xid) | |||
// dubbo java | |||
invocation.SetAttachment(common.XidKey, xid) | |||
invocation.SetAttachment(constant.XidKey, xid) | |||
} else if rpcXid != xid { | |||
ctx = tm.InitSeataContext(ctx) | |||
tm.SetXID(ctx, rpcXid) | |||
@@ -85,17 +83,17 @@ func (d *dubboTransactionFilter) getRpcXid(invocation protocol.Invocation) strin | |||
} | |||
func (*dubboTransactionFilter) getDubboGoRpcXid(invocation protocol.Invocation) string { | |||
rpcXid := invocation.GetAttachmentWithDefaultValue(common.SeataXidKey, "") | |||
rpcXid := invocation.GetAttachmentWithDefaultValue(constant.SeataXidKey, "") | |||
if rpcXid == "" { | |||
rpcXid = invocation.GetAttachmentWithDefaultValue(strings.ToLower(common.SeataXidKey), "") | |||
rpcXid = invocation.GetAttachmentWithDefaultValue(strings.ToLower(constant.SeataXidKey), "") | |||
} | |||
return rpcXid | |||
} | |||
func (*dubboTransactionFilter) getDubboJavaRpcXid(invocation protocol.Invocation) string { | |||
rpcXid := invocation.GetAttachmentWithDefaultValue(common.XidKey, "") | |||
rpcXid := invocation.GetAttachmentWithDefaultValue(constant.XidKey, "") | |||
if rpcXid == "" { | |||
rpcXid = invocation.GetAttachmentWithDefaultValue(strings.ToLower(common.XidKey), "") | |||
rpcXid = invocation.GetAttachmentWithDefaultValue(strings.ToLower(constant.XidKey), "") | |||
} | |||
return rpcXid | |||
} |
@@ -19,7 +19,6 @@ package dubbo | |||
import ( | |||
"context" | |||
"testing" | |||
"dubbo.apache.org/dubbo-go/v3/filter" | |||
@@ -45,7 +44,6 @@ func TestGetDubboTransactionFilter(t *testing.T) { | |||
for _, tt := range tests { | |||
t.Run(tt.name, func(t *testing.T) { | |||
assert.Equal(t, GetDubboTransactionFilter(), tt.want) | |||
}) | |||
} | |||
} | |||
@@ -89,7 +87,6 @@ func TestDubboTransactionFilterOnResponse(t *testing.T) { | |||
du := &dubboTransactionFilter{} | |||
got := du.OnResponse(tt.args.ctx, tt.args.result, tt.args.invoker, tt.args.invocation) | |||
assert.Equal(t, got, tt.want) | |||
}) | |||
} | |||
} |
@@ -22,22 +22,22 @@ import ( | |||
"github.com/gin-gonic/gin" | |||
"github.com/seata/seata-go/pkg/common" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/constant" | |||
"github.com/seata/seata-go/pkg/tm" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
) | |||
// TransactionMiddleware filter gin invocation | |||
// NOTE: when use gin,must set gin.ContextWithFallback true when gin version >= 1.8.1 | |||
func TransactionMiddleware() gin.HandlerFunc { | |||
return func(ctx *gin.Context) { | |||
xid := ctx.GetHeader(common.XidKey) | |||
xid := ctx.GetHeader(constant.XidKey) | |||
if xid == "" { | |||
xid = ctx.GetHeader(common.XidKeyLowercase) | |||
xid = ctx.GetHeader(constant.XidKeyLowercase) | |||
} | |||
if len(xid) == 0 { | |||
log.Errorf("Gin: header not contain header: %s, global transaction xid", common.XidKey) | |||
log.Errorf("Gin: header not contain header: %s, global transaction xid", constant.XidKey) | |||
ctx.AbortWithStatus(http.StatusBadRequest) | |||
return | |||
} | |||
@@ -24,9 +24,9 @@ import ( | |||
"google.golang.org/grpc" | |||
"google.golang.org/grpc/metadata" | |||
"github.com/seata/seata-go/pkg/common" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/constant" | |||
"github.com/seata/seata-go/pkg/tm" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
) | |||
// ClientTransactionInterceptor is client interceptor of grpc, | |||
@@ -34,11 +34,11 @@ import ( | |||
// and put it in the http header. | |||
func ClientTransactionInterceptor(ctx context.Context, method string, req, reply interface{}, | |||
cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { | |||
//set the XID when intercepting a client request and release it directly when intercepting a response | |||
// set the XID when intercepting a client request and release it directly when intercepting a response | |||
if tm.IsSeataContext(ctx) { | |||
xid := tm.GetXID(ctx) | |||
header := make(map[string]string) | |||
header[common.XidKey] = xid | |||
header[constant.XidKey] = xid | |||
ctx = metadata.NewOutgoingContext(ctx, metadata.New(header)) | |||
} | |||
@@ -60,11 +60,11 @@ func ServerTransactionInterceptor(ctx context.Context, req interface{}, | |||
log.Errorf("missing grpc metadata") | |||
} | |||
var xid string | |||
if slice := md.Get(common.XidKey); slice != nil && len(slice) > 0 { | |||
if slice := md.Get(constant.XidKey); slice != nil && len(slice) > 0 { | |||
xid = slice[0] | |||
} | |||
if xid == "" { | |||
if slice := md.Get(common.XidKeyLowercase); slice != nil && len(slice) > 0 { | |||
if slice := md.Get(constant.XidKeyLowercase); slice != nil && len(slice) > 0 { | |||
xid = slice[0] | |||
} | |||
} | |||
@@ -21,8 +21,10 @@ import ( | |||
"fmt" | |||
) | |||
type BranchType int8 | |||
type BranchStatus int8 | |||
type ( | |||
BranchType int8 | |||
BranchStatus int8 | |||
) | |||
const ( | |||
BranchTypeAT BranchType = 0 | |||
@@ -18,17 +18,16 @@ | |||
package codec | |||
import ( | |||
"github.com/seata/seata-go/pkg/common/bytes" | |||
"github.com/seata/seata-go/pkg/protocol/branch" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/seata/seata-go/pkg/util/bytes" | |||
) | |||
func init() { | |||
GetCodecManager().RegisterCodec(CodecTypeSeata, &BranchCommitRequestCodec{}) | |||
} | |||
type BranchCommitRequestCodec struct { | |||
} | |||
type BranchCommitRequestCodec struct{} | |||
func (g *BranchCommitRequestCodec) Decode(in []byte) interface{} { | |||
data := message.BranchCommitRequest{} | |||
@@ -20,19 +20,18 @@ package codec | |||
import ( | |||
"math" | |||
serror "github.com/seata/seata-go/pkg/common/errors" | |||
serror "github.com/seata/seata-go/pkg/util/errors" | |||
"github.com/seata/seata-go/pkg/common/bytes" | |||
"github.com/seata/seata-go/pkg/protocol/branch" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/seata/seata-go/pkg/util/bytes" | |||
) | |||
func init() { | |||
GetCodecManager().RegisterCodec(CodecTypeSeata, &BranchCommitResponseCodec{}) | |||
} | |||
type BranchCommitResponseCodec struct { | |||
} | |||
type BranchCommitResponseCodec struct{} | |||
func (g *BranchCommitResponseCodec) Decode(in []byte) interface{} { | |||
data := message.BranchCommitResponse{} | |||
@@ -22,9 +22,9 @@ import ( | |||
"github.com/stretchr/testify/assert" | |||
serror "github.com/seata/seata-go/pkg/common/errors" | |||
model2 "github.com/seata/seata-go/pkg/protocol/branch" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
serror "github.com/seata/seata-go/pkg/util/errors" | |||
) | |||
func TestBranchCommitResponseCodec(t *testing.T) { | |||
@@ -18,7 +18,7 @@ | |||
package codec | |||
import ( | |||
"github.com/seata/seata-go/pkg/common/bytes" | |||
"github.com/seata/seata-go/pkg/util/bytes" | |||
model2 "github.com/seata/seata-go/pkg/protocol/branch" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
@@ -28,8 +28,7 @@ func init() { | |||
GetCodecManager().RegisterCodec(CodecTypeSeata, &BranchRegisterRequestCodec{}) | |||
} | |||
type BranchRegisterRequestCodec struct { | |||
} | |||
type BranchRegisterRequestCodec struct{} | |||
func (g *BranchRegisterRequestCodec) Decode(in []byte) interface{} { | |||
data := message.BranchRegisterRequest{} | |||
@@ -20,17 +20,16 @@ package codec | |||
import ( | |||
"math" | |||
"github.com/seata/seata-go/pkg/common/bytes" | |||
serror "github.com/seata/seata-go/pkg/common/errors" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/seata/seata-go/pkg/util/bytes" | |||
serror "github.com/seata/seata-go/pkg/util/errors" | |||
) | |||
func init() { | |||
GetCodecManager().RegisterCodec(CodecTypeSeata, &BranchRegisterResponseCodec{}) | |||
} | |||
type BranchRegisterResponseCodec struct { | |||
} | |||
type BranchRegisterResponseCodec struct{} | |||
func (g *BranchRegisterResponseCodec) Decode(in []byte) interface{} { | |||
data := message.BranchRegisterResponse{} | |||
@@ -20,7 +20,7 @@ package codec | |||
import ( | |||
"testing" | |||
serror "github.com/seata/seata-go/pkg/common/errors" | |||
serror "github.com/seata/seata-go/pkg/util/errors" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/stretchr/testify/assert" | |||
@@ -18,17 +18,16 @@ | |||
package codec | |||
import ( | |||
"github.com/seata/seata-go/pkg/common/bytes" | |||
"github.com/seata/seata-go/pkg/protocol/branch" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/seata/seata-go/pkg/util/bytes" | |||
) | |||
func init() { | |||
GetCodecManager().RegisterCodec(CodecTypeSeata, &BranchRollbackRequestCodec{}) | |||
} | |||
type BranchRollbackRequestCodec struct { | |||
} | |||
type BranchRollbackRequestCodec struct{} | |||
func (g *BranchRollbackRequestCodec) Decode(in []byte) interface{} { | |||
data := message.BranchRollbackRequest{} | |||
@@ -20,18 +20,17 @@ package codec | |||
import ( | |||
"math" | |||
"github.com/seata/seata-go/pkg/common/bytes" | |||
serror "github.com/seata/seata-go/pkg/common/errors" | |||
"github.com/seata/seata-go/pkg/protocol/branch" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/seata/seata-go/pkg/util/bytes" | |||
serror "github.com/seata/seata-go/pkg/util/errors" | |||
) | |||
func init() { | |||
GetCodecManager().RegisterCodec(CodecTypeSeata, &BranchRollbackResponseCodec{}) | |||
} | |||
type BranchRollbackResponseCodec struct { | |||
} | |||
type BranchRollbackResponseCodec struct{} | |||
func (g *BranchRollbackResponseCodec) Decode(in []byte) interface{} { | |||
data := message.BranchRollbackResponse{} | |||
@@ -20,7 +20,7 @@ package codec | |||
import ( | |||
"testing" | |||
serror "github.com/seata/seata-go/pkg/common/errors" | |||
serror "github.com/seata/seata-go/pkg/util/errors" | |||
model2 "github.com/seata/seata-go/pkg/protocol/branch" | |||
@@ -21,8 +21,8 @@ import ( | |||
"bytes" | |||
"sync" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
"vimagination.zapto.org/byteio" | |||
) | |||
@@ -93,7 +93,7 @@ func (c *CodecManager) Decode(codecType CodecType, in []byte) interface{} { | |||
} | |||
func (c *CodecManager) Encode(codecType CodecType, in interface{}) []byte { | |||
var result = make([]byte, 0) | |||
result := make([]byte, 0) | |||
msg := in.(message.MessageTypeAware) | |||
typeCode := msg.GetTypeCode() | |||
@@ -18,12 +18,11 @@ | |||
package codec | |||
import ( | |||
"github.com/seata/seata-go/pkg/common/bytes" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/seata/seata-go/pkg/util/bytes" | |||
) | |||
type CommonGlobalEndRequestCodec struct { | |||
} | |||
type CommonGlobalEndRequestCodec struct{} | |||
func (c *CommonGlobalEndRequestCodec) Encode(in interface{}) []byte { | |||
data, _ := in.(message.AbstractGlobalEndRequest) | |||
@@ -20,13 +20,12 @@ package codec | |||
import ( | |||
"math" | |||
"github.com/seata/seata-go/pkg/common/bytes" | |||
serror "github.com/seata/seata-go/pkg/common/errors" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/seata/seata-go/pkg/util/bytes" | |||
serror "github.com/seata/seata-go/pkg/util/errors" | |||
) | |||
type CommonGlobalEndResponseCodec struct { | |||
} | |||
type CommonGlobalEndResponseCodec struct{} | |||
func (c *CommonGlobalEndResponseCodec) Encode(in interface{}) []byte { | |||
data := in.(message.AbstractGlobalEndResponse) | |||
@@ -18,12 +18,11 @@ | |||
package codec | |||
import ( | |||
"github.com/seata/seata-go/pkg/common/bytes" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/seata/seata-go/pkg/util/bytes" | |||
) | |||
type AbstractIdentifyRequestCodec struct { | |||
} | |||
type AbstractIdentifyRequestCodec struct{} | |||
func (c *AbstractIdentifyRequestCodec) Encode(in interface{}) []byte { | |||
data := in.(message.AbstractIdentifyRequest) | |||
@@ -18,12 +18,11 @@ | |||
package codec | |||
import ( | |||
"github.com/seata/seata-go/pkg/common/bytes" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/seata/seata-go/pkg/util/bytes" | |||
) | |||
type AbstractIdentifyResponseCodec struct { | |||
} | |||
type AbstractIdentifyResponseCodec struct{} | |||
func (c *AbstractIdentifyResponseCodec) Encode(in interface{}) []byte { | |||
data := in.(message.AbstractIdentifyResponse) | |||
@@ -20,16 +20,15 @@ package codec | |||
import ( | |||
"time" | |||
"github.com/seata/seata-go/pkg/common/bytes" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/seata/seata-go/pkg/util/bytes" | |||
) | |||
func init() { | |||
GetCodecManager().RegisterCodec(CodecTypeSeata, &GlobalBeginRequestCodec{}) | |||
} | |||
type GlobalBeginRequestCodec struct { | |||
} | |||
type GlobalBeginRequestCodec struct{} | |||
func (c *GlobalBeginRequestCodec) Encode(in interface{}) []byte { | |||
data := in.(message.GlobalBeginRequest) | |||
@@ -20,17 +20,16 @@ package codec | |||
import ( | |||
"math" | |||
"github.com/seata/seata-go/pkg/common/bytes" | |||
serror "github.com/seata/seata-go/pkg/common/errors" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/seata/seata-go/pkg/util/bytes" | |||
serror "github.com/seata/seata-go/pkg/util/errors" | |||
) | |||
func init() { | |||
GetCodecManager().RegisterCodec(CodecTypeSeata, &GlobalBeginResponseCodec{}) | |||
} | |||
type GlobalBeginResponseCodec struct { | |||
} | |||
type GlobalBeginResponseCodec struct{} | |||
func (c *GlobalBeginResponseCodec) Encode(in interface{}) []byte { | |||
data := in.(message.GlobalBeginResponse) | |||
@@ -22,8 +22,8 @@ import ( | |||
"github.com/stretchr/testify/assert" | |||
serror "github.com/seata/seata-go/pkg/common/errors" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
serror "github.com/seata/seata-go/pkg/util/errors" | |||
) | |||
func TestGlobalBeginResponseCodec(t *testing.T) { | |||
@@ -18,8 +18,8 @@ | |||
package codec | |||
import ( | |||
"github.com/seata/seata-go/pkg/common/bytes" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/seata/seata-go/pkg/util/bytes" | |||
) | |||
type GlobalReportRequestCodec struct { | |||
@@ -18,16 +18,15 @@ | |||
package codec | |||
import ( | |||
"github.com/seata/seata-go/pkg/common/bytes" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/seata/seata-go/pkg/util/bytes" | |||
) | |||
func init() { | |||
GetCodecManager().RegisterCodec(CodecTypeSeata, &RegisterRMRequestCodec{}) | |||
} | |||
type RegisterRMRequestCodec struct { | |||
} | |||
type RegisterRMRequestCodec struct{} | |||
func (g *RegisterRMRequestCodec) Decode(in []byte) interface{} { | |||
data := message.RegisterRMRequest{} | |||
@@ -29,7 +29,7 @@ func TestRegisterRMResponseCodec(t *testing.T) { | |||
AbstractIdentifyResponse: message.AbstractIdentifyResponse{ | |||
AbstractResultMessage: message.AbstractResultMessage{ | |||
ResultCode: message.ResultCodeFailed, | |||
//Msg: "TestMsg", | |||
// Msg: "TestMsg", | |||
}, | |||
Version: "V1,0", | |||
Identified: false, | |||
@@ -18,8 +18,8 @@ | |||
package message | |||
import ( | |||
"github.com/seata/seata-go/pkg/common/errors" | |||
model2 "github.com/seata/seata-go/pkg/protocol/branch" | |||
"github.com/seata/seata-go/pkg/util/errors" | |||
) | |||
type AbstractTransactionResponse struct { | |||
@@ -22,9 +22,9 @@ import ( | |||
gxtime "github.com/dubbogo/gost/time" | |||
"github.com/pkg/errors" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/protocol/codec" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
"go.uber.org/atomic" | |||
) | |||
@@ -59,7 +59,7 @@ func TestGettyRemotingClient_SendAsyncResponse(t *testing.T) { | |||
// TestGettyRemotingClient_SendAsyncRequest unit test for SendAsyncRequest function | |||
func TestGettyRemotingClient_SendAsyncRequest(t *testing.T) { | |||
var tests = []struct { | |||
tests := []struct { | |||
name string | |||
message interface{} | |||
}{ | |||
@@ -86,7 +86,7 @@ func TestGettyRemotingClient_SendAsyncRequest(t *testing.T) { | |||
// Test_syncCallback unit test for syncCallback function | |||
func Test_syncCallback(t *testing.T) { | |||
var tests = []struct { | |||
tests := []struct { | |||
name string | |||
respMsg *message.MessageFuture | |||
reqMsg message.RpcMessage | |||
@@ -133,7 +133,7 @@ func Test_syncCallback(t *testing.T) { | |||
// Test_asyncCallback unit test for asyncCallback function | |||
func Test_asyncCallback(t *testing.T) { | |||
var tests = []struct { | |||
tests := []struct { | |||
name string | |||
respMsg *message.MessageFuture | |||
reqMsg message.RpcMessage | |||
@@ -23,8 +23,8 @@ import ( | |||
getty "github.com/apache/dubbo-getty" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
) | |||
const ( | |||
@@ -123,9 +123,9 @@ func (g *GettyRemoting) NotifyRpcMessageResponse(rpcMessage message.RpcMessage) | |||
if messageFuture != nil { | |||
messageFuture.Response = rpcMessage.Body | |||
// todo add messageFuture.Err | |||
//messageFuture.Err = rpcMessage.Err | |||
// messageFuture.Err = rpcMessage.Err | |||
messageFuture.Done <- struct{}{} | |||
//client.msgFutures.Delete(rpcMessage.RequestID) | |||
// client.msgFutures.Delete(rpcMessage.RequestID) | |||
} else { | |||
log.Infof("msg: {} is not found in msgFutures.", rpcMessage.ID) | |||
} | |||
@@ -25,7 +25,7 @@ import ( | |||
) | |||
func TestGettyRemoting_GetMessageFuture(t *testing.T) { | |||
var tests = []struct { | |||
tests := []struct { | |||
name string | |||
msgID int32 | |||
messageFuture *message.MessageFuture | |||
@@ -61,7 +61,7 @@ func TestGettyRemoting_GetMessageFuture(t *testing.T) { | |||
} | |||
func TestGettyRemoting_RemoveMessageFuture(t *testing.T) { | |||
var tests = []struct { | |||
tests := []struct { | |||
name string | |||
msgID int32 | |||
messageFuture *message.MessageFuture | |||
@@ -90,7 +90,7 @@ func TestGettyRemoting_RemoveMessageFuture(t *testing.T) { | |||
} | |||
func TestGettyRemoting_GetMergedMessage(t *testing.T) { | |||
var tests = []struct { | |||
tests := []struct { | |||
name string | |||
msgID int32 | |||
mergedWarpMessage *message.MergedWarpMessage | |||
@@ -124,7 +124,7 @@ func TestGettyRemoting_GetMergedMessage(t *testing.T) { | |||
} | |||
func TestGettyRemoting_RemoveMergedMessageFuture(t *testing.T) { | |||
var tests = []struct { | |||
tests := []struct { | |||
name string | |||
msgID int32 | |||
mergedWarpMessage *message.MergedWarpMessage | |||
@@ -22,11 +22,11 @@ import ( | |||
"sync" | |||
getty "github.com/apache/dubbo-getty" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/config" | |||
"github.com/seata/seata-go/pkg/protocol/codec" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/seata/seata-go/pkg/remoting/processor" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
"go.uber.org/atomic" | |||
) | |||
@@ -20,7 +20,7 @@ package getty | |||
import ( | |||
"fmt" | |||
"github.com/seata/seata-go/pkg/common/bytes" | |||
"github.com/seata/seata-go/pkg/util/bytes" | |||
getty "github.com/apache/dubbo-getty" | |||
"github.com/pkg/errors" | |||
@@ -111,7 +111,7 @@ func (p *RpcPackageHandler) Read(ss getty.Session, data []byte) (interface{}, in | |||
return nil, int(header.TotalLength), nil | |||
} | |||
//r := byteio.BigEndianReader{Reader: bytes.NewReader(data)} | |||
// r := byteio.BigEndianReader{Reader: bytes.NewReader(data)} | |||
rpcMessage := message.RpcMessage{ | |||
Codec: header.CodecType, | |||
ID: int32(header.RequestID), | |||
@@ -27,8 +27,8 @@ import ( | |||
gxsync "github.com/dubbogo/gost/sync" | |||
"github.com/pkg/errors" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/config" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
) | |||
type RpcClient struct { | |||
@@ -30,9 +30,7 @@ const ( | |||
checkAliveInternal = 100 | |||
) | |||
var ( | |||
sessionManager = newSessionManager() | |||
) | |||
var sessionManager = newSessionManager() | |||
type SessionManager struct { | |||
// serverAddress -> rpc_client.Session -> bool | |||
@@ -20,7 +20,7 @@ package client | |||
import ( | |||
"context" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/seata/seata-go/pkg/remoting/getty" | |||
@@ -27,10 +27,10 @@ import ( | |||
func TestClientHeartBeatProcessor(t *testing.T) { | |||
// testcases | |||
var tests = []struct { | |||
tests := []struct { | |||
name string // testcase name | |||
rpcMsg message.RpcMessage // rpcMessage case | |||
wantErr bool //want testcase err or not | |||
wantErr bool // want testcase err or not | |||
}{ | |||
{ | |||
name: "chb-testcase1", | |||
@@ -82,5 +82,4 @@ func TestClientHeartBeatProcessor(t *testing.T) { | |||
} | |||
}) | |||
} | |||
} |
@@ -20,8 +20,8 @@ package client | |||
import ( | |||
"context" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
"github.com/seata/seata-go/pkg/remoting/getty" | |||
) | |||
@@ -42,8 +42,7 @@ func init() { | |||
getty.GetGettyClientHandlerInstance().RegisterProcessor(message.MessageTypeRegCltResult, clientOnResponseProcessor) | |||
} | |||
type clientOnResponseProcessor struct { | |||
} | |||
type clientOnResponseProcessor struct{} | |||
func (f *clientOnResponseProcessor) Process(ctx context.Context, rpcMessage message.RpcMessage) error { | |||
log.Infof("the rm client received clientOnResponse msg %#v from tc server.", rpcMessage) | |||
@@ -27,10 +27,10 @@ import ( | |||
func TestClientOnResponseProcessor(t *testing.T) { | |||
// testcases | |||
var tests = []struct { | |||
tests := []struct { | |||
name string // testcase name | |||
rpcMsg message.RpcMessage // rpcMessage case | |||
wantErr bool //want testcase err or not | |||
wantErr bool // want testcase err or not | |||
}{ | |||
{ | |||
name: "cor-testcase1-mergeResult", | |||
@@ -106,5 +106,4 @@ func TestClientOnResponseProcessor(t *testing.T) { | |||
} | |||
}) | |||
} | |||
} |
@@ -20,8 +20,8 @@ package client | |||
import ( | |||
"context" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
"github.com/seata/seata-go/pkg/remoting/getty" | |||
"github.com/seata/seata-go/pkg/rm" | |||
@@ -32,8 +32,7 @@ func init() { | |||
getty.GetGettyClientHandlerInstance().RegisterProcessor(message.MessageTypeBranchCommit, rmBranchCommitProcessor) | |||
} | |||
type rmBranchCommitProcessor struct { | |||
} | |||
type rmBranchCommitProcessor struct{} | |||
func (f *rmBranchCommitProcessor) Process(ctx context.Context, rpcMessage message.RpcMessage) error { | |||
log.Infof("the rm client received rmBranchCommit msg %#v from tc server.", rpcMessage) | |||
@@ -29,12 +29,11 @@ import ( | |||
) | |||
func TestRmBranchCommitProcessor(t *testing.T) { | |||
// testcases | |||
var tests = []struct { | |||
tests := []struct { | |||
name string // testcase name | |||
rpcMsg message.RpcMessage // rpcMessage case | |||
wantErr bool //want testcase err or not | |||
wantErr bool // want testcase err or not | |||
}{ | |||
{ | |||
name: "rbc-testcase1-failure", | |||
@@ -78,5 +77,4 @@ func TestRmBranchCommitProcessor(t *testing.T) { | |||
} | |||
}) | |||
} | |||
} |
@@ -20,8 +20,8 @@ package client | |||
import ( | |||
"context" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
"github.com/seata/seata-go/pkg/remoting/getty" | |||
"github.com/seata/seata-go/pkg/rm" | |||
@@ -32,8 +32,7 @@ func init() { | |||
getty.GetGettyClientHandlerInstance().RegisterProcessor(message.MessageTypeBranchRollback, rmBranchRollbackProcessor) | |||
} | |||
type rmBranchRollbackProcessor struct { | |||
} | |||
type rmBranchRollbackProcessor struct{} | |||
func (f *rmBranchRollbackProcessor) Process(ctx context.Context, rpcMessage message.RpcMessage) error { | |||
log.Infof("the rm client received rmBranchRollback msg %#v from tc server.", rpcMessage) | |||
@@ -29,12 +29,11 @@ import ( | |||
) | |||
func TestRmBranchRollbackProcessor(t *testing.T) { | |||
// testcases | |||
var tests = []struct { | |||
tests := []struct { | |||
name string // testcase name | |||
rpcMsg message.RpcMessage // rpcMessage case | |||
wantErr bool //want testcase err or not | |||
wantErr bool // want testcase err or not | |||
}{ | |||
{ | |||
name: "rbr-testcase1-failure", | |||
@@ -78,5 +77,4 @@ func TestRmBranchRollbackProcessor(t *testing.T) { | |||
} | |||
}) | |||
} | |||
} |
@@ -27,7 +27,6 @@ import ( | |||
) | |||
func TestGetRmCacheInstance(t *testing.T) { | |||
ctl := gomock.NewController(t) | |||
mockResourceManager := NewMockResourceManager(ctl) | |||
@@ -43,5 +42,4 @@ func TestGetRmCacheInstance(t *testing.T) { | |||
actual := GetRmCacheInstance().GetResourceManager(branch.BranchTypeTCC) | |||
assert.Equalf(t, mockResourceManager, actual, "GetRmCacheInstance()") | |||
}) | |||
} |
@@ -22,10 +22,10 @@ import ( | |||
"github.com/pkg/errors" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/protocol/branch" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/seata/seata-go/pkg/remoting/getty" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
) | |||
var ( | |||
@@ -33,9 +33,7 @@ var ( | |||
onceGettyRemoting = &sync.Once{} | |||
) | |||
var ( | |||
ErrBranchReportResponseFault = errors.New("branch report response fault") | |||
) | |||
var ErrBranchReportResponseFault = errors.New("branch report response fault") | |||
func GetRMRemotingInstance() *RMRemoting { | |||
if rmRemoting == nil { | |||
@@ -46,10 +44,9 @@ func GetRMRemotingInstance() *RMRemoting { | |||
return rmRemoting | |||
} | |||
type RMRemoting struct { | |||
} | |||
type RMRemoting struct{} | |||
//BranchRegister Register branch of global transaction | |||
// BranchRegister Register branch of global transaction | |||
func (r *RMRemoting) BranchRegister(param BranchRegisterParam) (int64, error) { | |||
request := message.BranchRegisterRequest{ | |||
Xid: param.Xid, | |||
@@ -98,7 +95,7 @@ func (r *RMRemoting) LockQuery(param LockQueryParam) (bool, error) { | |||
func (r *RMRemoting) RegisterResource(resource Resource) error { | |||
req := message.RegisterRMRequest{ | |||
AbstractIdentifyRequest: message.AbstractIdentifyRequest{ | |||
//todo replace with config | |||
// todo replace with config | |||
Version: "1.5.2", | |||
ApplicationId: "tcc-sample", | |||
TransactionServiceGroup: "my_test_tx_group", | |||
@@ -22,11 +22,11 @@ import ( | |||
"database/sql" | |||
"fmt" | |||
"github.com/seata/seata-go/pkg/common/errors" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/rm/tcc/fence/enum" | |||
"github.com/seata/seata-go/pkg/rm/tcc/fence/handler" | |||
"github.com/seata/seata-go/pkg/tm" | |||
"github.com/seata/seata-go/pkg/util/errors" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
) | |||
// WithFence This method is a suspended API interface that asserts the phase timing of a transaction | |||
@@ -23,7 +23,7 @@ import ( | |||
"fmt" | |||
"testing" | |||
"github.com/seata/seata-go/pkg/common/errors" | |||
"github.com/seata/seata-go/pkg/util/errors" | |||
"github.com/DATA-DOG/go-sqlmock" | |||
"github.com/stretchr/testify/assert" | |||
@@ -25,12 +25,12 @@ import ( | |||
"sync" | |||
"time" | |||
seataErrors "github.com/seata/seata-go/pkg/common/errors" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/rm/tcc/fence/enum" | |||
"github.com/seata/seata-go/pkg/rm/tcc/fence/store/db/dao" | |||
"github.com/seata/seata-go/pkg/rm/tcc/fence/store/db/model" | |||
"github.com/seata/seata-go/pkg/tm" | |||
seataErrors "github.com/seata/seata-go/pkg/util/errors" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
) | |||
type tccFenceWrapperHandler struct { | |||
@@ -138,7 +138,6 @@ func (handler *tccFenceWrapperHandler) RollbackFence(ctx context.Context, tx *sq | |||
branchId := tm.GetBusinessActionContext(ctx).BranchId | |||
actionName := tm.GetBusinessActionContext(ctx).ActionName | |||
fenceDo, err := handler.tccFenceDao.QueryTCCFenceDO(tx, xid, branchId) | |||
if err != nil { | |||
return seataErrors.NewTccFenceError(seataErrors.RollbackFenceError, | |||
fmt.Sprintf(" rollback fence method failed. xid= %s, branchId= %d ", xid, branchId), | |||
@@ -26,10 +26,10 @@ import ( | |||
"github.com/go-sql-driver/mysql" | |||
"github.com/seata/seata-go/pkg/common/errors" | |||
"github.com/seata/seata-go/pkg/rm/tcc/fence/enum" | |||
"github.com/seata/seata-go/pkg/rm/tcc/fence/store/db/model" | |||
sql2 "github.com/seata/seata-go/pkg/rm/tcc/fence/store/db/sql" | |||
"github.com/seata/seata-go/pkg/util/errors" | |||
) | |||
var ( | |||
@@ -45,7 +45,6 @@ func GetTccFenceStoreDatabaseMapper() *TccFenceStoreDatabaseMapper { | |||
}) | |||
} | |||
return tccFenceStoreDatabaseMapper | |||
} | |||
func (t *TccFenceStoreDatabaseMapper) InitLogTableName() { | |||
@@ -49,7 +49,6 @@ func TestTccFenceStoreDatabaseMapper_InsertTCCFenceDO(t *testing.T) { | |||
Status: enum.StatusSuspended, | |||
} | |||
db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) | |||
if err != nil { | |||
t.Fatalf("open db failed msg: %v", err) | |||
} | |||
@@ -46,7 +46,6 @@ var ( | |||
func GetInsertLocalTCCLogSQL(localTccTable string) string { | |||
return fmt.Sprintf(insertLocalTccLog, localTccTable) | |||
} | |||
func GetQuerySQLByBranchIdAndXid(localTccTable string) string { | |||
@@ -59,7 +58,6 @@ func GetUpdateStatusSQLByBranchIdAndXid(localTccTable string) string { | |||
func GetDeleteSQLByBranchIdAndXid(localTccTable string) string { | |||
return fmt.Sprintf(deleteByBranchIdAndXid, localTccTable) | |||
} | |||
func GetDeleteSQLByMdfDateAndStatus(localTccTable string) string { | |||
@@ -23,12 +23,12 @@ import ( | |||
"fmt" | |||
"sync" | |||
"github.com/seata/seata-go/pkg/common" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/constant" | |||
"github.com/seata/seata-go/pkg/protocol/branch" | |||
"github.com/seata/seata-go/pkg/rm" | |||
"github.com/seata/seata-go/pkg/rm/tcc/fence/enum" | |||
"github.com/seata/seata-go/pkg/tm" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
) | |||
var ( | |||
@@ -102,12 +102,12 @@ func (t *TCCResourceManager) BranchReport(ctx context.Context, param rm.BranchRe | |||
// LockQuery query lock status of transaction branch | |||
func (t *TCCResourceManager) LockQuery(ctx context.Context, param rm.LockQueryParam) (bool, error) { | |||
//TODO implement me | |||
// TODO implement me | |||
panic("implement me") | |||
} | |||
func (t *TCCResourceManager) UnregisterResource(resource rm.Resource) error { | |||
//TODO implement me | |||
// TODO implement me | |||
panic("implement me") | |||
} | |||
@@ -149,13 +149,13 @@ func (t *TCCResourceManager) BranchCommit(ctx context.Context, branchResource rm | |||
} | |||
func (t *TCCResourceManager) getBusinessActionContext(xid string, branchID int64, resourceID string, applicationData []byte) *tm.BusinessActionContext { | |||
var actionContextMap = make(map[string]interface{}, 2) | |||
actionContextMap := make(map[string]interface{}, 2) | |||
if len(applicationData) > 0 { | |||
var tccContext map[string]interface{} | |||
if err := json.Unmarshal(applicationData, &tccContext); err != nil { | |||
panic("application data failed to unmarshl as json") | |||
} | |||
if v, ok := tccContext[common.ActionContext]; ok { | |||
if v, ok := tccContext[constant.ActionContext]; ok { | |||
actionContextMap = v.(map[string]interface{}) | |||
} | |||
} | |||
@@ -24,16 +24,16 @@ import ( | |||
"sync" | |||
"time" | |||
gostnet "github.com/dubbogo/gost/net" | |||
"github.com/pkg/errors" | |||
"github.com/seata/seata-go/pkg/common" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/common/net" | |||
"github.com/seata/seata-go/pkg/common/types" | |||
"github.com/seata/seata-go/pkg/constant" | |||
"github.com/seata/seata-go/pkg/protocol/branch" | |||
"github.com/seata/seata-go/pkg/rm" | |||
"github.com/seata/seata-go/pkg/rm/tcc/fence/enum" | |||
"github.com/seata/seata-go/pkg/tm" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
"github.com/seata/seata-go/pkg/util/reflectx" | |||
) | |||
type TCCServiceProxy struct { | |||
@@ -73,7 +73,7 @@ func (t *TCCServiceProxy) Reference() string { | |||
if t.referenceName != "" { | |||
return t.referenceName | |||
} | |||
return types.GetReference(t.TCCResource.TwoPhaseAction.GetTwoPhaseService()) | |||
return reflectx.GetReference(t.TCCResource.TwoPhaseAction.GetTwoPhaseService()) | |||
} | |||
func (t *TCCServiceProxy) Prepare(ctx context.Context, params interface{}) (interface{}, error) { | |||
@@ -104,7 +104,7 @@ func (t *TCCServiceProxy) registeBranch(ctx context.Context, params interface{}) | |||
} | |||
applicationData, _ := json.Marshal(map[string]interface{}{ | |||
common.ActionContext: actionContext, | |||
constant.ActionContext: actionContext, | |||
}) | |||
branchId, err := rm.GetRMRemotingInstance().BranchRegister(rm.BranchRegisterParam{ | |||
BranchType: branch.BranchTypeTCC, | |||
@@ -126,12 +126,12 @@ func (t *TCCServiceProxy) registeBranch(ctx context.Context, params interface{}) | |||
// initActionContext init action context | |||
func (t *TCCServiceProxy) initActionContext(params interface{}) map[string]interface{} { | |||
actionContext := t.getActionContextParameters(params) | |||
actionContext[common.ActionStartTime] = time.Now().UnixNano() / 1e6 | |||
actionContext[common.PrepareMethod] = t.TCCResource.TwoPhaseAction.GetPrepareMethodName() | |||
actionContext[common.CommitMethod] = t.TCCResource.TwoPhaseAction.GetCommitMethodName() | |||
actionContext[common.RollbackMethod] = t.TCCResource.TwoPhaseAction.GetRollbackMethodName() | |||
actionContext[common.ActionName] = t.TCCResource.TwoPhaseAction.GetActionName() | |||
actionContext[common.HostName] = net.GetLocalIp() | |||
actionContext[constant.ActionStartTime] = time.Now().UnixNano() / 1e6 | |||
actionContext[constant.PrepareMethod] = t.TCCResource.TwoPhaseAction.GetPrepareMethodName() | |||
actionContext[constant.CommitMethod] = t.TCCResource.TwoPhaseAction.GetCommitMethodName() | |||
actionContext[constant.RollbackMethod] = t.TCCResource.TwoPhaseAction.GetRollbackMethodName() | |||
actionContext[constant.ActionName] = t.TCCResource.TwoPhaseAction.GetActionName() | |||
actionContext[constant.HostName], _ = gostnet.GetLocalIP() | |||
return actionContext | |||
} | |||
@@ -155,7 +155,7 @@ func (t *TCCServiceProxy) getActionContextParameters(params interface{}) map[str | |||
} | |||
structField := typ.Field(i) | |||
// skip ignored field | |||
tagVal, hasTag := structField.Tag.Lookup(common.TccBusinessActionContextParameter) | |||
tagVal, hasTag := structField.Tag.Lookup(constant.TccBusinessActionContextParameter) | |||
if !hasTag || tagVal == `-` || tagVal == "" { | |||
continue | |||
} | |||
@@ -246,8 +246,8 @@ func (t *TCCServiceProxy) GetTransactionInfo() tm.TransactionInfo { | |||
return tm.TransactionInfo{ | |||
TimeOut: 10000, | |||
Name: t.GetActionName(), | |||
//Propagation, Propagation | |||
//LockRetryInternal, int64 | |||
//LockRetryTimes int64 | |||
// Propagation, Propagation | |||
// LockRetryInternal, int64 | |||
// LockRetryTimes int64 | |||
} | |||
} |
@@ -27,13 +27,13 @@ import ( | |||
"time" | |||
"github.com/agiledragon/gomonkey" | |||
gostnet "github.com/dubbogo/gost/net" | |||
"github.com/seata/seata-go/pkg/constant" | |||
"github.com/stretchr/testify/assert" | |||
"github.com/seata/seata-go/pkg/common" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/common/net" | |||
"github.com/seata/seata-go/pkg/rm" | |||
"github.com/seata/seata-go/pkg/tm" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
"github.com/seata/seata-go/sample/tcc/dubbo/client/service" | |||
testdata2 "github.com/seata/seata-go/testdata" | |||
) | |||
@@ -93,15 +93,16 @@ func TestInitActionContext(t *testing.T) { | |||
}) | |||
defer p.Reset() | |||
result := testTccServiceProxy.initActionContext(param) | |||
localIp, _ := gostnet.GetLocalIP() | |||
assert.Equal(t, map[string]interface{}{ | |||
"addr": "Earth", | |||
"Other": []int8{1, 2, 3}, | |||
common.ActionStartTime: now.UnixNano() / 1e6, | |||
common.PrepareMethod: "Prepare", | |||
common.CommitMethod: "Commit", | |||
common.RollbackMethod: "Rollback", | |||
common.ActionName: testdata2.ActionName, | |||
common.HostName: net.GetLocalIp(), | |||
"addr": "Earth", | |||
"Other": []int8{1, 2, 3}, | |||
constant.ActionStartTime: now.UnixNano() / 1e6, | |||
constant.PrepareMethod: "Prepare", | |||
constant.CommitMethod: "Commit", | |||
constant.RollbackMethod: "Rollback", | |||
constant.ActionName: testdata2.ActionName, | |||
constant.HostName: localIp, | |||
}, result) | |||
} | |||
@@ -130,7 +131,7 @@ func TestGetActionContextParameters(t *testing.T) { | |||
} | |||
func TestGetOrCreateBusinessActionContext(t *testing.T) { | |||
var tests = []struct { | |||
tests := []struct { | |||
param interface{} | |||
want tm.BusinessActionContext | |||
}{ | |||
@@ -151,7 +152,8 @@ func TestGetOrCreateBusinessActionContext(t *testing.T) { | |||
"age": 12, | |||
}, | |||
}, | |||
}, { | |||
}, | |||
{ | |||
param: &tm.BusinessActionContext{ | |||
ActionContext: map[string]interface{}{ | |||
"name": "Jack", | |||
@@ -164,7 +166,8 @@ func TestGetOrCreateBusinessActionContext(t *testing.T) { | |||
"age": 13, | |||
}, | |||
}, | |||
}, { | |||
}, | |||
{ | |||
param: struct { | |||
Context *tm.BusinessActionContext | |||
}{ | |||
@@ -250,17 +253,23 @@ func TestNewTCCServiceProxy(t *testing.T) { | |||
want *TCCServiceProxy | |||
wantErr assert.ErrorAssertionFunc | |||
}{ | |||
{"test1", args1, &TCCServiceProxy{ | |||
TCCResource: &TCCResource{ | |||
ResourceGroupId: `default:"DEFAULT"`, | |||
AppName: "seata-go-mock-app-name", | |||
TwoPhaseAction: twoPhaseAction1}}, assert.NoError, | |||
{ | |||
"test1", args1, &TCCServiceProxy{ | |||
TCCResource: &TCCResource{ | |||
ResourceGroupId: `default:"DEFAULT"`, | |||
AppName: "seata-go-mock-app-name", | |||
TwoPhaseAction: twoPhaseAction1, | |||
}, | |||
}, assert.NoError, | |||
}, | |||
{"test2", args2, &TCCServiceProxy{ | |||
TCCResource: &TCCResource{ | |||
ResourceGroupId: `default:"DEFAULT"`, | |||
AppName: "seata-go-mock-app-name", | |||
TwoPhaseAction: twoPhaseAction2}}, assert.NoError, | |||
{ | |||
"test2", args2, &TCCServiceProxy{ | |||
TCCResource: &TCCResource{ | |||
ResourceGroupId: `default:"DEFAULT"`, | |||
AppName: "seata-go-mock-app-name", | |||
TwoPhaseAction: twoPhaseAction2, | |||
}, | |||
}, assert.NoError, | |||
}, | |||
} | |||
@@ -290,7 +299,8 @@ func TestTCCGetTransactionInfo(t1 *testing.T) { | |||
fields fields | |||
want tm.TransactionInfo | |||
}{ | |||
"test1", fields{ | |||
"test1", | |||
fields{ | |||
referenceName: "test1", | |||
registerResourceOnce: sync.Once{}, | |||
TCCResource: &TCCResource{ | |||
@@ -310,7 +320,6 @@ func TestTCCGetTransactionInfo(t1 *testing.T) { | |||
} | |||
assert.Equalf(t1, tests.want, t.GetTransactionInfo(), "GetTransactionInfo()") | |||
}) | |||
} | |||
func GetTestTwoPhaseService() rm.TwoPhaseInterface { | |||
@@ -266,7 +266,6 @@ func getCommitMethod(t reflect.StructField, f reflect.Value) (string, *reflect.V | |||
return "", nil, false | |||
} | |||
return t.Name, &f, true | |||
} | |||
func getRollbackMethod(t reflect.StructField, f reflect.Value) (string, *reflect.Value, bool) { | |||
@@ -174,8 +174,7 @@ func TestParseTwoPhaseActionExecuteMethod1(t *testing.T) { | |||
assert.Equal(t, "twoPhaseDemoService", twoPhaseService.GetActionName()) | |||
} | |||
type TwoPhaseDemoService2 struct { | |||
} | |||
type TwoPhaseDemoService2 struct{} | |||
func (t *TwoPhaseDemoService2) Prepare(ctx context.Context, params interface{}) (bool, error) { | |||
return false, fmt.Errorf("execute two phase prepare method, param %v", params) | |||
@@ -211,7 +210,6 @@ func TestParseTwoPhaseActionExecuteMethod2(t *testing.T) { | |||
} | |||
func TestIsTwoPhaseAction(t *testing.T) { | |||
userProvider := &testdata2.TestTwoPhaseService{} | |||
userProvider1 := service.UserProviderInstance | |||
type args struct { | |||
@@ -232,11 +230,9 @@ func TestIsTwoPhaseAction(t *testing.T) { | |||
assert.Equalf(t, tt.want, IsTwoPhaseAction(tt.args.v), "IsTwoPhaseAction(%v)", tt.args.v) | |||
}) | |||
} | |||
} | |||
func TestParseTwoPhaseAction(t *testing.T) { | |||
type args struct { | |||
v interface{} | |||
} | |||
@@ -259,7 +255,6 @@ func TestParseTwoPhaseAction(t *testing.T) { | |||
} | |||
assert.Equalf(t, tests.want.GetTwoPhaseService(), got.GetTwoPhaseService(), "ParseTwoPhaseAction(%v)", tests.args.v) | |||
}) | |||
} | |||
func TestParseTwoPhaseActionByInterface(t *testing.T) { | |||
@@ -25,10 +25,10 @@ import ( | |||
"github.com/pkg/errors" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/seata/seata-go/pkg/remoting/getty" | |||
"github.com/seata/seata-go/pkg/util/backoff" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
) | |||
type GlobalTransaction struct { | |||
@@ -52,8 +52,7 @@ func GetGlobalTransactionManager() *GlobalTransactionManager { | |||
return globalTransactionManager | |||
} | |||
type GlobalTransactionManager struct { | |||
} | |||
type GlobalTransactionManager struct{} | |||
// Begin a new global transaction with given timeout and given name. | |||
func (g *GlobalTransactionManager) Begin(ctx context.Context, gtr *GlobalTransaction, timeout time.Duration, name string) error { | |||
@@ -103,7 +102,7 @@ func (g *GlobalTransactionManager) Commit(ctx context.Context, gtr *GlobalTransa | |||
MaxBackoff: 200 * time.Millisecond, | |||
}) | |||
var req = message.GlobalCommitRequest{ | |||
req := message.GlobalCommitRequest{ | |||
AbstractGlobalEndRequest: message.AbstractGlobalEndRequest{Xid: gtr.Xid}, | |||
} | |||
var res interface{} | |||
@@ -146,7 +145,7 @@ func (g *GlobalTransactionManager) Rollback(ctx context.Context, gtr *GlobalTran | |||
}) | |||
var res interface{} | |||
var req = message.GlobalRollbackRequest{ | |||
req := message.GlobalRollbackRequest{ | |||
AbstractGlobalEndRequest: message.AbstractGlobalEndRequest{Xid: gtr.Xid}, | |||
} | |||
@@ -128,7 +128,7 @@ func TestBegin(t *testing.T) { | |||
assert.Nil(t, err) | |||
} | |||
//reset up stub | |||
// reset up stub | |||
if v.wantHasMock { | |||
stub.Reset() | |||
} | |||
@@ -24,8 +24,8 @@ import ( | |||
"github.com/pkg/errors" | |||
"github.com/seata/seata-go/pkg/common/log" | |||
"github.com/seata/seata-go/pkg/protocol/message" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
) | |||
type TransactionInfo struct { | |||
@@ -0,0 +1,119 @@ | |||
package fanout | |||
import ( | |||
"context" | |||
"log" | |||
"runtime" | |||
"sync" | |||
) | |||
type options struct { | |||
worker int | |||
buffer int | |||
} | |||
// Option is fanout option. | |||
type Option func(*options) | |||
// WithWorker with the worker of fanout. | |||
func WithWorker(n int) Option { | |||
return func(o *options) { | |||
o.worker = n | |||
} | |||
} | |||
// WithBuffer with the buffer of fanout. | |||
func WithBuffer(n int) Option { | |||
return func(o *options) { | |||
o.buffer = n | |||
} | |||
} | |||
type item struct { | |||
f func(c context.Context) | |||
ctx context.Context | |||
} | |||
// Fanout async consume data from chan. | |||
type Fanout struct { | |||
name string | |||
ch chan item | |||
options *options | |||
waiter sync.WaitGroup | |||
ctx context.Context | |||
cancel func() | |||
} | |||
// New new a fanout struct. | |||
func New(name string, opts ...Option) *Fanout { | |||
if name == "" { | |||
name = "anonymous" | |||
} | |||
o := &options{ | |||
worker: 1, | |||
buffer: 1000, | |||
} | |||
for _, op := range opts { | |||
op(o) | |||
} | |||
c := &Fanout{ | |||
ch: make(chan item, o.buffer), | |||
name: name, | |||
options: o, | |||
} | |||
c.ctx, c.cancel = context.WithCancel(context.Background()) | |||
c.waiter.Add(o.worker) | |||
for i := 0; i < o.worker; i++ { | |||
go c.proc() | |||
} | |||
return c | |||
} | |||
func (c *Fanout) proc() { | |||
defer c.waiter.Done() | |||
for { | |||
select { | |||
case t := <-c.ch: | |||
wrapFunc(t.f)(t.ctx) | |||
case <-c.ctx.Done(): | |||
return | |||
} | |||
} | |||
} | |||
func wrapFunc(f func(c context.Context)) (res func(context.Context)) { | |||
return func(ctx context.Context) { | |||
defer func() { | |||
if r := recover(); r != nil { | |||
buf := make([]byte, 64*1024) | |||
buf = buf[:runtime.Stack(buf, false)] | |||
log.Printf("panic in fanout proc, err: %s, stack: %s\n", r, buf) | |||
} | |||
}() | |||
f(ctx) | |||
} | |||
} | |||
// Do save a callback func. | |||
func (c *Fanout) Do(ctx context.Context, f func(ctx context.Context)) error { | |||
if f == nil || c.ctx.Err() != nil { | |||
return c.ctx.Err() | |||
} | |||
select { | |||
case c.ch <- item{f: f, ctx: ctx}: | |||
case <-ctx.Done(): | |||
return ctx.Err() | |||
} | |||
return nil | |||
} | |||
// Close close fanout. | |||
func (c *Fanout) Close() error { | |||
if err := c.ctx.Err(); err != nil { | |||
return err | |||
} | |||
c.cancel() | |||
c.waiter.Wait() | |||
return nil | |||
} |
@@ -0,0 +1,30 @@ | |||
package fanout | |||
import ( | |||
"context" | |||
"testing" | |||
"time" | |||
) | |||
func TestFanout_Do(t *testing.T) { | |||
ca := New("cache", WithWorker(1), WithBuffer(1024)) | |||
var run bool | |||
ca.Do(context.Background(), func(c context.Context) { | |||
run = true | |||
panic("error") | |||
}) | |||
time.Sleep(time.Millisecond * 50) | |||
t.Log("not panic") | |||
if !run { | |||
t.Fatal("expect run be true") | |||
} | |||
} | |||
func TestFanout_Close(t *testing.T) { | |||
ca := New("cache", WithWorker(1), WithBuffer(1024)) | |||
ca.Close() | |||
err := ca.Do(context.Background(), func(c context.Context) {}) | |||
if err == nil { | |||
t.Fatal("expect get err") | |||
} | |||
} |
@@ -0,0 +1,99 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package flagext | |||
import ( | |||
"net" | |||
"strings" | |||
"github.com/pkg/errors" | |||
) | |||
// CIDR is a network CIDR. | |||
type CIDR struct { | |||
Value *net.IPNet | |||
} | |||
// String implements flag.Value. | |||
func (c CIDR) String() string { | |||
if c.Value == nil { | |||
return "" | |||
} | |||
return c.Value.String() | |||
} | |||
// Set implements flag.Value. | |||
func (c *CIDR) Set(s string) error { | |||
_, value, err := net.ParseCIDR(s) | |||
if err != nil { | |||
return err | |||
} | |||
c.Value = value | |||
return nil | |||
} | |||
// CIDRSliceCSV is a slice of CIDRs that is parsed from a comma-separated string. | |||
// It implements flag.Value and yaml Marshalers. | |||
type CIDRSliceCSV []CIDR | |||
// String implements flag.Value | |||
func (c CIDRSliceCSV) String() string { | |||
values := make([]string, 0, len(c)) | |||
for _, cidr := range c { | |||
values = append(values, cidr.String()) | |||
} | |||
return strings.Join(values, ",") | |||
} | |||
// Set implements flag.Value | |||
func (c *CIDRSliceCSV) Set(s string) error { | |||
parts := strings.Split(s, ",") | |||
for _, part := range parts { | |||
cidr := &CIDR{} | |||
if err := cidr.Set(part); err != nil { | |||
return errors.Wrapf(err, "cidr: %s", part) | |||
} | |||
*c = append(*c, *cidr) | |||
} | |||
return nil | |||
} | |||
// UnmarshalYAML implements yaml.Unmarshaler. | |||
func (c *CIDRSliceCSV) UnmarshalYAML(unmarshal func(interface{}) error) error { | |||
var s string | |||
if err := unmarshal(&s); err != nil { | |||
return err | |||
} | |||
// An empty string means no CIDRs has been configured. | |||
if s == "" { | |||
*c = nil | |||
return nil | |||
} | |||
return c.Set(s) | |||
} | |||
// MarshalYAML implements yaml.Marshaler. | |||
func (c CIDRSliceCSV) MarshalYAML() (interface{}, error) { | |||
return c.String(), nil | |||
} |
@@ -0,0 +1,68 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package flagext | |||
import ( | |||
"testing" | |||
"github.com/stretchr/testify/assert" | |||
"gopkg.in/yaml.v2" | |||
) | |||
func Test_CIDRSliceCSV_YamlMarshaling(t *testing.T) { | |||
type TestStruct struct { | |||
CIDRs CIDRSliceCSV `yaml:"cidrs"` | |||
} | |||
tests := map[string]struct { | |||
input string | |||
expected []string | |||
}{ | |||
"should marshal empty config": { | |||
input: "cidrs: \"\"\n", | |||
expected: nil, | |||
}, | |||
"should marshal single value": { | |||
input: "cidrs: 127.0.0.1/32\n", | |||
expected: []string{"127.0.0.1/32"}, | |||
}, | |||
"should marshal multiple comma-separated values": { | |||
input: "cidrs: 127.0.0.1/32,10.0.10.0/28,fdf8:f53b:82e4::/100,192.168.0.0/20\n", | |||
expected: []string{"127.0.0.1/32", "10.0.10.0/28", "fdf8:f53b:82e4::/100", "192.168.0.0/20"}, | |||
}, | |||
} | |||
for name, tc := range tests { | |||
t.Run(name, func(t *testing.T) { | |||
// Unmarshal. | |||
actual := TestStruct{} | |||
err := yaml.Unmarshal([]byte(tc.input), &actual) | |||
assert.NoError(t, err) | |||
assert.Len(t, actual.CIDRs, len(tc.expected)) | |||
for idx, cidr := range actual.CIDRs { | |||
assert.Equal(t, tc.expected[idx], cidr.String()) | |||
} | |||
// Marshal. | |||
out, err := yaml.Marshal(actual) | |||
assert.NoError(t, err) | |||
assert.Equal(t, tc.input, string(out)) | |||
}) | |||
} | |||
} |
@@ -0,0 +1,76 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package flagext | |||
import ( | |||
"time" | |||
"github.com/prometheus/common/model" | |||
) | |||
const secondsInDay = 24 * 60 * 60 | |||
// DayValue is a model.Time that can be used as a flag. | |||
// NB it only parses days! | |||
type DayValue struct { | |||
model.Time | |||
set bool | |||
} | |||
// NewDayValue makes a new DayValue; will round t down to the nearest midnight. | |||
func NewDayValue(t model.Time) DayValue { | |||
return DayValue{ | |||
Time: model.TimeFromUnix((t.Unix() / secondsInDay) * secondsInDay), | |||
set: true, | |||
} | |||
} | |||
// String implements flag.Value | |||
func (v DayValue) String() string { | |||
return v.Time.Time().Format(time.RFC3339) | |||
} | |||
// Set implements flag.Value | |||
func (v *DayValue) Set(s string) error { | |||
t, err := time.Parse("2006-01-02", s) | |||
if err != nil { | |||
return err | |||
} | |||
v.Time = model.TimeFromUnix(t.Unix()) | |||
v.set = true | |||
return nil | |||
} | |||
// IsSet returns true is the DayValue has been set. | |||
func (v *DayValue) IsSet() bool { | |||
return v.set | |||
} | |||
// UnmarshalYAML implements yaml.Unmarshaler. | |||
func (v *DayValue) UnmarshalYAML(unmarshal func(interface{}) error) error { | |||
var s string | |||
if err := unmarshal(&s); err != nil { | |||
return err | |||
} | |||
return v.Set(s) | |||
} | |||
// MarshalYAML implements yaml.Marshaler. | |||
func (v DayValue) MarshalYAML() (interface{}, error) { | |||
return v.Time.Time().Format("2006-01-02"), nil | |||
} |
@@ -0,0 +1,71 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package flagext | |||
import ( | |||
"testing" | |||
"github.com/stretchr/testify/assert" | |||
"github.com/stretchr/testify/require" | |||
"gopkg.in/yaml.v2" | |||
) | |||
func TestDayValueYAML(t *testing.T) { | |||
// Test embedding of DayValue. | |||
{ | |||
type TestStruct struct { | |||
Day DayValue `yaml:"day"` | |||
} | |||
var testStruct TestStruct | |||
require.NoError(t, testStruct.Day.Set("1985-06-02")) | |||
expected := []byte(`day: "1985-06-02" | |||
`) | |||
actual, err := yaml.Marshal(testStruct) | |||
require.NoError(t, err) | |||
assert.Equal(t, expected, actual) | |||
var actualStruct TestStruct | |||
err = yaml.Unmarshal(expected, &actualStruct) | |||
require.NoError(t, err) | |||
assert.Equal(t, testStruct, actualStruct) | |||
} | |||
// Test pointers of DayValue. | |||
{ | |||
type TestStruct struct { | |||
Day *DayValue `yaml:"day"` | |||
} | |||
var testStruct TestStruct | |||
testStruct.Day = &DayValue{} | |||
require.NoError(t, testStruct.Day.Set("1985-06-02")) | |||
expected := []byte(`day: "1985-06-02" | |||
`) | |||
actual, err := yaml.Marshal(testStruct) | |||
require.NoError(t, err) | |||
assert.Equal(t, expected, actual) | |||
var actualStruct TestStruct | |||
err = yaml.Unmarshal(expected, &actualStruct) | |||
require.NoError(t, err) | |||
assert.Equal(t, testStruct, actualStruct) | |||
} | |||
} |
@@ -0,0 +1,54 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package flagext | |||
import ( | |||
"flag" | |||
"github.com/prometheus/client_golang/prometheus" | |||
"github.com/prometheus/client_golang/prometheus/promauto" | |||
"github.com/seata/seata-go/pkg/util/log" | |||
) | |||
// DeprecatedFlagsUsed is the metric that counts deprecated flags set. | |||
var DeprecatedFlagsUsed = promauto.NewCounter( | |||
prometheus.CounterOpts{ | |||
Namespace: "cortex", | |||
Name: "deprecated_flags_inuse_total", | |||
Help: "The number of deprecated flags currently set.", | |||
}) | |||
type deprecatedFlag struct { | |||
name string | |||
} | |||
func (deprecatedFlag) String() string { | |||
return "deprecated" | |||
} | |||
func (d deprecatedFlag) Set(string) error { | |||
log.Infof("msg", "flag disabled", "flag", d.name) | |||
DeprecatedFlagsUsed.Inc() | |||
return nil | |||
} | |||
// DeprecatedFlag logs a warning when you try to use it. | |||
func DeprecatedFlag(f *flag.FlagSet, name, message string) { | |||
f.Var(deprecatedFlag{name}, name, message) | |||
} |
@@ -15,4 +15,25 @@ | |||
* limitations under the License. | |||
*/ | |||
package runtime | |||
package flagext | |||
import ( | |||
"flag" | |||
) | |||
type ignoredFlag struct { | |||
name string | |||
} | |||
func (ignoredFlag) String() string { | |||
return "ignored" | |||
} | |||
func (d ignoredFlag) Set(string) error { | |||
return nil | |||
} | |||
// IgnoredFlag ignores set value, without any warning | |||
func IgnoredFlag(f *flag.FlagSet, name, message string) { | |||
f.Var(ignoredFlag{name}, name, message) | |||
} |
@@ -15,27 +15,27 @@ | |||
* limitations under the License. | |||
*/ | |||
package util | |||
package flagext | |||
import ( | |||
"errors" | |||
"strconv" | |||
"strings" | |||
) | |||
import "flag" | |||
// Int64Slice2Str | |||
func Int64Slice2Str(values interface{}, sep string) (string, error) { | |||
v, ok := values.([]int64) | |||
if !ok { | |||
return "", errors.New("param type is fault") | |||
} | |||
var valuesText []string | |||
// Registerer is a thing that can RegisterFlags | |||
type Registerer interface { | |||
RegisterFlags(*flag.FlagSet) | |||
} | |||
for i := range v { | |||
text := strconv.FormatInt(v[i], 10) | |||
valuesText = append(valuesText, text) | |||
// RegisterFlags registers flags with the provided Registerers | |||
func RegisterFlags(rs ...Registerer) { | |||
for _, r := range rs { | |||
r.RegisterFlags(flag.CommandLine) | |||
} | |||
} | |||
return strings.Join(valuesText, sep), nil | |||
// DefaultValues initiates a set of configs (Registerers) with their defaults. | |||
func DefaultValues(rs ...Registerer) { | |||
fs := flag.NewFlagSet("", flag.PanicOnError) | |||
for _, r := range rs { | |||
r.RegisterFlags(fs) | |||
} | |||
_ = fs.Parse([]string{}) | |||
} |
@@ -0,0 +1,51 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package flagext | |||
type Secret struct { | |||
Value string | |||
} | |||
// String implements flag.Value | |||
func (v Secret) String() string { | |||
return v.Value | |||
} | |||
// Set implements flag.Value | |||
func (v *Secret) Set(s string) error { | |||
v.Value = s | |||
return nil | |||
} | |||
// UnmarshalYAML implements yaml.Unmarshaler. | |||
func (v *Secret) UnmarshalYAML(unmarshal func(interface{}) error) error { | |||
var s string | |||
if err := unmarshal(&s); err != nil { | |||
return err | |||
} | |||
return v.Set(s) | |||
} | |||
// MarshalYAML implements yaml.Marshaler. | |||
func (v Secret) MarshalYAML() (interface{}, error) { | |||
if len(v.Value) == 0 { | |||
return "", nil | |||
} | |||
return "********", nil | |||
} |
@@ -0,0 +1,94 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package flagext | |||
import ( | |||
"testing" | |||
"github.com/stretchr/testify/assert" | |||
"github.com/stretchr/testify/require" | |||
"gopkg.in/yaml.v2" | |||
) | |||
func TestSecretdYAML(t *testing.T) { | |||
// Test embedding of Secret. | |||
{ | |||
type TestStruct struct { | |||
Secret Secret `yaml:"secret"` | |||
} | |||
var testStruct TestStruct | |||
require.NoError(t, testStruct.Secret.Set("pa55w0rd")) | |||
expected := []byte(`secret: '********' | |||
`) | |||
actual, err := yaml.Marshal(testStruct) | |||
require.NoError(t, err) | |||
assert.Equal(t, expected, actual) | |||
var actualStruct TestStruct | |||
yamlSecret := []byte(`secret: pa55w0rd | |||
`) | |||
err = yaml.Unmarshal(yamlSecret, &actualStruct) | |||
require.NoError(t, err) | |||
assert.Equal(t, testStruct, actualStruct) | |||
} | |||
// Test pointers of Secret. | |||
{ | |||
type TestStruct struct { | |||
Secret *Secret `yaml:"secret"` | |||
} | |||
var testStruct TestStruct | |||
testStruct.Secret = &Secret{} | |||
require.NoError(t, testStruct.Secret.Set("pa55w0rd")) | |||
expected := []byte(`secret: '********' | |||
`) | |||
actual, err := yaml.Marshal(testStruct) | |||
require.NoError(t, err) | |||
assert.Equal(t, expected, actual) | |||
var actualStruct TestStruct | |||
yamlSecret := []byte(`secret: pa55w0rd | |||
`) | |||
err = yaml.Unmarshal(yamlSecret, &actualStruct) | |||
require.NoError(t, err) | |||
assert.Equal(t, testStruct, actualStruct) | |||
} | |||
// Test no value set in Secret. | |||
{ | |||
type TestStruct struct { | |||
Secret Secret `yaml:"secret"` | |||
} | |||
var testStruct TestStruct | |||
expected := []byte(`secret: "" | |||
`) | |||
actual, err := yaml.Marshal(testStruct) | |||
require.NoError(t, err) | |||
assert.Equal(t, expected, actual) | |||
var actualStruct TestStruct | |||
err = yaml.Unmarshal(expected, &actualStruct) | |||
require.NoError(t, err) | |||
assert.Equal(t, testStruct, actualStruct) | |||
} | |||
} |
@@ -15,9 +15,20 @@ | |||
* limitations under the License. | |||
*/ | |||
package net | |||
package flagext | |||
func GetLocalIp() string { | |||
// todo | |||
return "127.0.0.1" | |||
import "fmt" | |||
// StringSlice is a slice of strings that implements flag.Value | |||
type StringSlice []string | |||
// String implements flag.Value | |||
func (v StringSlice) String() string { | |||
return fmt.Sprintf("%s", []string(v)) | |||
} | |||
// Set implements flag.Value | |||
func (v *StringSlice) Set(s string) error { | |||
*v = append(*v, s) | |||
return nil | |||
} |