vitess源码阅读笔记cache系列之用go实现mysql连接池ConnectionPool
2012-04-06 16:16 ngaut 阅读(1682) 评论(1) 编辑 收藏 举报上一篇笔记我们了解了通用资源池,就像人和人不同,池与池亦有异。往池里放水就成了水池,
往池里放内存就成了内存池。往池里放mysql连接呢?自然就成了本篇笔记的主角mysql连接池。当然这个连接池也分几种。
又的连接只用来做mysql查询,有的用来做事务操作。用来做mysql查询的连接池在vitess里面叫做ConnectionPool。
ConnectionPool在架构图中扮演的角色是什么呢?架构图上已经非常清晰的注明了,见架构图的右下角。
还是先上数据结构,看看往池里面放的是什么
type PoolConnection interface {
ExecuteFetch(query []byte, maxrows int) (*QueryResult, error)
Id() int64
Close()
IsClosed() bool
Recycle()
}
ExecuteFetch(query []byte, maxrows int) (*QueryResult, error)
Id() int64
Close()
IsClosed() bool
Recycle()
}
注意到要想放到连接池里面必须要满足这几个接口,其中Close和IsClosed是通用资源池必须满足的条件,连接池在通用池
的基础上做个更严格的要求。之所以叫做PoolConnection而不是Connection可能是从命名上就将作用明确,必须放进池中。
接下来请出主角,ConnectionPool的定义
// ConnectionPool re-exposes RoundRobin as a pool of DBConnection objects
type ConnectionPool struct {
*pools.RoundRobin
}
type ConnectionPool struct {
*pools.RoundRobin
}
好家伙,够简洁的,只是内嵌了一个通用池而已。
看代码实现,是对通用池的简单包装和转发,明确了通过池来存取的类型为pooledConnection
func NewConnectionPool(capacity int, idleTimeout time.Duration) *ConnectionPool {
return &ConnectionPool{pools.NewRoundRobin(capacity, idleTimeout)}
}
func (self *ConnectionPool) Open(connFactory CreateConnectionFunc) {
f := func() (pools.Resource, error) {
c, err := connFactory()
if err != nil {
return nil, err
}
return &pooledConnection{c, self}, nil
}
self.RoundRobin.Open(f)
}
// You must call Recycle on the PoolConnection once done.
func (self *ConnectionPool) Get() PoolConnection {
r, err := self.RoundRobin.Get()
if err != nil {
panic(NewTabletErrorSql(FATAL, err))
}
return r.(*pooledConnection)
}
// You must call Recycle on the PoolConnection once done.
func (self *ConnectionPool) TryGet() PoolConnection {
r, err := self.RoundRobin.TryGet()
if err != nil {
panic(NewTabletErrorSql(FATAL, err))
}
if r == nil {
return nil
}
return r.(*pooledConnection)
}
return &ConnectionPool{pools.NewRoundRobin(capacity, idleTimeout)}
}
func (self *ConnectionPool) Open(connFactory CreateConnectionFunc) {
f := func() (pools.Resource, error) {
c, err := connFactory()
if err != nil {
return nil, err
}
return &pooledConnection{c, self}, nil
}
self.RoundRobin.Open(f)
}
// You must call Recycle on the PoolConnection once done.
func (self *ConnectionPool) Get() PoolConnection {
r, err := self.RoundRobin.Get()
if err != nil {
panic(NewTabletErrorSql(FATAL, err))
}
return r.(*pooledConnection)
}
// You must call Recycle on the PoolConnection once done.
func (self *ConnectionPool) TryGet() PoolConnection {
r, err := self.RoundRobin.TryGet()
if err != nil {
panic(NewTabletErrorSql(FATAL, err))
}
if r == nil {
return nil
}
return r.(*pooledConnection)
}
那么pooledConnection是什么呢?接下来的代码可以看到
// pooledConnection re-exposes DBConnection as a PoolConnection
type pooledConnection struct {
*DBConnection
pool *ConnectionPool
}
type pooledConnection struct {
*DBConnection
pool *ConnectionPool
}
咋一看,貌似不符合放入池的条件,实现了ConnectionPool接口吗?继续追DBConnection的定义
// DBConnection re-exposes mysql.Connection with some wrapping.
type DBConnection struct {
*mysql.Connection
}
type DBConnection struct {
*mysql.Connection
}
mysql.go中定义了Connection,并在这个Connection上面实现了PoolConnection接口,所以可以放到池中。
具体实现见mysql.go,因为和本篇的内容的关系不大,留待以后去分析mysql.go的具体实现。
总结一下,在通用池的协助下,这个连接池实现简洁,相当简洁,一共只有30几行代码。