2014-04-08 06:51:53 +00:00
|
|
|
#pragma once
|
2011-03-04 20:58:19 +00:00
|
|
|
|
|
|
|
#include <list>
|
2015-10-01 14:22:01 +00:00
|
|
|
#include <memory>
|
2017-01-13 21:24:59 +00:00
|
|
|
#include <mutex>
|
2020-10-08 15:50:09 +00:00
|
|
|
#include <atomic>
|
2011-03-04 20:58:19 +00:00
|
|
|
|
|
|
|
#include <Poco/Exception.h>
|
|
|
|
#include <mysqlxx/Connection.h>
|
|
|
|
|
|
|
|
|
2017-07-28 15:28:57 +00:00
|
|
|
#define MYSQLXX_POOL_DEFAULT_START_CONNECTIONS 1
|
|
|
|
#define MYSQLXX_POOL_DEFAULT_MAX_CONNECTIONS 16
|
|
|
|
#define MYSQLXX_POOL_SLEEP_ON_CONNECT_FAIL 1
|
2011-03-17 20:00:04 +00:00
|
|
|
|
|
|
|
|
2011-03-04 20:58:19 +00:00
|
|
|
namespace mysqlxx
|
|
|
|
{
|
|
|
|
|
2017-07-18 11:52:46 +00:00
|
|
|
/** MySQL connections pool.
|
|
|
|
* This class is poorly connected with mysqlxx and is made in different style (was taken from old code).
|
|
|
|
* Usage:
|
|
|
|
* mysqlxx::Pool pool("mysql_params");
|
|
|
|
*
|
|
|
|
* void thread()
|
|
|
|
* {
|
|
|
|
* mysqlxx::Pool::Entry connection = pool.Get();
|
|
|
|
* std::string s = connection->query("SELECT 'Hello, world!' AS world").use().fetch()["world"].getString();
|
|
|
|
* }
|
|
|
|
* TODO: simplify with PoolBase.
|
|
|
|
*/
|
2015-02-05 18:47:45 +00:00
|
|
|
class Pool final
|
2011-03-04 20:58:19 +00:00
|
|
|
{
|
|
|
|
protected:
|
2017-07-18 11:52:46 +00:00
|
|
|
/// Information about connection.
|
2017-04-01 07:20:54 +00:00
|
|
|
struct Connection
|
|
|
|
{
|
|
|
|
mysqlxx::Connection conn;
|
2020-10-08 15:50:09 +00:00
|
|
|
/// Ref count modified in constructor/descructor of Entry
|
|
|
|
/// but also read in pool code.
|
|
|
|
std::atomic<int> ref_count = 0;
|
2017-04-01 07:20:54 +00:00
|
|
|
};
|
2011-03-04 20:58:19 +00:00
|
|
|
|
|
|
|
public:
|
2017-07-18 11:52:46 +00:00
|
|
|
/// Connection with database.
|
2017-04-01 07:20:54 +00:00
|
|
|
class Entry
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Entry() {}
|
|
|
|
|
|
|
|
Entry(const Entry & src)
|
|
|
|
: data(src.data), pool(src.pool)
|
|
|
|
{
|
|
|
|
incrementRefCount();
|
|
|
|
}
|
|
|
|
|
|
|
|
~Entry()
|
|
|
|
{
|
|
|
|
decrementRefCount();
|
|
|
|
}
|
|
|
|
|
|
|
|
Entry & operator= (const Entry & src)
|
|
|
|
{
|
|
|
|
pool = src.pool;
|
|
|
|
if (data)
|
|
|
|
decrementRefCount();
|
|
|
|
data = src.data;
|
|
|
|
if (data)
|
|
|
|
incrementRefCount();
|
|
|
|
return * this;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isNull() const
|
|
|
|
{
|
|
|
|
return data == nullptr;
|
|
|
|
}
|
|
|
|
|
2019-07-25 12:10:29 +00:00
|
|
|
operator mysqlxx::Connection & () &
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
forceConnected();
|
|
|
|
return data->conn;
|
|
|
|
}
|
|
|
|
|
2019-07-25 12:10:29 +00:00
|
|
|
operator const mysqlxx::Connection & () const &
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
forceConnected();
|
|
|
|
return data->conn;
|
|
|
|
}
|
|
|
|
|
2019-07-25 12:10:29 +00:00
|
|
|
const mysqlxx::Connection * operator->() const &
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
forceConnected();
|
|
|
|
return &data->conn;
|
|
|
|
}
|
|
|
|
|
2019-07-25 12:10:29 +00:00
|
|
|
mysqlxx::Connection * operator->() &
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
forceConnected();
|
|
|
|
return &data->conn;
|
|
|
|
}
|
|
|
|
|
|
|
|
Entry(Pool::Connection * conn, Pool * p)
|
|
|
|
: data(conn), pool(p)
|
|
|
|
{
|
|
|
|
incrementRefCount();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string getDescription() const
|
|
|
|
{
|
|
|
|
if (pool)
|
|
|
|
return pool->getDescription();
|
|
|
|
else
|
|
|
|
return "pool is null";
|
|
|
|
}
|
|
|
|
|
2019-05-24 14:44:32 +00:00
|
|
|
void disconnect();
|
2019-05-23 13:09:07 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
friend class Pool;
|
|
|
|
|
|
|
|
private:
|
2017-07-18 11:52:46 +00:00
|
|
|
/// Pointer to mysqlxx connection.
|
2017-04-01 07:20:54 +00:00
|
|
|
Connection * data = nullptr;
|
2017-07-18 11:52:46 +00:00
|
|
|
/// Pointer to pool we are belonging to.
|
2017-04-01 07:20:54 +00:00
|
|
|
Pool * pool = nullptr;
|
|
|
|
|
2017-07-18 11:52:46 +00:00
|
|
|
/// Connects to database. If connection is failed then waits and repeats again.
|
2017-04-01 07:20:54 +00:00
|
|
|
void forceConnected() const;
|
|
|
|
|
2017-07-18 11:52:46 +00:00
|
|
|
/// Connects to database. If connection is failed then returns false.
|
2020-12-03 20:36:10 +00:00
|
|
|
bool tryForceConnected() const;
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
void incrementRefCount();
|
|
|
|
void decrementRefCount();
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
Pool(const std::string & config_name,
|
|
|
|
unsigned default_connections_ = MYSQLXX_POOL_DEFAULT_START_CONNECTIONS,
|
|
|
|
unsigned max_connections_ = MYSQLXX_POOL_DEFAULT_MAX_CONNECTIONS,
|
|
|
|
const char * parent_config_name_ = nullptr)
|
|
|
|
: Pool{Poco::Util::Application::instance().config(), config_name,
|
|
|
|
default_connections_, max_connections_, parent_config_name_}
|
|
|
|
{}
|
|
|
|
|
|
|
|
/**
|
2017-07-18 11:52:46 +00:00
|
|
|
* @param config_name Setting name in configuration file
|
|
|
|
* @param default_connections_ Number of default connections
|
|
|
|
* @param max_connections_ Maximum number of connections
|
2017-04-01 07:20:54 +00:00
|
|
|
*/
|
|
|
|
Pool(const Poco::Util::AbstractConfiguration & cfg, const std::string & config_name,
|
|
|
|
unsigned default_connections_ = MYSQLXX_POOL_DEFAULT_START_CONNECTIONS,
|
|
|
|
unsigned max_connections_ = MYSQLXX_POOL_DEFAULT_MAX_CONNECTIONS,
|
|
|
|
const char * parent_config_name_ = nullptr);
|
|
|
|
|
2017-12-01 20:21:35 +00:00
|
|
|
/** Like with mysqlxx::Connection, either port either socket should be specified.
|
|
|
|
* If server is localhost and socket is not empty, than socket is used. Otherwise, server and port is used.
|
|
|
|
*/
|
2017-04-01 07:20:54 +00:00
|
|
|
Pool(const std::string & db_,
|
|
|
|
const std::string & server_,
|
|
|
|
const std::string & user_ = "",
|
|
|
|
const std::string & password_ = "",
|
|
|
|
unsigned port_ = 0,
|
2017-07-14 12:45:32 +00:00
|
|
|
const std::string & socket_ = "",
|
2017-04-01 07:20:54 +00:00
|
|
|
unsigned connect_timeout_ = MYSQLXX_DEFAULT_TIMEOUT,
|
|
|
|
unsigned rw_timeout_ = MYSQLXX_DEFAULT_RW_TIMEOUT,
|
|
|
|
unsigned default_connections_ = MYSQLXX_POOL_DEFAULT_START_CONNECTIONS,
|
2018-10-01 18:04:55 +00:00
|
|
|
unsigned max_connections_ = MYSQLXX_POOL_DEFAULT_MAX_CONNECTIONS,
|
|
|
|
unsigned enable_local_infile_ = MYSQLXX_DEFAULT_ENABLE_LOCAL_INFILE)
|
2017-04-01 07:20:54 +00:00
|
|
|
: default_connections(default_connections_), max_connections(max_connections_),
|
2017-12-01 20:21:35 +00:00
|
|
|
db(db_), server(server_), user(user_), password(password_), port(port_), socket(socket_),
|
2018-10-01 18:04:55 +00:00
|
|
|
connect_timeout(connect_timeout_), rw_timeout(rw_timeout_), enable_local_infile(enable_local_infile_) {}
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
Pool(const Pool & other)
|
|
|
|
: default_connections{other.default_connections},
|
|
|
|
max_connections{other.max_connections},
|
|
|
|
db{other.db}, server{other.server},
|
|
|
|
user{other.user}, password{other.password},
|
2017-07-14 12:45:32 +00:00
|
|
|
port{other.port}, socket{other.socket},
|
2018-10-01 18:04:55 +00:00
|
|
|
connect_timeout{other.connect_timeout}, rw_timeout{other.rw_timeout},
|
|
|
|
enable_local_infile{other.enable_local_infile}
|
2017-04-01 07:20:54 +00:00
|
|
|
{}
|
|
|
|
|
|
|
|
Pool & operator=(const Pool &) = delete;
|
|
|
|
|
|
|
|
~Pool();
|
|
|
|
|
2017-07-18 11:52:46 +00:00
|
|
|
/// Allocates connection.
|
2020-03-23 02:12:31 +00:00
|
|
|
Entry get();
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2017-07-18 11:52:46 +00:00
|
|
|
/// Allocates connection.
|
|
|
|
/// If database is not accessible, returns empty Entry object.
|
|
|
|
/// If pool is overflowed, throws exception.
|
2017-04-01 07:20:54 +00:00
|
|
|
Entry tryGet();
|
|
|
|
|
2017-07-18 11:52:46 +00:00
|
|
|
/// Get description of database.
|
2017-04-01 07:20:54 +00:00
|
|
|
std::string getDescription() const
|
|
|
|
{
|
|
|
|
return description;
|
|
|
|
}
|
2011-03-04 20:58:19 +00:00
|
|
|
|
2020-03-08 21:04:10 +00:00
|
|
|
void removeConnection(Connection * connection);
|
2020-02-27 09:34:06 +00:00
|
|
|
|
2011-03-04 20:58:19 +00:00
|
|
|
protected:
|
2017-07-18 11:52:46 +00:00
|
|
|
/// Number of MySQL connections which are created at launch.
|
2017-04-01 07:20:54 +00:00
|
|
|
unsigned default_connections;
|
2017-07-18 11:52:46 +00:00
|
|
|
/// Maximum possible number of connections
|
2017-04-01 07:20:54 +00:00
|
|
|
unsigned max_connections;
|
2011-03-04 20:58:19 +00:00
|
|
|
|
|
|
|
private:
|
2017-07-18 11:52:46 +00:00
|
|
|
/// Initialization flag.
|
2017-04-01 07:20:54 +00:00
|
|
|
bool initialized{false};
|
2017-07-18 11:52:46 +00:00
|
|
|
/// List of connections.
|
2017-04-01 07:20:54 +00:00
|
|
|
using Connections = std::list<Connection *>;
|
2017-07-18 11:52:46 +00:00
|
|
|
/// List of connections.
|
2017-04-01 07:20:54 +00:00
|
|
|
Connections connections;
|
2017-07-18 11:52:46 +00:00
|
|
|
/// Lock for connections list access
|
2017-04-01 07:20:54 +00:00
|
|
|
std::mutex mutex;
|
2017-07-18 11:52:46 +00:00
|
|
|
/// Description of connection.
|
2017-04-01 07:20:54 +00:00
|
|
|
std::string description;
|
|
|
|
|
2017-07-18 11:52:46 +00:00
|
|
|
/// Connection settings.
|
2017-04-01 07:20:54 +00:00
|
|
|
std::string db;
|
|
|
|
std::string server;
|
|
|
|
std::string user;
|
|
|
|
std::string password;
|
|
|
|
unsigned port;
|
2017-07-14 12:45:32 +00:00
|
|
|
std::string socket;
|
2017-04-01 07:20:54 +00:00
|
|
|
unsigned connect_timeout;
|
|
|
|
unsigned rw_timeout;
|
2017-09-09 21:26:02 +00:00
|
|
|
std::string ssl_ca;
|
|
|
|
std::string ssl_cert;
|
|
|
|
std::string ssl_key;
|
2018-10-01 18:04:55 +00:00
|
|
|
bool enable_local_infile;
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2017-07-18 11:52:46 +00:00
|
|
|
/// True if connection was established at least once.
|
2017-04-01 07:20:54 +00:00
|
|
|
bool was_successful{false};
|
|
|
|
|
2017-07-18 11:52:46 +00:00
|
|
|
/// Initialises class if it wasn't.
|
2017-04-01 07:20:54 +00:00
|
|
|
void initialize();
|
|
|
|
|
|
|
|
/** Create new connection. */
|
|
|
|
Connection * allocConnection(bool dont_throw_if_failed_first_time = false);
|
2011-03-04 20:58:19 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|