#if !defined(MYSQLPP_CPOOL_H)
#define MYSQLPP_CPOOL_H
#include "beemutex.h"
#include <list>
#include <assert.h>
#include <time.h>
namespace mysqlpp {
#if !defined(DOXYGEN_IGNORE)
// Make Doxygen ignore this
class MYSQLPP_EXPORT Connection;
#endif
class MYSQLPP_EXPORT ConnectionPool
{
public:
/// \brief Create empty pool
ConnectionPool() { }
/// \brief Destroy object
///
/// If the pool raises an assertion on destruction, it means our
/// subclass isn't calling clear() in its dtor as it should.
virtual ~ConnectionPool() { assert(empty()); }
/// \brief Returns true if pool is empty
bool empty() const { return pool_.empty(); }
/// \brief Return a defective connection to the pool and get a new
/// one back.
///
/// Call this on receiving a BadQuery exception, with errnum()
/// equal to CR_SERVER_GONE_ERROR. It means the server was
/// restarted or otherwise dropped your connection to it, so the
/// Connection object is no longer usable. You can avoid the
/// need to use this by setting the ReconnectOption in your grab()
/// override, but perhaps there are other reasons to need to
/// exchange a bad connection for a good one.
///
/// This function wraps grab(), not safe_grab(), even though that
/// could return another dead connection. The assumption is that if
/// your code is smart enough to detect one bad connection, it should
/// be smart enough to detect a whole string of them. Worst case,
/// the whole pool is bad -- remote server went away -- and we have
/// to empty the pool and start re-filling it.
///
/// \param pc pointer to a Connection object to be returned to the
/// pool and marked as unused.
///
/// \retval a pointer to a different Connection object; not
/// guaranteed to still be connected!
virtual Connection* exchange(const Connection* pc);
/// \brief Grab a free connection from the pool.
///
/// This method creates a new connection if an unused one doesn't
/// exist, and destroys any that have remained unused for too long.
/// If there is more than one free connection, we return the most
/// recently used one; this allows older connections to die off over
/// time when the caller's need for connections decreases.
///
/// Do not delete the returned pointer. This object manages the
/// lifetime of connection objects it creates.
///
/// \retval a pointer to the connection
virtual Connection* grab();
/// \brief Return a connection to the pool
///
/// Marks the connection as no longer in use.
///
/// The pool updates the last-used time of a connection only on
/// release, on the assumption that it was used just prior. There's
/// nothing forcing you to do it this way: your code is free to
/// delay releasing idle connections as long as it likes. You
/// want to avoid this because it will make the pool perform poorly;
/// if it doesn't know approximately how long a connection has
/// really been idle, it can't make good judgements about when to
/// remove it from the pool.
///
/// \param pc pointer to a Connection object to be returned to the
/// pool and marked as unused.
virtual void release(const Connection* pc);
/// \brief Removes the given connection from the pool
///
/// If you mean to simply return a connection to the pool after
/// you're finished using it, call release() instead. This method
/// is primarily for error handling: you somehow have figured out
/// that the connection is defective, so want it destroyed and
/// removed from the pool. If you also want a different connection
/// to retry your operation on, call exchange() instead.
///
/// \param pc pointer to a Connection object to be removed from
/// the pool and destroyed
void remove(const Connection* pc);
/// \brief Grab a free connection from the pool, testing that it's
/// connected before returning it.
///
/// This is just a wrapper around grab(), Connection::ping() and
/// release(), and is thus less efficient than grab(). Use it only
/// when it's possible for MySQL server connections to go away
/// unexpectedly, such as when the DB server can be restarted out
/// from under your application.
///
/// \retval a pointer to the connection
virtual Connection* safe_grab();
/// \brief Remove all unused connections from the pool
void shrink() { clear(false); }
protected:
/// \brief Drains the pool, freeing all allocated memory.
///
/// A derived class must call this in its dtor to avoid leaking all
/// Connection objects still in existence. We can't do it up at
/// this level because this class's dtor can't call our subclass's
/// destroy() method.
///
/// \param all if true, remove all connections, even those in use
void clear(bool all = true);
/// \brief Create a new connection
///
/// Subclasses must override this.
///
/// Essentially, this method lets your code tell ConnectionPool
/// what server to connect to, what login parameters to use, what
/// connection options to enable, etc. ConnectionPool can't know
/// any of this without your help.
///
/// \retval A connected Connection object
virtual Connection* create() = 0;
/// \brief Destroy a connection
///
/// Subclasses must override this.
///
/// This is for destroying the objects returned by create().
/// Because we can't know what the derived class did to create the
/// connection we can't reliably know how to destroy it.
virtual void destroy(Connection*) = 0;
/// \brief Returns the maximum number of seconds a connection is
/// able to remain idle before it is dropped.
///
/// Subclasses must override this as it encodes a policy issue,
/// something that MySQL++ can't declare by fiat.
///
/// \retval number of seconds before an idle connection is destroyed
/// due to lack of use
virtual unsigned int max_idle_time() = 0;
/// \brief Returns the current size of the internal connection pool.
size_t size() const { return pool_.size(); }
private:
Internal types
struct ConnectionInfo {
Connection* conn;
time_t last_used;
bool in_use;
ConnectionInfo(Connection* c) :
conn(c),
last_used(time(0)),
in_use(true)
{
}
// Strict weak ordering for ConnectionInfo objects.
//
// This ordering defines all in-use connections to be "less
// than" those not in use. Within each group, connections
// less recently touched are less than those more recent.
bool operator<(const ConnectionInfo& rhs) const
{
const ConnectionInfo& lhs = *this;
return lhs.in_use == rhs.in_use ?
lhs.last_used < rhs.last_used :
lhs.in_use;
}
};
typedef std::list<ConnectionInfo> PoolT;
typedef PoolT::iterator PoolIt;
Internal support functions
Connection* find_mru();
void remove(const PoolIt& it);
void remove_old_connections();
Internal data
PoolT pool_;
BeecryptMutex mutex_;
};
} // end namespace mysqlpp
#endif // !defined(MYSQLPP_CPOOL_H)
解读
PoolT pool_;
底层实现是 list , ConnectionInfo 是对 mysql Connection 的封装。
pool_ 用于存储 Connection。
virtual Connection* exchange(const Connection* pc);
返还一个无效的连接,并且返回一个新的连接。
/// \brief Grab a free connection from the pool.
///
/// This method creates a new connection if an unused one doesn't
/// exist, and destroys any that have remained unused for too long.
/// If there is more than one free connection, we return the most
/// recently used one; this allows older connections to die off over
/// time when the caller's need for connections decreases.
///
/// Do not delete the returned pointer. This object manages the
/// lifetime of connection objects it creates.
///
/// \retval a pointer to the connection
virtual Connection* grab();
从连接池中获得一个新的连接。
如果没有未使用的连接存在该方法会创建一个新的连接,并且销毁一个长期没有使用的连接。
如果存在有多于一个可使用的连接,我们返回最近使用的一个连接。
当caller需要去削减连接时,将会销毁最长时间未使用的 Connection。
不要删除返回的 pointer ,pool 会自己控制 连接 的生命周期。
/// \brief Return a connection to the pool
///
/// Marks the connection as no longer in use.
///
/// The pool updates the last-used time of a connection only on
/// release, on the assumption that it was used just prior. There's
/// nothing forcing you to do it this way: your code is free to
/// delay releasing idle connections as long as it likes. You
/// want to avoid this because it will make the pool perform poorly;
/// if it doesn't know approximately how long a connection has
/// really been idle, it can't make good judgements about when to
/// remove it from the pool.
///
/// \param pc pointer to a Connection object to be returned to the
/// pool and marked as unused.
virtual void release(const Connection* pc);
返回一个连接给连接池,标记该连接为未使用 unused 状态。
连接池 pool 只会在调用 release 时更新 connection 的最后使用时间。
/// \brief Removes the given connection from the pool
///
/// If you mean to simply return a connection to the pool after
/// you're finished using it, call release() instead. This method
/// is primarily for error handling: you somehow have figured out
/// that the connection is defective, so want it destroyed and
/// removed from the pool. If you also want a different connection
/// to retry your operation on, call exchange() instead.
///
/// \param pc pointer to a Connection object to be removed from
/// the pool and destroyed
void remove(const Connection* pc);
从连接池中删除该 connection。
如果你只是想在使用后返回一个connection 到 pool , 应该使用 release() 函数。该函数主要用于“错误处理”,当你发小某个连接有缺陷时,你想要从连接池中销毁该连接。如果你想获得另外一个可使用的连接,应该使用 exchange() 函数。
/// \brief Grab a free connection from the pool, testing that it's
/// connected before returning it.
///
/// This is just a wrapper around grab(), Connection::ping() and
/// release(), and is thus less efficient than grab(). Use it only
/// when it's possible for MySQL server connections to go away
/// unexpectedly, such as when the DB server can be restarted out
/// from under your application.
///
/// \retval a pointer to the connection
virtual Connection* safe_grab();
返回一个可用的连接,并且在返回该连接之前测试该连接是否可用。相对于 grab() 该函数的效率更低。
/// \brief Remove all unused connections from the pool
void shrink() { clear(false); }
在连接池中删除所有未使用的连接。
保护函数
/// \brief Drains the pool, freeing all allocated memory.
///
/// A derived class must call this in its dtor to avoid leaking all
/// Connection objects still in existence. We can't do it up at
/// this level because this class's dtor can't call our subclass's
/// destroy() method.
///
/// \param all if true, remove all connections, even those in use
void clear(bool all = true);
耗尽整个连接池,释放所有开辟的空间。
所有的 子类必须在析构函数中调用该函数防止内存泄露,因为子类的析构函数不能调用父类的析构函数。如果参数为 true ,删除所有的连接,尽管该连接正在使用中。
/// \brief Create a new connection
///
/// Subclasses must override this.
///
/// Essentially, this method lets your code tell ConnectionPool
/// what server to connect to, what login parameters to use, what
/// connection options to enable, etc. ConnectionPool can't know
/// any of this without your help.
///
/// \retval A connected Connection object
virtual Connection* create() = 0;
创建一个新的连接,子类必须实现该函数。
/// \brief Destroy a connection
///
/// Subclasses must override this.
///
/// This is for destroying the objects returned by create().
/// Because we can't know what the derived class did to create the
/// connection we can't reliably know how to destroy it.
virtual void destroy(Connection*) = 0;
删除一个连接,子类必须要实现该函数,用于删除 create() 函数创建的连接。
/// \brief Returns the maximum number of seconds a connection is
/// able to remain idle before it is dropped.
///
/// Subclasses must override this as it encodes a policy issue,
/// something that MySQL++ can't declare by fiat.
///
/// \retval number of seconds before an idle connection is destroyed
/// due to lack of use
virtual unsigned int max_idle_time() = 0;
返回一个连接可以保存的寿命,秒数。
/// \brief Returns the current size of the internal connection pool.
size_t size() const { return pool_.size(); }
返回当前连接池中连接数量的大小。