mirror of
https://github.com/araxiaonline/TrinityCore.git
synced 2026-06-17 13:39:46 -04:00
f5d6319d4d
- Make the mysql connectionpool shared for async and syncrhonous connections. - Allow configurable amount of connections for the pool - Allow configurable amount of delaythreads Note that delaythreads now only represent in-core threads. Whenever they execute a task they will pick a free connection from the pool instead of using their previously unique assigned connection. The purpose of this design change is better distribution of SQL requests (no bottlenecks paired with idling) among available resources. This also prevents a ¨memory waste¨ of preparing async prepared statements on synchronous connections (that were never called) - and vice versa. Now, connections aren´t explicitly async or synchronous, they serve both purposes. Use at own risk, might cause instabilities. Don´t forget to update your config files and clear your cmake cache. --HG-- branch : trunk
365 lines
11 KiB
C++
Executable File
365 lines
11 KiB
C++
Executable File
/*
|
|
* Copyright (C) 2008-2010 TrinityCore <http://www.trinitycore.org/>
|
|
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2 of the License, or (at your
|
|
* option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/// \addtogroup realmd Realm Daemon
|
|
/// @{
|
|
/// \file
|
|
|
|
#include "Common.h"
|
|
#include "Database/DatabaseEnv.h"
|
|
|
|
#include "Configuration/Config.h"
|
|
#include "Log.h"
|
|
#include "SystemConfig.h"
|
|
#include "Util.h"
|
|
#include "SignalHandler.h"
|
|
#include "RealmList.h"
|
|
#include "RealmAcceptor.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>
|
|
|
|
#ifndef _TRINITY_REALM_CONFIG
|
|
# define _TRINITY_REALM_CONFIG "authserver.conf"
|
|
#endif //_TRINITY_REALM_CONFIG
|
|
|
|
#ifdef _WIN32
|
|
#include "ServiceWin32.h"
|
|
char serviceName[] = "TrinityRealm";
|
|
char serviceLongName[] = "Trinity realm service";
|
|
char serviceDescription[] = "Massive Network Game Object Server";
|
|
/*
|
|
* -1 - not in service mode
|
|
* 0 - stopped
|
|
* 1 - running
|
|
* 2 - paused
|
|
*/
|
|
int m_ServiceStatus = -1;
|
|
#endif
|
|
|
|
bool StartDB();
|
|
|
|
bool stopEvent = false; ///< Setting it to true stops the server
|
|
|
|
LoginDatabaseWorkerPool LoginDatabase; ///< Accessor to the realm server database
|
|
|
|
/// Handle realmd's termination signals
|
|
class RealmdSignalHandler : public Trinity::SignalHandler
|
|
{
|
|
public:
|
|
virtual void HandleSignal(int SigNum)
|
|
{
|
|
switch (SigNum)
|
|
{
|
|
case SIGINT:
|
|
case SIGTERM:
|
|
stopEvent = true;
|
|
break;
|
|
#ifdef _WIN32
|
|
case SIGBREAK:
|
|
if (m_ServiceStatus != 1)
|
|
stopEvent = true;
|
|
break;
|
|
#endif /* _WIN32 */
|
|
}
|
|
}
|
|
};
|
|
|
|
/// Print out the usage string for this program on the console.
|
|
void usage(const char *prog)
|
|
{
|
|
sLog.outString("Usage: \n %s [<options>]\n"
|
|
" -c config_file use config_file as configuration file\n\r"
|
|
#ifdef _WIN32
|
|
" Running as service functions:\n\r"
|
|
" --service run as service\n\r"
|
|
" -s install install service\n\r"
|
|
" -s uninstall uninstall service\n\r"
|
|
#endif
|
|
,prog);
|
|
}
|
|
|
|
/// Launch the realm server
|
|
extern int main(int argc, char **argv)
|
|
{
|
|
sLog.SetLogDB(false);
|
|
///- Command line parsing to get the configuration file name
|
|
char const* cfg_file = _TRINITY_REALM_CONFIG;
|
|
int c=1;
|
|
while(c < argc)
|
|
{
|
|
if (strcmp(argv[c],"-c") == 0)
|
|
{
|
|
if (++c >= argc)
|
|
{
|
|
sLog.outError("Runtime-Error: -c option requires an input argument");
|
|
usage(argv[0]);
|
|
return 1;
|
|
}
|
|
else
|
|
cfg_file = argv[c];
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
////////////
|
|
//Services//
|
|
////////////
|
|
if (strcmp(argv[c],"-s") == 0)
|
|
{
|
|
if (++c >= argc)
|
|
{
|
|
sLog.outError("Runtime-Error: -s option requires an input argument");
|
|
usage(argv[0]);
|
|
return 1;
|
|
}
|
|
if (strcmp(argv[c],"install") == 0)
|
|
{
|
|
if (WinServiceInstall())
|
|
sLog.outString("Installing service");
|
|
return 1;
|
|
}
|
|
else if (strcmp(argv[c],"uninstall") == 0)
|
|
{
|
|
if (WinServiceUninstall())
|
|
sLog.outString("Uninstalling service");
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
sLog.outError("Runtime-Error: unsupported option %s",argv[c]);
|
|
usage(argv[0]);
|
|
return 1;
|
|
}
|
|
}
|
|
if (strcmp(argv[c],"--service") == 0)
|
|
{
|
|
WinServiceRun();
|
|
}
|
|
////
|
|
#endif
|
|
++c;
|
|
}
|
|
|
|
if (!sConfig.SetSource(cfg_file))
|
|
{
|
|
sLog.outError("Invalid or missing configuration file : %s", cfg_file);
|
|
sLog.outError("Verify that the file exists and has \'[authserver]\' written in the top of the file!");
|
|
return 1;
|
|
}
|
|
sLog.Initialize();
|
|
|
|
sLog.outString("%s (realm-daemon)", _FULLVERSION);
|
|
sLog.outString("<Ctrl-C> to stop.\n");
|
|
sLog.outString("Using configuration file %s.", cfg_file);
|
|
|
|
sLog.outDetail("%s (Library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION));
|
|
|
|
#if defined (ACE_HAS_EVENT_POLL) || defined (ACE_HAS_DEV_POLL)
|
|
ACE_Reactor::instance(new ACE_Reactor(new ACE_Dev_Poll_Reactor(ACE::max_handles(), 1), 1), true);
|
|
#else
|
|
ACE_Reactor::instance(new ACE_Reactor(new ACE_TP_Reactor(), true), true);
|
|
#endif
|
|
|
|
sLog.outBasic("Max allowed open files is %d", ACE::max_handles());
|
|
|
|
/// realmd PID file creation
|
|
std::string pidfile = sConfig.GetStringDefault("PidFile", "");
|
|
if (!pidfile.empty())
|
|
{
|
|
uint32 pid = CreatePIDFile(pidfile);
|
|
if (!pid)
|
|
{
|
|
sLog.outError("Cannot create PID file %s.\n", pidfile.c_str());
|
|
return 1;
|
|
}
|
|
|
|
sLog.outString("Daemon PID: %u\n", pid);
|
|
}
|
|
|
|
///- Initialize the database connection
|
|
if (!StartDB())
|
|
return 1;
|
|
|
|
///- Initialize the log database
|
|
sLog.SetLogDBLater(sConfig.GetBoolDefault("EnableLogDB", false)); // set var to enable DB logging once startup finished.
|
|
sLog.SetLogDB(false);
|
|
sLog.SetRealmID(0); // ensure we've set realm to 0 (realmd realmid)
|
|
|
|
///- Get the list of realms for the server
|
|
sRealmList->Initialize(sConfig.GetIntDefault("RealmsStateUpdateDelay", 20));
|
|
if (sRealmList->size() == 0)
|
|
{
|
|
sLog.outError("No valid realms specified.");
|
|
return 1;
|
|
}
|
|
|
|
///- Launch the listening network socket
|
|
RealmAcceptor acceptor;
|
|
|
|
uint16 rmport = sConfig.GetIntDefault("RealmServerPort", 3724);
|
|
std::string bind_ip = sConfig.GetStringDefault("BindIP", "0.0.0.0");
|
|
|
|
ACE_INET_Addr bind_addr(rmport, bind_ip.c_str());
|
|
|
|
if (acceptor.open(bind_addr, ACE_Reactor::instance(), ACE_NONBLOCK) == -1)
|
|
{
|
|
sLog.outError("Trinity realm can not bind to %s:%d", bind_ip.c_str(), rmport);
|
|
return 1;
|
|
}
|
|
|
|
// Initialise the signal handlers
|
|
RealmdSignalHandler SignalINT, SignalTERM;
|
|
#ifdef _WIN32
|
|
RealmdSignalHandler SignalBREAK;
|
|
#endif /* _WIN32 */
|
|
|
|
// Register realmd's signal handlers
|
|
ACE_Sig_Handler Handler;
|
|
Handler.register_handler(SIGINT, &SignalINT);
|
|
Handler.register_handler(SIGTERM, &SignalTERM);
|
|
#ifdef _WIN32
|
|
Handler.register_handler(SIGBREAK, &SignalBREAK);
|
|
#endif /* _WIN32 */
|
|
|
|
///- Handle affinity for multiple processors and process priority on Windows
|
|
#ifdef _WIN32
|
|
{
|
|
HANDLE hProcess = GetCurrentProcess();
|
|
|
|
uint32 Aff = sConfig.GetIntDefault("UseProcessors", 0);
|
|
if (Aff > 0)
|
|
{
|
|
ULONG_PTR appAff;
|
|
ULONG_PTR sysAff;
|
|
|
|
if (GetProcessAffinityMask(hProcess,&appAff,&sysAff))
|
|
{
|
|
ULONG_PTR curAff = Aff & appAff; // remove non accessible processors
|
|
|
|
if (!curAff)
|
|
{
|
|
sLog.outError("Processors marked in UseProcessors bitmask (hex) %x not accessible for realmd. Accessible processors bitmask (hex): %x",Aff,appAff);
|
|
}
|
|
else
|
|
{
|
|
if (SetProcessAffinityMask(hProcess,curAff))
|
|
sLog.outString("Using processors (bitmask, hex): %x", curAff);
|
|
else
|
|
sLog.outError("Can't set used processors (hex): %x", curAff);
|
|
}
|
|
}
|
|
sLog.outString();
|
|
}
|
|
|
|
bool Prio = sConfig.GetBoolDefault("ProcessPriority", false);
|
|
|
|
if (Prio)
|
|
{
|
|
if (SetPriorityClass(hProcess,HIGH_PRIORITY_CLASS))
|
|
sLog.outString("TrinityRealm process priority class set to HIGH");
|
|
else
|
|
sLog.outError("Can't set realmd process priority class.");
|
|
sLog.outString();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// maximum counter for next ping
|
|
uint32 numLoops = (sConfig.GetIntDefault("MaxPingTime", 30) * (MINUTE * 1000000 / 100000));
|
|
uint32 loopCounter = 0;
|
|
|
|
// possibly enable db logging; avoid massive startup spam by doing it here.
|
|
if (sLog.GetLogDBLater())
|
|
{
|
|
sLog.outString("Enabling database logging...");
|
|
sLog.SetLogDBLater(false);
|
|
// login db needs thread for logging
|
|
sLog.SetLogDB(true);
|
|
}
|
|
else
|
|
sLog.SetLogDB(false);
|
|
|
|
///- Wait for termination signal
|
|
while (!stopEvent)
|
|
{
|
|
// dont move this outside the loop, the reactor will modify it
|
|
ACE_Time_Value interval(0, 100000);
|
|
|
|
if (ACE_Reactor::instance()->run_reactor_event_loop(interval) == -1)
|
|
break;
|
|
|
|
if ((++loopCounter) == numLoops)
|
|
{
|
|
loopCounter = 0;
|
|
sLog.outDetail("Ping MySQL to keep connection alive");
|
|
LoginDatabase.KeepAlive();
|
|
}
|
|
#ifdef _WIN32
|
|
if (m_ServiceStatus == 0) stopEvent = true;
|
|
while (m_ServiceStatus == 2) Sleep(1000);
|
|
#endif
|
|
}
|
|
|
|
///- Close the Database Pool
|
|
LoginDatabase.Close();
|
|
|
|
sLog.outString("Halting process...");
|
|
return 0;
|
|
}
|
|
|
|
/// Initialize connection to the database
|
|
bool StartDB()
|
|
{
|
|
std::string dbstring = sConfig.GetStringDefault("LoginDatabaseInfo", "");
|
|
if (dbstring.empty())
|
|
{
|
|
sLog.outError("Database not specified");
|
|
return false;
|
|
}
|
|
|
|
uint8 worker_threads = sConfig.GetIntDefault("LoginDatabase.WorkerThreads", 1);
|
|
if (worker_threads < 1 || worker_threads > 32)
|
|
{
|
|
sLog.outError("Improper value specified for LoginDatabase.WorkerThreads, defaulting to 1.");
|
|
worker_threads = 1;
|
|
}
|
|
|
|
uint8 connections = sConfig.GetIntDefault("LoginDatabase.Connections", 2);
|
|
if (connections < 1 || connections > 32)
|
|
{
|
|
sLog.outError("Improper value specified for LoginDatabase.Connections, defaulting to 2.");
|
|
connections = 2;
|
|
}
|
|
|
|
/// 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(), worker_threads, connections))
|
|
{
|
|
sLog.outError("Cannot connect to database");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// @}
|