opensim-development – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 eva 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  
44 /// <summary>
45 /// Pool of packets available for reuse.
46 /// </summary>
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  
60 /// <summary>
61 /// The number of packets pooled
62 /// </summary>
63 public int PacketsPooled
64 {
65 get
66 {
67 lock (pool)
68 return pool.Count;
69 }
70 }
71  
72 /// <summary>
73 /// The number of blocks pooled.
74 /// </summary>
75 public int BlocksPooled
76 {
77 get
78 {
79 lock (DataBlocks)
80 return DataBlocks.Count;
81 }
82 }
83  
84 /// <summary>
85 /// Number of packets requested.
86 /// </summary>
87 public long PacketsRequested { get; private set; }
88  
89 /// <summary>
90 /// Number of packets reused.
91 /// </summary>
92 public long PacketsReused { get; private set; }
93  
94 /// <summary>
95 /// Number of packet blocks requested.
96 /// </summary>
97 public long BlocksRequested { get; private set; }
98  
99 /// <summary>
100 /// Number of packet blocks reused.
101 /// </summary>
102 public long BlocksReused { get; private set; }
103  
104 private PacketPool()
105 {
106 // defaults
107 RecyclePackets = true;
108 RecycleDataBlocks = true;
109 }
110  
111 /// <summary>
112 /// Gets a packet of the given type.
113 /// </summary>
114 /// <param name='type'></param>
115 /// <returns>Guaranteed to always return a packet, whether from the pool or newly constructed.</returns>
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  
195 /// <summary>
196 /// Return a packet to the packet pool
197 /// </summary>
198 /// <param name="packet"></param>
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 }