aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-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
-rw-r--r--bin/OpenSimDefaults.ini6
4 files changed, 130 insertions, 25 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
diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini
index 2fca6ce..b99a02e 100644
--- a/bin/OpenSimDefaults.ini
+++ b/bin/OpenSimDefaults.ini
@@ -1602,10 +1602,14 @@
1602 1602
1603 1603
1604[PacketPool] 1604[PacketPool]
1605 ; Enables the experimental packet pool. Yes, we've been here before.
1606 ;RecyclePackets = true; 1605 ;RecyclePackets = true;
1607 ;RecycleDataBlocks = true; 1606 ;RecycleDataBlocks = true;
1608 1607
1608 ; If true, then the basic packet objects used to receive data are also recycled, not just the LLUDP packets.
1609 ; This reduces data churn
1610 ; This setting is currently experimental and defaults to false.
1611 RecycleBaseUDPPackets = false;
1612
1609 1613
1610[InterestManagement] 1614[InterestManagement]
1611 ; This section controls how state updates are prioritized for each client 1615 ; This section controls how state updates are prioritized for each client