Use several sender threads with load balancing for sending the avatars. Remember last failed send operation (not yet a list, just the last) and cancel any more low prio sends to that sender.
This commit is contained in:
@@ -21,6 +21,7 @@
|
|||||||
#include <net/sendercallback.h>
|
#include <net/sendercallback.h>
|
||||||
#include <net/socket_msg.h>
|
#include <net/socket_msg.h>
|
||||||
#include <net/socket_helper.h>
|
#include <net/socket_helper.h>
|
||||||
|
#include <core/loghelper.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
@@ -29,8 +30,7 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#define SEND_ERROR_NORMAL_TIMEOUT_MSEC 20000
|
#define SEND_ERROR_TIMEOUT_MSEC 20000
|
||||||
#define SEND_ERROR_LOW_PRIO_TIMEOUT_MSEC 10000
|
|
||||||
#define SEND_TIMEOUT_MSEC 10
|
#define SEND_TIMEOUT_MSEC 10
|
||||||
#ifdef POKERTH_DEDICATED_SERVER
|
#ifdef POKERTH_DEDICATED_SERVER
|
||||||
#define SEND_QUEUE_SIZE 10000
|
#define SEND_QUEUE_SIZE 10000
|
||||||
@@ -41,7 +41,7 @@ using namespace std;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
SenderThread::SenderThread(SenderCallback &cb)
|
SenderThread::SenderThread(SenderCallback &cb)
|
||||||
: m_tmpOutBufSize(0), m_tmpIsLowPrio(false), m_callback(cb)
|
: m_tmpOutBufSize(0), m_lastInvalidSessionId(INVALID_SESSION), m_callback(cb)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,6 +89,27 @@ SenderThread::SendLowPrio(boost::shared_ptr<SessionData> session, const NetPacke
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
SenderThread::GetNumPacketsInQueue() const
|
||||||
|
{
|
||||||
|
unsigned numPackets;
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(m_lowPrioOutBufMutex);
|
||||||
|
numPackets = m_lowPrioOutBuf.size();
|
||||||
|
}
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(m_outBufMutex);
|
||||||
|
numPackets += m_outBuf.size();
|
||||||
|
}
|
||||||
|
return numPackets;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
SenderThread::operator<(const SenderThread &other) const
|
||||||
|
{
|
||||||
|
return GetNumPacketsInQueue() < other.GetNumPacketsInQueue();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SenderThread::InternalStore(SendDataDeque &sendQueue, unsigned maxQueueSize, boost::shared_ptr<SessionData> session, boost::shared_ptr<NetPacket> packet)
|
SenderThread::InternalStore(SendDataDeque &sendQueue, unsigned maxQueueSize, boost::shared_ptr<SessionData> session, boost::shared_ptr<NetPacket> packet)
|
||||||
{
|
{
|
||||||
@@ -133,6 +154,7 @@ SenderThread::Main()
|
|||||||
// For reasons of simplicity, only one packet is sent at a time.
|
// For reasons of simplicity, only one packet is sent at a time.
|
||||||
if (!m_tmpOutBufSize)
|
if (!m_tmpOutBufSize)
|
||||||
{
|
{
|
||||||
|
bool isLowPrio = false;
|
||||||
SendData tmpData;
|
SendData tmpData;
|
||||||
// Check main queue first.
|
// Check main queue first.
|
||||||
{
|
{
|
||||||
@@ -141,7 +163,6 @@ SenderThread::Main()
|
|||||||
{
|
{
|
||||||
tmpData = m_outBuf.front();
|
tmpData = m_outBuf.front();
|
||||||
m_outBuf.pop_front();
|
m_outBuf.pop_front();
|
||||||
m_tmpIsLowPrio = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,13 +174,13 @@ SenderThread::Main()
|
|||||||
{
|
{
|
||||||
tmpData = m_lowPrioOutBuf.front();
|
tmpData = m_lowPrioOutBuf.front();
|
||||||
m_lowPrioOutBuf.pop_front();
|
m_lowPrioOutBuf.pop_front();
|
||||||
m_tmpIsLowPrio = true;
|
isLowPrio = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tmpData.first.get())
|
if (tmpData.first.get() && tmpData.second.get())
|
||||||
{
|
{
|
||||||
if (tmpData.second.get())
|
if (!isLowPrio || tmpData.second->GetId() != m_lastInvalidSessionId)
|
||||||
{
|
{
|
||||||
u_int16_t tmpLen = tmpData.first->GetLen();
|
u_int16_t tmpLen = tmpData.first->GetLen();
|
||||||
if (tmpLen <= MAX_PACKET_SIZE)
|
if (tmpLen <= MAX_PACKET_SIZE)
|
||||||
@@ -243,21 +264,13 @@ SenderThread::Main()
|
|||||||
// Check whether the send timed out.
|
// Check whether the send timed out.
|
||||||
if (sendTimer.is_running())
|
if (sendTimer.is_running())
|
||||||
{
|
{
|
||||||
bool doRemove = false;
|
if (sendTimer.elapsed().total_milliseconds() > SEND_ERROR_TIMEOUT_MSEC)
|
||||||
|
|
||||||
unsigned msec = static_cast<unsigned>(sendTimer.elapsed().total_milliseconds());
|
|
||||||
if (m_tmpIsLowPrio)
|
|
||||||
{
|
|
||||||
if (msec > SEND_ERROR_LOW_PRIO_TIMEOUT_MSEC)
|
|
||||||
doRemove = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (msec > SEND_ERROR_NORMAL_TIMEOUT_MSEC)
|
|
||||||
doRemove = true;
|
|
||||||
}
|
|
||||||
if (doRemove)
|
|
||||||
{
|
{
|
||||||
|
if (m_curSession.get())
|
||||||
|
{
|
||||||
|
m_lastInvalidSessionId = m_curSession->GetId();
|
||||||
|
LOG_MSG("Send operation for session " << m_lastInvalidSessionId << " timed out.");
|
||||||
|
}
|
||||||
RemoveCurSendData();
|
RemoveCurSendData();
|
||||||
sendTimer.reset();
|
sendTimer.reset();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,14 +29,18 @@
|
|||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <algorithm>
|
||||||
#include <boost/lambda/lambda.hpp>
|
#include <boost/lambda/lambda.hpp>
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
|
||||||
#define SERVER_MAX_NUM_SESSIONS 512 // Maximum number of idle users in lobby.
|
#define SERVER_MAX_NUM_SESSIONS 512 // Maximum number of idle users in lobby.
|
||||||
#define SERVER_CACHE_CLEANUP_INTERVAL_SEC 86400 // 1 day
|
#define SERVER_CACHE_CLEANUP_INTERVAL_SEC 86400 // 1 day
|
||||||
#define SERVER_SAVE_STATISTICS_INTERVAL_SEC 60
|
#define SERVER_SAVE_STATISTICS_INTERVAL_SEC 60
|
||||||
#define SERVER_INIT_SESSION_TIMEOUT_SEC 20
|
#define SERVER_INIT_SESSION_TIMEOUT_SEC 20
|
||||||
|
|
||||||
|
#define SERVER_NUM_AVATAR_SENDER_THREADS 5
|
||||||
|
|
||||||
#define SERVER_COMPUTER_PLAYER_NAME "Computer"
|
#define SERVER_COMPUTER_PLAYER_NAME "Computer"
|
||||||
|
|
||||||
#define SERVER_STATISTICS_FILE_NAME "server_statistics.log"
|
#define SERVER_STATISTICS_FILE_NAME "server_statistics.log"
|
||||||
@@ -73,6 +77,8 @@ ServerLobbyThread::ServerLobbyThread(GuiInterface &gui, ConfigFile *playerConfig
|
|||||||
{
|
{
|
||||||
m_senderCallback.reset(new ServerSenderCallback(*this));
|
m_senderCallback.reset(new ServerSenderCallback(*this));
|
||||||
m_sender.reset(new SenderThread(GetSenderCallback()));
|
m_sender.reset(new SenderThread(GetSenderCallback()));
|
||||||
|
for (int i = 0; i < SERVER_NUM_AVATAR_SENDER_THREADS; i++)
|
||||||
|
m_avatarSenderThreadPool.push_back(boost::shared_ptr<SenderThread>(new SenderThread(GetSenderCallback())));
|
||||||
m_receiver.reset(new ReceiverHelper);
|
m_receiver.reset(new ReceiverHelper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,6 +279,7 @@ void
|
|||||||
ServerLobbyThread::Main()
|
ServerLobbyThread::Main()
|
||||||
{
|
{
|
||||||
GetSender().Run();
|
GetSender().Run();
|
||||||
|
for_each(m_avatarSenderThreadPool.begin(), m_avatarSenderThreadPool.end(), boost::mem_fn(&SenderThread::Run));
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -302,8 +309,10 @@ ServerLobbyThread::Main()
|
|||||||
TerminateGames();
|
TerminateGames();
|
||||||
|
|
||||||
GetSender().SignalTermination();
|
GetSender().SignalTermination();
|
||||||
if (!GetSender().Join(SENDER_THREAD_TERMINATE_TIMEOUT))
|
for_each(m_avatarSenderThreadPool.begin(), m_avatarSenderThreadPool.end(), boost::mem_fn(&SenderThread::SignalTermination));
|
||||||
LOG_ERROR("Fatal error: Unable to terminated Sender Thread in Lobby.");
|
|
||||||
|
GetSender().Join(SENDER_THREAD_TERMINATE_TIMEOUT);
|
||||||
|
for_each(m_avatarSenderThreadPool.begin(), m_avatarSenderThreadPool.end(), boost::bind(&SenderThread::Join, _1, SENDER_THREAD_TERMINATE_TIMEOUT));
|
||||||
|
|
||||||
CleanupConnectQueue();
|
CleanupConnectQueue();
|
||||||
}
|
}
|
||||||
@@ -564,7 +573,11 @@ ServerLobbyThread::HandleNetPacketRetrieveAvatar(SessionWrapper session, const N
|
|||||||
if (GetAvatarManager().AvatarFileToNetPackets(tmpFile, request.requestId, tmpPackets) == 0)
|
if (GetAvatarManager().AvatarFileToNetPackets(tmpFile, request.requestId, tmpPackets) == 0)
|
||||||
{
|
{
|
||||||
avatarFound = true;
|
avatarFound = true;
|
||||||
GetSender().SendLowPrio(session.sessionData, tmpPackets);
|
SenderThreadList::iterator pos = min_element(m_avatarSenderThreadPool.begin(), m_avatarSenderThreadPool.end(), *boost::lambda::_1 < *boost::lambda::_2);
|
||||||
|
if (pos != m_avatarSenderThreadPool.end())
|
||||||
|
(*pos)->SendLowPrio(session.sessionData, tmpPackets);
|
||||||
|
else
|
||||||
|
LOG_ERROR("Load balancing for avatar sender threads failed.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LOG_ERROR("Failed to read avatar file for network transmission.");
|
LOG_ERROR("Failed to read avatar file for network transmission.");
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ public:
|
|||||||
void SendLowPrio(boost::shared_ptr<SessionData> session, boost::shared_ptr<NetPacket> packet);
|
void SendLowPrio(boost::shared_ptr<SessionData> session, boost::shared_ptr<NetPacket> packet);
|
||||||
void SendLowPrio(boost::shared_ptr<SessionData> session, const NetPacketList &packetList);
|
void SendLowPrio(boost::shared_ptr<SessionData> session, const NetPacketList &packetList);
|
||||||
|
|
||||||
|
unsigned GetNumPacketsInQueue() const;
|
||||||
|
bool operator<(const SenderThread &other) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
typedef std::pair<boost::shared_ptr<NetPacket>, boost::shared_ptr<SessionData> > SendData;
|
typedef std::pair<boost::shared_ptr<NetPacket>, boost::shared_ptr<SessionData> > SendData;
|
||||||
typedef std::deque<SendData> SendDataDeque;
|
typedef std::deque<SendData> SendDataDeque;
|
||||||
@@ -68,6 +71,7 @@ private:
|
|||||||
char m_tmpOutBuf[MAX_PACKET_SIZE];
|
char m_tmpOutBuf[MAX_PACKET_SIZE];
|
||||||
unsigned m_tmpOutBufSize;
|
unsigned m_tmpOutBufSize;
|
||||||
bool m_tmpIsLowPrio;
|
bool m_tmpIsLowPrio;
|
||||||
|
unsigned m_lastInvalidSessionId;
|
||||||
|
|
||||||
SenderCallback &m_callback;
|
SenderCallback &m_callback;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ protected:
|
|||||||
typedef std::map<SessionId, boost::timers::portable::microsec_timer> InitTimerSessionMap;
|
typedef std::map<SessionId, boost::timers::portable::microsec_timer> InitTimerSessionMap;
|
||||||
typedef std::map<unsigned, boost::shared_ptr<ServerGameThread> > GameMap;
|
typedef std::map<unsigned, boost::shared_ptr<ServerGameThread> > GameMap;
|
||||||
typedef std::list<unsigned> RemoveGameList;
|
typedef std::list<unsigned> RemoveGameList;
|
||||||
|
typedef std::list<boost::shared_ptr<SenderThread> > SenderThreadList;
|
||||||
|
|
||||||
// Main function of the thread.
|
// Main function of the thread.
|
||||||
virtual void Main();
|
virtual void Main();
|
||||||
@@ -166,6 +167,7 @@ private:
|
|||||||
|
|
||||||
boost::shared_ptr<ReceiverHelper> m_receiver;
|
boost::shared_ptr<ReceiverHelper> m_receiver;
|
||||||
boost::shared_ptr<SenderThread> m_sender;
|
boost::shared_ptr<SenderThread> m_sender;
|
||||||
|
SenderThreadList m_avatarSenderThreadPool;
|
||||||
boost::shared_ptr<ServerSenderCallback> m_senderCallback;
|
boost::shared_ptr<ServerSenderCallback> m_senderCallback;
|
||||||
GuiInterface &m_gui;
|
GuiInterface &m_gui;
|
||||||
AvatarManager &m_avatarManager;
|
AvatarManager &m_avatarManager;
|
||||||
@@ -186,6 +188,7 @@ private:
|
|||||||
|
|
||||||
boost::timers::portable::microsec_timer m_cacheCleanupTimer;
|
boost::timers::portable::microsec_timer m_cacheCleanupTimer;
|
||||||
boost::timers::portable::microsec_timer m_saveStatisticsTimer;
|
boost::timers::portable::microsec_timer m_saveStatisticsTimer;
|
||||||
|
boost::timers::portable::microsec_timer m_uptimeTimer;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user