diff --git a/g/database/gdb/gdb.go b/g/database/gdb/gdb.go index 6e3131d29..25d47f249 100644 --- a/g/database/gdb/gdb.go +++ b/g/database/gdb/gdb.go @@ -122,11 +122,10 @@ func New(groupName...string) (*Db, error) { if len(masterList) < 1 { return nil, errors.New("at least one master node configuration's need to make sense") } - - masterNode := getConfigNodeByPriority(&masterList) + masterNode := getConfigNodeByPriority(masterList) var slaveNode *ConfigNode if len(slaveList) > 0 { - slaveNode = getConfigNodeByPriority(&slaveList) + slaveNode = getConfigNodeByPriority(slaveList) } return newDb(masterNode, slaveNode) } else { @@ -135,22 +134,31 @@ func New(groupName...string) (*Db, error) { } // 按照负载均衡算法(优先级配置)从数据库集群中选择一个配置节点出来使用 -func getConfigNodeByPriority (cg *ConfigGroup) *ConfigNode { - if len(*cg) < 2 { - return &(*cg)[0] +// 算法说明举例, +// 1、假如2个节点的priority都是1,那么随机大小范围为[0, 199]; +// 2、那么节点1的权重范围为[0, 99],节点2的权重范围为[100, 199],比例为1:1; +// 3、假如计算出的随机数为99; +// 4、那么选择的配置为节点1; +func getConfigNodeByPriority (cg ConfigGroup) *ConfigNode { + if len(cg) < 2 { + return &cg[0] } var total int - for i := 0; i < len(*cg); i++ { - total += (*cg)[i].Priority * 100 + for i := 0; i < len(cg); i++ { + total += cg[i].Priority * 100 } + // 不能取到末尾的边界点 r := grand.Rand(0, total) + if r > 0 { + r -= 1 + } min := 0 max := 0 - for i := 0; i < len(*cg); i++ { - max = min + (*cg)[i].Priority * 100 + for i := 0; i < len(cg); i++ { + max = min + cg[i].Priority * 100 //fmt.Printf("r: %d, min: %d, max: %d\n", r, min, max) if r >= min && r < max { - return &(*cg)[i] + return &cg[i] } else { min = max } @@ -178,7 +186,6 @@ func newDb (masterNode *ConfigNode, slaveNode *ConfigNode) (*Db, error) { return nil, err } } - return &Db { link : link, master : master, diff --git a/g/database/gdb/gdb_mysql.go b/g/database/gdb/gdb_mysql.go index e9895d117..d6b539a59 100644 --- a/g/database/gdb/gdb_mysql.go +++ b/g/database/gdb/gdb_mysql.go @@ -19,13 +19,13 @@ type dbmysql struct { // 创建SQL操作对象,内部采用了lazy link处理 func (db *dbmysql) Open (c *ConfigNode) (*sql.DB, error) { - var dbsource string + var source string if c.Linkinfo != "" { - dbsource = c.Linkinfo + source = c.Linkinfo } else { - dbsource = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s", c.User, c.Pass, c.Host, c.Port, c.Name) + source = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s", c.User, c.Pass, c.Host, c.Port, c.Name) } - if db, err := sql.Open("mysql", dbsource); err == nil { + if db, err := sql.Open("mysql", source); err == nil { return db, nil } else { return nil, err diff --git a/g/database/gdb/gdb_pgsql.go b/g/database/gdb/gdb_pgsql.go index 39b56e623..bf4bf903b 100644 --- a/g/database/gdb/gdb_pgsql.go +++ b/g/database/gdb/gdb_pgsql.go @@ -23,13 +23,13 @@ type dbpgsql struct { // 创建SQL操作对象,内部采用了lazy link处理 func (db *dbpgsql) Open (c *ConfigNode) (*sql.DB, error) { - var dbsource string + var source string if c.Linkinfo != "" { - dbsource = c.Linkinfo + source = c.Linkinfo } else { - dbsource = fmt.Sprintf("user=%s password=%s host=%s port=%s dbname=%s", c.User, c.Pass, c.Host, c.Port, c.Name) + source = fmt.Sprintf("user=%s password=%s host=%s port=%s dbname=%s", c.User, c.Pass, c.Host, c.Port, c.Name) } - if db, err := sql.Open("postgres", dbsource); err == nil { + if db, err := sql.Open("postgres", source); err == nil { return db, nil } else { return nil, err diff --git a/g/database/gdb/test/gdb_bench_test.go b/g/database/gdb/test/gdb_bench_test.go new file mode 100644 index 000000000..558a6cac2 --- /dev/null +++ b/g/database/gdb/test/gdb_bench_test.go @@ -0,0 +1,31 @@ +// Copyright 2018 gf Author(https://gitee.com/johng/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://gitee.com/johng/gf. + +// go test *.go -bench=".*" + +package test + +import ( + "testing" + "gitee.com/johng/gf/g" +) + +func init() { + // 这里需要修改为本地配置文件的目录地址 + g.Config().SetPath("/home/john/Workspace/Go/GOPATH/src/gitee.com/johng/gf/geg/frame") +} + +func Benchmark_New(b *testing.B) { + for i := 0; i < b.N; i++ { + g.Database() + } +} + +func Benchmark_NewAndClose(b *testing.B) { + for i := 0; i < b.N; i++ { + g.Database().Close() + } +} diff --git a/g/g.go b/g/g.go index e9bad31f2..f58eaab9d 100644 --- a/g/g.go +++ b/g/g.go @@ -9,15 +9,20 @@ package g import ( "strings" - "strconv" - "gitee.com/johng/gf/g/os/gview" "gitee.com/johng/gf/g/os/gcfg" + "gitee.com/johng/gf/g/os/gview" "gitee.com/johng/gf/g/util/gconv" "gitee.com/johng/gf/g/frame/gins" + "gitee.com/johng/gf/g/os/gcache" + "gitee.com/johng/gf/g/os/gfsnotify" "gitee.com/johng/gf/g/database/gdb" "gitee.com/johng/gf/g/database/gredis" ) +const ( + gIS_DATABASE_CONFIG_CACHED = "gf.core.component.database.cached" +) + // 常用map数据结构 type Map map[string]interface{} @@ -42,56 +47,61 @@ func Database(name...string) *gdb.Db { if config == nil { return nil } - if m := config.GetMap("database"); m != nil { - c := gdb.Config{} - for group, v := range m { - cg := gdb.ConfigGroup{} - if list, ok := v.([]interface{}); ok { - for _, nodev := range list { - node := gdb.ConfigNode{} - nodem := nodev.(map[string]interface{}) - if value, ok := nodem["host"]; ok { - node.Host = gconv.String(value) + // 数据库配置是否已经设置 + if gcache.Get(gIS_DATABASE_CONFIG_CACHED) == nil { + if m := config.GetMap("database"); m != nil { + c := gdb.Config{} + for group, v := range m { + cg := gdb.ConfigGroup{} + if list, ok := v.([]interface{}); ok { + for _, nodev := range list { + node := gdb.ConfigNode{} + nodem := nodev.(map[string]interface{}) + if value, ok := nodem["host"]; ok { + node.Host = gconv.String(value) + } + if value, ok := nodem["port"]; ok { + node.Port = gconv.String(value) + } + if value, ok := nodem["user"]; ok { + node.User = gconv.String(value) + } + if value, ok := nodem["pass"]; ok { + node.Pass = gconv.String(value) + } + if value, ok := nodem["name"]; ok { + node.Name = gconv.String(value) + } + if value, ok := nodem["type"]; ok { + node.Type = gconv.String(value) + } + if value, ok := nodem["role"]; ok { + node.Role = gconv.String(value) + } + if value, ok := nodem["charset"]; ok { + node.Charset = gconv.String(value) + } + if value, ok := nodem["priority"]; ok { + node.Priority = gconv.Int(value) + } + cg = append(cg, node) } - if value, ok := nodem["port"]; ok { - node.Port = gconv.String(value) - } - if value, ok := nodem["user"]; ok { - node.User = gconv.String(value) - } - if value, ok := nodem["pass"]; ok { - node.Pass = gconv.String(value) - } - if value, ok := nodem["name"]; ok { - node.Name = gconv.String(value) - } - if value, ok := nodem["type"]; ok { - node.Type = gconv.String(value) - } - if value, ok := nodem["role"]; ok { - node.Role = gconv.String(value) - } - if value, ok := nodem["charset"]; ok { - node.Charset = gconv.String(value) - } - if value, ok := nodem["priority"]; ok { - node.Priority, _ = strconv.Atoi(gconv.String(value)) - } - cg = append(cg, node) } + c[group] = cg } - c[group] = cg - } - gdb.SetConfig(c) - - if db, err := gdb.New(name...); err == nil { - return db - } else { - return nil + gdb.SetConfig(c) + gcache.Set(gIS_DATABASE_CONFIG_CACHED, struct{}{}, 0) + // 使用gfsnotify进行文件监控,当配置文件有任何变化时,清空数据库配置缓存 + gfsnotify.Add(Config().GetFilePath(), func(event *gfsnotify.Event) { + gcache.Remove(gIS_DATABASE_CONFIG_CACHED) + }) } } - - return nil + if db, err := gdb.New(name...); err == nil { + return db + } else { + return nil + } } // Redis操作对象,使用了连接池 diff --git a/g/util/grand/rand.go b/g/util/grand/grand.go similarity index 87% rename from g/util/grand/rand.go rename to g/util/grand/grand.go index ab13fc387..d884544df 100644 --- a/g/util/grand/rand.go +++ b/g/util/grand/grand.go @@ -14,13 +14,20 @@ import ( var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") var digits = []rune("0123456789") +// 修改全局随机数seed +func Seed (seed...int64) { + if len(seed) > 0 { + rand.Seed(seed[0]) + } else { + rand.Seed(time.Now().UnixNano()) + } +} + // 获得一个 min, max 之间的随机数(min <= x <= max) func Rand (min, max int) int { - //fmt.Printf("min: %d, max: %d\n", min, max) if min >= max { return min } - rand.Seed(time.Now().UnixNano()) n := rand.Intn(max + 1) if n < min { return Rand(min, max) @@ -30,7 +37,6 @@ func Rand (min, max int) int { // 获得指定长度的随机字符串(可能包含数字和字母) func RandStr(n int) string { - rand.Seed(time.Now().UnixNano()) b := make([]rune, n) for i := range b { if rand.Intn(2) == 1 { @@ -44,7 +50,6 @@ func RandStr(n int) string { // 获得指定长度的随机数字字符串 func RandDigits(n int) string { - rand.Seed(time.Now().UnixNano()) b := make([]rune, n) for i := range b { b[i] = digits[rand.Intn(10)] @@ -54,7 +59,6 @@ func RandDigits(n int) string { // 获得指定长度的随机字母字符串 func RandLetters(n int) string { - rand.Seed(time.Now().UnixNano()) b := make([]rune, n) for i := range b { b[i] = letters[rand.Intn(52)] diff --git a/g/util/grand/grand_test.go b/g/util/grand/grand_test.go new file mode 100644 index 000000000..f3bd601d8 --- /dev/null +++ b/g/util/grand/grand_test.go @@ -0,0 +1,20 @@ +// Copyright 2018 gf Author(https://gitee.com/johng/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://gitee.com/johng/gf. + +// go test *.go -bench=".*" + +package grand_test + +import ( + "testing" + "gitee.com/johng/gf/g/util/grand" +) + +func Benchmark_Rand(b *testing.B) { + for i := 0; i < b.N; i++ { + grand.Rand(0, 200) + } +} diff --git a/geg/other/test.go b/geg/other/test.go index 87ab4ea8f..5aa12c1dc 100644 --- a/geg/other/test.go +++ b/geg/other/test.go @@ -2,62 +2,11 @@ package main import ( "fmt" + "math/rand" ) -var arabicNumber2RomanSymbolMap = map[int]string{ - 1 : "I", - 5 : "V", - 10 : "X", - 50 : "L", - 100 : "C", - 500 : "D", - 1000 : "M", -} - -var romanSymbol2ArabicNumberMap = map[int]string{ - 4000 : "MMMCMC", - 1000 : "M", - 900 : "CM", - 500 : "D", - 400 : "CD", - 100 : "C", - 90 : "XC", - 50 : "L", - 40 : "XL", - 10 : "X", - 9 : "IX", - 5 : "V", - 4 : "IV", - 1 : "I", -} - -var array = []int{4000, 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1} - - -// Arabic numbers to Roman symbols -func romanSymbols2ArabicNumber(s string) int { - -} - -// Arabic numbers to Roman symbols -func arabicNumberToRomanSymbols(i int) string { - r := "" - for i > 0 { - for _, v := range array { - if i >= v { - r += romans[v] - i -= v - break - } - } - } - return r -} - func main() { - fmt.Println(intToRomans(1944)) - //for i := 0; i < 10; i++ { - // fmt.Println(intToRomans(i)) - //} - + for i := 0; i < 100; i++ { + fmt.Println(rand.Intn(200)) + } } \ No newline at end of file