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.cs282
1 files changed, 282 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..71f6fe1
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
@@ -0,0 +1,282 @@
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 "clientstack",
51 "packetpool",
52 StatVerbosity.Debug,
53 "Number of packets reused out of all requests to the packet pool");
54
55 private PercentageStat m_blocksReusedStat = new PercentageStat(
56 "BlocksReused",
57 "Blocks reused",
58 "clientstack",
59 "packetpool",
60 StatVerbosity.Debug,
61 "Number of data blocks reused out of all requests to the packet pool");
62
63 /// <summary>
64 /// Pool of packets available for reuse.
65 /// </summary>
66 private readonly Dictionary<PacketType, Stack<Packet>> pool = new Dictionary<PacketType, Stack<Packet>>();
67
68 private static Dictionary<Type, Stack<Object>> DataBlocks = new Dictionary<Type, Stack<Object>>();
69
70 public static PacketPool Instance
71 {
72 get { return instance; }
73 }
74
75 public bool RecyclePackets
76 {
77 set { packetPoolEnabled = value; }
78 get { return packetPoolEnabled; }
79 }
80
81 public bool RecycleDataBlocks
82 {
83 set { dataBlockPoolEnabled = value; }
84 get { return dataBlockPoolEnabled; }
85 }
86
87 private PacketPool()
88 {
89 StatsManager.RegisterStat(m_packetsReusedStat);
90 StatsManager.RegisterStat(m_blocksReusedStat);
91 }
92
93 /// <summary>
94 /// Gets a packet of the given type.
95 /// </summary>
96 /// <param name='type'></param>
97 /// <returns>Guaranteed to always return a packet, whether from the pool or newly constructed.</returns>
98 public Packet GetPacket(PacketType type)
99 {
100 m_packetsReusedStat.Consequent++;
101
102 Packet packet;
103
104 if (!packetPoolEnabled)
105 return Packet.BuildPacket(type);
106
107 lock (pool)
108 {
109 if (!pool.ContainsKey(type) || pool[type] == null || (pool[type]).Count == 0)
110 {
111 // Creating a new packet if we cannot reuse an old package
112 packet = Packet.BuildPacket(type);
113 }
114 else
115 {
116 // Recycle old packages
117 m_packetsReusedStat.Antecedent++;
118
119 packet = (pool[type]).Pop();
120 }
121 }
122
123 return packet;
124 }
125
126 // private byte[] decoded_header = new byte[10];
127 private static PacketType GetType(byte[] bytes)
128 {
129 byte[] decoded_header = new byte[10 + 8];
130 ushort id;
131 PacketFrequency freq;
132
133 if ((bytes[0] & Helpers.MSG_ZEROCODED) != 0)
134 {
135 Helpers.ZeroDecode(bytes, 16, decoded_header);
136 }
137 else
138 {
139 Buffer.BlockCopy(bytes, 0, decoded_header, 0, 10);
140 }
141
142 if (decoded_header[6] == 0xFF)
143 {
144 if (decoded_header[7] == 0xFF)
145 {
146 id = (ushort) ((decoded_header[8] << 8) + decoded_header[9]);
147 freq = PacketFrequency.Low;
148 }
149 else
150 {
151 id = decoded_header[7];
152 freq = PacketFrequency.Medium;
153 }
154 }
155 else
156 {
157 id = decoded_header[6];
158 freq = PacketFrequency.High;
159 }
160
161 return Packet.GetType(id, freq);
162 }
163
164 public Packet GetPacket(byte[] bytes, ref int packetEnd, byte[] zeroBuffer)
165 {
166 PacketType type = GetType(bytes);
167
168// Array.Clear(zeroBuffer, 0, zeroBuffer.Length);
169
170 int i = 0;
171 Packet packet = GetPacket(type);
172 if (packet == null)
173 m_log.WarnFormat("[PACKETPOOL]: Failed to get packet of type {0}", type);
174 else
175 packet.FromBytes(bytes, ref i, ref packetEnd, zeroBuffer);
176
177 return packet;
178 }
179
180 /// <summary>
181 /// Return a packet to the packet pool
182 /// </summary>
183 /// <param name="packet"></param>
184 public void ReturnPacket(Packet packet)
185 {
186 if (dataBlockPoolEnabled)
187 {
188 switch (packet.Type)
189 {
190 case PacketType.ObjectUpdate:
191 ObjectUpdatePacket oup = (ObjectUpdatePacket)packet;
192
193 foreach (ObjectUpdatePacket.ObjectDataBlock oupod in oup.ObjectData)
194 ReturnDataBlock<ObjectUpdatePacket.ObjectDataBlock>(oupod);
195
196 oup.ObjectData = null;
197 break;
198
199 case PacketType.ImprovedTerseObjectUpdate:
200 ImprovedTerseObjectUpdatePacket itoup = (ImprovedTerseObjectUpdatePacket)packet;
201
202 foreach (ImprovedTerseObjectUpdatePacket.ObjectDataBlock itoupod in itoup.ObjectData)
203 ReturnDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(itoupod);
204
205 itoup.ObjectData = null;
206 break;
207 }
208 }
209
210 if (packetPoolEnabled)
211 {
212 switch (packet.Type)
213 {
214 // List pooling packets here
215 case PacketType.AgentUpdate:
216 case PacketType.PacketAck:
217 case PacketType.ObjectUpdate:
218 case PacketType.ImprovedTerseObjectUpdate:
219 lock (pool)
220 {
221 PacketType type = packet.Type;
222
223 if (!pool.ContainsKey(type))
224 {
225 pool[type] = new Stack<Packet>();
226 }
227
228 if ((pool[type]).Count < 50)
229 {
230 (pool[type]).Push(packet);
231 }
232 }
233 break;
234
235 // Other packets wont pool
236 default:
237 return;
238 }
239 }
240 }
241
242 public T GetDataBlock<T>() where T: new()
243 {
244 lock (DataBlocks)
245 {
246 m_blocksReusedStat.Consequent++;
247
248 Stack<Object> s;
249
250 if (DataBlocks.TryGetValue(typeof(T), out s))
251 {
252 if (s.Count > 0)
253 {
254 m_blocksReusedStat.Antecedent++;
255 return (T)s.Pop();
256 }
257 }
258 else
259 {
260 DataBlocks[typeof(T)] = new Stack<Object>();
261 }
262
263 return new T();
264 }
265 }
266
267 public void ReturnDataBlock<T>(T block) where T: new()
268 {
269 if (block == null)
270 return;
271
272 lock (DataBlocks)
273 {
274 if (!DataBlocks.ContainsKey(typeof(T)))
275 DataBlocks[typeof(T)] = new Stack<Object>();
276
277 if (DataBlocks[typeof(T)].Count < 50)
278 DataBlocks[typeof(T)].Push(block);
279 }
280 }
281 }
282} \ No newline at end of file