Browse Source

optimization

tags/v1.0.1
liu.xiaomin 4 years ago
parent
commit
1889277ad5
53 changed files with 774 additions and 750 deletions
  1. +1
    -1
      cmd/profiles/dev/config.yml
  2. +15
    -7
      cmd/tc/main.go
  3. +1
    -1
      go.mod
  4. +0
    -6
      pkg/base/common/constant/env.go
  5. +0
    -12
      pkg/base/common/constant/key.go
  6. +10
    -16
      pkg/base/common/xid.go
  7. +2
    -2
      pkg/base/config/config_center_config.go
  8. +19
    -0
      pkg/base/config/getty_session_param.go
  9. +10
    -0
      pkg/base/config/registry_config.go
  10. +5
    -5
      pkg/base/config_center/base_operate.go
  11. +0
    -1
      pkg/base/config_center/config_center_factory.go
  12. +12
    -12
      pkg/base/config_center/nacos/factory.go
  13. +5
    -0
      pkg/base/constant/env.go
  14. +8
    -0
      pkg/base/constant/key.go
  15. +1
    -1
      pkg/base/extension/config_center.go
  16. +0
    -1
      pkg/base/extension/registry.go
  17. +0
    -50
      pkg/base/getty/config/getty_session_param.go
  18. +4
    -4
      pkg/base/meta/global_status.go
  19. +5
    -6
      pkg/base/registry/file/registry.go
  20. +24
    -26
      pkg/base/registry/nacos/registry.go
  21. +1
    -1
      pkg/client/at/exec/datasource_manager.go
  22. +0
    -27
      pkg/client/config/at_config.go
  23. +73
    -94
      pkg/client/config/client_config.go
  24. +9
    -27
      pkg/client/config/getty_config.go
  25. +5
    -8
      pkg/client/rpc_client.go
  26. +1
    -1
      pkg/client/rpc_client/rpc_remoting_client.go
  27. +1
    -1
      pkg/client/tcc/tcc_resource_manager.go
  28. +0
    -63
      pkg/client/tm/proxy_test.go
  29. +0
    -60
      pkg/tc/config/getty_config.go
  30. +99
    -101
      pkg/tc/config/server_config.go
  31. +0
    -5
      pkg/tc/config/undo_config.go
  32. +3
    -7
      pkg/tc/holder/db_based_session_manager.go
  33. +0
    -5
      pkg/tc/holder/db_transaction_store_manager.go
  34. +2
    -2
      pkg/tc/holder/default_session_manager_test.go
  35. +0
    -37
      pkg/tc/holder/file_based_session_manager.go
  36. +0
    -3
      pkg/tc/holder/file_transaction_store_manager.go
  37. +1
    -1
      pkg/tc/holder/log_store_database_dao.go
  38. +1
    -1
      pkg/tc/holder/session_holder.go
  39. +0
    -3
      pkg/tc/holder/transaction_store_manager.go
  40. +12
    -10
      pkg/tc/lock/lock_manager_test.go
  41. +1
    -1
      pkg/tc/lock/lock_store_database_dao_test.go
  42. +48
    -43
      pkg/tc/server/default_coordinator.go
  43. +2
    -2
      pkg/tc/server/default_coordinator_server_message_sender.go
  44. +3
    -3
      pkg/tc/server/default_core.go
  45. +8
    -13
      pkg/tc/server/server.go
  46. +2
    -2
      pkg/tc/session/branch_session.go
  47. +1
    -1
      pkg/tc/session/branch_session_test.go
  48. +2
    -2
      pkg/tc/session/global_session.go
  49. +1
    -1
      pkg/testutil/util.go
  50. +57
    -27
      pkg/util/log/logging.go
  51. +209
    -0
      pkg/util/parser/parser.go
  52. +110
    -0
      pkg/util/uuid/id_worker.go
  53. +0
    -47
      pkg/util/uuid/uuid_generator.go

+ 1
- 1
cmd/profiles/dev/config.yml View File

@@ -3,7 +3,7 @@ port: "8091"
max_rollback_retry_timeout: -1 max_rollback_retry_timeout: -1
max_commit_retry_timeout: -1 max_commit_retry_timeout: -1
timeout_retry_period: "1s" timeout_retry_period: "1s"
rollbacking_retry_period: "1s"
rolling_back_retry_period: "1s"
committing_retry_period: "1s" committing_retry_period: "1s"
async_committing_retry_period: "10s" async_committing_retry_period: "10s"
log_delete_period: "24h" log_delete_period: "24h"


+ 15
- 7
cmd/tc/main.go View File

@@ -1,6 +1,7 @@
package main package main


import ( import (
"fmt"
"os" "os"
"strconv" "strconv"
) )
@@ -42,19 +43,26 @@ func main() {
}, },
Action: func(c *cli.Context) error { Action: func(c *cli.Context) error {
configPath := c.String("config") configPath := c.String("config")
serverNode := c.Int("serverNode")
ip, _ := gxnet.GetLocalIP()
serverNode := c.Int64("serverNode")

conf, err := config.InitConf(configPath)
if err != nil {
log.Fatal(err)
}


config.InitConf(configPath)
conf := config.GetServerConfig()
port, _ := strconv.Atoi(conf.Port)
common.GetXID().Init(ip, port)
ip, _ := gxnet.GetLocalIP()
port, err := strconv.Atoi(conf.Port)
if err != nil {
log.Fatal(err)
}


common.Init(ip, port)
uuid.Init(serverNode) uuid.Init(serverNode)
lock.Init() lock.Init()
holder.Init() holder.Init()

srv := server.NewServer() srv := server.NewServer()
srv.Start(conf.Host + ":" + conf.Port)
srv.Start(fmt.Sprintf(":%s", conf.Port))
return nil return nil
}, },
}, },


+ 1
- 1
go.mod View File

@@ -16,6 +16,7 @@ require (
github.com/mattn/go-sqlite3 v2.0.1+incompatible // indirect github.com/mattn/go-sqlite3 v2.0.1+incompatible // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/nacos-group/nacos-sdk-go v1.0.8 github.com/nacos-group/nacos-sdk-go v1.0.8
github.com/natefinch/lumberjack v2.0.0+incompatible
github.com/opentrx/seata-golang/v2 v2.0.0-rc1 // indirect github.com/opentrx/seata-golang/v2 v2.0.0-rc1 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/pingcap/check v0.0.0-20200212061837-5e12011dc712 // indirect github.com/pingcap/check v0.0.0-20200212061837-5e12011dc712 // indirect
@@ -25,7 +26,6 @@ require (
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.9.0 github.com/prometheus/client_golang v1.9.0
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a
github.com/shima-park/agollo v1.2.6
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
github.com/urfave/cli/v2 v2.3.0 github.com/urfave/cli/v2 v2.3.0
go.uber.org/atomic v1.7.0 go.uber.org/atomic v1.7.0


+ 0
- 6
pkg/base/common/constant/env.go View File

@@ -1,6 +0,0 @@
package constant

const (
// seata客服端文件配置路径KEY
CONF_CLIENT_FILE_PATH = "CONF_CLIENT_FILE_PATH"
)

+ 0
- 12
pkg/base/common/constant/key.go View File

@@ -1,12 +0,0 @@
package constant

const (
NACOS_KEY = "nacos"
)
const (
FILE_KEY = "file"
)
const (
NACOS_DEFAULT_GROUP = "SEATA_GROUP"
NACOS_DEFAULT_DATA_ID = "seata"
)

+ 10
- 16
pkg/base/common/xid.go View File

@@ -6,24 +6,18 @@ import (
"strings" "strings"
) )


type XID struct {
IpAddress string
Port int
}

var xID = &XID{}

func GetXID() *XID {
return xID
}
var (
IPAddress string
Port int
)


func (xid *XID) Init(ipAddress string, port int) {
xid.IpAddress = ipAddress
xid.Port = port
func Init(ipAddress string, port int) {
IPAddress = ipAddress
Port = port
} }


func (xid *XID) GenerateXID(tranID int64) string {
return fmt.Sprintf("%s:%d:%d", xid.IpAddress, xid.Port, tranID)
func GenerateXID(tranID int64) string {
return fmt.Sprintf("%s:%d:%d", IPAddress, Port, tranID)
} }


func GetTransactionID(xid string) int64 { func GetTransactionID(xid string) int64 {
@@ -37,4 +31,4 @@ func GetTransactionID(xid string) int64 {
} }
tranID, _ := strconv.ParseInt(xid[idx+1:], 10, 64) tranID, _ := strconv.ParseInt(xid[idx+1:], 10, 64)
return tranID return tranID
}
}

+ 2
- 2
pkg/base/config/config_center_config.go View File

