Skip to content

Commit

Permalink
feat: xorm support cluster config
Browse files Browse the repository at this point in the history
  • Loading branch information
dapeng committed Nov 19, 2024
1 parent 55540b7 commit bc37c5e
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 12 deletions.
65 changes: 54 additions & 11 deletions goner/xorm/implement.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,28 @@ func newEngine(driverName string, dataSourceName string) (xorm.EngineInterface,
return xorm.NewEngine(driverName, dataSourceName)
}

type ClusterNodeConf struct {
DriverName string `properties:"driver-name" mapstructure:"driver-name"`
DSN string `properties:"dsn" mapstructure:"dsn"`
}

//go:generate mockgen -package xorm -destination=./engine_mock_test.go xorm.io/xorm EngineInterface
type engine struct {
gone.Flag
xorm.EngineInterface
gone.Logger `gone:"gone-logger"`

driverName string `gone:"config,database.driver-name"`
dsn string `gone:"config,database.dsn"`
maxIdleCount int `gone:"config,database.max-idle-count"`
maxOpen int `gone:"config,database.max-open"`
maxLifetime time.Duration `gone:"config,database.max-lifetime"`
showSql bool `gone:"config,database.showSql,default=false"`
driverName string `gone:"config,database.driver-name"`
dsn string `gone:"config,database.dsn"`
maxIdleCount int `gone:"config,database.max-idle-count"`
maxOpen int `gone:"config,database.max-open"`
maxLifetime time.Duration `gone:"config,database.max-lifetime"`
showSql bool `gone:"config,database.showSql,default=false"`
enableCluster bool `gone:"config,database.cluster.enable,default=false"`
masterConf *ClusterNodeConf `gone:"config,database.cluster.master"`
slavesConf []*ClusterNodeConf `gone:"config,database.cluster.slaves"`

group *xorm.EngineGroup

newFunc func(driverName string, dataSourceName string) (xorm.EngineInterface, error)
}
Expand All @@ -49,10 +59,39 @@ func (e *engine) create() error {
return gone.NewInnerError("duplicate call Start()", gone.StartError)
}

var err error
e.EngineInterface, err = e.newFunc(e.driverName, e.dsn)
if err != nil {
return gone.NewInnerError(err.Error(), gone.StartError)
if e.enableCluster {
if e.masterConf == nil {
return gone.NewInnerError("master config(database.cluster.master) is nil", gone.StartError)
}

if len(e.slavesConf) == 0 {
return gone.NewInnerError("slaves config(database.cluster.slaves) is nil", gone.StartError)
}
master, err := e.newFunc(e.masterConf.DriverName, e.masterConf.DSN)
if err != nil {
return gone.NewInnerError(err.Error(), gone.StartError)
}

slaves := make([]*xorm.Engine, 0, len(e.slavesConf))
for _, slave := range e.slavesConf {
slaveEngine, err := e.newFunc(slave.DriverName, slave.DSN)
if err != nil {
return gone.NewInnerError(err.Error(), gone.StartError)
}
slaves = append(slaves, slaveEngine.(*xorm.Engine))
}

e.group, err = xorm.NewEngineGroup(master, slaves)
if err != nil {
return gone.NewInnerError(err.Error(), gone.StartError)
}
e.EngineInterface = e.group
} else {
var err error
e.EngineInterface, err = e.newFunc(e.driverName, e.dsn)
if err != nil {
return gone.NewInnerError(err.Error(), gone.StartError)
}
}
return nil
}
Expand All @@ -65,7 +104,11 @@ func (e *engine) config() {
}

func (e *engine) Stop(gone.Cemetery) error {
return e.EngineInterface.(*xorm.Engine).Close()
if e.group != nil {
return e.group.Close()
} else {
return e.EngineInterface.(*xorm.Engine).Close()
}
}

func (e *engine) Sqlx(sql string, args ...any) *xorm.Session {
Expand Down
4 changes: 3 additions & 1 deletion goner/xorm/priest.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
)

func Priest(cemetery gone.Cemetery) error {
cemetery.BuryOnce(NewXormEngine())
xormEngine, id, option, g := NewXormEngine()
cemetery.BuryOnce(xormEngine, id, option, g)
cemetery.BuryOnce(NewProvider(xormEngine.(*engine)))
return nil
}
119 changes: 119 additions & 0 deletions goner/xorm/provider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package xorm

