273 lines
5.5 KiB
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))
|
|
}
|