@@ -7,10 +7,10 @@ type ConfigCenterConfig struct {


type NacosConfigCenter struct { type NacosConfigCenter struct {
ServerAddr string `yaml:"server_addr" json:"server_addr,omitempty"` ServerAddr string `yaml:"server_addr" json:"server_addr,omitempty"`
Group string `default:"SEATA_GROUP" yaml:"group" json:"group,omitempty"`
Group string `default:"SEATA_GROUP" yaml:"group" json:"group,omitempty"`
Namespace string `yaml:"namespace" json:"namespace,omitempty"` Namespace string `yaml:"namespace" json:"namespace,omitempty"`
Cluster string `yaml:"cluster" json:"cluster,omitempty"` Cluster string `yaml:"cluster" json:"cluster,omitempty"`
UserName string `yaml:"username" json:"username,omitempty"` UserName string `yaml:"username" json:"username,omitempty"`
Password string `yaml:"password" json:"password,omitempty"` Password string `yaml:"password" json:"password,omitempty"`
DataId string `default:"seata" yaml:"data_id" json:"data_id,omitempty"`
DataId string `default:"seata" yaml:"data_id" json:"data_id,omitempty"`
} }

+ 19
- 0
pkg/base/config/getty_session_param.go View File

@@ -0,0 +1,19 @@
package config

import (
"time"
)

type GettySessionParam struct {
CompressEncoding bool `default:"false" yaml:"compress_encoding" json:"compress_encoding,omitempty"`
TcpNoDelay bool `default:"true" yaml:"tcp_no_delay" json:"tcp_no_delay,omitempty"`
TcpKeepAlive bool `default:"true" yaml:"tcp_keep_alive" json:"tcp_keep_alive,omitempty"`
KeepAlivePeriod time.Duration `default:"180s" yaml:"keep_alive_period" json:"keep_alive_period,omitempty"`
TcpRBufSize int `default:"262144" yaml:"tcp_r_buf_size" json:"tcp_r_buf_size,omitempty"`
TcpWBufSize int `default:"65536" yaml:"tcp_w_buf_size" json:"tcp_w_buf_size,omitempty"`
TcpReadTimeout time.Duration `default:"1s" yaml:"tcp_read_timeout" json:"tcp_read_timeout,omitempty"`
TcpWriteTimeout time.Duration `default:"5s" yaml:"tcp_write_timeout" json:"tcp_write_timeout,omitempty"`
WaitTimeout time.Duration `default:"7s" yaml:"wait_timeout" json:"wait_timeout,omitempty"`
MaxMsgLen int `default:"4096" yaml:"max_msg_len" json:"max_msg_len,omitempty"`
SessionName string `default:"rpc" yaml:"session_name" json:"session_name,omitempty"`
}

pkg/tc/config/registry_config.go → pkg/base/config/registry_config.go View File

@@ -1,5 +1,7 @@
package config package config


var config *RegistryConfig

type RegistryConfig struct { type RegistryConfig struct {
Mode string `yaml:"type" json:"type,omitempty"` //类型 Mode string `yaml:"type" json:"type,omitempty"` //类型
NacosConfig NacosConfig `yaml:"nacos" json:"nacos,omitempty"` NacosConfig NacosConfig `yaml:"nacos" json:"nacos,omitempty"`
@@ -14,3 +16,11 @@ type NacosConfig struct {
UserName string `yaml:"username" json:"username,omitempty"` UserName string `yaml:"username" json:"username,omitempty"`
Password string `yaml:"password" json:"password,omitempty"` Password string `yaml:"password" json:"password,omitempty"`
} }

func InitRegistryConfig(registryConfig *RegistryConfig) {
config = registryConfig
}

func GetRegistryConfig() *RegistryConfig {
return config
}

+ 5
- 5
pkg/base/config_center/base_operate.go View File

@@ -2,7 +2,7 @@ package config_center


import "github.com/transaction-wg/seata-golang/pkg/base/config" import "github.com/transaction-wg/seata-golang/pkg/base/config"


func AddLisenter(cc DynamicConfigurationFactory, conf *config.ConfigCenterConfig, listener ConfigurationListener) {
func AddListener(cc DynamicConfigurationFactory, conf *config.ConfigCenterConfig, listener ConfigurationListener) {
if conf.Mode == "" { if conf.Mode == "" {
return return
} }
@@ -10,8 +10,8 @@ func AddLisenter(cc DynamicConfigurationFactory, conf *config.ConfigCenterConfig
} }


func LoadConfigCenterConfig(cc DynamicConfigurationFactory, conf *config.ConfigCenterConfig, listener ConfigurationListener) string { func LoadConfigCenterConfig(cc DynamicConfigurationFactory, conf *config.ConfigCenterConfig, listener ConfigurationListener) string {
confStr := cc.GetConfig(conf)
//监听远程配置情况,发生变更进行配置修改
AddLisenter(cc, conf, listener)
return confStr
remoteConfig := cc.GetConfig(conf)
// listen remote config, change config item
AddListener(cc, conf, listener)
return remoteConfig
} }

+ 0
- 1
pkg/base/config_center/config_center_factory.go View File

@@ -5,5 +5,4 @@ import "github.com/transaction-wg/seata-golang/pkg/base/config"
type DynamicConfigurationFactory interface { type DynamicConfigurationFactory interface {
GetConfig(conf *config.ConfigCenterConfig) string //返回配置信息 GetConfig(conf *config.ConfigCenterConfig) string //返回配置信息
AddListener(conf *config.ConfigCenterConfig, listener ConfigurationListener) //添加配置监听 AddListener(conf *config.ConfigCenterConfig, listener ConfigurationListener) //添加配置监听

} }

+ 12
- 12
pkg/base/config_center/nacos/factory.go View File

@@ -13,21 +13,21 @@ import (
) )


import ( import (
"github.com/transaction-wg/seata-golang/pkg/base/common/constant"
"github.com/transaction-wg/seata-golang/pkg/base/common/extension"
baseConfig "github.com/transaction-wg/seata-golang/pkg/base/config"
"github.com/transaction-wg/seata-golang/pkg/base/config"
"github.com/transaction-wg/seata-golang/pkg/base/config_center" "github.com/transaction-wg/seata-golang/pkg/base/config_center"
"github.com/transaction-wg/seata-golang/pkg/base/constant"
"github.com/transaction-wg/seata-golang/pkg/base/extension"
) )


func init() { func init() {
extension.SetConfigCenter(constant.NACOS_KEY, newNacosConfigCenterFactory)
extension.SetConfigCenter(constant.NacosKey, newNacosConfigCenterFactory)
} }


type nacosConfigCenter struct { type nacosConfigCenter struct {
client config_client.IConfigClient client config_client.IConfigClient
} }


func (nc *nacosConfigCenter) AddListener(conf *baseConfig.ConfigCenterConfig, listener config_center.ConfigurationListener) {
func (nc *nacosConfigCenter) AddListener(conf *config.ConfigCenterConfig, listener config_center.ConfigurationListener) {
dataId := getDataId(conf) dataId := getDataId(conf)
group := getGroup(conf) group := getGroup(conf)
_ = nc.client.ListenConfig(vo.ConfigParam{ _ = nc.client.ListenConfig(vo.ConfigParam{
@@ -39,23 +39,23 @@ func (nc *nacosConfigCenter) AddListener(conf *baseConfig.ConfigCenterConfig, li
}) })
} }


func getGroup(conf *baseConfig.ConfigCenterConfig) string {
func getGroup(conf *config.ConfigCenterConfig) string {
group := conf.NacosConfig.Group group := conf.NacosConfig.Group
if group == "" { if group == "" {
group = constant.NACOS_DEFAULT_GROUP
group = constant.NacosDefaultGroup
} }
return group return group
} }


func getDataId(conf *baseConfig.ConfigCenterConfig) string {
func getDataId(conf *config.ConfigCenterConfig) string {
dataId := conf.NacosConfig.DataId dataId := conf.NacosConfig.DataId
if dataId == "" { if dataId == "" {
dataId = constant.NACOS_DEFAULT_DATA_ID
dataId = constant.NacosDefaultDataID
} }
return dataId return dataId
} }


func (nc *nacosConfigCenter) GetConfig(conf *baseConfig.ConfigCenterConfig) string {
func (nc *nacosConfigCenter) GetConfig(conf *config.ConfigCenterConfig) string {
dataId := getDataId(conf) dataId := getDataId(conf)
group := getGroup(conf) group := getGroup(conf)
config, _ := nc.client.GetConfig(vo.ConfigParam{ config, _ := nc.client.GetConfig(vo.ConfigParam{
@@ -64,7 +64,7 @@ func (nc *nacosConfigCenter) GetConfig(conf *baseConfig.ConfigCenterConfig) stri
return config return config
} }


func newNacosConfigCenterFactory(conf *baseConfig.ConfigCenterConfig) (factory config_center.DynamicConfigurationFactory, e error) {
func newNacosConfigCenterFactory(conf *config.ConfigCenterConfig) (factory config_center.DynamicConfigurationFactory, e error) {
nacosConfig, err := getNacosConfig(conf) nacosConfig, err := getNacosConfig(conf)
if err != nil { if err != nil {
return &nacosConfigCenter{}, err return &nacosConfigCenter{}, err
@@ -80,7 +80,7 @@ func newNacosConfigCenterFactory(conf *baseConfig.ConfigCenterConfig) (factory c
} }


//获取Nacos配置信息 //获取Nacos配置信息
func getNacosConfig(conf *baseConfig.ConfigCenterConfig) (map[string]interface{}, error) {
func getNacosConfig(conf *config.ConfigCenterConfig) (map[string]interface{}, error) {
configMap := make(map[string]interface{}, 2) configMap := make(map[string]interface{}, 2)
addr := conf.NacosConfig.ServerAddr addr := conf.NacosConfig.ServerAddr




+ 5
- 0
pkg/base/constant/env.go View File

@@ -0,0 +1,5 @@
package constant

const (
ClientConfigFilePath = "ConfClientFilePath"
)

+ 8
- 0
pkg/base/constant/key.go View File

@@ -0,0 +1,8 @@
package constant

const (
NacosDefaultGroup = "SEATA_GROUP"
NacosDefaultDataID = "seata"
NacosKey = "nacos"
FileKey = "file"
)

pkg/base/common/extension/config_center.go → pkg/base/extension/config_center.go View File


pkg/base/common/extension/registry.go → pkg/base/extension/registry.go View File

@@ -38,5 +38,4 @@ func GetRegistry(name string) (registry.Registry, error) {
return nil, errors.Errorf("registry for " + name + " is not existing, make sure you have import the package.") return nil, errors.Errorf("registry for " + name + " is not existing, make sure you have import the package.")
} }
return registry() return registry()

} }

+ 0
- 50
pkg/base/getty/config/getty_session_param.go View File

@@ -1,50 +0,0 @@
package config

import (
"time"
)

import (
"github.com/pkg/errors"
)

type GettySessionParam struct {
CompressEncoding bool `default:"false" yaml:"compress_encoding" json:"compress_encoding,omitempty"`
TcpNoDelay bool `default:"true" yaml:"tcp_no_delay" json:"tcp_no_delay,omitempty"`
TcpKeepAlive bool `default:"true" yaml:"tcp_keep_alive" json:"tcp_keep_alive,omitempty"`
KeepAlivePrd string `default:"180s" yaml:"keep_alive_period" json:"keep_alive_period,omitempty"`
KeepAlivePeriod time.Duration
TcpRBufSize int `default:"262144" yaml:"tcp_r_buf_size" json:"tcp_r_buf_size,omitempty"`
TcpWBufSize int `default:"65536" yaml:"tcp_w_buf_size" json:"tcp_w_buf_size,omitempty"`
TcpReadTmt string `default:"1s" yaml:"tcp_read_timeout" json:"tcp_read_timeout,omitempty"`
TcpReadTimeout time.Duration
TcpWriteTmt string `default:"5s" yaml:"tcp_write_timeout" json:"tcp_write_timeout,omitempty"`
TcpWriteTimeout time.Duration
WaitTmt string `default:"7s" yaml:"wait_timeout" json:"wait_timeout,omitempty"`
WaitTimeout time.Duration
MaxMsgLen int `default:"4096" yaml:"max_msg_len" json:"max_msg_len,omitempty"`
SessionName string `default:"rpc" yaml:"session_name" json:"session_name,omitempty"`
}

// CheckValidity ...
func (c *GettySessionParam) CheckValidity() error {
var err error

if c.KeepAlivePeriod, err = time.ParseDuration(c.KeepAlivePrd); err != nil {
return errors.WithMessagef(err, "time.ParseDuration(KeepAlivePeriod{%#v})", c.KeepAlivePrd)
}

if c.TcpReadTimeout, err = time.ParseDuration(c.TcpReadTmt); err != nil {
return errors.WithMessagef(err, "time.ParseDuration(TcpReadTimeout{%#v})", c.TcpReadTmt)
}

if c.TcpWriteTimeout, err = time.ParseDuration(c.TcpWriteTmt); err != nil {
return errors.WithMessagef(err, "time.ParseDuration(TcpWriteTimeout{%#v})", c.TcpWriteTmt)
}

if c.WaitTimeout, err = time.ParseDuration(c.WaitTmt); err != nil {
return errors.WithMessagef(err, "time.ParseDuration(WaitTimeout{%#v})", c.WaitTmt)
}

return nil
}

+ 4
- 4
pkg/base/meta/global_status.go View File

@@ -42,10 +42,10 @@ const (
GlobalStatusRollbackRetrying GlobalStatusRollbackRetrying


/** /**
* The Timeout rollbacking.
* The Timeout rollingBack.
*/ */
// Rollbacking since timeout
GlobalStatusTimeoutRollbacking
// RollingBack since timeout
GlobalStatusTimeoutRollingBack


/** /**
* The Timeout rollback retrying. * The Timeout rollback retrying.
@@ -116,7 +116,7 @@ func (s GlobalStatus) String() string {
return "Rollbacking" return "Rollbacking"
case GlobalStatusRollbackRetrying: case GlobalStatusRollbackRetrying:
return "RollbackRetrying" return "RollbackRetrying"
case GlobalStatusTimeoutRollbacking:
case GlobalStatusTimeoutRollingBack:
return "TimeoutRollbacking" return "TimeoutRollbacking"
case GlobalStatusTimeoutRollbackRetrying: case GlobalStatusTimeoutRollbackRetrying:
return "TimeoutRollbackRetrying" return "TimeoutRollbackRetrying"


+ 5
- 6
pkg/base/registry/file/registry.go View File

@@ -5,22 +5,21 @@ import (
) )


import ( import (
"github.com/transaction-wg/seata-golang/pkg/base/common/constant"
"github.com/transaction-wg/seata-golang/pkg/base/common/extension"
"github.com/transaction-wg/seata-golang/pkg/base/constant"
"github.com/transaction-wg/seata-golang/pkg/base/extension"
"github.com/transaction-wg/seata-golang/pkg/base/registry" "github.com/transaction-wg/seata-golang/pkg/base/registry"
"github.com/transaction-wg/seata-golang/pkg/client/config" "github.com/transaction-wg/seata-golang/pkg/client/config"
"github.com/transaction-wg/seata-golang/pkg/util/log" "github.com/transaction-wg/seata-golang/pkg/util/log"
) )


func init() { func init() {
extension.SetRegistry(constant.FILE_KEY, newFileRegistry)
extension.SetRegistry(constant.FileKey, newFileRegistry)
} }


type fileRegistry struct { type fileRegistry struct {
} }


func (nr *fileRegistry) Register(addr *registry.Address) error { func (nr *fileRegistry) Register(addr *registry.Address) error {
//文件不需要注册
log.Info("file register") log.Info("file register")
return nil return nil
} }
@@ -28,10 +27,12 @@ func (nr *fileRegistry) Register(addr *registry.Address) error {
func (nr *fileRegistry) UnRegister(addr *registry.Address) error { func (nr *fileRegistry) UnRegister(addr *registry.Address) error {
return nil return nil
} }

func (nr *fileRegistry) Lookup() ([]string, error) { func (nr *fileRegistry) Lookup() ([]string, error) {
addressList := strings.Split(config.GetClientConfig().TransactionServiceGroup, ",") addressList := strings.Split(config.GetClientConfig().TransactionServiceGroup, ",")
return addressList, nil return addressList, nil
} }

func (nr *fileRegistry) Subscribe(notifyListener registry.EventListener) error { func (nr *fileRegistry) Subscribe(notifyListener registry.EventListener) error {
return nil return nil
} }
@@ -40,9 +41,7 @@ func (nr *fileRegistry) UnSubscribe(notifyListener registry.EventListener) error
return nil return nil
} }


// newNacosRegistry will create new instance
func newFileRegistry() (registry.Registry, error) { func newFileRegistry() (registry.Registry, error) {

tmpRegistry := &fileRegistry{} tmpRegistry := &fileRegistry{}
return tmpRegistry, nil return tmpRegistry, nil
} }

+ 24
- 26
pkg/base/registry/nacos/registry.go View File

@@ -15,45 +15,45 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
import ( import (
"github.com/transaction-wg/seata-golang/pkg/base/common/constant"
"github.com/transaction-wg/seata-golang/pkg/base/common/extension"
"github.com/transaction-wg/seata-golang/pkg/base/config"
"github.com/transaction-wg/seata-golang/pkg/base/constant"
"github.com/transaction-wg/seata-golang/pkg/base/extension"
"github.com/transaction-wg/seata-golang/pkg/base/registry" "github.com/transaction-wg/seata-golang/pkg/base/registry"
clientConfig "github.com/transaction-wg/seata-golang/pkg/client/config"
"github.com/transaction-wg/seata-golang/pkg/tc/config"
"github.com/transaction-wg/seata-golang/pkg/util/log" "github.com/transaction-wg/seata-golang/pkg/util/log"
) )


func init() { func init() {
extension.SetRegistry(constant.NACOS_KEY, newNacosRegistry)
extension.SetRegistry(constant.NacosKey, newNacosRegistry)
} }


type nacosRegistry struct { type nacosRegistry struct {
namingClient naming_client.INamingClient
registryConfig *config.RegistryConfig
namingClient naming_client.INamingClient
} }

type nacosEventListener struct { type nacosEventListener struct {
} }


func (nr *nacosEventListener) OnEvent(service []*registry.Service) error { func (nr *nacosEventListener) OnEvent(service []*registry.Service) error {
data, err := json.Marshal(service) data, err := json.Marshal(service)
log.Info("servie info change:" + string(data))
log.Info("service info change:" + string(data))
return err return err
} }
func (nr *nacosRegistry) Register(addr *registry.Address) error {
registryConfig := config.GetRegistryConfig()


param := createRegisterParam(registryConfig, addr)
func (nr *nacosRegistry) Register(addr *registry.Address) error {
param := createRegisterParam(nr.registryConfig, addr)
isRegistry, err := nr.namingClient.RegisterInstance(param) isRegistry, err := nr.namingClient.RegisterInstance(param)
if err != nil { if err != nil {
return err return err
} }
if !isRegistry { if !isRegistry {
return errors.Errorf("registry [" + registryConfig.NacosConfig.Application + "] to nacos failed")
return errors.Errorf("registry [" + nr.registryConfig.NacosConfig.Application + "] to nacos failed")
} }
return nil return nil
} }


//创建服务注册信息 //创建服务注册信息
func createRegisterParam(registryConfig config.RegistryConfig, addr *registry.Address) vo.RegisterInstanceParam {
func createRegisterParam(registryConfig *config.RegistryConfig, addr *registry.Address) vo.RegisterInstanceParam {
serviceName := registryConfig.NacosConfig.Application serviceName := registryConfig.NacosConfig.Application
params := make(map[string]string) params := make(map[string]string)


@@ -78,11 +78,10 @@ func (nr *nacosRegistry) UnRegister(addr *registry.Address) error {


//noinspection ALL //noinspection ALL
func (nr *nacosRegistry) Lookup() ([]string, error) { func (nr *nacosRegistry) Lookup() ([]string, error) {
registryConfig := clientConfig.GetRegistryConfig()
clusterName := registryConfig.NacosConfig.Cluster
clusterName := nr.registryConfig.NacosConfig.Cluster
instances, err := nr.namingClient.SelectInstances(vo.SelectInstancesParam{ instances, err := nr.namingClient.SelectInstances(vo.SelectInstancesParam{
ServiceName: registryConfig.NacosConfig.Application,
GroupName: registryConfig.NacosConfig.Group, // default value is DEFAULT_GROUP
ServiceName: nr.registryConfig.NacosConfig.Application,
GroupName: nr.registryConfig.NacosConfig.Group, // default value is DEFAULT_GROUP
Clusters: []string{clusterName}, // default value is DEFAULT Clusters: []string{clusterName}, // default value is DEFAULT
HealthyOnly: true, HealthyOnly: true,
}) })
@@ -97,12 +96,12 @@ func (nr *nacosRegistry) Lookup() ([]string, error) {
nr.Subscribe(&nacosEventListener{}) nr.Subscribe(&nacosEventListener{})
return addrs, nil return addrs, nil
} }

func (nr *nacosRegistry) Subscribe(notifyListener registry.EventListener) error { func (nr *nacosRegistry) Subscribe(notifyListener registry.EventListener) error {
registryConfig := clientConfig.GetRegistryConfig()
clusterName := registryConfig.NacosConfig.Cluster
clusterName := nr.registryConfig.NacosConfig.Cluster
err := nr.namingClient.Subscribe(&vo.SubscribeParam{ err := nr.namingClient.Subscribe(&vo.SubscribeParam{
ServiceName: registryConfig.NacosConfig.Application,
GroupName: registryConfig.NacosConfig.Group, // default value is DEFAULT_GROUP
ServiceName: nr.registryConfig.NacosConfig.Application,
GroupName: nr.registryConfig.NacosConfig.Group, // default value is DEFAULT_GROUP
Clusters: []string{clusterName}, // default value is DEFAULT Clusters: []string{clusterName}, // default value is DEFAULT
SubscribeCallback: func(services []model.SubscribeService, err error) { SubscribeCallback: func(services []model.SubscribeService, err error) {
serviceList := make([]*registry.Service, 0, len(services)) serviceList := make([]*registry.Service, 0, len(services))
@@ -134,18 +133,17 @@ func newNacosRegistry() (registry.Registry, error) {
if err != nil { if err != nil {
return &nacosRegistry{}, err return &nacosRegistry{}, err
} }
tmpRegistry := &nacosRegistry{
namingClient: client,
registry := &nacosRegistry{
registryConfig: config.GetRegistryConfig(),
namingClient: client,
} }
return tmpRegistry, nil
return registry, nil
} }


//获取Nacos配置信息 //获取Nacos配置信息
func getNacosConfig() (map[string]interface{}, error) { func getNacosConfig() (map[string]interface{}, error) {
registryConfig := config.GetRegistryConfig() registryConfig := config.GetRegistryConfig()
if registryConfig.Mode == "" {
registryConfig = clientConfig.GetRegistryConfig()
}

configMap := make(map[string]interface{}, 2) configMap := make(map[string]interface{}, 2)
addr := registryConfig.NacosConfig.ServerAddr addr := registryConfig.NacosConfig.ServerAddr




+ 1
- 1
pkg/client/at/exec/datasource_manager.go View File

@@ -142,7 +142,7 @@ func (resourceManager DataSourceManager) doBranchCommit(request protocal.BranchC
func (resourceManager DataSourceManager) doBranchRollback(request protocal.BranchRollbackRequest) protocal.BranchRollbackResponse { func (resourceManager DataSourceManager) doBranchRollback(request protocal.BranchRollbackRequest) protocal.BranchRollbackResponse {
var resp = protocal.BranchRollbackResponse{} var resp = protocal.BranchRollbackResponse{}


log.Infof("Branch rollbacking: %s %d %s", request.XID, request.BranchID, request.ResourceID)
log.Infof("Branch rolling back: %s %d %s", request.XID, request.BranchID, request.ResourceID)
status, err := resourceManager.BranchRollback(request.BranchType, request.XID, request.BranchID, request.ResourceID, request.ApplicationData) status, err := resourceManager.BranchRollback(request.BranchType, request.XID, request.BranchID, request.ResourceID, request.ApplicationData)
if err != nil { if err != nil {
resp.ResultCode = protocal.ResultCodeFailed resp.ResultCode = protocal.ResultCodeFailed


+ 0
- 27
pkg/client/config/at_config.go View File

@@ -1,27 +0,0 @@
package config

import (
"time"
)

import (
"github.com/pkg/errors"
)

type ATConfig struct {
DSN string `yaml:"dsn" json:"dsn,omitempty"`
ReportRetryCount int `default:"5" yaml:"report_retry_count" json:"report_retry_count,omitempty"`
ReportSuccessEnable bool `default:"false" yaml:"report_success_enable" json:"report_success_enable,omitempty"`
LockRetryItv string `default:"10ms" yaml:"lock_retry_interval" json:"lock_retry_interval,omitempty"`
LockRetryInterval time.Duration
LockRetryTimes int `default:"30" yaml:"lock_retry_times" json:"lock_retry_times,omitempty"`
}

func (c *ATConfig) CheckValidity() error {
var err error

if c.LockRetryInterval, err = time.ParseDuration(c.LockRetryItv); err != nil {
return errors.WithMessagef(err, "time.ParseDuration(LockRetryInterval{%#v})", c.LockRetryItv)
}
return nil
}

+ 73
- 94
pkg/client/config/client_config.go View File

@@ -1,54 +1,49 @@
package config package config


import ( import (
"flag"
"fmt"
"io"
"io/ioutil" "io/ioutil"
"os" "os"
"path"
"time"
) )


import ( import (
"github.com/imdario/mergo" "github.com/imdario/mergo"
"github.com/pkg/errors"
"github.com/shima-park/agollo"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
) )


import ( import (
"github.com/transaction-wg/seata-golang/pkg/base/common/constant"
"github.com/transaction-wg/seata-golang/pkg/base/common/extension"
baseConfig "github.com/transaction-wg/seata-golang/pkg/base/config"
"github.com/transaction-wg/seata-golang/pkg/base/config"
"github.com/transaction-wg/seata-golang/pkg/base/config_center" "github.com/transaction-wg/seata-golang/pkg/base/config_center"
"github.com/transaction-wg/seata-golang/pkg/tc/config"
"github.com/transaction-wg/seata-golang/pkg/base/extension"
"github.com/transaction-wg/seata-golang/pkg/util/log" "github.com/transaction-wg/seata-golang/pkg/util/log"
"github.com/transaction-wg/seata-golang/pkg/util/parser"
) )


var clientConfig *ClientConfig

type ClientConfig struct { type ClientConfig struct {
ApplicationID string `yaml:"application_id" json:"application_id,omitempty"`
TransactionServiceGroup string `yaml:"transaction_service_group" json:"transaction_service_group,omitempty"`
EnableClientBatchSendRequest bool `yaml:"enable-rpc_client-batch-send-request" json:"enable-rpc_client-batch-send-request,omitempty"`
SeataVersion string `yaml:"seata_version" json:"seata_version,omitempty"`
GettyConfig GettyConfig `yaml:"getty" json:"getty,omitempty"`
TMConfig TMConfig `yaml:"tm" json:"tm,omitempty"`
ATConfig ATConfig `yaml:"at" json:"at,omitempty"`
RegistryConfig config.RegistryConfig `yaml:"registry_config" json:"registry_config,omitempty"` //注册中心配置信息
ConfigCenterConfig baseConfig.ConfigCenterConfig `yaml:"config_center" json:"config_center,omitempty"` //配置中心配置信息
ApplicationID string `yaml:"application_id" json:"application_id,omitempty"`
TransactionServiceGroup string `yaml:"transaction_service_group" json:"transaction_service_group,omitempty"`
EnableClientBatchSendRequest bool `yaml:"enable-rpc_client-batch-send-request" json:"enable-rpc_client-batch-send-request,omitempty"`
SeataVersion string `yaml:"seata_version" json:"seata_version,omitempty"`
GettyConfig GettyConfig `yaml:"getty" json:"getty,omitempty"`

TMConfig TMConfig `yaml:"tm" json:"tm,omitempty"`

ATConfig struct {
DSN string `yaml:"dsn" json:"dsn,omitempty"`
ReportRetryCount int `default:"5" yaml:"report_retry_count" json:"report_retry_count,omitempty"`
ReportSuccessEnable bool `default:"false" yaml:"report_success_enable" json:"report_success_enable,omitempty"`
LockRetryInterval time.Duration `default:"10ms" yaml:"lock_retry_interval" json:"lock_retry_interval,omitempty"`
LockRetryTimes int `default:"30" yaml:"lock_retry_times" json:"lock_retry_times,omitempty"`
} `yaml:"at" json:"at,omitempty"`

RegistryConfig config.RegistryConfig `yaml:"registry_config" json:"registry_config,omitempty"` //注册中心配置信息
ConfigCenterConfig config.ConfigCenterConfig `yaml:"config_center" json:"config_center,omitempty"` //配置中心配置信息
} }


var clientConfig ClientConfig
var (
confFile string
)

func init() {
fs := flag.NewFlagSet("config", flag.ContinueOnError)
fs.StringVar(&confFile, "conConf", os.Getenv(constant.CONF_CLIENT_FILE_PATH), "default client config path")
}
func GetRegistryConfig() config.RegistryConfig {
return clientConfig.RegistryConfig
}
func GetClientConfig() ClientConfig {
func GetClientConfig() *ClientConfig {
return clientConfig return clientConfig
} }


@@ -56,104 +51,88 @@ func GetTMConfig() TMConfig {
return clientConfig.TMConfig return clientConfig.TMConfig
} }


func GetATConfig() ATConfig {
return clientConfig.ATConfig
}

func GetDefaultClientConfig(applicationID string) ClientConfig { func GetDefaultClientConfig(applicationID string) ClientConfig {
return ClientConfig{ return ClientConfig{
ApplicationID: applicationID,
SeataVersion: "1.1.0",
TransactionServiceGroup: "127.0.0.1:8091",
GettyConfig: GetDefaultGettyConfig(),
TMConfig: GetDefaultTmConfig(),
ApplicationID: applicationID,
TransactionServiceGroup: "127.0.0.1:8091",
EnableClientBatchSendRequest: false,
SeataVersion: "1.1.0",
GettyConfig: GetDefaultGettyConfig(),
TMConfig: GetDefaultTmConfig(),
} }
} }


func InitConf() error {
var err error

if confFile == "" {
return errors.New(fmt.Sprintf("application configure file name is nil"))
}
if path.Ext(confFile) != ".yml" {
return errors.New(fmt.Sprintf("application configure file name{%v} suffix must be .yml", confFile))
}

clientConfig = ClientConfig{}
confFileStream, err := ioutil.ReadFile(confFile)
// Parse parses an input configuration yaml document into a Configuration struct
//
// Environment variables may be used to override configuration parameters other than version,
// following the scheme below:
// Configuration.Abc may be replaced by the value of SEATA_ABC,
// Configuration.Abc.Xyz may be replaced by the value of SEATA_ABC_XYZ, and so forth
func parse(rd io.Reader) (*ClientConfig, error) {
in, err := ioutil.ReadAll(rd)
if err != nil { if err != nil {
return errors.WithMessagef(err, fmt.Sprintf("ioutil.ReadFile(file:%s) = error:%s", confFile, err))
return nil, err
} }
err = yaml.Unmarshal(confFileStream, &clientConfig)

p := parser.NewParser("seata")

config := new(ClientConfig)
err = p.Parse(in, config)
if err != nil { if err != nil {
return errors.WithMessagef(err, fmt.Sprintf("yaml.Unmarshal() = error:%s", err))
return nil, err
} }
//加载获取远程配置
loadConfigCenterConfig(&clientConfig.ConfigCenterConfig)

(&clientConfig).GettyConfig.CheckValidity()
(&clientConfig).ATConfig.CheckValidity()


return nil
return config, nil
} }


func loadConfigCenterConfig(conf *baseConfig.ConfigCenterConfig) {
if conf.Mode == "" {
func loadConfigCenterConfig(config *ClientConfig) {
if config.ConfigCenterConfig.Mode == "" {
return return
} }
cc, err := extension.GetConfigCenter(conf.Mode, conf)

cc, err := extension.GetConfigCenter(config.ConfigCenterConfig.Mode, &config.ConfigCenterConfig)
if err != nil { if err != nil {
log.Error("ConfigCenter can not connect success.Error message is %s", err.Error()) log.Error("ConfigCenter can not connect success.Error message is %s", err.Error())
} }
confStr := config_center.LoadConfigCenterConfig(cc, conf, &ClientConfigListener{})
updateConf(&clientConfig, confStr)
}
func updateConf(config *ClientConfig, confStr string) {
newConf := &ClientConfig{}
confByte := []byte(confStr)
yaml.Unmarshal(confByte, newConf)
//合并配置中心的配置和本地文件的配置,形成新的配置
if err := mergo.Merge(config, newConf, mergo.WithOverride); err != nil {
log.Error("merge config fail %s ", err.Error())
}
remoteConfig := config_center.LoadConfigCenterConfig(cc, &config.ConfigCenterConfig, &ClientConfigListener{})
updateConf(clientConfig, remoteConfig)
} }


type ClientConfigListener struct { type ClientConfigListener struct {

} }


func (ClientConfigListener) Process(event *config_center.ConfigChangeEvent) { func (ClientConfigListener) Process(event *config_center.ConfigChangeEvent) {
//更新conf
conf := GetClientConfig() conf := GetClientConfig()
updateConf(&conf, event.Value.(string))
updateConf(conf, event.Value.(string))
} }


func InitConfWithDefault(applicationID string) {
clientConfig = GetDefaultClientConfig(applicationID)
(&clientConfig).GettyConfig.CheckValidity()
func updateConf(config *ClientConfig, remoteConfig string) {
newConf := &ClientConfig{}
confByte := []byte(remoteConfig)
yaml.Unmarshal(confByte, newConf)
if err := mergo.Merge(config, newConf, mergo.WithOverride); err != nil {
log.Error("merge config fail %s ", err.Error())
}
} }


func InitApolloConf(serverAddr string, appID string, nameSpace string) error {

a, err := agollo.New(serverAddr, appID, agollo.AutoFetchOnCacheMiss())
// InitConf init ClientConfig from a file path
func InitConf(confFile string) error {
fp, err := os.Open(confFile)
if err != nil { if err != nil {
return errors.WithMessagef(err, fmt.Sprintf("get etcd error:%s", err))
log.Fatalf("open configuration file fail, %v", err)
} }


var config = a.Get("content", agollo.WithNamespace(nameSpace))
return initCommonConf([]byte(config))
}
defer fp.Close()


func initCommonConf(confStream []byte) error {
var err error
err = yaml.Unmarshal(confStream, &clientConfig)
fmt.Println("config", clientConfig)
conf, err := parse(fp)
if err != nil { if err != nil {
return errors.WithMessagef(err, fmt.Sprintf("yaml.Unmarshal() = error:%s", err))
log.Fatalf("error parsing %s: %v", confFile, err)
} }


(&clientConfig).GettyConfig.CheckValidity()
(&clientConfig).ATConfig.CheckValidity()
loadConfigCenterConfig(conf)
config.InitRegistryConfig(&conf.RegistryConfig)
clientConfig = conf


return nil return nil
} }

+ 9
- 27
pkg/client/config/getty_config.go View File

@@ -1,17 +1,10 @@
package config package config


import ( import (
config2 "github.com/transaction-wg/seata-golang/pkg/base/config"
"time" "time"
) )


import (
"github.com/pkg/errors"
)

import (
"github.com/transaction-wg/seata-golang/pkg/base/getty/config"
)

// GettyConfig // GettyConfig
//Config holds supported types by the multiconfig package //Config holds supported types by the multiconfig package
type GettyConfig struct { type GettyConfig struct {
@@ -20,40 +13,29 @@ type GettyConfig struct {
ConnectionNum int `default:"16" yaml:"connection_number" json:"connection_number,omitempty"` ConnectionNum int `default:"16" yaml:"connection_number" json:"connection_number,omitempty"`


// heartbeat // heartbeat
HeartbeatPrd string `default:"15s" yaml:"heartbeat_period" json:"heartbeat_period,omitempty"`
HeartbeatPeriod time.Duration
HeartbeatPeriod time.Duration `default:"15s" yaml:"heartbeat_period" json:"heartbeat_period,omitempty"`


// getty_session tcp parameters // getty_session tcp parameters
GettySessionParam config.GettySessionParam `required:"true" yaml:"getty_session_param" json:"getty_session_param,omitempty"`
GettySessionParam config2.GettySessionParam `required:"true" yaml:"getty_session_param" json:"getty_session_param,omitempty"`
} }


// CheckValidity ...
func (c *GettyConfig) CheckValidity() error {
var err error

if c.HeartbeatPeriod, err = time.ParseDuration(c.HeartbeatPrd); err != nil {
return errors.WithMessagef(err, "time.ParseDuration(HeartbeatPeriod{%#v})", c.HeartbeatPrd)
}

return errors.WithStack(c.GettySessionParam.CheckValidity())
}


// GetDefaultGettyConfig ... // GetDefaultGettyConfig ...
func GetDefaultGettyConfig() GettyConfig { func GetDefaultGettyConfig() GettyConfig {
return GettyConfig{ return GettyConfig{
ReconnectInterval: 0, ReconnectInterval: 0,
ConnectionNum: 1, ConnectionNum: 1,
HeartbeatPrd: "10s",
GettySessionParam: config.GettySessionParam{
HeartbeatPeriod: 10 * time.Second,
GettySessionParam: config2.GettySessionParam{
CompressEncoding: false, CompressEncoding: false,
TcpNoDelay: true, TcpNoDelay: true,
TcpKeepAlive: true, TcpKeepAlive: true,
KeepAlivePrd: "180s",
KeepAlivePeriod: 180 * time.Second,
TcpRBufSize: 262144, TcpRBufSize: 262144,
TcpWBufSize: 65536, TcpWBufSize: 65536,
TcpReadTmt: "1s",
TcpWriteTmt: "5s",
WaitTmt: "1s",
TcpReadTimeout: time.Second,
TcpWriteTimeout: 5 * time.Second,
WaitTimeout: time.Second,
MaxMsgLen: 4096, MaxMsgLen: 4096,
SessionName: "rpc_client", SessionName: "rpc_client",
}, },


+ 5
- 8
pkg/client/rpc_client.go View File

@@ -12,7 +12,7 @@ import (
) )


import ( import (
"github.com/transaction-wg/seata-golang/pkg/base/common/extension"
"github.com/transaction-wg/seata-golang/pkg/base/extension"
"github.com/transaction-wg/seata-golang/pkg/base/getty/readwriter" "github.com/transaction-wg/seata-golang/pkg/base/getty/readwriter"
"github.com/transaction-wg/seata-golang/pkg/client/config" "github.com/transaction-wg/seata-golang/pkg/client/config"
getty2 "github.com/transaction-wg/seata-golang/pkg/client/rpc_client" getty2 "github.com/transaction-wg/seata-golang/pkg/client/rpc_client"
@@ -20,7 +20,7 @@ import (
) )


type RpcClient struct { type RpcClient struct {
conf config.ClientConfig
conf *config.ClientConfig
gettyClients []getty.Client gettyClients []getty.Client
rpcHandler *getty2.RpcRemoteClient rpcHandler *getty2.RpcRemoteClient
} }
@@ -36,9 +36,7 @@ func NewRpcClient() *RpcClient {
} }


func (c *RpcClient) init() { func (c *RpcClient) init() {
//addressList := strings.Split(c.conf.TransactionServiceGroup, ",")
//通过注册中心获取服务地址信息
addressList := getAvailServerList()
addressList := getAvailServerList(c.conf)
if len(addressList) == 0 { if len(addressList) == 0 {
log.Warn("no have valid seata server list") log.Warn("no have valid seata server list")
} }
@@ -54,9 +52,8 @@ func (c *RpcClient) init() {
} }
} }


func getAvailServerList() []string {
registryConfig := config.GetRegistryConfig()
reg, err := extension.GetRegistry(registryConfig.Mode)
func getAvailServerList(config *config.ClientConfig) []string {
reg, err := extension.GetRegistry(config.RegistryConfig.Mode)
if err != nil { if err != nil {
logger.Errorf("Registry can not connect success, program is going to panic.Error message is %s", err.Error()) logger.Errorf("Registry can not connect success, program is going to panic.Error message is %s", err.Error())
panic(err.Error()) panic(err.Error())


+ 1
- 1
pkg/client/rpc_client/rpc_remoting_client.go View File

@@ -50,7 +50,7 @@ func GetRpcRemoteClient() *RpcRemoteClient {
} }


type RpcRemoteClient struct { type RpcRemoteClient struct {
conf config.ClientConfig
conf *config.ClientConfig
idGenerator *atomic.Uint32 idGenerator *atomic.Uint32
futures *sync.Map futures *sync.Map
mergeMsgMap *sync.Map mergeMsgMap *sync.Map


+ 1
- 1
pkg/client/tcc/tcc_resource_manager.go View File

@@ -176,7 +176,7 @@ func (resourceManager TCCResourceManager) doBranchCommit(request protocal.Branch
func (resourceManager TCCResourceManager) doBranchRollback(request protocal.BranchRollbackRequest) protocal.BranchRollbackResponse { func (resourceManager TCCResourceManager) doBranchRollback(request protocal.BranchRollbackRequest) protocal.BranchRollbackResponse {
var resp = protocal.BranchRollbackResponse{} var resp = protocal.BranchRollbackResponse{}


log.Infof("Branch rollbacking: %s %d %s", request.XID, request.BranchID, request.ResourceID)
log.Infof("Branch rolling back: %s %d %s", request.XID, request.BranchID, request.ResourceID)
status, err := resourceManager.BranchRollback(request.BranchType, request.XID, request.BranchID, request.ResourceID, request.ApplicationData) status, err := resourceManager.BranchRollback(request.BranchType, request.XID, request.BranchID, request.ResourceID, request.ApplicationData)
if err != nil { if err != nil {
resp.ResultCode = protocal.ResultCodeFailed resp.ResultCode = protocal.ResultCodeFailed


+ 0
- 63
pkg/client/tm/proxy_test.go View File

@@ -1,63 +0,0 @@
package tm

import (
"context"
"github.com/transaction-wg/seata-golang/pkg/client"
"testing"
)

import (
"github.com/stretchr/testify/assert"
)

import (
"github.com/transaction-wg/seata-golang/pkg/client/config"
)

type Dog struct {
}

type Cat struct {
}

type ZooService struct {
}

func (svc *ZooService) ManageAnimal(ctx context.Context, dog *Dog, cat *Cat) (bool, error) {
return true, nil
}

type TestService struct {
*ZooService
ManageAnimal func(ctx context.Context, dog *Dog, cat *Cat) (bool, error)
}

var methodTransactionInfo = make(map[string]*TransactionInfo)

func init() {
methodTransactionInfo["ManageAnimal"] = &TransactionInfo{
TimeOut: 60000,
Name: "",
Propagation: REQUIRED,
}
}

func (svc *TestService) GetProxyService() interface{} {
return svc.ZooService
}

func (svc *TestService) GetMethodTransactionInfo(methodName string) *TransactionInfo {
return methodTransactionInfo[methodName]
}

func TestProxy_Implement(t *testing.T) {
config.InitConfWithDefault("testService")
client.NewRpcClient()
zooSvc := &ZooService{}

ts := &TestService{ZooService: zooSvc}
Implement(ts)
result, err := ts.ManageAnimal(context.Background(), &Dog{}, &Cat{})
assert.True(t, result)
assert.Nil(t, err)
}

+ 0
- 60
pkg/tc/config/getty_config.go View File

@@ -1,60 +0,0 @@
package config

import (
"time"
)

import (
getty "github.com/apache/dubbo-getty"
"github.com/pkg/errors"
)

import (
"github.com/transaction-wg/seata-golang/pkg/base/getty/config"
)

// Config holds supported types by the multiconfig package
type GettyConfig struct {
// getty_session
Session_Timeout string `default:"60s" yaml:"session_timeout" json:"session_timeout,omitempty"`
SessionTimeout time.Duration

// getty_session tcp parameters
GettySessionParam config.GettySessionParam `required:"true" yaml:"getty_session_param" json:"getty_session_param,omitempty"`
}

// CheckValidity ...
func (c *GettyConfig) CheckValidity() error {
var err error

if c.SessionTimeout, err = time.ParseDuration(c.Session_Timeout); err != nil {
return errors.WithMessagef(err, "time.ParseDuration(SessionTimeout{%#v})", c.SessionTimeout)
}

if c.SessionTimeout >= time.Duration(getty.MaxWheelTimeSpan) {
return errors.WithMessagef(err, "session_timeout %s should be less than %s",
c.SessionTimeout, time.Duration(getty.MaxWheelTimeSpan))
}

return errors.WithStack(c.GettySessionParam.CheckValidity())
}

// GetDefaultGettyConfig ...
func GetDefaultGettyConfig() GettyConfig {
return GettyConfig{
Session_Timeout: "180s",
GettySessionParam: config.GettySessionParam{
CompressEncoding: false,
TcpNoDelay: true,
TcpKeepAlive: true,
KeepAlivePrd: "180s",
TcpRBufSize: 262144,
TcpWBufSize: 65536,
TcpReadTmt: "1s",
TcpWriteTmt: "5s",
WaitTmt: "1s",
MaxMsgLen: 102400,
SessionName: "server",
},
}
}

+ 99
- 101
pkg/tc/config/server_config.go View File

@@ -2,161 +2,159 @@ package config


import ( import (
"fmt" "fmt"
"github.com/go-xorm/xorm"
"io"
"io/ioutil" "io/ioutil"
"os" "os"
"path"
"time" "time"
) )


import ( import (
"github.com/go-xorm/xorm"
getty "github.com/apache/dubbo-getty"
"github.com/imdario/mergo" "github.com/imdario/mergo"
"github.com/pkg/errors" "github.com/pkg/errors"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
) )

import ( import (
"github.com/transaction-wg/seata-golang/pkg/base/common/extension"
baseConfig "github.com/transaction-wg/seata-golang/pkg/base/config"
"github.com/transaction-wg/seata-golang/pkg/base/config"
"github.com/transaction-wg/seata-golang/pkg/base/config_center" "github.com/transaction-wg/seata-golang/pkg/base/config_center"
"github.com/transaction-wg/seata-golang/pkg/base/extension"
"github.com/transaction-wg/seata-golang/pkg/util/log" "github.com/transaction-wg/seata-golang/pkg/util/log"
"github.com/transaction-wg/seata-golang/pkg/util/parser"
) )


var (
conf ServerConfig
)

func GetServerConfig() ServerConfig {
return conf
}

func GetStoreConfig() StoreConfig {
return conf.StoreConfig
}
func GetRegistryConfig() RegistryConfig {
return conf.RegistryConfig
}
func GetConfigCenterConfig() baseConfig.ConfigCenterConfig {
return conf.ConfigCenterConfig
}
var serverConfig *ServerConfig


type ServerConfig struct { type ServerConfig struct {
Host string `yaml:"host" default:"127.0.0.1" json:"host,omitempty"`
Port string `default:"8091" yaml:"port" json:"port,omitempty"` Port string `default:"8091" yaml:"port" json:"port,omitempty"`
MaxRollbackRetryTimeout int64 `default:"-1" yaml:"max_rollback_retry_timeout" json:"max_rollback_retry_timeout,omitempty"` MaxRollbackRetryTimeout int64 `default:"-1" yaml:"max_rollback_retry_timeout" json:"max_rollback_retry_timeout,omitempty"`
RollbackRetryTimeoutUnlockEnable bool `default:"false" yaml:"rollback_retry_timeout_unlock_enable" json:"rollback_retry_timeout_unlock_enable,omitempty"` RollbackRetryTimeoutUnlockEnable bool `default:"false" yaml:"rollback_retry_timeout_unlock_enable" json:"rollback_retry_timeout_unlock_enable,omitempty"`
MaxCommitRetryTimeout int64 `default:"-1" yaml:"max_commit_retry_timeout" json:"max_commit_retry_timeout,omitempty"` MaxCommitRetryTimeout int64 `default:"-1" yaml:"max_commit_retry_timeout" json:"max_commit_retry_timeout,omitempty"`
Timeout_Retry_Period string `default:"1s" yaml:"timeout_retry_period" json:"timeout_retry_period,omitempty"`
TimeoutRetryPeriod time.Duration
Rollbacking_Retry_Period string `default:"1s" yaml:"rollbacking_retry_period" json:"rollbacking_retry_period,omitempty"`
RollbackingRetryPeriod time.Duration
Committing_Retry_Period string `default:"1s" yaml:"committing_retry_period" json:"committing_retry_period,omitempty"`
CommittingRetryPeriod time.Duration
Async_Committing_Retry_Period string `default:"1s" yaml:"async_committing_retry_period" json:"async_committing_retry_period,omitempty"`
AsyncCommittingRetryPeriod time.Duration
Log_Delete_Period string `default:"24h" yaml:"log_delete_period" json:"log_delete_period,omitempty"`
LogDeletePeriod time.Duration
GettyConfig GettyConfig `required:"true" yaml:"getty_config" json:"getty_config,omitempty"`
UndoConfig UndoConfig `required:"true" yaml:"undo_config" json:"undo_config,omitempty"`
StoreConfig StoreConfig `required:"true" yaml:"store_config" json:"store_config,omitempty"`
RegistryConfig RegistryConfig `yaml:"registry_config" json:"registry_config,omitempty"` //注册中心配置信息
ConfigCenterConfig baseConfig.ConfigCenterConfig `yaml:"config_center" json:"config_center,omitempty"` //配置中心配置信息
}


func (c *ServerConfig) CheckValidity() error {
var err error
if conf.TimeoutRetryPeriod, err = time.ParseDuration(conf.Timeout_Retry_Period); err != nil {
return errors.WithMessagef(err, "time.ParseDuration(Timeout_Retry_Period{%#v})", conf.Timeout_Retry_Period)
}

if conf.RollbackingRetryPeriod, err = time.ParseDuration(conf.Rollbacking_Retry_Period); err != nil {
return errors.WithMessagef(err, "time.ParseDuration(Rollbacking_Retry_Period{%#v})", conf.Rollbacking_Retry_Period)
}
TimeoutRetryPeriod time.Duration `default:"1s" yaml:"timeout_retry_period" json:"timeout_retry_period,omitempty"`
RollingBackRetryPeriod time.Duration `default:"1s" yaml:"rolling_back_retry_period" json:"rolling_back_retry_period,omitempty"`
CommittingRetryPeriod time.Duration `default:"1s" yaml:"committing_retry_period" json:"committing_retry_period,omitempty"`
AsyncCommittingRetryPeriod time.Duration `default:"1s" yaml:"async_committing_retry_period" json:"async_committing_retry_period,omitempty"`
LogDeletePeriod time.Duration `default:"24h" yaml:"log_delete_period" json:"log_delete_period,omitempty"`


if conf.CommittingRetryPeriod, err = time.ParseDuration(conf.Committing_Retry_Period); err != nil {
return errors.WithMessagef(err, "time.ParseDuration(Committing_Retry_Period{%#v})", conf.Committing_Retry_Period)
}
GettyConfig struct {
SessionTimeout time.Duration `default:"60s" yaml:"session_timeout" json:"session_timeout,omitempty"`


if conf.AsyncCommittingRetryPeriod, err = time.ParseDuration(conf.Async_Committing_Retry_Period); err != nil {
return errors.WithMessagef(err, "time.ParseDuration(Async_Committing_Retry_Period{%#v})", conf.Async_Committing_Retry_Period)
}
GettySessionParam config.GettySessionParam `required:"true" yaml:"getty_session_param" json:"getty_session_param,omitempty"`
} `required:"true" yaml:"getty_config" json:"getty_config,omitempty"`


if conf.LogDeletePeriod, err = time.ParseDuration(conf.Log_Delete_Period); err != nil {
return errors.WithMessagef(err, "time.ParseDuration(Log_Delete_Period{%#v})", conf.Log_Delete_Period)
}
UndoConfig struct {
LogSaveDays int16 `default:"7" yaml:"log_save_days" json:"log_save_days,omitempty"`
} `required:"true" yaml:"undo_config" json:"undo_config,omitempty"`


return errors.WithStack(c.GettyConfig.CheckValidity())
StoreConfig StoreConfig `required:"true" yaml:"store_config" json:"store_config,omitempty"`
RegistryConfig config.RegistryConfig `yaml:"registry_config" json:"registry_config,omitempty"` //注册中心配置信息
ConfigCenterConfig config.ConfigCenterConfig `yaml:"config_center" json:"config_center,omitempty"` //配置中心配置信息
} }


// LoadFromEnv provides env variable fallback for config.
// Credential configs, such as db password, can be provided by env variables.
func (c *ServerConfig) LoadFromEnv() {
// store config
if c.StoreConfig.DBStoreConfig.DSN == "" {
c.StoreConfig.DBStoreConfig.DSN = os.Getenv("SEATA_STORE_DB_DSN")
}
func GetServerConfig() *ServerConfig {
return serverConfig
} }


func InitConf(confFile string) error {
var err error

if confFile == "" {
return errors.WithMessagef(err, fmt.Sprintf("application configure file name is nil"))
}
if path.Ext(confFile) != ".yml" {
return errors.WithMessagef(err, fmt.Sprintf("application configure file name{%v} suffix must be .yml", confFile))
}
func GetStoreConfig() StoreConfig {
return serverConfig.StoreConfig
}


conf = ServerConfig{}
confFileStream, err := ioutil.ReadFile(confFile)
// Parse parses an input configuration yaml document into a ServerConfig struct
//
// Environment variables may be used to override configuration parameters other than version,
// following the scheme below:
// ServerConfig.Abc may be replaced by the value of SEATA_ABC,
// ServerConfig.Abc.Xyz may be replaced by the value of SEATA_ABC_XYZ, and so forth
func parse(rd io.Reader) (*ServerConfig, error) {
in, err := ioutil.ReadAll(rd)
if err != nil { if err != nil {
return errors.WithMessagef(err, fmt.Sprintf("ioutil.ReadFile(file:%s) = error:%s", confFile, err))
return nil, err
} }
err = yaml.Unmarshal(confFileStream, &conf)

p := parser.NewParser("seata")

config := new(ServerConfig)
err = p.Parse(in, config)
if err != nil { if err != nil {
return errors.WithMessagef(err, fmt.Sprintf("yaml.Unmarshal() = error:%s", err))
}
(&conf).LoadFromEnv()
//加载获取远程配置
loadConfigCenterConfig(&conf.ConfigCenterConfig)
(&conf).CheckValidity()
if conf.StoreConfig.StoreMode == "db" && conf.StoreConfig.DBStoreConfig.DSN != "" {
engine, err := xorm.NewEngine("mysql", conf.StoreConfig.DBStoreConfig.DSN)
if err != nil {
panic(err)
}
conf.StoreConfig.DBStoreConfig.Engine = engine
return nil, err
} }


return nil
return config, nil
} }


func loadConfigCenterConfig(centerConf *baseConfig.ConfigCenterConfig) {
if centerConf.Mode == "" {
func loadConfigCenterConfig(config *ServerConfig) {
if config.ConfigCenterConfig.Mode == "" {
return return
} }
cc, err := extension.GetConfigCenter(centerConf.Mode, centerConf)
cc, err := extension.GetConfigCenter(config.ConfigCenterConfig.Mode, &config.ConfigCenterConfig)
if err != nil { if err != nil {
log.Error("ConfigCenter can not connect success.Error message is %s", err.Error()) log.Error("ConfigCenter can not connect success.Error message is %s", err.Error())
} }
confStr := config_center.LoadConfigCenterConfig(cc, centerConf, &ServerConfigListener{})
updateConf(&conf, confStr)
remoteConfig := config_center.LoadConfigCenterConfig(cc, &config.ConfigCenterConfig, &ServerConfigListener{})
updateConf(config, remoteConfig)
} }


type ServerConfigListener struct { type ServerConfigListener struct {

} }


func (ServerConfigListener) Process(event *config_center.ConfigChangeEvent) { func (ServerConfigListener) Process(event *config_center.ConfigChangeEvent) {
//更新conf
conf := GetServerConfig()
updateConf(&conf, event.Value.(string))
serverConfig := GetServerConfig()
updateConf(serverConfig, event.Value.(string))
} }


func updateConf(config *ServerConfig, confStr string) {
func updateConf(config *ServerConfig, remoteConfig string) {
newConf := &ServerConfig{} newConf := &ServerConfig{}
confByte := []byte(confStr)
confByte := []byte(remoteConfig)
yaml.Unmarshal(confByte, newConf) yaml.Unmarshal(confByte, newConf)
//合并配置中心的配置和本地文件的配置,形成新的配置
if err := mergo.Merge(config, newConf, mergo.WithOverride); err != nil { if err := mergo.Merge(config, newConf, mergo.WithOverride); err != nil {
log.Error("merge config fail %s ", err.Error()) log.Error("merge config fail %s ", err.Error())
} }
} }

func InitConf(configPath string) (*ServerConfig, error) {
var configFilePath string

if configPath != "" {
configFilePath = configPath
} else if os.Getenv("SEATA_CONFIGURATION_PATH") != "" {
configFilePath = os.Getenv("SEATA_CONFIGURATION_PATH")
}

if configFilePath == "" {
return nil, fmt.Errorf("configuration path unspecified")
}

fp, err := os.Open(configFilePath)
if err != nil {
return nil, err
}

defer fp.Close()

conf, err := parse(fp)
if err != nil {
return nil, fmt.Errorf("error parsing %s: %v", configFilePath, err)
}

if conf.GettyConfig.SessionTimeout >= time.Duration(getty.MaxWheelTimeSpan) {
return nil, errors.Errorf("session_timeout %s should be less than %s",
serverConfig.GettyConfig.SessionTimeout, time.Duration(getty.MaxWheelTimeSpan))
}

loadConfigCenterConfig(conf)
config.InitRegistryConfig(&conf.RegistryConfig)
serverConfig = conf

if conf.StoreConfig.StoreMode == "db" && conf.StoreConfig.DBStoreConfig.DSN != "" {
engine, err := xorm.NewEngine("mysql", conf.StoreConfig.DBStoreConfig.DSN)
if err != nil {
panic(err)
}
conf.StoreConfig.DBStoreConfig.Engine = engine
}

return serverConfig, nil
}

+ 0
- 5
pkg/tc/config/undo_config.go View File

@@ -1,5 +0,0 @@
package config

type UndoConfig struct {
LogSaveDays int16 `default:"7" yaml:"log_save_days" json:"log_save_days,omitempty"`
}

+ 3
- 7
pkg/tc/holder/db_based_session_manager.go View File

@@ -9,7 +9,6 @@ import (
"github.com/transaction-wg/seata-golang/pkg/tc/config" "github.com/transaction-wg/seata-golang/pkg/tc/config"
"github.com/transaction-wg/seata-golang/pkg/tc/model" "github.com/transaction-wg/seata-golang/pkg/tc/model"
"github.com/transaction-wg/seata-golang/pkg/tc/session" "github.com/transaction-wg/seata-golang/pkg/tc/session"
"github.com/transaction-wg/seata-golang/pkg/util/uuid"
) )


type DataBaseSessionManager struct { type DataBaseSessionManager struct {
@@ -123,7 +122,7 @@ func (sessionManager *DataBaseSessionManager) AllSessions() []*session.GlobalSes
ss := sessionManager.FindGlobalSessions(model.SessionCondition{ ss := sessionManager.FindGlobalSessions(model.SessionCondition{
Statuses: []meta.GlobalStatus{meta.GlobalStatusRollbackRetrying, Statuses: []meta.GlobalStatus{meta.GlobalStatusRollbackRetrying,
meta.GlobalStatusRollbacking, meta.GlobalStatusRollbacking,
meta.GlobalStatusTimeoutRollbacking,
meta.GlobalStatusTimeoutRollingBack,
meta.GlobalStatusTimeoutRollbackRetrying, meta.GlobalStatusTimeoutRollbackRetrying,
}, },
}) })
@@ -132,7 +131,7 @@ func (sessionManager *DataBaseSessionManager) AllSessions() []*session.GlobalSes
return sessionManager.FindGlobalSessions(model.SessionCondition{ return sessionManager.FindGlobalSessions(model.SessionCondition{
Statuses: []meta.GlobalStatus{meta.GlobalStatusUnknown, meta.GlobalStatusBegin, Statuses: []meta.GlobalStatus{meta.GlobalStatusUnknown, meta.GlobalStatusBegin,
meta.GlobalStatusCommitting, meta.GlobalStatusCommitRetrying, meta.GlobalStatusRollbacking, meta.GlobalStatusCommitting, meta.GlobalStatusCommitRetrying, meta.GlobalStatusRollbacking,
meta.GlobalStatusRollbackRetrying, meta.GlobalStatusTimeoutRollbacking, meta.GlobalStatusTimeoutRollbackRetrying,
meta.GlobalStatusRollbackRetrying, meta.GlobalStatusTimeoutRollingBack, meta.GlobalStatusTimeoutRollbackRetrying,
meta.GlobalStatusAsyncCommitting, meta.GlobalStatusAsyncCommitting,
}, },
}) })
@@ -144,8 +143,5 @@ func (sessionManager *DataBaseSessionManager) FindGlobalSessions(condition model
} }


func (sessionManager *DataBaseSessionManager) Reload() { func (sessionManager *DataBaseSessionManager) Reload() {
maxSessionID := sessionManager.TransactionStoreManager.GetCurrentMaxSessionID()
if maxSessionID > uuid.UUID {
uuid.SetUUID(uuid.UUID, maxSessionID)
}

} }

+ 0
- 5
pkg/tc/holder/db_transaction_store_manager.go View File

@@ -5,7 +5,6 @@ import (
"github.com/transaction-wg/seata-golang/pkg/tc/model" "github.com/transaction-wg/seata-golang/pkg/tc/model"
"github.com/transaction-wg/seata-golang/pkg/tc/session" "github.com/transaction-wg/seata-golang/pkg/tc/session"
"github.com/transaction-wg/seata-golang/pkg/util/log" "github.com/transaction-wg/seata-golang/pkg/util/log"
"github.com/transaction-wg/seata-golang/pkg/util/uuid"
) )


type DBTransactionStoreManager struct { type DBTransactionStoreManager struct {
@@ -144,10 +143,6 @@ func (storeManager *DBTransactionStoreManager) Shutdown() {


} }


func (storeManager *DBTransactionStoreManager) GetCurrentMaxSessionID() int64 {
return storeManager.LogStore.GetCurrentMaxSessionID(uuid.GetMaxUUID(), uuid.GetInitUUID())
}

func getGlobalSession(globalTransactionDO *model.GlobalTransactionDO, branchTransactionDOs []*model.BranchTransactionDO) *session.GlobalSession { func getGlobalSession(globalTransactionDO *model.GlobalTransactionDO, branchTransactionDOs []*model.BranchTransactionDO) *session.GlobalSession {
globalSession := convertGlobalTransaction(globalTransactionDO) globalSession := convertGlobalTransaction(globalTransactionDO)
if branchTransactionDOs != nil && len(branchTransactionDOs) > 0 { if branchTransactionDOs != nil && len(branchTransactionDOs) > 0 {


+ 2
- 2
pkg/tc/holder/default_session_manager_test.go View File

@@ -35,7 +35,7 @@ func TestDefaultSessionManager_FindGlobalSession(t *testing.T) {
} }


func globalSessionsProvider() []*session.GlobalSession { func globalSessionsProvider() []*session.GlobalSession {
common.GetXID().Init("127.0.0.1", 9876)
common.Init("127.0.0.1", 9876)


result := make([]*session.GlobalSession, 0) result := make([]*session.GlobalSession, 0)
gs1 := session.NewGlobalSession( gs1 := session.NewGlobalSession(
@@ -60,7 +60,7 @@ func globalSessionsProvider() []*session.GlobalSession {
func globalSessionProvider(t *testing.T) *session.GlobalSession { func globalSessionProvider(t *testing.T) *session.GlobalSession {
testutil.InitServerConfig(t) testutil.InitServerConfig(t)


common.GetXID().Init("127.0.0.1", 9876)
common.Init("127.0.0.1", 9876)


gs := session.NewGlobalSession( gs := session.NewGlobalSession(
session.WithGsApplicationID("demo-cmd"), session.WithGsApplicationID("demo-cmd"),


+ 0
- 37
pkg/tc/holder/file_based_session_manager.go View File

@@ -5,7 +5,6 @@ import (
"github.com/transaction-wg/seata-golang/pkg/tc/config" "github.com/transaction-wg/seata-golang/pkg/tc/config"
"github.com/transaction-wg/seata-golang/pkg/tc/session" "github.com/transaction-wg/seata-golang/pkg/tc/session"
"github.com/transaction-wg/seata-golang/pkg/util/log" "github.com/transaction-wg/seata-golang/pkg/util/log"
"github.com/transaction-wg/seata-golang/pkg/util/uuid"
) )


type FileBasedSessionManager struct { type FileBasedSessionManager struct {
@@ -89,11 +88,9 @@ func (sessionManager *FileBasedSessionManager) washSessions() {
} }


func (sessionManager *FileBasedSessionManager) restore(stores []*TransactionWriteStore, unhandledBranchSessions map[int64]*session.BranchSession) { func (sessionManager *FileBasedSessionManager) restore(stores []*TransactionWriteStore, unhandledBranchSessions map[int64]*session.BranchSession) {
maxRecoverID := uuid.UUID
for _, store := range stores { for _, store := range stores {
logOperation := store.LogOperation logOperation := store.LogOperation
sessionStorable := store.SessionRequest sessionStorable := store.SessionRequest
maxRecoverID = getMaxID(maxRecoverID, sessionStorable)
switch logOperation { switch logOperation {
case LogOperationGlobalAdd, LogOperationGlobalUpdate: case LogOperationGlobalAdd, LogOperationGlobalUpdate:
{ {
@@ -164,38 +161,4 @@ func (sessionManager *FileBasedSessionManager) restore(stores []*TransactionWrit
break break
} }
} }
setMaxID(maxRecoverID)
}

func getMaxID(maxRecoverID int64, sessionStorable session.SessionStorable) int64 {
var currentID int64 = 0
var gs, ok1 = sessionStorable.(*session.GlobalSession)
if ok1 {
currentID = gs.TransactionID
}

var bs, ok2 = sessionStorable.(*session.BranchSession)
if ok2 {
currentID = bs.BranchID
}

if maxRecoverID > currentID {
return maxRecoverID
} else {
return currentID
}
}

func setMaxID(maxRecoverID int64) {
var currentID int64
// will be recover multi-thread later
for {
currentID = uuid.UUID
if currentID < maxRecoverID {
if uuid.SetUUID(currentID, maxRecoverID) {
break
}
}
break
}
} }

+ 0
- 3
pkg/tc/holder/file_transaction_store_manager.go View File

@@ -113,9 +113,6 @@ func (storeManager *FileTransactionStoreManager) Shutdown() {
storeManager.currFileChannel.Close() storeManager.currFileChannel.Close()
} }


func (storeManager *FileTransactionStoreManager) GetCurrentMaxSessionID() int64 {
return int64(0)
}


func (storeManager *FileTransactionStoreManager) saveHistory() { func (storeManager *FileTransactionStoreManager) saveHistory() {
storeManager.findTimeoutAndSave() storeManager.findTimeoutAndSave()


+ 1
- 1
pkg/tc/holder/log_store_database_dao.go View File

@@ -25,7 +25,7 @@ const (
status, client_id, application_data, gmt_create, gmt_modified) values(?, ?, ?, ?, ?, ?, ?, ?, ?, now(6), now(6))` status, client_id, application_data, gmt_create, gmt_modified) values(?, ?, ?, ?, ?, ?, ?, ?, ?, now(6), now(6))`
UpdateBranchTransactionDO = "update branch_table set status = ?, gmt_modified = now(6) where xid = ? and branch_id = ?" UpdateBranchTransactionDO = "update branch_table set status = ?, gmt_modified = now(6) where xid = ? and branch_id = ?"
DeleteBranchTransactionDO = "delete from branch_table where xid = ? and branch_id = ?" DeleteBranchTransactionDO = "delete from branch_table where xid = ? and branch_id = ?"
QueryMaxTransactionID = "select max(transaction_id) as maxTransactioID from global_table where transaction_id < ? and transaction_id > ?"
QueryMaxTransactionID = "select max(transaction_id) as maxTransactionID from global_table where transaction_id < ? and transaction_id > ?"
QueryMaxBranchID = "select max(branch_id) as maxBranchID from branch_table where branch_id < ? and branch_id > ?" QueryMaxBranchID = "select max(branch_id) as maxBranchID from branch_table where branch_id < ? and branch_id > ?"
) )




+ 1
- 1
pkg/tc/holder/session_holder.go View File

@@ -82,7 +82,7 @@ func (sessionHolder SessionHolder) reload() {
case meta.GlobalStatusCommitting, meta.GlobalStatusCommitRetrying: case meta.GlobalStatusCommitting, meta.GlobalStatusCommitRetrying:
sessionHolder.RetryCommittingSessionManager.AddGlobalSession(globalSession) sessionHolder.RetryCommittingSessionManager.AddGlobalSession(globalSession)
break break
case meta.GlobalStatusRollbacking, meta.GlobalStatusRollbackRetrying, meta.GlobalStatusTimeoutRollbacking,
case meta.GlobalStatusRollbacking, meta.GlobalStatusRollbackRetrying, meta.GlobalStatusTimeoutRollingBack,
meta.GlobalStatusTimeoutRollbackRetrying: meta.GlobalStatusTimeoutRollbackRetrying:
sessionHolder.RetryRollbackingSessionManager.AddGlobalSession(globalSession) sessionHolder.RetryRollbackingSessionManager.AddGlobalSession(globalSession)
break break


+ 0
- 3
pkg/tc/holder/transaction_store_manager.go View File

@@ -74,9 +74,6 @@ type TransactionStoreManager interface {


// Shutdown. // Shutdown.
Shutdown() Shutdown()

// Gets current max session id.
GetCurrentMaxSessionID() int64
} }


type AbstractTransactionStoreManager struct { type AbstractTransactionStoreManager struct {


+ 12
- 10
pkg/tc/lock/lock_manager_test.go View File

@@ -24,8 +24,9 @@ func TestLockManager_AcquireLock(t *testing.T) {
} }


func TestLockManager_IsLockable(t *testing.T) { func TestLockManager_IsLockable(t *testing.T) {
transID := uuid.GeneratorUUID()
ok := GetLockManager().IsLockable(common.GetXID().GenerateXID(transID), "tb_1", "tb_1:13")
transID := uuid.NextID()
common.Init("127.0.0.1", 9876)
ok := GetLockManager().IsLockable(common.GenerateXID(transID), "tb_1", "tb_1:13")
assert.Equal(t, ok, true) assert.Equal(t, ok, true)
} }


@@ -67,7 +68,7 @@ func TestLockManager_IsLockable2(t *testing.T) {
result1 := GetLockManager().IsLockable(bs.XID, bs.ResourceID, bs.LockKey) result1 := GetLockManager().IsLockable(bs.XID, bs.ResourceID, bs.LockKey)
assert.True(t, result1) assert.True(t, result1)
GetLockManager().AcquireLock(bs) GetLockManager().AcquireLock(bs)
bs.TransactionID = uuid.GeneratorUUID()
bs.TransactionID = uuid.NextID()
result2 := GetLockManager().IsLockable(bs.XID, bs.ResourceID, bs.LockKey) result2 := GetLockManager().IsLockable(bs.XID, bs.ResourceID, bs.LockKey)
assert.False(t, result2) assert.False(t, result2)
} }
@@ -103,10 +104,11 @@ func branchSessionsProvider() []*session.BranchSession {


func baseBranchSessionsProvider(resourceID string, lockKey1 string, lockKey2 string) []*session.BranchSession { func baseBranchSessionsProvider(resourceID string, lockKey1 string, lockKey2 string) []*session.BranchSession {
var branchSessions = make([]*session.BranchSession, 0) var branchSessions = make([]*session.BranchSession, 0)
transID := uuid.GeneratorUUID()
transID2 := uuid.GeneratorUUID()
transID := uuid.NextID()
transID2 := uuid.NextID()
common.Init("127.0.0.1", 9876)
bs := session.NewBranchSession( bs := session.NewBranchSession(
session.WithBsXid(common.GetXID().GenerateXID(transID)),
session.WithBsXid(common.GenerateXID(transID)),
session.WithBsTransactionID(transID), session.WithBsTransactionID(transID),
session.WithBsBranchID(1), session.WithBsBranchID(1),
session.WithBsResourceGroupID("my_test_tx_group"), session.WithBsResourceGroupID("my_test_tx_group"),
@@ -119,7 +121,7 @@ func baseBranchSessionsProvider(resourceID string, lockKey1 string, lockKey2 str
) )


bs1 := session.NewBranchSession( bs1 := session.NewBranchSession(
session.WithBsXid(common.GetXID().GenerateXID(transID2)),
session.WithBsXid(common.GenerateXID(transID2)),
session.WithBsTransactionID(transID2), session.WithBsTransactionID(transID2),
session.WithBsBranchID(1), session.WithBsBranchID(1),
session.WithBsResourceGroupID("my_test_tx_group"), session.WithBsResourceGroupID("my_test_tx_group"),
@@ -137,11 +139,11 @@ func baseBranchSessionsProvider(resourceID string, lockKey1 string, lockKey2 str
} }


func branchSessionProvider() *session.BranchSession { func branchSessionProvider() *session.BranchSession {
common.GetXID().Init("127.0.0.1", 9876)
common.Init("127.0.0.1", 9876)


transID := uuid.GeneratorUUID()
transID := uuid.NextID()
bs := session.NewBranchSession( bs := session.NewBranchSession(
session.WithBsXid(common.GetXID().GenerateXID(transID)),
session.WithBsXid(common.GenerateXID(transID)),
session.WithBsTransactionID(transID), session.WithBsTransactionID(transID),
session.WithBsBranchID(1), session.WithBsBranchID(1),
session.WithBsResourceGroupID("my_test_tx_group"), session.WithBsResourceGroupID("my_test_tx_group"),


+ 1
- 1
pkg/tc/lock/lock_store_database_dao_test.go View File

@@ -17,5 +17,5 @@ func TestLockStoreDataBaseDao_UnLockByXidAndBranchIDs(t *testing.T) {
} }
lockStore := &LockStoreDataBaseDao{engine: engine} lockStore := &LockStoreDataBaseDao{engine: engine}


lockStore.UnLockByXidAndBranchIDs(":0:2000042936", []int64{2000042938})
lockStore.UnLockByXIDAndBranchIDs(":0:2000042936", []int64{2000042938})
} }

+ 48
- 43
pkg/tc/server/default_coordinator.go View File

@@ -27,38 +27,28 @@ import (
) )


const ( const (
RPC_REQUEST_TIMEOUT = 30 * time.Second
ALWAYS_RETRY_BOUNDARY = 0
RpcRequestTimeout = 30 * time.Second
AlwaysRetryBoundary = 0
) )


type DefaultCoordinator struct { type DefaultCoordinator struct {
conf config.ServerConfig
conf *config.ServerConfig
core TransactionCoordinator core TransactionCoordinator
idGenerator *atomic.Uint32 idGenerator *atomic.Uint32
futures *sync.Map futures *sync.Map
timeoutCheckTicker *time.Ticker
retryRollbackingTicker *time.Ticker
retryCommittingTicker *time.Ticker
asyncCommittingTicker *time.Ticker
undoLogDeleteTicker *time.Ticker
} }


func NewDefaultCoordinator(conf config.ServerConfig) *DefaultCoordinator {
func NewDefaultCoordinator(conf *config.ServerConfig) *DefaultCoordinator {
coordinator := &DefaultCoordinator{ coordinator := &DefaultCoordinator{
conf: conf, conf: conf,
idGenerator: &atomic.Uint32{}, idGenerator: &atomic.Uint32{},
futures: &sync.Map{}, futures: &sync.Map{},
timeoutCheckTicker: time.NewTicker(conf.TimeoutRetryPeriod),
retryRollbackingTicker: time.NewTicker(conf.RollbackingRetryPeriod),
retryCommittingTicker: time.NewTicker(conf.CommittingRetryPeriod),
asyncCommittingTicker: time.NewTicker(conf.AsyncCommittingRetryPeriod),
undoLogDeleteTicker: time.NewTicker(conf.LogDeletePeriod),
} }
core := NewCore(coordinator) core := NewCore(coordinator)
coordinator.core = core coordinator.core = core


go coordinator.processTimeoutCheck() go coordinator.processTimeoutCheck()
go coordinator.processRetryRollbacking()
go coordinator.processRetryRollingBack()
go coordinator.processRetryCommitting() go coordinator.processRetryCommitting()
go coordinator.processAsyncCommitting() go coordinator.processAsyncCommitting()
go coordinator.processUndoLogDelete() go coordinator.processUndoLogDelete()
@@ -139,36 +129,56 @@ func (coordinator *DefaultCoordinator) defaultSendResponse(request protocal.RpcM


func (coordinator *DefaultCoordinator) processTimeoutCheck() { func (coordinator *DefaultCoordinator) processTimeoutCheck() {
for { for {
<-coordinator.timeoutCheckTicker.C
coordinator.timeoutCheck()
timer := time.NewTimer(coordinator.conf.TimeoutRetryPeriod)
select {
case <-timer.C:
coordinator.timeoutCheck()
}
timer.Stop()
} }
} }


func (coordinator *DefaultCoordinator) processRetryRollbacking() {
func (coordinator *DefaultCoordinator) processRetryRollingBack() {
for { for {
<-coordinator.retryRollbackingTicker.C
coordinator.handleRetryRollbacking()
timer := time.NewTimer(coordinator.conf.RollingBackRetryPeriod)
select {
case <-timer.C:
coordinator.handleRetryRollbacking()
}
timer.Stop()
} }
} }


func (coordinator *DefaultCoordinator) processRetryCommitting() { func (coordinator *DefaultCoordinator) processRetryCommitting() {
for { for {
<-coordinator.retryCommittingTicker.C
coordinator.handleRetryCommitting()
timer := time.NewTimer(coordinator.conf.CommittingRetryPeriod)
select {
case <-timer.C:
coordinator.handleRetryCommitting()
}
timer.Stop()
} }
} }


func (coordinator *DefaultCoordinator) processAsyncCommitting() { func (coordinator *DefaultCoordinator) processAsyncCommitting() {
for { for {
<-coordinator.asyncCommittingTicker.C
coordinator.handleAsyncCommitting()
timer := time.NewTimer(coordinator.conf.AsyncCommittingRetryPeriod)
select {
case <-timer.C:
coordinator.handleAsyncCommitting()
}
timer.Stop()
} }
} }


func (coordinator *DefaultCoordinator) processUndoLogDelete() { func (coordinator *DefaultCoordinator) processUndoLogDelete() {
for { for {
<-coordinator.undoLogDeleteTicker.C
coordinator.undoLogDelete()
timer := time.NewTimer(coordinator.conf.LogDeletePeriod)
select {
case <-timer.C:
coordinator.undoLogDelete()
}
timer.Stop()
} }
} }


@@ -190,7 +200,7 @@ func (coordinator *DefaultCoordinator) timeoutCheck() {
if globalSession.Active { if globalSession.Active {
globalSession.Active = false globalSession.Active = false
} }
changeGlobalSessionStatus(globalSession, meta.GlobalStatusTimeoutRollbacking)
changeGlobalSessionStatus(globalSession, meta.GlobalStatusTimeoutRollingBack)
evt := event.NewGlobalTransactionEvent(globalSession.TransactionID, event.RoleTC, globalSession.TransactionName, globalSession.BeginTime, 0, globalSession.Status) evt := event.NewGlobalTransactionEvent(globalSession.TransactionID, event.RoleTC, globalSession.TransactionName, globalSession.BeginTime, 0, globalSession.Status)
event.EventBus.GlobalTransactionEventChannel <- evt event.EventBus.GlobalTransactionEventChannel <- evt
return true return true
@@ -205,32 +215,32 @@ func (coordinator *DefaultCoordinator) timeoutCheck() {
} }


func (coordinator *DefaultCoordinator) handleRetryRollbacking() { func (coordinator *DefaultCoordinator) handleRetryRollbacking() {
rollbackingSessions := holder.GetSessionHolder().RetryRollbackingSessionManager.AllSessions()
if rollbackingSessions == nil && len(rollbackingSessions) <= 0 {
rollingBackSessions := holder.GetSessionHolder().RetryRollbackingSessionManager.AllSessions()
if rollingBackSessions == nil && len(rollingBackSessions) <= 0 {
return return
} }
now := time2.CurrentTimeMillis() now := time2.CurrentTimeMillis()
for _, rollbackingSession := range rollbackingSessions {
if rollbackingSession.Status == meta.GlobalStatusRollbacking && !rollbackingSession.IsRollbackingDead() {
for _, rollingBackSession := range rollingBackSessions {
if rollingBackSession.Status == meta.GlobalStatusRollbacking && !rollingBackSession.IsRollbackingDead() {
continue continue
} }
if isRetryTimeout(int64(now), coordinator.conf.MaxRollbackRetryTimeout, rollbackingSession.BeginTime) {
if isRetryTimeout(int64(now), coordinator.conf.MaxRollbackRetryTimeout, rollingBackSession.BeginTime) {
if coordinator.conf.RollbackRetryTimeoutUnlockEnable { if coordinator.conf.RollbackRetryTimeoutUnlockEnable {
lock.GetLockManager().ReleaseGlobalSessionLock(rollbackingSession)
lock.GetLockManager().ReleaseGlobalSessionLock(rollingBackSession)
} }
holder.GetSessionHolder().RetryRollbackingSessionManager.RemoveGlobalSession(rollbackingSession)
log.Errorf("GlobalSession rollback retry timeout and removed [%s]", rollbackingSession.XID)
holder.GetSessionHolder().RetryRollbackingSessionManager.RemoveGlobalSession(rollingBackSession)
log.Errorf("GlobalSession rollback retry timeout and removed [%s]", rollingBackSession.XID)
continue continue
} }
_, err := coordinator.core.doGlobalRollback(rollbackingSession, true)
_, err := coordinator.core.doGlobalRollback(rollingBackSession, true)
if err != nil { if err != nil {
log.Infof("Failed to retry rollbacking [%s]", rollbackingSession.XID)
log.Infof("Failed to retry rolling back [%s]", rollingBackSession.XID)
} }
} }
} }


func isRetryTimeout(now int64, timeout int64, beginTime int64) bool { func isRetryTimeout(now int64, timeout int64, beginTime int64) bool {
if timeout >= ALWAYS_RETRY_BOUNDARY && now-beginTime > timeout {
if timeout >= AlwaysRetryBoundary && now-beginTime > timeout {
return true return true
} }
return false return false
@@ -287,9 +297,4 @@ func (coordinator *DefaultCoordinator) undoLogDelete() {
} }


func (coordinator *DefaultCoordinator) Stop() { func (coordinator *DefaultCoordinator) Stop() {
coordinator.timeoutCheckTicker.Stop()
coordinator.retryRollbackingTicker.Stop()
coordinator.retryCommittingTicker.Stop()
coordinator.asyncCommittingTicker.Stop()
coordinator.undoLogDeleteTicker.Stop()
} }

+ 2
- 2
pkg/tc/server/default_coordinator_server_message_sender.go View File

@@ -25,7 +25,7 @@ func (coordinator *DefaultCoordinator) SendResponse(request protocal.RpcMessage,
} }


func (coordinator *DefaultCoordinator) SendSyncRequest(resourceID string, clientID string, message interface{}) (interface{}, error) { func (coordinator *DefaultCoordinator) SendSyncRequest(resourceID string, clientID string, message interface{}) (interface{}, error) {
return coordinator.SendSyncRequestWithTimeout(resourceID, clientID, message, RPC_REQUEST_TIMEOUT)
return coordinator.SendSyncRequestWithTimeout(resourceID, clientID, message, RpcRequestTimeout)
} }


func (coordinator *DefaultCoordinator) SendSyncRequestWithTimeout(resourceID string, clientID string, message interface{}, timeout time.Duration) (interface{}, error) { func (coordinator *DefaultCoordinator) SendSyncRequestWithTimeout(resourceID string, clientID string, message interface{}, timeout time.Duration) (interface{}, error) {
@@ -37,7 +37,7 @@ func (coordinator *DefaultCoordinator) SendSyncRequestWithTimeout(resourceID str
} }


func (coordinator *DefaultCoordinator) SendSyncRequestByGetty(session getty.Session, message interface{}) (interface{}, error) { func (coordinator *DefaultCoordinator) SendSyncRequestByGetty(session getty.Session, message interface{}) (interface{}, error) {
return coordinator.SendSyncRequestByGettyWithTimeout(session, message, RPC_REQUEST_TIMEOUT)
return coordinator.SendSyncRequestByGettyWithTimeout(session, message, RpcRequestTimeout)
} }


func (coordinator *DefaultCoordinator) SendSyncRequestByGettyWithTimeout(session getty.Session, message interface{}, timeout time.Duration) (interface{}, error) { func (coordinator *DefaultCoordinator) SendSyncRequestByGettyWithTimeout(session getty.Session, message interface{}, timeout time.Duration) (interface{}, error) {


+ 3
- 3
pkg/tc/server/default_core.go View File

@@ -469,7 +469,7 @@ func (core *DefaultCore) doGlobalRollback(globalSession *session.GlobalSession,
} }
branchStatus, err1 := core.branchRollback(globalSession, bs) branchStatus, err1 := core.branchRollback(globalSession, bs)
if err1 != nil { if err1 != nil {
log.Errorf("Exception rollbacking branch xid=%d branchID=%d", globalSession.XID, bs.BranchID)
log.Errorf("Exception rolling back branch xid=%d branchID=%d", globalSession.XID, bs.BranchID)
if !retrying { if !retrying {
queueToRetryRollback(globalSession) queueToRetryRollback(globalSession)
} }
@@ -501,7 +501,7 @@ func (core *DefaultCore) doGlobalRollback(globalSession *session.GlobalSession,
// failure due to data changes. // failure due to data changes.
gs := holder.GetSessionHolder().RootSessionManager.FindGlobalSession(globalSession.XID) gs := holder.GetSessionHolder().RootSessionManager.FindGlobalSession(globalSession.XID)
if gs != nil && gs.HasBranch() { if gs != nil && gs.HasBranch() {
log.Infof("Global[%d] rollbacking is NOT done.", globalSession.XID)
log.Infof("Global[%d] rolling back is NOT done.", globalSession.XID)
return false, nil return false, nil
} }
} }
@@ -576,7 +576,7 @@ func queueToRetryRollback(globalSession *session.GlobalSession) {
func isTimeoutGlobalStatus(status meta.GlobalStatus) bool { func isTimeoutGlobalStatus(status meta.GlobalStatus) bool {
return status == meta.GlobalStatusTimeoutRollbacked || return status == meta.GlobalStatusTimeoutRollbacked ||
status == meta.GlobalStatusTimeoutRollbackFailed || status == meta.GlobalStatusTimeoutRollbackFailed ||
status == meta.GlobalStatusTimeoutRollbacking ||
status == meta.GlobalStatusTimeoutRollingBack ||
status == meta.GlobalStatusTimeoutRollbackRetrying status == meta.GlobalStatusTimeoutRollbackRetrying
} }




+ 8
- 13
pkg/tc/server/server.go View File

@@ -6,7 +6,6 @@ import (
"os" "os"
"os/signal" "os/signal"
"strconv" "strconv"
"strings"
"syscall" "syscall"
"time" "time"
) )
@@ -18,7 +17,7 @@ import (
) )


import ( import (
"github.com/transaction-wg/seata-golang/pkg/base/common/extension"
"github.com/transaction-wg/seata-golang/pkg/base/extension"
"github.com/transaction-wg/seata-golang/pkg/base/getty/readwriter" "github.com/transaction-wg/seata-golang/pkg/base/getty/readwriter"
"github.com/transaction-wg/seata-golang/pkg/base/registry" "github.com/transaction-wg/seata-golang/pkg/base/registry"
"github.com/transaction-wg/seata-golang/pkg/tc/config" "github.com/transaction-wg/seata-golang/pkg/tc/config"
@@ -26,7 +25,7 @@ import (
) )


type Server struct { type Server struct {
conf config.ServerConfig
conf *config.ServerConfig
tcpServer getty.Server tcpServer getty.Server
rpcHandler *DefaultCoordinator rpcHandler *DefaultCoordinator
} }
@@ -81,18 +80,16 @@ func (s *Server) Start(addr string) {
var ( var (
tcpServer getty.Server tcpServer getty.Server
) )
//直接使用addr绑定有ip,如果是127.0.0.1,则通过网卡正式ip不能访问
addrs := strings.Split(addr, ":")

tcpServer = getty.NewTCPServer( tcpServer = getty.NewTCPServer(
//getty.WithLocalAddress(addr),
getty.WithLocalAddress(":"+addrs[1]),
getty.WithLocalAddress(addr),
getty.WithServerTaskPool(gxsync.NewTaskPoolSimple(0)), getty.WithServerTaskPool(gxsync.NewTaskPoolSimple(0)),
) )
tcpServer.RunEventLoop(s.newSession) tcpServer.RunEventLoop(s.newSession)
log.Debugf("s bind addr{%s} ok!", addr) log.Debugf("s bind addr{%s} ok!", addr)
s.tcpServer = tcpServer s.tcpServer = tcpServer
//向注册中心注册实例 //向注册中心注册实例
registryInstance()
registryInstance(s.conf)
c := make(chan os.Signal, 1) c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT) signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for { for {
@@ -110,16 +107,14 @@ func (s *Server) Start(addr string) {
} }
} }


func registryInstance() {
registryConfig := config.GetRegistryConfig()
reg, err := extension.GetRegistry(registryConfig.Mode)
func registryInstance(config *config.ServerConfig) {
reg, err := extension.GetRegistry(config.RegistryConfig.Mode)
if err != nil { if err != nil {
log.Error("Registry can not connect success, program is going to panic.Error message is %s", err.Error()) log.Error("Registry can not connect success, program is going to panic.Error message is %s", err.Error())
panic(err.Error()) panic(err.Error())
} }
ip, _ := gxnet.GetLocalIP() ip, _ := gxnet.GetLocalIP()
conf := config.GetServerConfig()
port, _ := strconv.Atoi(conf.Port)
port, _ := strconv.Atoi(config.Port)
reg.Register(&registry.Address{ reg.Register(&registry.Address{
IP: ip, IP: ip,
Port: uint64(port), Port: uint64(port),


+ 2
- 2
pkg/tc/session/branch_session.go View File

@@ -102,7 +102,7 @@ func WithBsApplicationData(applicationData []byte) BranchSessionOption {


func NewBranchSession(opts ...BranchSessionOption) *BranchSession { func NewBranchSession(opts ...BranchSessionOption) *BranchSession {
session := &BranchSession{ session := &BranchSession{
BranchID: uuid.GeneratorUUID(),
BranchID: uuid.NextID(),
Status: meta.BranchStatusUnknown, Status: meta.BranchStatusUnknown,
} }
for _, o := range opts { for _, o := range opts {
@@ -115,7 +115,7 @@ func NewBranchSessionByGlobal(gs GlobalSession, opts ...BranchSessionOption) *Br
bs := &BranchSession{ bs := &BranchSession{
XID: gs.XID, XID: gs.XID,
TransactionID: gs.TransactionID, TransactionID: gs.TransactionID,
BranchID: uuid.GeneratorUUID(),
BranchID: uuid.NextID(),
Status: meta.BranchStatusUnknown, Status: meta.BranchStatusUnknown,
} }
for _, o := range opts { for _, o := range opts {


+ 1
- 1
pkg/tc/session/branch_session_test.go View File

@@ -29,7 +29,7 @@ func TestBranchSession_Encode_Decode(t *testing.T) {


func branchSessionProvider() *BranchSession { func branchSessionProvider() *BranchSession {
bs := NewBranchSession( bs := NewBranchSession(
WithBsTransactionID(uuid.GeneratorUUID()),
WithBsTransactionID(uuid.NextID()),
WithBsBranchID(1), WithBsBranchID(1),
WithBsResourceGroupID("my_test_tx_group"), WithBsResourceGroupID("my_test_tx_group"),
WithBsResourceID("tb_1"), WithBsResourceID("tb_1"),


+ 2
- 2
pkg/tc/session/global_session.go View File

@@ -106,10 +106,10 @@ func WithGsActive(active bool) GlobalSessionOption {
func NewGlobalSession(opts ...GlobalSessionOption) *GlobalSession { func NewGlobalSession(opts ...GlobalSessionOption) *GlobalSession {
gs := &GlobalSession{ gs := &GlobalSession{
BranchSessions: make(map[*BranchSession]bool), BranchSessions: make(map[*BranchSession]bool),
TransactionID: uuid.GeneratorUUID(),
TransactionID: uuid.NextID(),
Active: true, Active: true,
} }
gs.XID = common.GetXID().GenerateXID(gs.TransactionID)
gs.XID = common.GenerateXID(gs.TransactionID)
for _, o := range opts { for _, o := range opts {
o(gs) o(gs)
} }


+ 1
- 1
pkg/testutil/util.go View File

@@ -30,6 +30,6 @@ func InitServerConfig(t *testing.T) {
_, err = file.Write(bytes) _, err = file.Write(bytes)
assert.NoError(t, err, "Write() should success") assert.NoError(t, err, "Write() should success")


err = config.InitConf(file.Name())
_, err = config.InitConf(file.Name())
assert.NoError(t, err, "InitConf() should success") assert.NoError(t, err, "InitConf() should success")
} }

+ 57
- 27
pkg/util/log/logging.go View File

@@ -1,6 +1,11 @@
package log package log


import ( import (
"bytes"
"errors"
"fmt"

"github.com/natefinch/lumberjack"
"go.uber.org/zap" "go.uber.org/zap"
"go.uber.org/zap/zapcore" "go.uber.org/zap/zapcore"
) )
@@ -26,6 +31,36 @@ const (
FatalLevel = LogLevel(zapcore.FatalLevel) FatalLevel = LogLevel(zapcore.FatalLevel)
) )


func (l *LogLevel) UnmarshalText(text []byte) error {
if l == nil {
return errors.New("can't unmarshal a nil *Level")
}
if !l.unmarshalText(text) && !l.unmarshalText(bytes.ToLower(text)) {
return fmt.Errorf("unrecognized level: %q", text)
}
return nil
}

func (l *LogLevel) unmarshalText(text []byte) bool {
switch string(text) {
case "debug", "DEBUG":
*l = DebugLevel
case "info", "INFO", "": // make the zero value useful
*l = InfoLevel
case "warn", "WARN":
*l = WarnLevel
case "error", "ERROR":
*l = ErrorLevel
case "panic", "PANIC":
*l = PanicLevel
case "fatal", "FATAL":
*l = FatalLevel
default:
return false
}
return true
}

type Logger interface { type Logger interface {
Debug(v ...interface{}) Debug(v ...interface{})
Debugf(format string, v ...interface{}) Debugf(format string, v ...interface{})
@@ -71,6 +106,27 @@ func init() {
log = zapLogger.Sugar() log = zapLogger.Sugar()
} }


func Init(logPath string, level LogLevel) {
lumberJackLogger := &lumberjack.Logger{
Filename: logPath,
MaxSize: 10,
MaxBackups: 5,
MaxAge: 30,
Compress: false,
}
syncer := zapcore.AddSync(lumberJackLogger)

encoderConfig := zap.NewProductionEncoderConfig()
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder

encoder := zapcore.NewConsoleEncoder(encoderConfig)
core := zapcore.NewCore(encoder, syncer, zap.NewAtomicLevelAt(zapcore.Level(level)))
zapLogger = zap.New(core, zap.AddCaller())

log = zapLogger.Sugar()
}

// SetLogger: customize yourself logger. // SetLogger: customize yourself logger.
func SetLogger(logger Logger) { func SetLogger(logger Logger) {
log = logger log = logger
@@ -81,32 +137,6 @@ func GetLogger() Logger {
return log return log
} }


// SetLoggerLevel
func SetLoggerLevel(level LogLevel) error {
var err error
zapLoggerConfig.Level = zap.NewAtomicLevelAt(zapcore.Level(level))
zapLogger, err = zapLoggerConfig.Build()
if err != nil {
return err
}
log = zapLogger.Sugar()
return nil
}

// SetLoggerCallerDisable: disable caller info in production env for performance improve.
// It is highly recommended that you execute this method in a production environment.
func SetLoggerCallerDisable() error {
var err error
zapLoggerConfig.Development = false
zapLoggerConfig.DisableCaller = true
zapLogger, err = zapLoggerConfig.Build()
if err != nil {
return err
}
log = zapLogger.Sugar()
return nil
}

// Debug ... // Debug ...
func Debug(v ...interface{}) { func Debug(v ...interface{}) {
log.Debug(v...) log.Debug(v...)
@@ -165,4 +195,4 @@ func Fatal(v ...interface{}) {
// Fatalf ... // Fatalf ...
func Fatalf(format string, v ...interface{}) { func Fatalf(format string, v ...interface{}) {
log.Fatalf(format, v...) log.Fatalf(format, v...)
}
}

+ 209
- 0
pkg/util/parser/parser.go View File

@@ -0,0 +1,209 @@
package parser

import (
"fmt"
"os"
"reflect"
"sort"
"strings"

"gopkg.in/yaml.v2"

"github.com/transaction-wg/seata-golang/pkg/util/log"
)

type envVar struct {
name string
value string
}

type envVars []envVar

func (a envVars) Len() int { return len(a) }
func (a envVars) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a envVars) Less(i, j int) bool { return a[i].name < a[j].name }

// Parser can be used to parse a configuration file and environment
// into a unified output structure
type Parser struct {
prefix string
env envVars
}

// NewParser returns a *Parser with the given environment prefix which handles
// configurations which match the given parseInfos
func NewParser(prefix string) *Parser {
p := Parser{prefix: prefix}

for _, env := range os.Environ() {
envParts := strings.SplitN(env, "=", 2)
p.env = append(p.env, envVar{envParts[0], envParts[1]})
}

// We must sort the environment variables lexically by name so that
// more specific variables are applied before less specific ones
// but it's a lot simpler and easier to get right than unmarshalling
// map entries into temporaries and merging with the existing entry.
sort.Sort(p.env)

return &p
}

// Parse reads in the given []byte and environment and writes the resulting
// configuration into the input v
//
// Environment variables may be used to override configuration parameters,
// following the scheme below:
// v.Abc may be replaced by the value of PREFIX_ABC,
// v.Abc.Xyz may be replaced by the value of PREFIX_ABC_XYZ, and so forth
func (p *Parser) Parse(in []byte, v interface{}) error {
err := yaml.Unmarshal(in, v)
if err != nil {
return err
}

for _, envVar := range p.env {
pathStr := envVar.name
if strings.HasPrefix(pathStr, strings.ToUpper(p.prefix)+"_") {
path := strings.Split(pathStr, "_")

err = p.overwriteFields(reflect.ValueOf(v), pathStr, path[1:], envVar.value)
if err != nil {
return err
}
}
}

return nil
}

// overwriteFields replaces configuration values with alternate values specified
// through the environment. Precondition: an empty path slice must never be
// passed in.
func (p *Parser) overwriteFields(v reflect.Value, fullPath string, path []string, payload string) error {
for v.Kind() == reflect.Ptr {
if v.IsNil() {
panic("encountered nil pointer while handling environment variable " + fullPath)
}
v = reflect.Indirect(v)
}
switch v.Kind() {
case reflect.Struct:
return p.overwriteStruct(v, fullPath, path, payload)
case reflect.Map:
return p.overwriteMap(v, fullPath, path, payload)
case reflect.Interface:
if v.NumMethod() == 0 {
if !v.IsNil() {
return p.overwriteFields(v.Elem(), fullPath, path, payload)
}
// Interface was empty; create an implicit map
var template map[string]interface{}
wrappedV := reflect.MakeMap(reflect.TypeOf(template))
v.Set(wrappedV)
return p.overwriteMap(wrappedV, fullPath, path, payload)
}
}
return nil
}

func (p *Parser) overwriteStruct(v reflect.Value, fullpath string, path []string, payload string) error {
// Generate case-insensitive map of struct fields
byUpperCase := make(map[string]int)
for i := 0; i < v.NumField(); i++ {
sf := v.Type().Field(i)
upper := strings.ToUpper(sf.Name)
if _, present := byUpperCase[upper]; present {
panic(fmt.Sprintf("field name collision in configuration object: %s", sf.Name))
}
byUpperCase[upper] = i
}

fieldIndex, present := byUpperCase[path[0]]
if !present {
log.Warnf("ignoring unrecognized environment variable %s", fullpath)
return nil
}
field := v.Field(fieldIndex)
sf := v.Type().Field(fieldIndex)

if len(path) == 1 {
// Env var specifies this field directly
fieldVal := reflect.New(sf.Type)
err := yaml.Unmarshal([]byte(payload), fieldVal.Interface())
if err != nil {
return err
}
field.Set(reflect.Indirect(fieldVal))
return nil
}

// If the field is nil, must create an object
switch sf.Type.Kind() {
case reflect.Map:
if field.IsNil() {
field.Set(reflect.MakeMap(sf.Type))
}
case reflect.Ptr:
if field.IsNil() {
field.Set(reflect.New(field.Type().Elem()))
}
}

err := p.overwriteFields(field, fullpath, path[1:], payload)
if err != nil {
return err
}

return nil
}

func (p *Parser) overwriteMap(m reflect.Value, fullpath string, path []string, payload string) error {
if m.Type().Key().Kind() != reflect.String {
// non-string keys unsupported
log.Warnf("ignoring environment variable %s involving map with non-string keys", fullpath)
return nil
}

if len(path) > 1 {
// If a matching key exists, get its value and continue the
// overwriting process.
for _, k := range m.MapKeys() {
if strings.ToUpper(k.String()) == path[0] {
mapValue := m.MapIndex(k)
// If the existing value is nil, we want to
// recreate it instead of using this value.
if (mapValue.Kind() == reflect.Ptr ||
mapValue.Kind() == reflect.Interface ||
mapValue.Kind() == reflect.Map) &&
mapValue.IsNil() {
break
}
return p.overwriteFields(mapValue, fullpath, path[1:], payload)
}
}
}

// (Re)create this key
var mapValue reflect.Value
if m.Type().Elem().Kind() == reflect.Map {
mapValue = reflect.MakeMap(m.Type().Elem())
} else {
mapValue = reflect.New(m.Type().Elem())
}
if len(path) > 1 {
err := p.overwriteFields(mapValue, fullpath, path[1:], payload)
if err != nil {
return err
}
} else {
err := yaml.Unmarshal([]byte(payload), mapValue.Interface())
if err != nil {
return err
}
}

m.SetMapIndex(reflect.ValueOf(strings.ToLower(path[0])), reflect.Indirect(mapValue))

return nil
}

+ 110
- 0
pkg/util/uuid/id_worker.go View File

@@ -0,0 +1,110 @@
package uuid

import (
"fmt"
"math/rand"
"net"
"sync/atomic"

time2 "github.com/transaction-wg/seata-golang/pkg/util/time"
)

const (
// Start time cut (2020-05-03)
epoch uint64 = 1588435200000

// The number of bits occupied by workerID
workerIDBits = 10

// The number of bits occupied by timestamp
timestampBits = 41

// The number of bits occupied by sequence
sequenceBits = 12

// Maximum supported machine id, the result is 1023
maxWorkerID = -1 ^ (-1 << workerIDBits)

// mask that help to extract timestamp and sequence from a long
timestampAndSequenceMask uint64 = -1 ^ (-1 << (timestampBits + sequenceBits))
)

// timestamp and sequence mix in one Long
// highest 11 bit: not used
// middle 41 bit: timestamp
// lowest 12 bit: sequence
var timestampAndSequence uint64 = 0

// business meaning: machine ID (0 ~ 1023)
// actual layout in memory:
// highest 1 bit: 0
// middle 10 bit: workerID
// lowest 53 bit: all 0
var workerID = generateWorkerID() << (timestampBits + sequenceBits)

func init() {
timestamp := getNewestTimestamp()
timestampWithSequence := timestamp << sequenceBits
atomic.StoreUint64(&timestampAndSequence, timestampWithSequence)
}

func Init(serverNode int64) error {
if serverNode > maxWorkerID || serverNode < 0 {
return fmt.Errorf("worker id can't be greater than %d or less than 0", maxWorkerID)
}
workerID = serverNode << (timestampBits + sequenceBits)
return nil
}

func NextID() int64 {
waitIfNecessary()
next := atomic.AddUint64(&timestampAndSequence, 1)
timestampWithSequence := next & timestampAndSequenceMask
return int64(uint64(workerID) | timestampWithSequence)
}

func waitIfNecessary() {
currentWithSequence := atomic.LoadUint64(&timestampAndSequence)
current := currentWithSequence >> sequenceBits
newest := getNewestTimestamp()
for current >= newest {
newest = getNewestTimestamp()
}
}

// get newest timestamp relative to twepoch
func getNewestTimestamp() uint64 {
return time2.CurrentTimeMillis() - epoch
}

// auto generate workerID, try using mac first, if failed, then randomly generate one
func generateWorkerID() int64 {
id, err := generateWorkerIDBaseOnMac()
if err != nil {
id = generateRandomWorkerID()
}
return id
}

// use lowest 10 bit of available MAC as workerID
func generateWorkerIDBaseOnMac() (int64, error) {
ifaces, _ := net.Interfaces()
for _, iface := range ifaces {
if iface.Flags&net.FlagUp == 0 {
continue // interface down
}
if iface.Flags&net.FlagLoopback != 0 {
continue // loopback interface
}

mac := iface.HardwareAddr

return int64(int((mac[4]&0b11)<<8) | int(mac[5]&0xFF)), nil
}
return 0, fmt.Errorf("no available mac found")
}

// randomly generate one as workerID
func generateRandomWorkerID() int64 {
return rand.Int63n(maxWorkerID + 1)
}

+ 0
- 47
pkg/util/uuid/uuid_generator.go View File

@@ -1,47 +0,0 @@
package uuid

import (
"github.com/transaction-wg/seata-golang/pkg/util/time"
"sync/atomic"
)

var (
UUID int64 = 1000
serverNodeID = 1
UUID_INTERNAL int64 = 2000000000
initUUID int64 = 0
)

func GeneratorUUID() int64 {
id := atomic.AddInt64(&UUID, 1)
if id >= GetMaxUUID() {
if UUID >= id {
newID := id - UUID_INTERNAL
atomic.CompareAndSwapInt64(&UUID, id, newID)
return newID
}
}
return id
}

func SetUUID(expect int64, update int64) bool {
return atomic.CompareAndSwapInt64(&UUID, expect, update)
}

func GetMaxUUID() int64 {
return UUID_INTERNAL * (int64(serverNodeID) + 1)
}

func GetInitUUID() int64 {
return initUUID
}

func Init(svrNodeID int) {
// 2019-01-01 与 java 版 seata 一致
var base uint64 = 1546272000000
serverNodeID = svrNodeID
atomic.CompareAndSwapInt64(&UUID, UUID, UUID_INTERNAL*int64(serverNodeID))
current := time.CurrentTimeMillis()
id := atomic.AddInt64(&UUID, int64((current-base)/time.UnixTimeUnitOffset))
initUUID = id
}

Loading…
Cancel
Save