@@ -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" | ||||
@@ -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 | ||||
}, | }, | ||||
}, | }, | ||||
@@ -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 | ||||
@@ -1,6 +0,0 @@ | |||||
package constant | |||||
const ( | |||||
// seata客服端文件配置路径KEY | |||||
CONF_CLIENT_FILE_PATH = "CONF_CLIENT_FILE_PATH" | |||||
) |
@@ -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" | |||||
) |
@@ -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 | ||||
} | |||||
} |
@@ -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"` | |||||
} | } |
@@ -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"` | |||||
} |
@@ -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 | |||||
} |
@@ -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 | |||||
} | } |
@@ -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) //添加配置监听 | ||||
} | } |
@@ -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 | ||||
@@ -0,0 +1,5 @@ | |||||
package constant | |||||
const ( | |||||
ClientConfigFilePath = "ConfClientFilePath" | |||||
) |
@@ -0,0 +1,8 @@ | |||||
package constant | |||||
const ( | |||||
NacosDefaultGroup = "SEATA_GROUP" | |||||
NacosDefaultDataID = "seata" | |||||
NacosKey = "nacos" | |||||
FileKey = "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() | ||||
} | } |
@@ -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 | |||||
} |
@@ -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,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 | ||||
} | } |
@@ -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 | ||||
@@ -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 | ||||
@@ -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 | |||||
} |
@@ -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 | ||||
} | } |
@@ -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", | ||||
}, | }, | ||||
@@ -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()) | ||||
@@ -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 | ||||
@@ -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 | ||||
@@ -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) | |||||
} |
@@ -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", | |||||
}, | |||||
} | |||||
} |
@@ -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 | |||||
} |
@@ -1,5 +0,0 @@ | |||||
package config | |||||
type UndoConfig struct { | |||||
LogSaveDays int16 `default:"7" yaml:"log_save_days" json:"log_save_days,omitempty"` | |||||
} |
@@ -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) | |||||
} | |||||
} | } |
@@ -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 { | ||||
@@ -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"), | ||||
@@ -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 | |||||
} | |||||
} | } |
@@ -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() | ||||
@@ -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 > ?" | ||||
) | ) | ||||
@@ -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 | ||||
@@ -74,9 +74,6 @@ type TransactionStoreManager interface { | |||||
// Shutdown. | // Shutdown. | ||||
Shutdown() | Shutdown() | ||||
// Gets current max session id. | |||||
GetCurrentMaxSessionID() int64 | |||||
} | } | ||||
type AbstractTransactionStoreManager struct { | type AbstractTransactionStoreManager struct { | ||||
@@ -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"), | ||||
@@ -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}) | |||||
} | } |
@@ -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() | |||||
} | } |
@@ -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) { | ||||
@@ -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 | ||||
} | } | ||||
@@ -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(®istry.Address{ | reg.Register(®istry.Address{ | ||||
IP: ip, | IP: ip, | ||||
Port: uint64(port), | Port: uint64(port), | ||||
@@ -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 { | ||||
@@ -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"), | ||||
@@ -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) | ||||
} | } | ||||
@@ -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") | ||||
} | } |
@@ -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...) | ||||
} | |||||
} |
@@ -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 | |||||
} |
@@ -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(×tampAndSequence, 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(×tampAndSequence, 1) | |||||
timestampWithSequence := next & timestampAndSequenceMask | |||||
return int64(uint64(workerID) | timestampWithSequence) | |||||
} | |||||
func waitIfNecessary() { | |||||
currentWithSequence := atomic.LoadUint64(×tampAndSequence) | |||||
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) | |||||
} |
@@ -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 | |||||
} |