aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2012-10-16 23:35:05 +0100
committerJustin Clark-Casey (justincc)2012-10-16 23:35:05 +0100
commitfc861c7904840b2b0b9de0621e9b5d976c8071b1 (patch)
treea0ed86f346171665d95196c33ec952ddd3753883 /OpenSim
parentMake it possible to separate start and stop lludp packet processing from the ... (diff)
downloadopensim-SC-fc861c7904840b2b0b9de0621e9b5d976c8071b1.zip
opensim-SC-fc861c7904840b2b0b9de0621e9b5d976c8071b1.tar.gz
opensim-SC-fc861c7904840b2b0b9de0621e9b5d976c8071b1.tar.bz2
opensim-SC-fc861c7904840b2b0b9de0621e9b5d976c8071b1.tar.xz
Add optional pool for the UDPPacketBuffer objects that handle all incoming UDP data.
Even when an avatar is standing still, it's sending in a constant stream of AgentUpdate packets that the client creates new UDPPacketBuffer objects to handle. This option pools those objects. This reduces memory churn. Currently off by default. Works but the scope can be expanded.
Diffstat (limited to 'OpenSim')
-rw-r--r--OpenSim/Framework/Pool.cs76
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs42
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs31
3 files changed, 125 insertions, 24 deletions
diff --git a/OpenSim/Framework/Pool.cs b/OpenSim/Framework/Pool.cs
new file mode 100644
index 0000000..1ca06c3
--- /dev/null
+++ b/OpenSim/Framework/Pool.cs
@@ -0,0 +1,76 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30
31namespace OpenSim.Framework
32{
33 /// <summary>
34 /// Naive pool implementation.
35 /// </summary>
36 /// <remarks>
37 /// Currently assumes that objects are in a useable state when returned.
38 /// </remarks>
39 public class Pool<T>
40 {
41 private Stack<T> m_pool;
42
43 private int m_maxPoolSize;
44
45 private Func<T> m_createFunction;
46
47 public Pool(Func<T> createFunction, int maxSize)
48 {
49 m_maxPoolSize = maxSize;
50 m_createFunction = createFunction;
51 m_pool = new Stack<T>(m_maxPoolSize);
52 }
53
54 public T GetObject()
55 {
56 lock (m_pool)
57 {
58 if (m_pool.Count > 0)
59 return m_pool.Pop();
60 else
61 return m_createFunction();
62 }
63 }
64
65 public void ReturnObject(T obj)
66 {
67 lock (m_pool)
68 {
69 if (m_pool.Count >= m_maxPoolSize)
70 return;
71 else
72 m_pool.Push(obj);
73 }
74 }
75 }
76} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index fc6dd4d..42247ca 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -188,7 +188,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
188 /// </summary> 188 /// </summary>
189 private IClientAPI m_currentIncomingClient; 189 private IClientAPI m_currentIncomingClient;
190 190
191 public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) 191 public LLUDPServer(
192 IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port,
193 IConfigSource configSource, AgentCircuitManager circuitManager)
192 : base(listenIP, (int)port) 194 : base(listenIP, (int)port)
193 { 195 {
194 #region Environment.TickCount Measurement 196 #region Environment.TickCount Measurement
@@ -242,6 +244,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
242 { 244 {
243 PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean("RecyclePackets", true); 245 PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean("RecyclePackets", true);
244 PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean("RecycleDataBlocks", true); 246 PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean("RecycleDataBlocks", true);
247 UsePools = packetConfig.GetBoolean("RecycleBaseUDPPackets", false);
245 } 248 }
246 249
247 #region BinaryStats 250 #region BinaryStats
@@ -284,8 +287,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
284 private void StartInbound() 287 private void StartInbound()
285 { 288 {
286 m_log.InfoFormat( 289 m_log.InfoFormat(
287 "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode", 290 "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode with UsePools = {1}",
288 m_asyncPacketHandling ? "asynchronous" : "synchronous"); 291 m_asyncPacketHandling ? "asynchronous" : "synchronous", UsePools);
289 292
290 base.StartInbound(m_recvBufferSize, m_asyncPacketHandling); 293 base.StartInbound(m_recvBufferSize, m_asyncPacketHandling);
291 294
@@ -300,7 +303,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
300 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS); 303 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
301 } 304 }
302 305
303 private void StartOutbound() 306 private new void StartOutbound()
304 { 307 {
305 m_log.Info("[LLUDPSERVER]: Starting outbound packet processing for the LLUDP server"); 308 m_log.Info("[LLUDPSERVER]: Starting outbound packet processing for the LLUDP server");
306 309
@@ -317,7 +320,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
317 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS); 320 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
318 } 321 }
319 322
320 public new void Stop() 323 public void Stop()
321 { 324 {
322 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName); 325 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName);
323 base.StopOutbound(); 326 base.StopOutbound();
@@ -806,7 +809,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
806 LLUDPClient udpClient = null; 809 LLUDPClient udpClient = null;
807 Packet packet = null; 810 Packet packet = null;
808 int packetEnd = buffer.DataLength - 1; 811 int packetEnd = buffer.DataLength - 1;
809 IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint; 812 IPEndPoint endPoint = (IPEndPoint)buffer.RemoteEndPoint;
810 813
811 #region Decoding 814 #region Decoding
812 815
@@ -816,7 +819,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
816// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", 819// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}",
817// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); 820// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
818 821
819 return; // Drop undersizd packet 822 return; // Drop undersized packet
820 } 823 }
821 824
822 int headerLen = 7; 825 int headerLen = 7;
@@ -842,6 +845,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
842// packet = Packet.BuildPacket(buffer.Data, ref packetEnd, 845// packet = Packet.BuildPacket(buffer.Data, ref packetEnd,
843// // Only allocate a buffer for zerodecoding if the packet is zerocoded 846// // Only allocate a buffer for zerodecoding if the packet is zerocoded
844// ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); 847// ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
848 // If OpenSimUDPBase.UsePool == true (which is currently separate from the PacketPool) then we
849 // assume that packet construction does not retain a reference to byte[] buffer.Data (instead, all
850 // bytes are copied out).
845 packet = PacketPool.Instance.GetPacket(buffer.Data, ref packetEnd, 851 packet = PacketPool.Instance.GetPacket(buffer.Data, ref packetEnd,
846 // Only allocate a buffer for zerodecoding if the packet is zerocoded 852 // Only allocate a buffer for zerodecoding if the packet is zerocoded
847 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); 853 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
@@ -884,7 +890,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
884 // UseCircuitCode handling 890 // UseCircuitCode handling
885 if (packet.Type == PacketType.UseCircuitCode) 891 if (packet.Type == PacketType.UseCircuitCode)
886 { 892 {
887 object[] array = new object[] { buffer, packet }; 893 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
894 // buffer.
895 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
888 896
889 Util.FireAndForget(HandleUseCircuitCode, array); 897 Util.FireAndForget(HandleUseCircuitCode, array);
890 898
@@ -893,7 +901,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
893 901
894 // Determine which agent this packet came from 902 // Determine which agent this packet came from
895 IClientAPI client; 903 IClientAPI client;
896 if (!m_scene.TryGetClient(address, out client) || !(client is LLClientView)) 904 if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
897 { 905 {
898 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); 906 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
899 return; 907 return;
@@ -1091,21 +1099,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1091 1099
1092 private void HandleUseCircuitCode(object o) 1100 private void HandleUseCircuitCode(object o)
1093 { 1101 {
1094 IPEndPoint remoteEndPoint = null; 1102 IPEndPoint endPoint = null;
1095 IClientAPI client = null; 1103 IClientAPI client = null;
1096 1104
1097 try 1105 try
1098 { 1106 {
1099 // DateTime startTime = DateTime.Now; 1107 // DateTime startTime = DateTime.Now;
1100 object[] array = (object[])o; 1108 object[] array = (object[])o;
1101 UDPPacketBuffer buffer = (UDPPacketBuffer)array[0]; 1109 endPoint = (IPEndPoint)array[0];
1102 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1]; 1110 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1];
1103 1111
1104 m_log.DebugFormat( 1112 m_log.DebugFormat(
1105 "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}", 1113 "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}",
1106 uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, buffer.RemoteEndPoint); 1114 uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, endPoint);
1107
1108 remoteEndPoint = (IPEndPoint)buffer.RemoteEndPoint;
1109 1115
1110 AuthenticateResponse sessionInfo; 1116 AuthenticateResponse sessionInfo;
1111 if (IsClientAuthorized(uccp, out sessionInfo)) 1117 if (IsClientAuthorized(uccp, out sessionInfo))
@@ -1116,13 +1122,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1116 uccp.CircuitCode.Code, 1122 uccp.CircuitCode.Code,
1117 uccp.CircuitCode.ID, 1123 uccp.CircuitCode.ID,
1118 uccp.CircuitCode.SessionID, 1124 uccp.CircuitCode.SessionID,
1119 remoteEndPoint, 1125 endPoint,
1120 sessionInfo); 1126 sessionInfo);
1121 1127
1122 // Send ack straight away to let the viewer know that the connection is active. 1128 // Send ack straight away to let the viewer know that the connection is active.
1123 // The client will be null if it already exists (e.g. if on a region crossing the client sends a use 1129 // The client will be null if it already exists (e.g. if on a region crossing the client sends a use
1124 // circuit code to the existing child agent. This is not particularly obvious. 1130 // circuit code to the existing child agent. This is not particularly obvious.
1125 SendAckImmediate(remoteEndPoint, uccp.Header.Sequence); 1131 SendAckImmediate(endPoint, uccp.Header.Sequence);
1126 1132
1127 // We only want to send initial data to new clients, not ones which are being converted from child to root. 1133 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1128 if (client != null) 1134 if (client != null)
@@ -1133,7 +1139,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1133 // Don't create clients for unauthorized requesters. 1139 // Don't create clients for unauthorized requesters.
1134 m_log.WarnFormat( 1140 m_log.WarnFormat(
1135 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", 1141 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
1136 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, remoteEndPoint); 1142 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
1137 } 1143 }
1138 1144
1139 // m_log.DebugFormat( 1145 // m_log.DebugFormat(
@@ -1145,7 +1151,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1145 { 1151 {
1146 m_log.ErrorFormat( 1152 m_log.ErrorFormat(
1147 "[LLUDPSERVER]: UseCircuitCode handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}", 1153 "[LLUDPSERVER]: UseCircuitCode handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
1148 remoteEndPoint != null ? remoteEndPoint.ToString() : "n/a", 1154 endPoint != null ? endPoint.ToString() : "n/a",
1149 client != null ? client.Name : "unknown", 1155 client != null ? client.Name : "unknown",
1150 client != null ? client.AgentId.ToString() : "unknown", 1156 client != null ? client.AgentId.ToString() : "unknown",
1151 e.Message, 1157 e.Message,
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index 828c23c..6e6b3ef 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
@@ -30,6 +30,7 @@ using System.Net;
30using System.Net.Sockets; 30using System.Net.Sockets;
31using System.Threading; 31using System.Threading;
32using log4net; 32using log4net;
33using OpenSim.Framework;
33 34
34namespace OpenMetaverse 35namespace OpenMetaverse
35{ 36{
@@ -58,6 +59,16 @@ namespace OpenMetaverse
58 /// <summary>Flag to process packets asynchronously or synchronously</summary> 59 /// <summary>Flag to process packets asynchronously or synchronously</summary>
59 private bool m_asyncPacketHandling; 60 private bool m_asyncPacketHandling;
60 61
62 /// <summary>
63 /// Pool to use for handling data. May be null if UsePools = false;
64 /// </summary>
65 protected OpenSim.Framework.Pool<UDPPacketBuffer> m_pool;
66
67 /// <summary>
68 /// Are we to use object pool(s) to reduce memory churn when receiving data?
69 /// </summary>
70 public bool UsePools { get; protected set; }
71
61 /// <summary>Returns true if the server is currently listening for inbound packets, otherwise false</summary> 72 /// <summary>Returns true if the server is currently listening for inbound packets, otherwise false</summary>
62 public bool IsRunningInbound { get; private set; } 73 public bool IsRunningInbound { get; private set; }
63 74
@@ -70,6 +81,7 @@ namespace OpenMetaverse
70 /// </summary> 81 /// </summary>
71 /// <param name="bindAddress">Local IP address to bind the server to</param> 82 /// <param name="bindAddress">Local IP address to bind the server to</param>
72 /// <param name="port">Port to listening for incoming UDP packets on</param> 83 /// <param name="port">Port to listening for incoming UDP packets on</param>
84 /// /// <param name="usePool">Are we to use an object pool to get objects for handing inbound data?</param>
73 public OpenSimUDPBase(IPAddress bindAddress, int port) 85 public OpenSimUDPBase(IPAddress bindAddress, int port)
74 { 86 {
75 m_localBindAddress = bindAddress; 87 m_localBindAddress = bindAddress;
@@ -94,6 +106,11 @@ namespace OpenMetaverse
94 /// necessary</remarks> 106 /// necessary</remarks>
95 public void StartInbound(int recvBufferSize, bool asyncPacketHandling) 107 public void StartInbound(int recvBufferSize, bool asyncPacketHandling)
96 { 108 {
109 if (UsePools)
110 m_pool = new Pool<UDPPacketBuffer>(() => new UDPPacketBuffer(), 500);
111 else
112 m_pool = null;
113
97 m_asyncPacketHandling = asyncPacketHandling; 114 m_asyncPacketHandling = asyncPacketHandling;
98 115
99 if (!IsRunningInbound) 116 if (!IsRunningInbound)
@@ -165,9 +182,12 @@ namespace OpenMetaverse
165 182
166 private void AsyncBeginReceive() 183 private void AsyncBeginReceive()
167 { 184 {
168 // allocate a packet buffer 185 UDPPacketBuffer buf;
169 //WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut(); 186
170 UDPPacketBuffer buf = new UDPPacketBuffer(); 187 if (UsePools)
188 buf = m_pool.GetObject();
189 else
190 buf = new UDPPacketBuffer();
171 191
172 if (IsRunningInbound) 192 if (IsRunningInbound)
173 { 193 {
@@ -231,8 +251,6 @@ namespace OpenMetaverse
231 251
232 // get the buffer that was created in AsyncBeginReceive 252 // get the buffer that was created in AsyncBeginReceive
233 // this is the received data 253 // this is the received data
234 //WrappedObject<UDPPacketBuffer> wrappedBuffer = (WrappedObject<UDPPacketBuffer>)iar.AsyncState;
235 //UDPPacketBuffer buffer = wrappedBuffer.Instance;
236 UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; 254 UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
237 255
238 try 256 try
@@ -249,7 +267,8 @@ namespace OpenMetaverse
249 catch (ObjectDisposedException) { } 267 catch (ObjectDisposedException) { }
250 finally 268 finally
251 { 269 {
252 //wrappedBuffer.Dispose(); 270 if (UsePools)
271 m_pool.ReturnObject(buffer);
253 272
254 // Synchronous mode waits until the packet callback completes 273 // Synchronous mode waits until the packet callback completes
255 // before starting the receive to fetch another packet 274 // before starting the receive to fetch another packet