parallel delta queue processing

thread safe packet construction, compilation, compression, gump compilation, sending, coalescing, and many other fixes
TODO:  delta queue recursion fixups, ipooledenumerable fixups/generics
This commit is contained in:
Mark Sturgill 2013-10-11 00:01:05 -07:00
parent 9404651774
commit ddcc4e7a20
16 changed files with 619 additions and 575 deletions

View file

@ -19,12 +19,14 @@
***************************************************************************/
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
#if Framework_4_0
using System.Threading.Tasks;
#endif
using Server;
using Server.Accounting;
using Server.Network;
@ -588,14 +590,15 @@ namespace Server.Network {
}
}
private bool _sending;
private object _sendL = new object();
public virtual void Send( Packet p ) {
if ( m_Socket == null || m_BlockAllPackets ) {
p.OnSend();
return;
}
PacketSendProfile prof = PacketSendProfile.Acquire( p.GetType() );
int length;
byte[] buffer = p.Compile( m_CompressionEnabled, out length );
@ -605,6 +608,10 @@ namespace Server.Network {
return;
}
PacketSendProfile prof = null;
if (Core.Profiling) prof = PacketSendProfile.Acquire(p.GetType());
if ( prof != null ) {
prof.Start();
}
@ -616,22 +623,27 @@ namespace Server.Network {
try {
SendQueue.Gram gram;
lock ( m_SendQueue ) {
gram = m_SendQueue.Enqueue( buffer, length );
}
lock (_sendL) {
lock (m_SendQueue)
gram = m_SendQueue.Enqueue(buffer, length);
if ( gram != null ) {
if (gram != null) {
#if NewAsyncSockets
m_SendEventArgs.SetBuffer( gram.Buffer, 0, gram.Length );
Send_Start();
m_SendEventArgs.SetBuffer( gram.Buffer, 0, gram.Length );
Send_Start();
#else
try {
m_Socket.BeginSend( gram.Buffer, 0, gram.Length, SocketFlags.None, m_OnSend, m_Socket );
} catch ( Exception ex ) {
TraceException( ex );
Dispose( false );
}
try {
if (!_sending) {
_sending = true;
m_Socket.BeginSend(gram.Buffer, 0, gram.Length, SocketFlags.None, m_OnSend, m_Socket);
}
}
catch (Exception ex) {
TraceException(ex);
Dispose(false);
}
#endif
}
}
} catch ( CapacityExceededException ) {
Console.WriteLine( "Client: {0}: Too much data pending, disconnecting...", this );
@ -814,13 +826,15 @@ namespace Server.Network {
}
public bool Flush() {
if ( m_Socket == null || !m_SendQueue.IsFlushReady ) {
return false;
}
if ( m_Socket == null )
return false;
SendQueue.Gram gram;
lock ( m_SendQueue ) {
if (!m_SendQueue.IsFlushReady)
return false;
gram = m_SendQueue.CheckFlushReady();
}
@ -914,23 +928,26 @@ namespace Server.Network {
m_NextCheckActivity = Core.TickCount + 90000;
if ( m_CoalesceSleep >= 0 ) {
Thread.Sleep( m_CoalesceSleep );
if (m_CoalesceSleep >= 0) {
Thread.Sleep(m_CoalesceSleep);
}
SendQueue.Gram gram;
lock ( m_SendQueue ) {
lock (m_SendQueue) {
gram = m_SendQueue.Dequeue();
}
if ( gram != null ) {
if (gram != null) {
try {
s.BeginSend( gram.Buffer, 0, gram.Length, SocketFlags.None, m_OnSend, s );
} catch ( Exception ex ) {
TraceException( ex );
Dispose( false );
s.BeginSend(gram.Buffer, 0, gram.Length, SocketFlags.None, m_OnSend, s);
} catch (Exception ex) {
TraceException(ex);
Dispose(false);
}
} else {
lock (_sendL)
_sending = false;
}
} catch ( Exception ){
Dispose( false );
@ -974,23 +991,31 @@ namespace Server.Network {
}
public bool Flush() {
if ( m_Socket == null || !m_SendQueue.IsFlushReady ) {
if (m_Socket == null)
return false;
}
SendQueue.Gram gram;
lock (_sendL) {
if (_sending)
return false;
lock ( m_SendQueue ) {
gram = m_SendQueue.CheckFlushReady();
}
SendQueue.Gram gram;
if ( gram != null ) {
try {
m_Socket.BeginSend( gram.Buffer, 0, gram.Length, SocketFlags.None, m_OnSend, m_Socket );
return true;
} catch ( Exception ex ) {
TraceException( ex );
Dispose( false );
lock (m_SendQueue) {
if (!m_SendQueue.IsFlushReady)
return false;
gram = m_SendQueue.CheckFlushReady();
}
if (gram != null) {
try {
_sending = true;
m_Socket.BeginSend(gram.Buffer, 0, gram.Length, SocketFlags.None, m_OnSend, m_Socket);
return true;
} catch (Exception ex) {
TraceException(ex);
Dispose(false);
}
}
}
@ -1007,11 +1032,13 @@ namespace Server.Network {
}
public static void FlushAll() {
#if Framework_4_0
Parallel.ForEach( m_Instances, ns => ns.Flush() );
#else
for ( int i = 0; i < m_Instances.Count; ++i ) {
NetState ns = m_Instances[i];
ns.Flush();
m_Instances[i].Flush();
}
#endif
}
private static int m_CoalesceSleep = -1;
@ -1109,10 +1136,11 @@ namespace Server.Network {
m_Running = false;
m_Disposed.Enqueue( this );
lock (m_Disposed)
m_Disposed.Enqueue( this );
if ( /*!flush &&*/ !m_SendQueue.IsEmpty ) {
lock ( m_SendQueue )
lock (m_SendQueue)
if ( /*!flush &&*/ !m_SendQueue.IsEmpty ) {
m_SendQueue.Clear();
}
}
@ -1131,37 +1159,38 @@ namespace Server.Network {
}
}
private static Queue m_Disposed = Queue.Synchronized( new Queue() );
private static Queue<NetState> m_Disposed = new Queue<NetState>();
public static void ProcessDisposedQueue() {
int breakout = 0;
lock (m_Disposed) {
int breakout = 0;
while ( breakout < 200 && m_Disposed.Count > 0 ) {
++breakout;
while ( breakout < 200 && m_Disposed.Count > 0 ) {
++breakout;
NetState ns = m_Disposed.Dequeue();
NetState ns = ( NetState ) m_Disposed.Dequeue();
Mobile m = ns.m_Mobile;
IAccount a = ns.m_Account;
Mobile m = ns.m_Mobile;
IAccount a = ns.m_Account;
if ( m != null ) {
m.NetState = null;
ns.m_Mobile = null;
}
if ( m != null ) {
m.NetState = null;
ns.m_Mobile = null;
}
ns.m_Gumps.Clear();
ns.m_Menus.Clear();
ns.m_HuePickers.Clear();
ns.m_Account = null;
ns.m_ServerInfo = null;
ns.m_CityInfo = null;
ns.m_Gumps.Clear();
ns.m_Menus.Clear();
ns.m_HuePickers.Clear();
ns.m_Account = null;
ns.m_ServerInfo = null;
ns.m_CityInfo = null;
m_Instances.Remove( ns );
m_Instances.Remove( ns );
if ( a != null ) {
ns.WriteConsole( "Disconnected. [{0} Online] [{1}]", m_Instances.Count, a );
} else {
ns.WriteConsole( "Disconnected. [{0} Online]", m_Instances.Count );
if ( a != null ) {
ns.WriteConsole( "Disconnected. [{0} Online] [{1}]", m_Instances.Count, a );
} else {
ns.WriteConsole( "Disconnected. [{0} Online]", m_Instances.Count );
}
}
}
}