goserver_sync/core/mongo/config.go

273 lines
5.5 KiB
Go

package mongo
import (
"fmt"
"mongo.games.com/goserver/core/logger"
"sync"
"sync/atomic"
"time"
"github.com/globalsign/mgo"
"mongo.games.com/goserver/core"
"mongo.games.com/goserver/core/container"
)
var Config = Configuration{
Dbs: make(map[string]DbConfig),
}
var autoPingInterval time.Duration = 30 * time.Second
var mgoSessions = container.NewSynchronizedMap()
var databases = container.NewSynchronizedMap()
var cLock sync.RWMutex
var collections = make(map[string]*Collection)
var resetingSess int32
type Configuration struct {
Dbs map[string]DbConfig
}
type DbConfig struct {
Host string
Database string
User string
Password string
Safe mgo.Safe
}
func (c *Configuration) Name() string {
return "mongo"
}
func (c *Configuration) Init() error {
//auto ping, ensure net is connected
go func() {
for {
select {
case <-time.After(autoPingInterval):
Ping()
}
}
}()
return nil
}
func (c *Configuration) Close() error {
sessions := mgoSessions.Items()
for k, s := range sessions {
if session, ok := s.(*mgo.Session); ok && session != nil {
logger.Logger.Warnf("mongo.Close!!! (%v)", k)
session.Close()
}
}
return nil
}
func init() {
core.RegistePackage(&Config)
}
type Collection struct {
*mgo.Collection
Ref int32
valid bool
}
func (c *Collection) Hold() {
if atomic.AddInt32(&c.Ref, 1) == 1 {
key := c.Database.Name + c.FullName
cLock.Lock()
if old, exist := collections[key]; exist {
old.valid = false
}
collections[key] = c
cLock.Unlock()
}
}
func (c *Collection) Unhold() {
if atomic.AddInt32(&c.Ref, -1) == 0 {
key := c.Database.Name + c.FullName
cLock.Lock()
delete(collections, key)
cLock.Unlock()
}
}
func (c *Collection) IsValid() bool {
return c.valid
}
func newDBSession(dbc *DbConfig) (s *mgo.Session, err error) {
login := ""
if dbc.User != "" {
login = dbc.User + ":" + dbc.Password + "@"
}
host := "localhost"
if dbc.Host != "" {
host = dbc.Host
}
// http://goneat.org/pkg/labix.org/v2/mgo/#Session.Mongo
// [mongodb://][user:pass@]host1[:port1][,host2[:port2],...][/database][?options]
url := fmt.Sprintf("mongodb://%s%s/admin", login, host)
//fmt.Println(url)
session, err := mgo.Dial(url)
if err != nil {
return
}
session.SetSafe(&dbc.Safe)
s = session
return
}
func Ping() {
if atomic.LoadInt32(&resetingSess) == 1 {
return
}
var err error
sessions := mgoSessions.Items()
for k, s := range sessions {
if session, ok := s.(*mgo.Session); ok && session != nil {
if atomic.LoadInt32(&resetingSess) == 1 {
return
}
err = session.Ping()
if err != nil {
logger.Logger.Errorf("mongo.Ping (%v) err:%v", k, err)
if atomic.LoadInt32(&resetingSess) == 1 {
return
}
session.Refresh()
} else {
logger.Logger.Tracef("mongo.Ping (%v) suc", k)
}
}
}
}
func SetAutoPing(interv time.Duration) {
autoPingInterval = interv
}
func Database(dbName string) *mgo.Database {
if atomic.LoadInt32(&resetingSess) == 1 {
return nil
}
var dbc DbConfig
var exist bool
if dbc, exist = Config.Dbs[dbName]; !exist {
return nil
}
d := databases.Get(dbName)
if d == nil {
s, err := newDBSession(&dbc)
if err != nil {
fmt.Println("Database:", dbName, " error:", err)
return nil
}
mgoSessions.Set(dbName, s)
db := s.DB(dbc.Database)
if db == nil {
return nil
}
databases.Set(dbName, db)
return db
} else {
if db, ok := d.(*mgo.Database); ok {
return db
}
}
return nil
}
func DatabaseWithSubName(dbName, subName string) *mgo.Database {
if atomic.LoadInt32(&resetingSess) == 1 {
return nil
}
var dbc DbConfig
var exist bool
if dbc, exist = Config.Dbs[dbName]; !exist {
return nil
}
fullName := fmt.Sprintf("%s_%s", dbName, subName)
d := databases.Get(fullName)
if d == nil {
s, err := newDBSession(&dbc)
if err != nil {
fmt.Println("Database:", fullName, " error:", err)
return nil
}
mgoSessions.Set(dbName, s)
db := s.DB(dbc.Database + subName)
if db == nil {
return nil
}
databases.Set(fullName, db)
return db
} else {
if db, ok := d.(*mgo.Database); ok {
return db
}
}
return nil
}
func DatabaseC(dbName, collectionName string) *Collection {
if atomic.LoadInt32(&resetingSess) == 1 {
return nil
}
//一个库共享一个连接池
db := Database(dbName)
if db != nil {
c := db.C(collectionName)
if c != nil {
return &Collection{Collection: c, valid: true}
}
}
return nil
}
func DatabaseWithSubNameC(dbName, subName, collectionName string) *Collection {
if atomic.LoadInt32(&resetingSess) == 1 {
return nil
}
//一个库共享一个连接池
db := DatabaseWithSubName(dbName, subName)
if db != nil {
c := db.C(collectionName)
if c != nil {
return &Collection{Collection: c, valid: true}
}
}
return nil
}
// 不严格的多线程保护
func ResetAllSession() {
atomic.StoreInt32(&resetingSess, 1)
defer atomic.StoreInt32(&resetingSess, 0)
tstart := time.Now()
logger.Logger.Warnf("ResetAllSession!!! start.")
sessions := mgoSessions.Items()
mgoSessions = container.NewSynchronizedMap()
databases = container.NewSynchronizedMap()
//使缓存无效
cLock.Lock()
for k, c := range collections {
c.valid = false
logger.Logger.Warnf("%s collections reset.", k)
}
collections = make(map[string]*Collection)
cLock.Unlock()
//关闭旧的session
for k, s := range sessions {
if session, ok := s.(*mgo.Session); ok && session != nil {
logger.Logger.Warnf("mongo.Close!!! (%v)", k)
session.Close()
}
}
logger.Logger.Warnf("ResetAllSession!!! end. take:%v", time.Now().Sub(tstart))
}