xorm/pool.go

257 lines
6.1 KiB
Go
Raw Normal View History

2013-06-16 03:05:16 +00:00
package xorm
import (
"database/sql"
2013-06-21 04:40:24 +00:00
//"fmt"
"sync"
//"sync/atomic"
"time"
2013-06-16 03:05:16 +00:00
)
// Interface IConnecPool is a connection pool interface, all implements should implement
// Init, RetrieveDB, ReleaseDB and Close methods.
// Init for init when engine be created or invoke SetPool
// RetrieveDB for requesting a connection to db;
// ReleaseDB for releasing a db connection;
// Close for invoking when engine.Close
type IConnectPool interface {
Init(engine *Engine) error
2013-06-16 03:05:16 +00:00
RetrieveDB(engine *Engine) (*sql.DB, error)
ReleaseDB(engine *Engine, db *sql.DB)
Close(engine *Engine) error
SetMaxIdleConns(conns int)
MaxIdleConns() int
2013-08-29 09:26:33 +00:00
SetMaxConns(conns int)
MaxConns() int
2013-06-16 03:05:16 +00:00
}
// Struct NoneConnectPool is a implement for IConnectPool. It provides directly invoke driver's
// open and release connection function
2013-06-16 03:05:16 +00:00
type NoneConnectPool struct {
}
// NewNoneConnectPool new a NoneConnectPool.
func NewNoneConnectPool() IConnectPool {
return &NoneConnectPool{}
}
// Init do nothing
func (p *NoneConnectPool) Init(engine *Engine) error {
return nil
}
2013-06-21 04:33:54 +00:00
// RetrieveDB directly open a connection
func (p *NoneConnectPool) RetrieveDB(engine *Engine) (db *sql.DB, err error) {
2013-06-16 03:05:16 +00:00
db, err = engine.OpenDB()
return
}
// ReleaseDB directly close a connection
func (p *NoneConnectPool) ReleaseDB(engine *Engine, db *sql.DB) {
2013-06-16 03:05:16 +00:00
db.Close()
}
// Close do nothing
func (p *NoneConnectPool) Close(engine *Engine) error {
return nil
}
func (p *NoneConnectPool) SetMaxIdleConns(conns int) {
}
func (p *NoneConnectPool) MaxIdleConns() int {
return 0
}
2013-08-29 09:26:33 +00:00
// not implemented
func (p *NoneConnectPool) SetMaxConns(conns int) {
}
// not implemented
func (p *NoneConnectPool) MaxConns() int {
return -1
}
// Struct SysConnectPool is a simple wrapper for using system default connection pool.
// About the system connection pool, you can review the code database/sql/sql.go
// It's currently default Pool implments.
type SysConnectPool struct {
db *sql.DB
maxIdleConns int
2013-08-29 09:26:33 +00:00
maxConns int
curConns int
mutex *sync.Mutex
2013-09-01 02:37:46 +00:00
condMutex *sync.Mutex
2013-08-29 09:26:33 +00:00
cond *sync.Cond
}
// NewSysConnectPool new a SysConnectPool.
func NewSysConnectPool() IConnectPool {
return &SysConnectPool{}
}
// Init create a db immediately and keep it util engine closed.
func (s *SysConnectPool) Init(engine *Engine) error {
db, err := engine.OpenDB()
if err != nil {
return err
}
s.db = db
s.maxIdleConns = 2
2013-08-29 09:26:33 +00:00
s.maxConns = -1
s.curConns = 0
s.mutex = &sync.Mutex{}
2013-09-01 02:37:46 +00:00
s.condMutex = &sync.Mutex{}
s.cond = sync.NewCond(s.condMutex)
return nil
}
// RetrieveDB just return the only db
func (p *SysConnectPool) RetrieveDB(engine *Engine) (db *sql.DB, err error) {
2013-08-29 09:26:33 +00:00
if p.maxConns != -1 {
p.cond.L.Lock()
//fmt.Println("before retrieve - current connections:", p.curConns, p.maxConns)
for p.curConns >= p.maxConns-1 {
//fmt.Println("waiting...")
p.cond.Wait()
}
p.curConns += 1
2013-09-01 02:37:46 +00:00
p.cond.L.Unlock()
2013-08-29 09:26:33 +00:00
}
return p.db, nil
}
// ReleaseDB do nothing
func (p *SysConnectPool) ReleaseDB(engine *Engine, db *sql.DB) {
2013-08-29 09:26:33 +00:00
if p.maxConns != -1 {
p.cond.L.Lock()
//fmt.Println("before release - current connections:", p.curConns, p.maxConns)
2013-09-01 02:37:46 +00:00
//if p.curConns >= p.maxConns-2 {
//fmt.Println("signaling...")
p.cond.Signal()
//}
2013-08-29 09:26:33 +00:00
p.curConns -= 1
2013-09-01 02:37:46 +00:00
p.cond.L.Unlock()
2013-08-29 09:26:33 +00:00
}
}
// Close closed the only db
func (p *SysConnectPool) Close(engine *Engine) error {
return p.db.Close()
}
func (p *SysConnectPool) SetMaxIdleConns(conns int) {
p.db.SetMaxIdleConns(conns)
p.maxIdleConns = conns
}
func (p *SysConnectPool) MaxIdleConns() int {
return p.maxIdleConns
}
2013-08-29 09:26:33 +00:00
// not implemented
func (p *SysConnectPool) SetMaxConns(conns int) {
p.maxConns = conns
}
// not implemented
func (p *SysConnectPool) MaxConns() int {
return p.maxConns
}
// NewSimpleConnectPool new a SimpleConnectPool
func NewSimpleConnectPool() IConnectPool {
return &SimpleConnectPool{releasedConnects: make([]*sql.DB, 10),
usingConnects: map[*sql.DB]time.Time{},
cur: -1,
maxWaitTimeOut: 14400,
maxIdleConns: 10,
mutex: &sync.Mutex{},
}
}
// Struct SimpleConnectPool is a simple implementation for IConnectPool.
// It's a custom connection pool and not use system connection pool.
// Opening or Closing a database connection must be enter a lock.
// This implements will be improved in furture.
type SimpleConnectPool struct {
releasedConnects []*sql.DB
2013-06-16 03:05:16 +00:00
cur int
usingConnects map[*sql.DB]time.Time
2013-06-16 03:05:16 +00:00
maxWaitTimeOut int
mutex *sync.Mutex
maxIdleConns int
}
func (s *SimpleConnectPool) Init(engine *Engine) error {
return nil
2013-06-16 03:05:16 +00:00
}
// RetrieveDB get a connection from connection pool
func (p *SimpleConnectPool) RetrieveDB(engine *Engine) (*sql.DB, error) {
2013-06-16 03:05:16 +00:00
p.mutex.Lock()
defer p.mutex.Unlock()
var db *sql.DB = nil
var err error = nil
//fmt.Printf("%x, rbegin - released:%v, using:%v\n", &p, p.cur+1, len(p.usingConnects))
2013-06-16 03:05:16 +00:00
if p.cur < 0 {
db, err = engine.OpenDB()
if err != nil {
return nil, err
}
p.usingConnects[db] = time.Now()
2013-06-16 03:05:16 +00:00
} else {
db = p.releasedConnects[p.cur]
p.usingConnects[db] = time.Now()
p.releasedConnects[p.cur] = nil
2013-06-16 03:05:16 +00:00
p.cur = p.cur - 1
}
//fmt.Printf("%x, rend - released:%v, using:%v\n", &p, p.cur+1, len(p.usingConnects))
2013-06-16 03:05:16 +00:00
return db, nil
}
// ReleaseDB release a db from connection pool
func (p *SimpleConnectPool) ReleaseDB(engine *Engine, db *sql.DB) {
2013-06-16 03:05:16 +00:00
p.mutex.Lock()
defer p.mutex.Unlock()
//fmt.Printf("%x, lbegin - released:%v, using:%v\n", &p, p.cur+1, len(p.usingConnects))
if p.cur >= p.maxIdleConns-1 {
2013-06-16 03:05:16 +00:00
db.Close()
} else {
p.cur = p.cur + 1
p.releasedConnects[p.cur] = db
2013-06-16 03:05:16 +00:00
}
delete(p.usingConnects, db)
//fmt.Printf("%x, lend - released:%v, using:%v\n", &p, p.cur+1, len(p.usingConnects))
}
// Close release all db
func (p *SimpleConnectPool) Close(engine *Engine) error {
p.mutex.Lock()
defer p.mutex.Unlock()
for len(p.releasedConnects) > 0 {
p.releasedConnects[0].Close()
p.releasedConnects = p.releasedConnects[1:]
}
return nil
}
func (p *SimpleConnectPool) SetMaxIdleConns(conns int) {
p.maxIdleConns = conns
}
func (p *SimpleConnectPool) MaxIdleConns() int {
return p.maxIdleConns
}
2013-08-29 09:26:33 +00:00
// not implemented
func (p *SimpleConnectPool) SetMaxConns(conns int) {
}
// not implemented
func (p *SimpleConnectPool) MaxConns() int {
return -1
}