OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
PacketPool.cs
Go to the documentation of this file.
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 
28 using System;
29 using System.Collections.Generic;
30 using System.Reflection;
31 using OpenMetaverse;
32 using OpenMetaverse.Packets;
33 using log4net;
34 using OpenSim.Framework.Monitoring;
35 
36 namespace 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 
47  private readonly Dictionary<PacketType, Stack<Packet>> pool = new Dictionary<PacketType, Stack<Packet>>();
48 
49  private static Dictionary<Type, Stack<Object>> DataBlocks = new Dictionary<Type, Stack<Object>>();
50 
51  public static PacketPool Instance
52  {
53  get { return instance; }
54  }
55 
56  public bool RecyclePackets { get; set; }
57 
58  public bool RecycleDataBlocks { get; set; }
59 
63  public int PacketsPooled
64  {
65  get
66  {
67  lock (pool)
68  return pool.Count;
69  }
70  }
71 
75  public int BlocksPooled
76  {
77  get
78  {
79  lock (DataBlocks)
80  return DataBlocks.Count;
81  }
82  }
83 
87  public long PacketsRequested { get; private set; }
88 
92  public long PacketsReused { get; private set; }
93 
97  public long BlocksRequested { get; private set; }
98 
102  public long BlocksReused { get; private set; }
103 
104  private PacketPool()
105  {
106  // defaults
107  RecyclePackets = true;
108  RecycleDataBlocks = true;
109  }
110 
116  public Packet GetPacket(PacketType type)
117  {
118  PacketsRequested++;
119 
120  Packet packet;
121 
122  if (!RecyclePackets)
123  return Packet.BuildPacket(type);
124 
125  lock (pool)
126  {
127  if (!pool.ContainsKey(type) || pool[type] == null || (pool[type]).Count == 0)
128  {
129 // m_log.DebugFormat("[PACKETPOOL]: Building {0} packet", type);
130 
131  // Creating a new packet if we cannot reuse an old package
132  packet = Packet.BuildPacket(type);
133  }
134  else
135  {
136 // m_log.DebugFormat("[PACKETPOOL]: Pulling {0} packet", type);
137 
138  // Recycle old packages
139  PacketsReused++;
140 
141  packet = pool[type].Pop();
142  }
143  }
144 
145  return packet;
146  }
147 
148  private static PacketType GetType(byte[] bytes)
149  {
150  ushort id;
151  PacketFrequency freq;
152  bool isZeroCoded = (bytes[0] & Helpers.MSG_ZEROCODED) != 0;
153 
154  if (bytes[6] == 0xFF)
155  {
156  if (bytes[7] == 0xFF)
157  {
158  freq = PacketFrequency.Low;
159  if (isZeroCoded && bytes[8] == 0)
160  id = bytes[10];
161  else
162  id = (ushort)((bytes[8] << 8) + bytes[9]);
163  }
164  else
165  {
166  freq = PacketFrequency.Medium;
167  id = bytes[7];
168  }
169  }
170  else
171  {
172  freq = PacketFrequency.High;
173  id = bytes[6];
174  }
175 
176  return Packet.GetType(id, freq);
177  }
178 
179  public Packet GetPacket(byte[] bytes, ref int packetEnd, byte[] zeroBuffer)
180  {
181  PacketType type = GetType(bytes);
182 
183 // Array.Clear(zeroBuffer, 0, zeroBuffer.Length);
184 
185  int i = 0;
186  Packet packet = GetPacket(type);
187  if (packet == null)
188  m_log.WarnFormat("[PACKETPOOL]: Failed to get packet of type {0}", type);
189  else
190  packet.FromBytes(bytes, ref i, ref packetEnd, zeroBuffer);
191 
192  return packet;
193  }
194 
199  public void ReturnPacket(Packet packet)
200  {
201  if (RecycleDataBlocks)
202  {
203  switch (packet.Type)
204  {
205  case PacketType.ObjectUpdate:
206  ObjectUpdatePacket oup = (ObjectUpdatePacket)packet;
207 
208  foreach (ObjectUpdatePacket.ObjectDataBlock oupod in oup.ObjectData)
209  ReturnDataBlock<ObjectUpdatePacket.ObjectDataBlock>(oupod);
210 
211  oup.ObjectData = null;
212  break;
213 
214  case PacketType.ImprovedTerseObjectUpdate:
215  ImprovedTerseObjectUpdatePacket itoup = (ImprovedTerseObjectUpdatePacket)packet;
216 
217  foreach (ImprovedTerseObjectUpdatePacket.ObjectDataBlock itoupod in itoup.ObjectData)
218  ReturnDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(itoupod);
219 
220  itoup.ObjectData = null;
221  break;
222  }
223  }
224 
225  if (RecyclePackets)
226  {
227  switch (packet.Type)
228  {
229  // List pooling packets here
230  case PacketType.AgentUpdate:
231  case PacketType.PacketAck:
232  case PacketType.ObjectUpdate:
233  case PacketType.ImprovedTerseObjectUpdate:
234  lock (pool)
235  {
236  PacketType type = packet.Type;
237 
238  if (!pool.ContainsKey(type))
239  {
240  pool[type] = new Stack<Packet>();
241  }
242 
243  if ((pool[type]).Count < 50)
244  {
245 // m_log.DebugFormat("[PACKETPOOL]: Pushing {0} packet", type);
246 
247  pool[type].Push(packet);
248  }
249  }
250  break;
251 
252  // Other packets wont pool
253  default:
254  return;
255  }
256  }
257  }
258 
259  public T GetDataBlock<T>() where T: new()
260  {
261  lock (DataBlocks)
262  {
263  BlocksRequested++;
264 
265  Stack<Object> s;
266 
267  if (DataBlocks.TryGetValue(typeof(T), out s))
268  {
269  if (s.Count > 0)
270  {
271  BlocksReused++;
272  return (T)s.Pop();
273  }
274  }
275  else
276  {
277  DataBlocks[typeof(T)] = new Stack<Object>();
278  }
279 
280  return new T();
281  }
282  }
283 
284  public void ReturnDataBlock<T>(T block) where T: new()
285  {
286  if (block == null)
287  return;
288 
289  lock (DataBlocks)
290  {
291  if (!DataBlocks.ContainsKey(typeof(T)))
292  DataBlocks[typeof(T)] = new Stack<Object>();
293 
294  if (DataBlocks[typeof(T)].Count < 50)
295  DataBlocks[typeof(T)].Push(block);
296  }
297  }
298  }
299 }
void ReturnPacket(Packet packet)
Return a packet to the packet pool
Definition: PacketPool.cs:199
Packet GetPacket(byte[] bytes, ref int packetEnd, byte[] zeroBuffer)
Definition: PacketPool.cs:179
Packet GetPacket(PacketType type)
Gets a packet of the given type.
Definition: PacketPool.cs:116