mysqlpp::ConnectionPool 源码解读

#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(); }

返回当前连接池中连接数量的大小。

猜你喜欢

转载自blog.csdn.net/weixin_40021744/article/details/87475934