import (
"fmt"
"github.com/gone-io/gone"
"github.com/gone-io/gone/goner"
"github.com/stretchr/testify/assert"
"reflect"
"strconv"
"strings"
)

func NewProvider(engine *engine) (gone.Vampire, gone.GonerOption) {
return &provider{
engine: engine,
}, gone.GonerId("xorm")
}

type provider struct {
gone.Flag
engine *engine
gone.Logger `gone:"*"`
}

var xormInterface = gone.GetInterfaceType(new(gone.XormEngine))
var xormInterfaceSlice = gone.GetInterfaceType(new([]gone.XormEngine))

func (e *provider) Suck(conf string, v reflect.Value) gone.SuckError {
if !e.engine.enableCluster {
return gone.NewInnerError("cluster is not enabled, xorm only support cluster", gone.InjectError)
}

switch v.Type() {
case xormInterface:
if conf == "master" {
v.Set(reflect.ValueOf(&engine{
EngineInterface: e.engine.group.Master(),
}))
return nil
} else {
if strings.HasPrefix(conf, "slave") {
slaveIndex := strings.TrimPrefix(conf, "slave")
i, err := strconv.ParseInt(slaveIndex, 10, 64)
if err != nil {
return gone.NewInnerError("invalid slave index: "+slaveIndex, gone.InjectError)
}
slaves := e.engine.group.Slaves()
if int(i) < len(slaves) {
v.Set(reflect.ValueOf(
&engine{
EngineInterface: slaves[i],
},
))
return nil
}
}
}
return gone.NewInnerError(fmt.Sprintf("invalid xorm interface conf: %s, only support master、salve{Index}", conf), gone.InjectError)

case xormInterfaceSlice:
if conf != "" {
e.Warnf("ignore xorm interface slice conf: %s", conf)
}

engines := e.engine.group.Slaves()
xormEngines := make([]gone.XormEngine, 0, len(engines))
for _, eng := range engines {
xormEngines = append(xormEngines, &engine{
EngineInterface: eng,
})
}
v.Set(reflect.ValueOf(xormEngines))
return nil
default:
return gone.CannotFoundGonerByTypeError(v.Type())
}
}

//database.cluster.enable=true
//database.cluster.master.driver-name=mysql
//database.cluster.master.dsn=${db.username}:${db.password}@tcp(${db.host}:${db.port})/${db.name}?charset=utf8mb4&loc=Local
//
//database.cluster.slaves[0].driver-name=mysql
//database.cluster.slaves[0].dsn=${db.username}:${db.password}@tcp(${db.host}:${db.port})/${db.name}?charset=utf8mb4&loc=Local
//
//database.cluster.slaves[1].driver-name=mysql
//database.cluster.slaves[1].dsn=${db.username}:${db.password}@tcp(${db.host}:${db.port})/${db.name}?charset=utf8mb4&loc=Local
//
//database.cluster.slaves[2].driver-name=mysql
//database.cluster.slaves[2].dsn=${db.username}:${db.password}@tcp(${db.host}:${db.port})/${db.name}?charset=utf8mb4&loc=Local

//func Test_iCommission_Tmp(t *testing.T) {
// gone.RunTest(func(e struct {
// group gone.XormEngine `gone:"*"`
// master gone.XormEngine `gone:"xorm,master"`
// slave0 gone.XormEngine `gone:"xorm,slave0"`
// slave1 gone.XormEngine `gone:"xorm,slave1"`
// slave2 gone.XormEngine `gone:"xorm,slave2"`
// slaves []gone.XormEngine `gone:"xorm,xxx"`
// }) {
// assert.Equal(t, 3, len(e.slaves))
// assert.Equal(t, e.slaves[0], e.slave0)
// assert.Equal(t, e.slaves[1], e.slave1)
// assert.Equal(t, e.slaves[2], e.slave2)
// assert.NotNil(t, e.master)
//
// err := e.master.Ping()
// assert.Nil(t, err)
// err = e.slave0.Ping()
// assert.Nil(t, err)
// err = e.slave1.Ping()
// assert.Nil(t, err)
// err = e.slave2.Ping()
// assert.Nil(t, err)
//
// err = e.group.Ping()
// assert.Nil(t, err)
// }, goner.XormPriest)
//}

0 comments on commit bc37c5e

Please sign in to comment.