change UDPPacketBuffer pools (does waste a bit of memory)

This commit is contained in:
UbitUmarov
2019-02-25 21:46:23 +00:00
parent 4dd89ce094
commit d01165818d
6 changed files with 157 additions and 324 deletions

View File

@@ -26,6 +26,7 @@
*/
using System;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using System.Threading;
@@ -57,15 +58,9 @@ namespace OpenMetaverse
/// <summary>UDP socket, used in either client or server mode</summary>
private Socket m_udpSocket;
/// <summary>
/// Are we to use object pool(s) to reduce memory churn when receiving data?
/// </summary>
public bool UsePools { get; protected set; }
/// <summary>
/// Pool to use for handling data. May be null if UsePools = false;
/// </summary>
protected OpenSim.Framework.Pool<UDPPacketBuffer> Pool { get; private set; }
public static Object m_udpBuffersPoolLock = new Object();
public static UDPPacketBuffer[] m_udpBuffersPool = new UDPPacketBuffer[1000];
public static int m_udpBuffersPoolPtr = -1;
/// <summary>Returns true if the server is currently listening for inbound packets, otherwise false</summary>
public bool IsRunningInbound { get; private set; }
@@ -186,6 +181,52 @@ namespace OpenMetaverse
if(m_udpSocket !=null)
try { m_udpSocket.Close(); } catch { }
}
public UDPPacketBuffer GetNewUDPBuffer()
{
lock (m_udpBuffersPoolLock)
{
if (m_udpBuffersPoolPtr >= 0)
{
UDPPacketBuffer buf = m_udpBuffersPool[m_udpBuffersPoolPtr];
m_udpBuffersPool[m_udpBuffersPoolPtr] = null;
m_udpBuffersPoolPtr--;
buf.RemoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
return buf;
}
}
return new UDPPacketBuffer(new IPEndPoint(IPAddress.Any, 0));
}
public UDPPacketBuffer GetNewUDPBuffer(IPEndPoint remoteEndpoint)
{
lock (m_udpBuffersPoolLock)
{
if (m_udpBuffersPoolPtr >= 0)
{
UDPPacketBuffer buf = m_udpBuffersPool[m_udpBuffersPoolPtr];
m_udpBuffersPool[m_udpBuffersPoolPtr] = null;
m_udpBuffersPoolPtr--;
buf.RemoteEndPoint = remoteEndpoint;
return buf;
}
}
return new UDPPacketBuffer(remoteEndpoint);
}
public void FreeUDPBuffer(UDPPacketBuffer buf)
{
lock (m_udpBuffersPoolLock)
{
if (m_udpBuffersPoolPtr < 999)
{
buf.RemoteEndPoint = null;
m_udpBuffersPoolPtr++;
m_udpBuffersPool[m_udpBuffersPoolPtr] = buf;
}
}
}
/// <summary>
/// Start inbound UDP packet handling.
/// </summary>
@@ -202,6 +243,7 @@ namespace OpenMetaverse
/// manner (not throwing an exception when the remote side resets the
/// connection). This call is ignored on Mono where the flag is not
/// necessary</remarks>
public virtual void StartInbound(int recvBufferSize)
{
if (!IsRunningInbound)
@@ -306,101 +348,64 @@ namespace OpenMetaverse
IsRunningOutbound = false;
}
public virtual bool EnablePools()
{
if (!UsePools)
{
Pool = new Pool<UDPPacketBuffer>(() => new UDPPacketBuffer(), 500);
UsePools = true;
return true;
}
return false;
}
public virtual bool DisablePools()
{
if (UsePools)
{
UsePools = false;
// We won't null out the pool to avoid a race condition with code that may be in the middle of using it.
return true;
}
return false;
}
private void AsyncBeginReceive()
{
UDPPacketBuffer buf;
if (!IsRunningInbound)
return;
// FIXME: Disabled for now as this causes issues with reused packet objects interfering with each other
// on Windows with m_asyncPacketHandling = true, though this has not been seen on Linux.
// Possibly some unexpected issue with fetching UDP data concurrently with multiple threads. Requires more investigation.
// if (UsePools)
// buf = Pool.GetObject();
// else
buf = new UDPPacketBuffer();
if (IsRunningInbound)
UDPPacketBuffer buf = GetNewUDPBuffer();
try
{
try
// kick off an async read
m_udpSocket.BeginReceiveFrom(
//wrappedBuffer.Instance.Data,
buf.Data,
0,
UDPPacketBuffer.BUFFER_SIZE,
SocketFlags.None,
ref buf.RemoteEndPoint,
AsyncEndReceive,
//wrappedBuffer);
buf);
}
catch (SocketException e)
{
if (e.SocketErrorCode == SocketError.ConnectionReset)
{
// kick off an async read
m_udpSocket.BeginReceiveFrom(
//wrappedBuffer.Instance.Data,
buf.Data,
0,
UDPPacketBuffer.BUFFER_SIZE,
SocketFlags.None,
ref buf.RemoteEndPoint,
AsyncEndReceive,
//wrappedBuffer);
buf);
}
catch (SocketException e)
{
if (e.SocketErrorCode == SocketError.ConnectionReset)
m_log.Warn("[UDPBASE]: SIO_UDP_CONNRESET was ignored, attempting to salvage the UDP listener on port " + m_udpPort);
bool salvaged = false;
while (!salvaged)
{
m_log.Warn("[UDPBASE]: SIO_UDP_CONNRESET was ignored, attempting to salvage the UDP listener on port " + m_udpPort);
bool salvaged = false;
while (!salvaged)
try
{
try
{
m_udpSocket.BeginReceiveFrom(
//wrappedBuffer.Instance.Data,
buf.Data,
0,
UDPPacketBuffer.BUFFER_SIZE,
SocketFlags.None,
ref buf.RemoteEndPoint,
AsyncEndReceive,
//wrappedBuffer);
buf);
salvaged = true;
}
catch (SocketException) { }
catch (ObjectDisposedException) { return; }
m_udpSocket.BeginReceiveFrom(
//wrappedBuffer.Instance.Data,
buf.Data,
0,
UDPPacketBuffer.BUFFER_SIZE,
SocketFlags.None,
ref buf.RemoteEndPoint,
AsyncEndReceive,
//wrappedBuffer);
buf);
salvaged = true;
}
m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort);
catch (SocketException) { }
catch (ObjectDisposedException) { return; }
}
m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort);
}
catch (ObjectDisposedException e)
{
m_log.Error(
string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e);
}
catch (Exception e)
{
m_log.Error(
string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e);
}
}
catch (ObjectDisposedException e)
{
m_log.Error(
string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e);
}
catch (Exception e)
{
m_log.Error(
string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e);
}
}
@@ -465,14 +470,12 @@ namespace OpenMetaverse
}
finally
{
// if (UsePools)
// Pool.ReturnObject(buffer);
AsyncBeginReceive();
}
}
}
/* not in use
public void AsyncBeginSend(UDPPacketBuffer buf)
{
// if (IsRunningOutbound)
@@ -511,7 +514,7 @@ namespace OpenMetaverse
catch (SocketException) { }
catch (ObjectDisposedException) { }
}
*/
public void SyncSend(UDPPacketBuffer buf)
{
try