mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-24 14:16:31 +00:00
feat(Core/Database): implement db loader (#4431)
This commit is contained in:
10
src/common/Database/DatabaseEnv.cpp
Normal file
10
src/common/Database/DatabaseEnv.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
|
||||
*/
|
||||
|
||||
#include "DatabaseEnv.h"
|
||||
|
||||
WorldDatabaseWorkerPool WorldDatabase;
|
||||
CharacterDatabaseWorkerPool CharacterDatabase;
|
||||
LoginDatabaseWorkerPool LoginDatabase;
|
||||
@@ -22,12 +22,17 @@
|
||||
#define _CONCAT3_(A, B, C) "CONCAT( " A ", " B ", " C " )"
|
||||
#define _OFFSET_ "LIMIT %d, 1"
|
||||
|
||||
#include "Implementation/LoginDatabase.h"
|
||||
#include "Implementation/CharacterDatabase.h"
|
||||
#include "Implementation/WorldDatabase.h"
|
||||
#include "LoginDatabase.h"
|
||||
#include "CharacterDatabase.h"
|
||||
#include "WorldDatabase.h"
|
||||
|
||||
/// Accessor to the world database
|
||||
extern WorldDatabaseWorkerPool WorldDatabase;
|
||||
|
||||
/// Accessor to the character database
|
||||
extern CharacterDatabaseWorkerPool CharacterDatabase;
|
||||
|
||||
/// Accessor to the realm/login database
|
||||
extern LoginDatabaseWorkerPool LoginDatabase;
|
||||
|
||||
#endif
|
||||
|
||||
142
src/common/Database/DatabaseLoader.cpp
Normal file
142
src/common/Database/DatabaseLoader.cpp
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
|
||||
*/
|
||||
|
||||
#include "DatabaseLoader.h"
|
||||
#include "Config.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "Log.h"
|
||||
#include "Duration.h"
|
||||
#include <mysqld_error.h>
|
||||
#include <errmsg.h>
|
||||
|
||||
template <class T>
|
||||
DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool<T>& pool, std::string const& name)
|
||||
{
|
||||
_open.push([this, name, &pool]() -> bool
|
||||
{
|
||||
std::string const dbString = sConfigMgr->GetOption<std::string>(name + "DatabaseInfo", "");
|
||||
if (dbString.empty())
|
||||
{
|
||||
sLog->outSQLDriver("Database %s not specified in configuration file!", name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8 const asyncThreads = sConfigMgr->GetOption<uint8>(name + "Database.WorkerThreads", 1);
|
||||
if (asyncThreads < 1 || asyncThreads > 32)
|
||||
{
|
||||
sLog->outSQLDriver("%s database: invalid number of worker threads specified. Please pick a value between 1 and 32.", name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8 const synchThreads = sConfigMgr->GetOption<uint8>(name + "Database.SynchThreads", 1);
|
||||
|
||||
pool.SetConnectionInfo(dbString, asyncThreads, synchThreads);
|
||||
|
||||
if (uint32 error = pool.Open())
|
||||
{
|
||||
// Try reconnect
|
||||
if (error == CR_CONNECTION_ERROR)
|
||||
{
|
||||
// Possible improvement for future: make ATTEMPTS and SECONDS configurable values
|
||||
uint32 const ATTEMPTS = 5;
|
||||
Seconds durationSecs = 5s;
|
||||
uint32 count = 1;
|
||||
|
||||
auto sleepThread = [&]()
|
||||
{
|
||||
sLog->outSQLDriver("> Retrying after %u seconds", durationSecs.count());
|
||||
std::this_thread::sleep_for(durationSecs);
|
||||
};
|
||||
|
||||
sleepThread();
|
||||
|
||||
do
|
||||
{
|
||||
error = pool.Open();
|
||||
|
||||
if (error == CR_CONNECTION_ERROR)
|
||||
{
|
||||
sleepThread();
|
||||
count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
} while (count < ATTEMPTS);
|
||||
}
|
||||
|
||||
// If the error wasn't handled quit
|
||||
if (error)
|
||||
{
|
||||
sLog->outSQLDriver("DatabasePool %s NOT opened. There were errors opening the MySQL connections. Check your SQLDriverLogFile for specific errors", name.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the close operation
|
||||
_close.push([&pool]
|
||||
{
|
||||
pool.Close();
|
||||
});
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
_prepare.push([name, &pool]() -> bool
|
||||
{
|
||||
if (!pool.PrepareStatements())
|
||||
{
|
||||
sLog->outSQLDriver("Could not prepare statements of the %s database, see log for details.", name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool DatabaseLoader::Load()
|
||||
{
|
||||
return OpenDatabases() && PrepareStatements();
|
||||
}
|
||||
|
||||
bool DatabaseLoader::OpenDatabases()
|
||||
{
|
||||
return Process(_open);
|
||||
}
|
||||
|
||||
bool DatabaseLoader::PrepareStatements()
|
||||
{
|
||||
return Process(_prepare);
|
||||
}
|
||||
|
||||
bool DatabaseLoader::Process(std::queue<Predicate>& queue)
|
||||
{
|
||||
while (!queue.empty())
|
||||
{
|
||||
if (!queue.front()())
|
||||
{
|
||||
// Close all open databases which have a registered close operation
|
||||
while (!_close.empty())
|
||||
{
|
||||
_close.top()();
|
||||
_close.pop();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
queue.pop();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template DatabaseLoader& DatabaseLoader::AddDatabase<LoginDatabaseConnection>(DatabaseWorkerPool<LoginDatabaseConnection>&, std::string const&);
|
||||
template DatabaseLoader& DatabaseLoader::AddDatabase<CharacterDatabaseConnection>(DatabaseWorkerPool<CharacterDatabaseConnection>&, std::string const&);
|
||||
template DatabaseLoader& DatabaseLoader::AddDatabase<WorldDatabaseConnection>(DatabaseWorkerPool<WorldDatabaseConnection>&, std::string const&);
|
||||
56
src/common/Database/DatabaseLoader.h
Normal file
56
src/common/Database/DatabaseLoader.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
|
||||
*/
|
||||
|
||||
#ifndef DatabaseLoader_h__
|
||||
#define DatabaseLoader_h__
|
||||
|
||||
#include "Define.h"
|
||||
#include <functional>
|
||||
#include <queue>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
|
||||
template <class T>
|
||||
class DatabaseWorkerPool;
|
||||
|
||||
// A helper class to initiate all database worker pools,
|
||||
// handles updating, delays preparing of statements and cleans up on failure.
|
||||
class DatabaseLoader
|
||||
{
|
||||
public:
|
||||
// Register a database to the loader (lazy implemented)
|
||||
template <class T>
|
||||
DatabaseLoader& AddDatabase(DatabaseWorkerPool<T>& pool, std::string const& name);
|
||||
|
||||
// Load all databases
|
||||
bool Load();
|
||||
|
||||
enum DatabaseTypeFlags
|
||||
{
|
||||
DATABASE_NONE = 0,
|
||||
|
||||
DATABASE_LOGIN = 1,
|
||||
DATABASE_CHARACTER = 2,
|
||||
DATABASE_WORLD = 4,
|
||||
|
||||
DATABASE_MASK_ALL = DATABASE_LOGIN | DATABASE_CHARACTER | DATABASE_WORLD
|
||||
};
|
||||
|
||||
private:
|
||||
bool OpenDatabases();
|
||||
bool PrepareStatements();
|
||||
|
||||
using Predicate = std::function<bool()>;
|
||||
using Closer = std::function<void()>;
|
||||
|
||||
// Invokes all functions in the given queue and closes the databases on errors.
|
||||
// Returns false when there was an error.
|
||||
bool Process(std::queue<Predicate>& queue);
|
||||
|
||||
std::queue<Predicate> _open, _prepare;
|
||||
std::stack<Closer> _close;
|
||||
};
|
||||
|
||||
#endif // DatabaseLoader_h__
|
||||
@@ -12,7 +12,9 @@
|
||||
|
||||
template <class T> DatabaseWorkerPool<T>::DatabaseWorkerPool() :
|
||||
_mqueue(new ACE_Message_Queue<ACE_SYNCH>(2 * 1024 * 1024, 2 * 1024 * 1024)),
|
||||
_queue(new ACE_Activation_Queue(_mqueue))
|
||||
_queue(new ACE_Activation_Queue(_mqueue)),
|
||||
_async_threads(0),
|
||||
_synch_threads(0)
|
||||
{
|
||||
memset(_connectionCount, 0, sizeof(_connectionCount));
|
||||
_connections.resize(IDX_SIZE);
|
||||
@@ -22,45 +24,39 @@ template <class T> DatabaseWorkerPool<T>::DatabaseWorkerPool() :
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool DatabaseWorkerPool<T>::Open(const std::string& infoString, uint8 async_threads, uint8 synch_threads)
|
||||
void DatabaseWorkerPool<T>::SetConnectionInfo(std::string const& infoString,
|
||||
uint8 const asyncThreads, uint8 const synchThreads)
|
||||
{
|
||||
bool res = true;
|
||||
_connectionInfo = MySQLConnectionInfo(infoString);
|
||||
_connectionInfo = std::make_unique<MySQLConnectionInfo>(infoString);
|
||||
|
||||
_async_threads = asyncThreads;
|
||||
_synch_threads = synchThreads;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
uint32 DatabaseWorkerPool<T>::Open()
|
||||
{
|
||||
WPFatal(_connectionInfo.get(), "Connection info was not set!");
|
||||
|
||||
sLog->outSQLDriver("Opening DatabasePool '%s'. Asynchronous connections: %u, synchronous connections: %u.",
|
||||
GetDatabaseName(), async_threads, synch_threads);
|
||||
GetDatabaseName(), _async_threads, _synch_threads);
|
||||
|
||||
//! Open asynchronous connections (delayed operations)
|
||||
_connections[IDX_ASYNC].resize(async_threads);
|
||||
for (uint8 i = 0; i < async_threads; ++i)
|
||||
uint32 error = OpenConnections(IDX_ASYNC, _async_threads);
|
||||
|
||||
if (error)
|
||||
{
|
||||
T* t = new T(_queue, _connectionInfo);
|
||||
res &= t->Open();
|
||||
if (res) // only check mysql version if connection is valid
|
||||
WPFatal(mysql_get_server_version(t->GetHandle()) >= MIN_MYSQL_SERVER_VERSION, "AzerothCore does not support MySQL versions below 5.7");
|
||||
|
||||
_connections[IDX_ASYNC][i] = t;
|
||||
++_connectionCount[IDX_ASYNC];
|
||||
return error;
|
||||
}
|
||||
|
||||
//! Open synchronous connections (direct, blocking operations)
|
||||
_connections[IDX_SYNCH].resize(synch_threads);
|
||||
for (uint8 i = 0; i < synch_threads; ++i)
|
||||
error = OpenConnections(IDX_SYNCH, _synch_threads);
|
||||
|
||||
if (!error)
|
||||
{
|
||||
T* t = new T(_connectionInfo);
|
||||
res &= t->Open();
|
||||
_connections[IDX_SYNCH][i] = t;
|
||||
++_connectionCount[IDX_SYNCH];
|
||||
sLog->outSQLDriver("DatabasePool '%s' opened successfully. %u total connections running.",
|
||||
GetDatabaseName(), (_connectionCount[IDX_SYNCH] + _connectionCount[IDX_ASYNC]));
|
||||
}
|
||||
|
||||
if (res)
|
||||
sLog->outSQLDriver("DatabasePool '%s' opened successfully. %u total connections running.", GetDatabaseName(),
|
||||
(_connectionCount[IDX_SYNCH] + _connectionCount[IDX_ASYNC]));
|
||||
else
|
||||
sLog->outError("DatabasePool %s NOT opened. There were errors opening the MySQL connections. Check your SQLDriverLogFile "
|
||||
"for specific errors.", GetDatabaseName());
|
||||
|
||||
return res;
|
||||
return error;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@@ -99,6 +95,91 @@ void DatabaseWorkerPool<T>::Close()
|
||||
sLog->outSQLDriver("All connections on DatabasePool '%s' closed.", GetDatabaseName());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
uint32 DatabaseWorkerPool<T>::OpenConnections(InternalIndex type, uint8 numConnections)
|
||||
{
|
||||
_connections[type].resize(numConnections);
|
||||
for (uint8 i = 0; i < numConnections; ++i)
|
||||
{
|
||||
T* t;
|
||||
|
||||
if (type == IDX_ASYNC)
|
||||
{
|
||||
t = new T(_queue, *_connectionInfo);
|
||||
}
|
||||
else if (type == IDX_SYNCH)
|
||||
{
|
||||
t = new T(*_connectionInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(false, "> Incorrect InternalIndex (%u)", static_cast<uint32>(type));
|
||||
}
|
||||
|
||||
_connections[type][i] = t;
|
||||
++_connectionCount[type];
|
||||
|
||||
uint32 error = t->Open();
|
||||
|
||||
if (!error)
|
||||
{
|
||||
if (mysql_get_server_version(t->GetHandle()) < MIN_MYSQL_SERVER_VERSION)
|
||||
{
|
||||
sLog->outSQLDriver("Not support MySQL versions below 5.7");
|
||||
error = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Failed to open a connection or invalid version, abort and cleanup
|
||||
if (error)
|
||||
{
|
||||
while (_connectionCount[type] != 0)
|
||||
{
|
||||
T* t = _connections[type][i--];
|
||||
delete t;
|
||||
--_connectionCount[type];
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
// Everything is fine
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool DatabaseWorkerPool<T>::PrepareStatements()
|
||||
{
|
||||
for (uint8 i = 0; i < IDX_SIZE; ++i)
|
||||
{
|
||||
for (uint32 c = 0; c < _connectionCount[i]; ++c)
|
||||
{
|
||||
T* t = _connections[i][c];
|
||||
t->LockIfReady();
|
||||
|
||||
if (!t->PrepareStatements())
|
||||
{
|
||||
t->Unlock();
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
t->Unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
char const* DatabaseWorkerPool<T>::GetDatabaseName() const
|
||||
{
|
||||
return _connectionInfo->database.c_str();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void DatabaseWorkerPool<T>::Execute(const char* sql)
|
||||
{
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
#ifndef _DATABASEWORKERPOOL_H
|
||||
#define _DATABASEWORKERPOOL_H
|
||||
|
||||
#include <ace/Thread_Mutex.h>
|
||||
|
||||
#include "Common.h"
|
||||
#include "Callback.h"
|
||||
#include "MySQLConnection.h"
|
||||
@@ -20,6 +18,7 @@
|
||||
#include "QueryHolder.h"
|
||||
#include "AdhocStatement.h"
|
||||
#include "StringFormat.h"
|
||||
#include <ace/Thread_Mutex.h>
|
||||
|
||||
class PingOperation : public SQLOperation
|
||||
{
|
||||
@@ -37,13 +36,20 @@ class DatabaseWorkerPool
|
||||
public:
|
||||
/* Activity state */
|
||||
DatabaseWorkerPool();
|
||||
|
||||
~DatabaseWorkerPool() = default;
|
||||
|
||||
bool Open(const std::string& infoString, uint8 async_threads, uint8 synch_threads);
|
||||
|
||||
void SetConnectionInfo(std::string const& infoString, uint8 const asyncThreads, uint8 const synchThreads);
|
||||
uint32 Open();
|
||||
void Close();
|
||||
|
||||
//! Prepares all prepared statements
|
||||
bool PrepareStatements();
|
||||
|
||||
inline MySQLConnectionInfo const* GetConnectionInfo() const
|
||||
{
|
||||
return _connectionInfo.get();
|
||||
}
|
||||
|
||||
/**
|
||||
Delayed one-way statement methods.
|
||||
*/
|
||||
@@ -199,11 +205,6 @@ public:
|
||||
//! Keeps all our MySQL connections alive, prevent the server from disconnecting us.
|
||||
void KeepAlive();
|
||||
|
||||
[[nodiscard]] char const* GetDatabaseName() const
|
||||
{
|
||||
return _connectionInfo.database.c_str();
|
||||
}
|
||||
|
||||
void EscapeString(std::string& str)
|
||||
{
|
||||
if (str.empty())
|
||||
@@ -216,28 +217,33 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void Enqueue(SQLOperation* op)
|
||||
{
|
||||
_queue->enqueue(op);
|
||||
}
|
||||
|
||||
//! Gets a free connection in the synchronous connection pool.
|
||||
//! Caller MUST call t->Unlock() after touching the MySQL context to prevent deadlocks.
|
||||
T* GetFreeConnection();
|
||||
|
||||
private:
|
||||
enum _internalIndex
|
||||
enum InternalIndex
|
||||
{
|
||||
IDX_ASYNC,
|
||||
IDX_SYNCH,
|
||||
IDX_SIZE
|
||||
};
|
||||
|
||||
ACE_Message_Queue<ACE_SYNCH>* _mqueue;
|
||||
ACE_Activation_Queue* _queue; //! Queue shared by async worker threads.
|
||||
std::vector<std::vector<T*>> _connections;
|
||||
uint32 _connectionCount[2]; //! Counter of MySQL connections;
|
||||
MySQLConnectionInfo _connectionInfo;
|
||||
uint32 OpenConnections(InternalIndex type, uint8 numConnections);
|
||||
|
||||
void Enqueue(SQLOperation* op)
|
||||
{
|
||||
_queue->enqueue(op);
|
||||
}
|
||||
|
||||
[[nodiscard]] char const* GetDatabaseName() const;
|
||||
|
||||
//! Gets a free connection in the synchronous connection pool.
|
||||
//! Caller MUST call t->Unlock() after touching the MySQL context to prevent deadlocks.
|
||||
T* GetFreeConnection();
|
||||
|
||||
ACE_Message_Queue<ACE_SYNCH>* _mqueue;
|
||||
ACE_Activation_Queue* _queue; //! Queue shared by async worker threads.
|
||||
std::vector<std::vector<T*>> _connections;
|
||||
uint32 _connectionCount[IDX_SIZE]; //! Counter of MySQL connections;
|
||||
std::unique_ptr<MySQLConnectionInfo> _connectionInfo;
|
||||
std::vector<uint8> _preparedStatementSize;
|
||||
uint8 _async_threads, _synch_threads;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -47,12 +47,14 @@ MySQLConnection::MySQLConnection(ACE_Activation_Queue* queue, MySQLConnectionInf
|
||||
|
||||
MySQLConnection::~MySQLConnection()
|
||||
{
|
||||
ASSERT (m_Mysql); /// MySQL context must be present at this point
|
||||
for (auto stmt : m_stmts)
|
||||
delete stmt;
|
||||
|
||||
for (size_t i = 0; i < m_stmts.size(); ++i)
|
||||
delete m_stmts[i];
|
||||
|
||||
mysql_close(m_Mysql);
|
||||
if (m_Mysql)
|
||||
{
|
||||
mysql_close(m_Mysql);
|
||||
m_Mysql = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void MySQLConnection::Close()
|
||||
@@ -61,10 +63,9 @@ void MySQLConnection::Close()
|
||||
delete this;
|
||||
}
|
||||
|
||||
bool MySQLConnection::Open()
|
||||
uint32 MySQLConnection::Open()
|
||||
{
|
||||
MYSQL* mysqlInit;
|
||||
mysqlInit = mysql_init(nullptr);
|
||||
MYSQL* mysqlInit = mysql_init(nullptr);
|
||||
if (!mysqlInit)
|
||||
{
|
||||
sLog->outError("Could not initialize Mysql connection to database `%s`", m_connectionInfo.database.c_str());
|
||||
@@ -106,59 +107,44 @@ bool MySQLConnection::Open()
|
||||
}
|
||||
#endif
|
||||
|
||||
// Possible improvement for future: make ATTEMPTS and SECONDS configurable values
|
||||
uint32 const ATTEMPTS = 180;
|
||||
m_Mysql = mysql_real_connect(
|
||||
mysqlInit,
|
||||
m_connectionInfo.host.c_str(),
|
||||
m_connectionInfo.user.c_str(),
|
||||
m_connectionInfo.password.c_str(),
|
||||
m_connectionInfo.database.c_str(),
|
||||
port,
|
||||
unix_socket,
|
||||
0);
|
||||
|
||||
uint32 count = 0;
|
||||
do
|
||||
if (m_Mysql)
|
||||
{
|
||||
m_Mysql = mysql_real_connect(
|
||||
mysqlInit,
|
||||
m_connectionInfo.host.c_str(),
|
||||
m_connectionInfo.user.c_str(),
|
||||
m_connectionInfo.password.c_str(),
|
||||
m_connectionInfo.database.c_str(),
|
||||
port,
|
||||
unix_socket,
|
||||
0);
|
||||
|
||||
if (m_Mysql)
|
||||
if (!m_reconnecting)
|
||||
{
|
||||
if (!m_reconnecting)
|
||||
sLog->outSQLDriver("MySQL client library: %s", mysql_get_client_info());
|
||||
sLog->outSQLDriver("MySQL server ver: %s ", mysql_get_server_info(m_Mysql));
|
||||
|
||||
if (mysql_get_server_version(m_Mysql) != mysql_get_client_version())
|
||||
{
|
||||
sLog->outSQLDriver("MySQL client library: %s", mysql_get_client_info());
|
||||
sLog->outSQLDriver("MySQL server ver: %s ", mysql_get_server_info(m_Mysql));
|
||||
// MySQL version above 5.1 IS required in both client and server and there is no known issue with different versions above 5.1
|
||||
// if (mysql_get_server_version(m_Mysql) != mysql_get_client_version())
|
||||
// sLog->outInfo(LOG_FILTER_SQL, "[WARNING] MySQL client/server version mismatch; may conflict with behaviour of prepared statements.");
|
||||
sLog->outSQLDriver("[WARNING] MySQL client/server version mismatch; may conflict with behaviour of prepared statements.");
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
|
||||
sLog->outDetail("Connected to MySQL database at %s", m_connectionInfo.host.c_str());
|
||||
sLog->outDetail("Connected to MySQL database at %s", m_connectionInfo.host.c_str());
|
||||
#endif
|
||||
mysql_autocommit(m_Mysql, 1);
|
||||
mysql_autocommit(m_Mysql, 1);
|
||||
|
||||
// set connection properties to UTF8 to properly handle locales for different
|
||||
// server configs - core sends data in UTF8, so MySQL must expect UTF8 too
|
||||
mysql_set_character_set(m_Mysql, "utf8");
|
||||
return PrepareStatements();
|
||||
}
|
||||
else
|
||||
{
|
||||
count++;
|
||||
sLog->outError("Could not connect to MySQL database at %s: %s\n", m_connectionInfo.host.c_str(), mysql_error(mysqlInit));
|
||||
sLog->outError("Retrying in 10 seconds...\n\n");
|
||||
std::this_thread::sleep_for(10s);
|
||||
}
|
||||
} while (!m_Mysql && count < ATTEMPTS);
|
||||
// set connection properties to UTF8 to properly handle locales for different
|
||||
// server configs - core sends data in UTF8, so MySQL must expect UTF8 too
|
||||
mysql_set_character_set(m_Mysql, "utf8");
|
||||
return 0;
|
||||
}
|
||||
|
||||
sLog->outError(
|
||||
"Could not connect to MySQL database at %s: %s after %d attempts\n",
|
||||
m_connectionInfo.host.c_str(),
|
||||
mysql_error(mysqlInit),
|
||||
ATTEMPTS);
|
||||
sLog->outError("Could not connect to MySQL database at %s: %s", m_connectionInfo.host.c_str(), mysql_error(mysqlInit));
|
||||
uint32 errorCode = mysql_errno(mysqlInit);
|
||||
mysql_close(mysqlInit);
|
||||
return false;
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
bool MySQLConnection::PrepareStatements()
|
||||
|
||||
@@ -63,8 +63,9 @@ public:
|
||||
MySQLConnection(ACE_Activation_Queue* queue, MySQLConnectionInfo& connInfo); //! Constructor for asynchronous connections.
|
||||
virtual ~MySQLConnection();
|
||||
|
||||
virtual bool Open();
|
||||
virtual uint32 Open();
|
||||
void Close();
|
||||
bool PrepareStatements();
|
||||
|
||||
public:
|
||||
bool Execute(const char* sql);
|
||||
@@ -102,7 +103,6 @@ protected:
|
||||
MySQLPreparedStatement* GetPreparedStatement(uint32 index);
|
||||
void PrepareStatement(uint32 index, const char* sql, ConnectionFlags flags);
|
||||
|
||||
bool PrepareStatements();
|
||||
virtual void DoPrepareStatements() = 0;
|
||||
|
||||
protected:
|
||||
@@ -121,6 +121,9 @@ private:
|
||||
MySQLConnectionInfo& m_connectionInfo; //! Connection info (used for logging)
|
||||
ConnectionFlags m_connectionFlags; //! Connection flags (for preparing relevant statements)
|
||||
ACE_Thread_Mutex m_Mutex;
|
||||
|
||||
MySQLConnection(MySQLConnection const& right) = delete;
|
||||
MySQLConnection& operator=(MySQLConnection const& right) = delete;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,21 +12,22 @@
|
||||
* authentication server
|
||||
*/
|
||||
|
||||
#include <ace/Dev_Poll_Reactor.h>
|
||||
#include <ace/TP_Reactor.h>
|
||||
#include <ace/ACE.h>
|
||||
#include <openssl/opensslv.h>
|
||||
#include <openssl/crypto.h>
|
||||
|
||||
#include "Common.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "Configuration/Config.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "Config.h"
|
||||
#include "Log.h"
|
||||
#include "GitRevision.h"
|
||||
#include "Util.h"
|
||||
#include "SignalHandler.h"
|
||||
#include "RealmList.h"
|
||||
#include "RealmAcceptor.h"
|
||||
#include "DatabaseLoader.h"
|
||||
#include <ace/Dev_Poll_Reactor.h>
|
||||
#include <ace/TP_Reactor.h>
|
||||
#include <ace/ACE.h>
|
||||
#include <ace/Sig_Handler.h>
|
||||
#include <openssl/opensslv.h>
|
||||
#include <openssl/crypto.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sched.h>
|
||||
@@ -43,8 +44,6 @@ void StopDB();
|
||||
|
||||
bool stopEvent = false; // Setting it to true stops the server
|
||||
|
||||
LoginDatabaseWorkerPool LoginDatabase; // Accessor to the authserver database
|
||||
|
||||
/// Print out the usage string for this program on the console.
|
||||
void usage(const char* prog)
|
||||
{
|
||||
@@ -281,33 +280,15 @@ bool StartDB()
|
||||
{
|
||||
MySQL::Library_Init();
|
||||
|
||||
std::string dbstring = sConfigMgr->GetOption<std::string>("LoginDatabaseInfo", "");
|
||||
if (dbstring.empty())
|
||||
{
|
||||
sLog->outError("Database not specified");
|
||||
// Load databases
|
||||
// NOTE: While authserver is singlethreaded you should keep synch_threads == 1.
|
||||
// Increasing it is just silly since only 1 will be used ever.
|
||||
DatabaseLoader loader;
|
||||
loader
|
||||
.AddDatabase(LoginDatabase, "Login");
|
||||
|
||||
if (!loader.Load())
|
||||
return false;
|
||||
}
|
||||
|
||||
int32 worker_threads = sConfigMgr->GetOption<int32>("LoginDatabase.WorkerThreads", 1);
|
||||
if (worker_threads < 1 || worker_threads > 32)
|
||||
{
|
||||
sLog->outError("Improper value specified for LoginDatabase.WorkerThreads, defaulting to 1.");
|
||||
worker_threads = 1;
|
||||
}
|
||||
|
||||
int32 synch_threads = sConfigMgr->GetOption<int32>("LoginDatabase.SynchThreads", 1);
|
||||
if (synch_threads < 1 || synch_threads > 32)
|
||||
{
|
||||
sLog->outError("Improper value specified for LoginDatabase.SynchThreads, defaulting to 1.");
|
||||
synch_threads = 1;
|
||||
}
|
||||
|
||||
// NOTE: While authserver is singlethreaded you should keep synch_threads == 1. Increasing it is just silly since only 1 will be used ever.
|
||||
if (!LoginDatabase.Open(dbstring.c_str(), uint8(worker_threads), uint8(synch_threads)))
|
||||
{
|
||||
sLog->outError("Cannot connect to database");
|
||||
return false;
|
||||
}
|
||||
|
||||
sLog->outString("Started auth database connection pool.");
|
||||
return true;
|
||||
|
||||
@@ -19852,7 +19852,6 @@ bool Player::Satisfy(DungeonProgressionRequirements const* ar, uint32 target_map
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Difficulty target_difficulty = GetDifficulty(mapEntry->IsRaid());
|
||||
MapDifficulty const* mapDiff = GetDownscaledMapDifficultyData(target_map, target_difficulty);
|
||||
if (LevelMin || LevelMax || ilvlRequirementNotMet
|
||||
|
||||
@@ -6342,7 +6342,6 @@ void ObjectMgr::LoadAccessRequirements()
|
||||
currentRequirementsList->push_back(progression_requirement);
|
||||
}
|
||||
|
||||
|
||||
} while (progression_requirements_results->NextRow());
|
||||
}
|
||||
|
||||
@@ -6360,7 +6359,6 @@ void ObjectMgr::LoadAccessRequirements()
|
||||
_accessRequirementStore[mapid][difficulty] = ar;
|
||||
} while (access_template_result->NextRow());
|
||||
|
||||
|
||||
sLog->outString(">> Loaded %u rows from dungeon_access_template and %u rows from dungeon_access_requirements in %u ms", count, countProgressionRequirements, GetMSTimeDiffToNow(oldMSTime));
|
||||
sLog->outString();
|
||||
}
|
||||
|
||||
@@ -53,5 +53,4 @@ inline AI* GetAhnkahetAI(T* obj)
|
||||
return GetInstanceAI<AI>(obj, AhnahetScriptName);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "WorldRunnable.h"
|
||||
#include "WorldSocket.h"
|
||||
#include "WorldSocketMgr.h"
|
||||
#include "DatabaseLoader.h"
|
||||
#include <ace/Sig_Handler.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -388,80 +389,16 @@ bool Master::_StartDB()
|
||||
MySQL::Library_Init();
|
||||
|
||||
sLog->SetLogDB(false);
|
||||
std::string dbstring;
|
||||
uint8 async_threads, synch_threads;
|
||||
|
||||
dbstring = sConfigMgr->GetOption<std::string>("WorldDatabaseInfo", "");
|
||||
if (dbstring.empty())
|
||||
{
|
||||
sLog->outError("World database not specified in configuration file");
|
||||
// Load databases
|
||||
DatabaseLoader loader;
|
||||
loader
|
||||
.AddDatabase(LoginDatabase, "Login")
|
||||
.AddDatabase(CharacterDatabase, "Character")
|
||||
.AddDatabase(WorldDatabase, "World");
|
||||
|
||||
if (!loader.Load())
|
||||
return false;
|
||||
}
|
||||
|
||||
async_threads = uint8(sConfigMgr->GetOption<int32>("WorldDatabase.WorkerThreads", 1));
|
||||
if (async_threads < 1 || async_threads > 32)
|
||||
{
|
||||
sLog->outError("World database: invalid number of worker threads specified. "
|
||||
"Please pick a value between 1 and 32.");
|
||||
return false;
|
||||
}
|
||||
|
||||
synch_threads = uint8(sConfigMgr->GetOption<int32>("WorldDatabase.SynchThreads", 1));
|
||||
///- Initialise the world database
|
||||
if (!WorldDatabase.Open(dbstring, async_threads, synch_threads))
|
||||
{
|
||||
sLog->outError("Cannot connect to world database %s", dbstring.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
///- Get character database info from configuration file
|
||||
dbstring = sConfigMgr->GetOption<std::string>("CharacterDatabaseInfo", "");
|
||||
if (dbstring.empty())
|
||||
{
|
||||
sLog->outError("Character database not specified in configuration file");
|
||||
return false;
|
||||
}
|
||||
|
||||
async_threads = uint8(sConfigMgr->GetOption<int32>("CharacterDatabase.WorkerThreads", 1));
|
||||
if (async_threads < 1 || async_threads > 32)
|
||||
{
|
||||
sLog->outError("Character database: invalid number of worker threads specified. "
|
||||
"Please pick a value between 1 and 32.");
|
||||
return false;
|
||||
}
|
||||
|
||||
synch_threads = uint8(sConfigMgr->GetOption<int32>("CharacterDatabase.SynchThreads", 2));
|
||||
|
||||
///- Initialise the Character database
|
||||
if (!CharacterDatabase.Open(dbstring, async_threads, synch_threads))
|
||||
{
|
||||
sLog->outError("Cannot connect to Character database %s", dbstring.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
///- Get login database info from configuration file
|
||||
dbstring = sConfigMgr->GetOption<std::string>("LoginDatabaseInfo", "");
|
||||
if (dbstring.empty())
|
||||
{
|
||||
sLog->outError("Login database not specified in configuration file");
|
||||
return false;
|
||||
}
|
||||
|
||||
async_threads = uint8(sConfigMgr->GetOption<int32>("LoginDatabase.WorkerThreads", 1));
|
||||
if (async_threads < 1 || async_threads > 32)
|
||||
{
|
||||
sLog->outError("Login database: invalid number of worker threads specified. "
|
||||
"Please pick a value between 1 and 32.");
|
||||
return false;
|
||||
}
|
||||
|
||||
synch_threads = uint8(sConfigMgr->GetOption<int32>("LoginDatabase.SynchThreads", 1));
|
||||
///- Initialise the login database
|
||||
if (!LoginDatabase.Open(dbstring, async_threads, synch_threads))
|
||||
{
|
||||
sLog->outError("Cannot connect to login database %s", dbstring.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
///- Get the realm Id from the configuration file
|
||||
realmID = sConfigMgr->GetOption<int32>("RealmID", 0);
|
||||
|
||||
@@ -120,7 +120,6 @@ bool Model::ConvertToVMAPModel(const char* outfilename)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Vec3D fixCoordSystem(Vec3D const& v)
|
||||
{
|
||||
return Vec3D(v.x, v.z, -v.y);
|
||||
@@ -250,4 +249,3 @@ void Doodad::ExtractSet(WMODoodadData const& doodadData, ADT::MODF const& wmo, u
|
||||
fwrite(ModelInstName, sizeof(char), nlen, pDirfile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -558,5 +558,4 @@ void MapObject::Extract(ADT::MODF const& mapObjDef, char const* WmoInstName, uin
|
||||
fwrite(&nlen, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(WmoInstName, sizeof(char), nlen, pDirfile);
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user