aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs')
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs316
1 files changed, 316 insertions, 0 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
new file mode 100644
index 0000000..9f22fb4
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
@@ -0,0 +1,316 @@
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;
30using System.Reflection;
31using OpenMetaverse;
32using OpenMetaverse.Packets;
33using log4net;
34using OpenSim.Framework.Monitoring;
35
36namespace OpenSim.Region.ClientStack.LindenUDP
37{
38 public sealed class PacketPool
39 {
40 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
41
42 private static readonly PacketPool instance = new PacketPool();
43
44 private bool packetPoolEnabled = true;
45 private bool dataBlockPoolEnabled = true;
46
47 private PercentageStat m_packetsReusedStat = new PercentageStat(
48 "PacketsReused",
49 "Packets reused",
50 "Number of packets reused out of all requests to the packet pool",
51 "clientstack",
52 "packetpool",
53 StatType.Push,
54 null,
55 StatVerbosity.Debug);
56
57 private PercentageStat m_blocksReusedStat = new PercentageStat(
58 "PacketDataBlocksReused",
59 "Packet data blocks reused",
60 "Number of data blocks reused out of all requests to the packet pool",
61 "clientstack",
62 "packetpool",
63 StatType.Push,
64 null,
65 StatVerbosity.Debug);
66
67 /// <summary>
68 /// Pool of packets available for reuse.
69 /// </summary>
70 private readonly Dictionary<PacketType, Stack<Packet>> pool = new Dictionary<PacketType, Stack<Packet>>();
71
72 private static Dictionary<Type, Stack<Object>> DataBlocks = new Dictionary<Type, Stack<Object>>();
73
74 public static PacketPool Instance
75 {
76 get { return instance; }
77 }
78
79 public bool RecyclePackets
80 {
81 set { packetPoolEnabled = value; }
82 get { return packetPoolEnabled; }
83 }
84
85 public bool RecycleDataBlocks
86 {
87 set { dataBlockPoolEnabled = value; }
88 get { return dataBlockPoolEnabled; }
89 }
90
91 private PacketPool()
92 {
93 StatsManager.RegisterStat(m_packetsReusedStat);
94 StatsManager.RegisterStat(m_blocksReusedStat);
95
96 StatsManager.RegisterStat(
97 new Stat(
98 "PacketsPoolCount",
99 "Objects within the packet pool",
100 "The number of objects currently stored within the packet pool",
101 "",
102 "clientstack",
103 "packetpool",
104 StatType.Pull,
105 stat => { lock (pool) { stat.Value = pool.Count; } },
106 StatVerbosity.Debug));
107
108 StatsManager.RegisterStat(
109 new Stat(
110 "PacketDataBlocksPoolCount",
111 "Objects within the packet data block pool",
112 "The number of objects currently stored within the packet data block pool",
113 "",
114 "clientstack",
115 "packetpool",
116 StatType.Pull,
117 stat => { lock (DataBlocks) { stat.Value = DataBlocks.Count; } },
118 StatVerbosity.Debug));
119 }
120
121 /// <summary>
122 /// Gets a packet of the given type.
123 /// </summary>
124 /// <param name='type'></param>
125 /// <returns>Guaranteed to always return a packet, whether from the pool or newly constructed.</returns>
126 public Packet GetPacket(PacketType type)
127 {
128 m_packetsReusedStat.Consequent++;
129
130 Packet packet;
131
132 if (!packetPoolEnabled)
133 return Packet.BuildPacket(type);
134
135 lock (pool)
136 {
137 if (!pool.ContainsKey(type) || pool[type] == null || (pool[type]).Count == 0)
138 {
139// m_log.DebugFormat("[PACKETPOOL]: Building {0} packet", type);
140
141 // Creating a new packet if we cannot reuse an old package
142 packet = Packet.BuildPacket(type);
143 }
144 else
145 {
146// m_log.DebugFormat("[PACKETPOOL]: Pulling {0} packet", type);
147
148 // Recycle old packages
149 m_packetsReusedStat.Antecedent++;
150
151 packet = pool[type].Pop();
152 }
153 }
154
155 return packet;
156 }
157
158 // private byte[] decoded_header = new byte[10];
159 private static PacketType GetType(byte[] bytes)
160 {
161 byte[] decoded_header = new byte[10 + 8];
162 ushort id;
163 PacketFrequency freq;
164
165 if ((bytes[0] & Helpers.MSG_ZEROCODED) != 0)
166 {
167 Helpers.ZeroDecode(bytes, 16, decoded_header);
168 }
169 else
170 {
171 Buffer.BlockCopy(bytes, 0, decoded_header, 0, 10);
172 }
173
174 if (decoded_header[6] == 0xFF)
175 {
176 if (decoded_header[7] == 0xFF)
177 {
178 id = (ushort) ((decoded_header[8] << 8) + decoded_header[9]);
179 freq = PacketFrequency.Low;
180 }
181 else
182 {
183 id = decoded_header[7];
184 freq = PacketFrequency.Medium;
185 }
186 }
187 else
188 {
189 id = decoded_header[6];
190 freq = PacketFrequency.High;
191 }
192
193 return Packet.GetType(id, freq);
194 }
195
196 public Packet GetPacket(byte[] bytes, ref int packetEnd, byte[] zeroBuffer)
197 {
198 PacketType type = GetType(bytes);
199
200// Array.Clear(zeroBuffer, 0, zeroBuffer.Length);
201
202 int i = 0;
203 Packet packet = GetPacket(type);
204 if (packet == null)
205 m_log.WarnFormat("[PACKETPOOL]: Failed to get packet of type {0}", type);
206 else
207 packet.FromBytes(bytes, ref i, ref packetEnd, zeroBuffer);
208
209 return packet;
210 }
211
212 /// <summary>
213 /// Return a packet to the packet pool
214 /// </summary>
215 /// <param name="packet"></param>
216 public void ReturnPacket(Packet packet)
217 {
218 if (dataBlockPoolEnabled)
219 {
220 switch (packet.Type)
221 {
222 case PacketType.ObjectUpdate:
223 ObjectUpdatePacket oup = (ObjectUpdatePacket)packet;
224
225 foreach (ObjectUpdatePacket.ObjectDataBlock oupod in oup.ObjectData)
226 ReturnDataBlock<ObjectUpdatePacket.ObjectDataBlock>(oupod);
227
228 oup.ObjectData = null;
229 break;
230
231 case PacketType.ImprovedTerseObjectUpdate:
232 ImprovedTerseObjectUpdatePacket itoup = (ImprovedTerseObjectUpdatePacket)packet;
233
234 foreach (ImprovedTerseObjectUpdatePacket.ObjectDataBlock itoupod in itoup.ObjectData)
235 ReturnDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(itoupod);
236
237 itoup.ObjectData = null;
238 break;
239 }
240 }
241
242 if (packetPoolEnabled)
243 {
244 switch (packet.Type)
245 {
246 // List pooling packets here
247 case PacketType.AgentUpdate:
248 case PacketType.PacketAck:
249 case PacketType.ObjectUpdate:
250 case PacketType.ImprovedTerseObjectUpdate:
251 lock (pool)
252 {
253 PacketType type = packet.Type;
254
255 if (!pool.ContainsKey(type))
256 {
257 pool[type] = new Stack<Packet>();
258 }
259
260 if ((pool[type]).Count < 50)
261 {
262// m_log.DebugFormat("[PACKETPOOL]: Pushing {0} packet", type);
263
264 pool[type].Push(packet);
265 }
266 }
267 break;
268
269 // Other packets wont pool
270 default:
271 return;
272 }
273 }
274 }
275
276 public T GetDataBlock<T>() where T: new()
277 {
278 lock (DataBlocks)
279 {
280 m_blocksReusedStat.Consequent++;
281
282 Stack<Object> s;
283
284 if (DataBlocks.TryGetValue(typeof(T), out s))
285 {
286 if (s.Count > 0)
287 {
288 m_blocksReusedStat.Antecedent++;
289 return (T)s.Pop();
290 }
291 }
292 else
293 {
294 DataBlocks[typeof(T)] = new Stack<Object>();
295 }
296
297 return new T();
298 }
299 }
300
301 public void ReturnDataBlock<T>(T block) where T: new()
302 {
303 if (block == null)
304 return;
305
306 lock (DataBlocks)
307 {
308 if (!DataBlocks.ContainsKey(typeof(T)))
309 DataBlocks[typeof(T)] = new Stack<Object>();
310
311 if (DataBlocks[typeof(T)].Count < 50)
312 DataBlocks[typeof(T)].Push(block);
313 }
314 }
315 }
316} \ No newline at end of file