代码改变世界

vitess源码阅读笔记cache系列之用go实现mysql连接池ConnectionPool

2012-04-06 16:16  ngaut  阅读(1674)  评论(1编辑  收藏  举报
上一篇笔记我们了解了通用资源池,就像人和人不同,池与池亦有异。往池里放水就成了水池,
往池里放内存就成了内存池。往池里放mysql连接呢?自然就成了本篇笔记的主角mysql连接池。当然这个连接池也分几种。
又的连接只用来做mysql查询,有的用来做事务操作。用来做mysql查询的连接池在vitess里面叫做ConnectionPool。
ConnectionPool在架构图中扮演的角色是什么呢?架构图上已经非常清晰的注明了,见架构图的右下角。

还是先上数据结构,看看往池里面放的是什么 

type PoolConnection interface { 
    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
}

 

好家伙,够简洁的,只是内嵌了一个通用池而已。
看代码实现,是对通用池的简单包装和转发,明确了通过池来存取的类型为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)
}

 那么pooledConnection是什么呢?接下来的代码可以看到 

// pooledConnection re-exposes DBConnection as a PoolConnection
type pooledConnection struct {
    *DBConnection
    pool *ConnectionPool
}

 咋一看,貌似不符合放入池的条件,实现了ConnectionPool接口吗?继续追DBConnection的定义 

// DBConnection re-exposes mysql.Connection with some wrapping.
type DBConnection struct {
    *mysql.Connection
}

mysql.go中定义了Connection,并在这个Connection上面实现了PoolConnection接口,所以可以放到池中。

具体实现见mysql.go,因为和本篇的内容的关系不大,留待以后去分析mysql.go的具体实现。

 

总结一下,在通用池的协助下,这个连接池实现简洁,相当简洁,一共只有30几行代码。