36#include <boost/asio/use_future.hpp>
37#include <mysqld_error.h>
41#include <boost/stacktrace.hpp>
44#define MIN_MYSQL_SERVER_VERSION 50700u
45#define MIN_MYSQL_SERVER_VERSION_STRING "5.7"
46#define MIN_MYSQL_CLIENT_VERSION 50700u
47#define MIN_MYSQL_CLIENT_VERSION_STRING "5.7"
49#define MIN_MARIADB_SERVER_VERSION 100209u
50#define MIN_MARIADB_SERVER_VERSION_STRING "10.2.9"
51#define MIN_MARIADB_CLIENT_VERSION 30003u
52#define MIN_MARIADB_CLIENT_VERSION_STRING "3.0.3"
69 if (_pool != other.
_pool)
84 if (_pool != other._pool)
89 _pool = std::exchange(other._pool,
nullptr);
106 : _async_threads(0), _synch_threads(0)
108 WPFatal(mysql_thread_safe(),
"Used MySQL library isn't thread-safe.");
110#if defined(LIBMARIADB) && MARIADB_PACKAGE_VERSION_ID >= 30200
112 WPFatal(mysql_get_client_version() == MARIADB_PACKAGE_VERSION_ID,
"Used MariaDB library version (%s id %lu) does not match the version id used to compile TrinityCore (id %u). Search on forum for TCE00011.", mysql_get_client_info(), mysql_get_client_version(), MARIADB_PACKAGE_VERSION_ID);
115 WPFatal(mysql_get_client_version() == MYSQL_VERSION_ID,
"Used MySQL library version (%s id %lu) does not match the version id used to compile TrinityCore (id %u). Search on forum for TCE00011.", mysql_get_client_info(), mysql_get_client_version(), MYSQL_VERSION_ID);
126 uint8 const asyncThreads,
uint8 const synchThreads)
128 _connectionInfo = std::make_unique<MySQLConnectionInfo>(infoString);
130 _async_threads = asyncThreads;
131 _synch_threads = synchThreads;
137 WPFatal(_connectionInfo.get(),
"Connection info was not set!");
139 TC_LOG_INFO(
"sql.driver",
"Opening DatabasePool '{}'. "
140 "Asynchronous connections: {}, synchronous connections: {}.",
141 GetDatabaseName(), _async_threads, _synch_threads);
143 _ioContext = std::make_unique<Trinity::Asio::IoContext>(_async_threads);
145 uint32 error = OpenConnections(IDX_ASYNC, _async_threads);
150 error = OpenConnections(IDX_SYNCH, _synch_threads);
155 for (std::unique_ptr<T>
const& connection : _connections[IDX_ASYNC])
156 connection->StartWorkerThread(_ioContext.get());
158 TC_LOG_INFO(
"sql.driver",
"DatabasePool '{}' opened successfully. "
159 "{} total connections running.", GetDatabaseName(),
160 (_connections[IDX_SYNCH].
size() + _connections[IDX_ASYNC].
size()));
168 TC_LOG_INFO(
"sql.driver",
"Closing down DatabasePool '{}'.", GetDatabaseName());
174 _connections[IDX_ASYNC].clear();
178 TC_LOG_INFO(
"sql.driver",
"Asynchronous connections on DatabasePool '{}' terminated. "
179 "Proceeding with synchronous connections.",
186 _connections[IDX_SYNCH].clear();
188 TC_LOG_INFO(
"sql.driver",
"All connections on DatabasePool '{}' closed.", GetDatabaseName());
194 for (
auto& connections : _connections)
196 for (
auto& connection : connections)
198 connection->LockIfReady();
199 if (!connection->PrepareStatements())
201 connection->Unlock();
206 connection->Unlock();
208 size_t const preparedSize = connection->m_stmts.size();
209 if (_preparedStatementSize.size() < preparedSize)
210 _preparedStatementSize.resize(preparedSize);
212 for (
size_t i = 0; i < preparedSize; ++i)
216 if (_preparedStatementSize[i] > 0)
221 uint32 const paramCount = stmt->GetParameterCount();
224 ASSERT(paramCount < std::numeric_limits<uint8>::max());
226 _preparedStatementSize[i] =
static_cast<uint8>(paramCount);
239 connection = GetFreeConnection();
242 connection->Unlock();
250 T* connection = GetFreeConnection();
252 connection->Unlock();
265 T* conn = GetAsyncConnectionForCurrentThread();
276 T* conn = GetAsyncConnectionForCurrentThread();
287 T* conn = GetAsyncConnectionForCurrentThread();
290 return { std::move(holder), std::move(result) };
296 return std::make_shared<Transaction<T>>();
306 switch (transaction->GetSize())
309 TC_LOG_DEBUG(
"sql.driver",
"Transaction contains 0 queries. Not executing.");
312 TC_LOG_DEBUG(
"sql.driver",
"Warning: Transaction only holds 1 query, consider removing Transaction context in code.");
321 T* conn = GetAsyncConnectionForCurrentThread();
333 switch (transaction->GetSize())
336 TC_LOG_DEBUG(
"sql.driver",
"Transaction contains 0 queries. Not executing.");
339 TC_LOG_DEBUG(
"sql.driver",
"Warning: Transaction only holds 1 query, consider removing Transaction context in code.");
348 T* conn = GetAsyncConnectionForCurrentThread();
357 T* connection = GetFreeConnection();
358 int errorCode = connection->ExecuteTransaction(transaction);
361 connection->Unlock();
367 if (errorCode == ER_LOCK_DEADLOCK)
370 uint8 loopBreaker = 5;
371 for (
uint8 i = 0; i < loopBreaker; ++i)
373 if (!connection->ExecuteTransaction(transaction))
379 transaction->Cleanup();
381 connection->Unlock();
396 char* buf =
new char[str.size() * 2 + 1];
397 EscapeString(buf, str.c_str(),
uint32(str.size()));
406 for (
auto& connection : _connections[IDX_SYNCH])
408 if (connection->LockIfReady())
411 connection->Unlock();
418 auto const count = _connections[IDX_ASYNC].size();
419 for (
uint8 i = 0; i < count; ++i)
423 T* conn = GetAsyncConnectionForCurrentThread();
432 for (
uint8 i = 0; i < numConnections; ++i)
437 std::unique_ptr<T> connection = std::make_unique<T>(*_connectionInfo,
flags[type]);
439 if (
uint32 error = connection->Open())
442 _connections[type].clear();
461 _connections[type].push_back(std::move(connection));
472 if (!to || !from || !length)
475 return _connections[IDX_SYNCH].front()->EscapeString(to, from, length);
488 if (_warnSyncQueries)
490 std::ostringstream ss;
491 ss << boost::stacktrace::stacktrace();
492 TC_LOG_WARN(
"sql.performances",
"Sync query at:\n{}", ss.str());
497 auto const num_cons = _connections[IDX_SYNCH].size();
498 T* connection =
nullptr;
502 connection = _connections[IDX_SYNCH][i++ % num_cons].get();
504 if (connection->LockIfReady())
514 std::thread::id
id = std::this_thread::get_id();
515 for (
auto&& connection : _connections[IDX_ASYNC])
516 if (connection->GetWorkerThreadId() ==
id)
517 return connection.get();
525 return _connectionInfo->database.c_str();
536 T* conn = GetAsyncConnectionForCurrentThread();
546 T* conn = GetAsyncConnectionForCurrentThread();
557 T* connection = GetFreeConnection();
559 connection->Unlock();
565 T* connection = GetFreeConnection();
567 connection->Unlock();
std::future< PreparedQueryResult > PreparedQueryResultFuture
std::future< QueryResult > QueryResultFuture
std::shared_ptr< ResultSet > QueryResult
std::shared_ptr< Transaction< T > > SQLTransaction
std::shared_ptr< PreparedResultSet > PreparedQueryResult
std::future< bool > TransactionFuture
std::future< void > QueryResultHolderFuture
#define MIN_MARIADB_CLIENT_VERSION
#define MIN_MARIADB_CLIENT_VERSION_STRING
#define MIN_MYSQL_SERVER_VERSION_STRING
#define MIN_MARIADB_SERVER_VERSION
#define MIN_MYSQL_CLIENT_VERSION
#define MIN_MARIADB_SERVER_VERSION_STRING
#define MIN_MYSQL_SERVER_VERSION
#define MIN_MYSQL_CLIENT_VERSION_STRING
#define WPFatal(cond,...)
#define TC_LOG_WARN(filterType__,...)
#define TC_LOG_DEBUG(filterType__,...)
#define TC_LOG_ERROR(filterType__,...)
#define TC_LOG_INFO(filterType__,...)
static bool Execute(MySQLConnection *conn, char const *sql)
static QueryResult Query(MySQLConnection *conn, char const *sql)
uint32 OpenConnections(InternalIndex type, uint8 numConnections)
void CommitTransaction(SQLTransaction< T > transaction)
QueryResult Query(char const *sql, T *connection=nullptr)
bool PrepareStatements()
Prepares all prepared statements.
T * GetAsyncConnectionForCurrentThread() const
void SetConnectionInfo(std::string const &infoString, uint8 const asyncThreads, uint8 const synchThreads)
void ExecuteOrAppend(SQLTransaction< T > &trans, char const *sql)
std::atomic< size_t > _queueSize
SQLTransaction< T > BeginTransaction()
Begins an automanaged transaction pointer that will automatically rollback if not commited....
void DirectCommitTransaction(SQLTransaction< T > &transaction)
void KeepAlive()
Keeps all our MySQL connections alive, prevent the server from disconnecting us.
T::Statements PreparedStatementIndex
char const * GetDatabaseName() const
PreparedStatement< T > * GetPreparedStatement(PreparedStatementIndex index)
void DirectExecute(char const *sql)
SQLQueryHolderCallback DelayQueryHolder(std::shared_ptr< SQLQueryHolder< T > > holder)
void EscapeString(std::string &str)
Apply escape string'ing for current collation. (utf8)
void Execute(char const *sql)
QueryCallback AsyncQuery(char const *sql)
TransactionCallback AsyncCommitTransaction(SQLTransaction< T > transaction)
static PreparedQueryResult Query(MySQLConnection *conn, PreparedStatementBase *stmt)
static bool Execute(MySQLConnection *conn, PreparedStatementBase *stmt)
static bool Execute(MySQLConnection *conn, SQLQueryHolderBase *holder)
static bool Execute(MySQLConnection *conn, std::shared_ptr< TransactionBase > trans)
decltype(auto) post(boost::asio::io_context &ioContext, T &&t)
constexpr std::size_t size()
QueueSizeTracker & operator=(QueueSizeTracker const &other)
QueueSizeTracker(DatabaseWorkerPool *pool)
QueueSizeTracker(QueueSizeTracker &&other) noexcept
QueueSizeTracker & operator=(QueueSizeTracker &&other) noexcept
QueueSizeTracker(QueueSizeTracker const &other)
DatabaseWorkerPool * _pool