opensim – 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.Threading;
30 using System.Collections;
31 using System.Collections.Generic;
32 using System.Reflection;
33 using OpenMetaverse;
34 using OpenMetaverse.Imaging;
35 using OpenSim.Framework;
36 using OpenSim.Region.Framework.Interfaces;
37 using OpenSim.Services.Interfaces;
38 using log4net;
39  
40 namespace OpenSim.Region.ClientStack.LindenUDP
41 {
42 /// <summary>
43 /// This class handles UDP texture requests.
44 /// </summary>
45 public class LLImageManager
46 {
47 private sealed class J2KImageComparer : IComparer<J2KImage>
48 {
49 public int Compare(J2KImage x, J2KImage y)
50 {
51 return x.Priority.CompareTo(y.Priority);
52 }
53 }
54  
55 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
56 private bool m_shuttingdown;
57 private AssetBase m_missingImage;
58 private IAssetService m_assetCache;
59 private IJ2KDecoder m_j2kDecodeModule;
60  
61 /// <summary>
62 /// Priority queue for determining which image to send first.
63 /// </summary>
64 private C5.IntervalHeap<J2KImage> m_priorityQueue = new C5.IntervalHeap<J2KImage>(10, new J2KImageComparer());
65  
66 /// <summary>
67 /// Used to control thread access to the priority queue.
68 /// </summary>
69 private object m_syncRoot = new object();
70  
71 /// <summary>
72 /// Client served by this image manager
73 /// </summary>
74 public IClientAPI Client { get; private set; }
75  
76 public AssetBase MissingImage { get { return m_missingImage; } }
77  
78 public LLImageManager(IClientAPI client, IAssetService pAssetCache, IJ2KDecoder pJ2kDecodeModule)
79 {
80 Client = client;
81 m_assetCache = pAssetCache;
82  
83 if (pAssetCache != null)
84 m_missingImage = pAssetCache.Get("5748decc-f629-461c-9a36-a35a221fe21f");
85  
86 if (m_missingImage == null)
87 m_log.Error("[ClientView] - Couldn't set missing image asset, falling back to missing image packet. This is known to crash the client");
88  
89 m_j2kDecodeModule = pJ2kDecodeModule;
90 }
91  
92 /// <summary>
93 /// Handles an incoming texture request or update to an existing texture request
94 /// </summary>
95 /// <param name="newRequest"></param>
96 public void EnqueueReq(TextureRequestArgs newRequest)
97 {
98 if (!m_shuttingdown)
99 {
100 J2KImage imgrequest;
101  
102 // Do a linear search for this texture download
103 lock (m_syncRoot)
104 m_priorityQueue.Find(delegate(J2KImage img) { return img.TextureID == newRequest.RequestedAssetID; }, out imgrequest);
105  
106 if (imgrequest != null)
107 {
108 if (newRequest.DiscardLevel == -1 && newRequest.Priority == 0f)
109 {
110 //m_log.Debug("[TEX]: (CAN) ID=" + newRequest.RequestedAssetID);
111  
112 try
113 {
114 lock (m_syncRoot)
115 m_priorityQueue.Delete(imgrequest.PriorityQueueHandle);
116 }
117 catch (Exception) { }
118 }
119 else
120 {
121 // m_log.DebugFormat(
122 // "[LL IMAGE MANAGER]: Received duplicate of existing request for {0}, start packet {1} from {2}",
123 // newRequest.RequestedAssetID, newRequest.PacketNumber, m_client.Name);
124  
125 // m_log.DebugFormat("[TEX]: (UPD) ID={0}: D={1}, S={2}, P={3}",
126 // newRequest.RequestedAssetID, newRequest.DiscardLevel, newRequest.PacketNumber, newRequest.Priority);
127  
128 //Check the packet sequence to make sure this isn't older than
129 //one we've already received
130 if (newRequest.requestSequence > imgrequest.LastSequence)
131 {
132 //Update the sequence number of the last RequestImage packet
133 imgrequest.LastSequence = newRequest.requestSequence;
134  
135 //Update the requested discard level
136 imgrequest.DiscardLevel = newRequest.DiscardLevel;
137  
138 //Update the requested packet number
139 imgrequest.StartPacket = Math.Max(1, newRequest.PacketNumber);
140  
141 //Update the requested priority
142 imgrequest.Priority = newRequest.Priority;
143  
144 UpdateImageInQueue(imgrequest);
145  
146 imgrequest.RunUpdate();
147  
148 // J2KImage imgrequest2 = new J2KImage(this);
149 // imgrequest2.J2KDecoder = m_j2kDecodeModule;
150 // imgrequest2.AssetService = m_assetCache;
151 // imgrequest2.AgentID = m_client.AgentId;
152 // imgrequest2.InventoryAccessModule = m_client.Scene.RequestModuleInterface<IInventoryAccessModule>();
153 // imgrequest2.DiscardLevel = newRequest.DiscardLevel;
154 // imgrequest2.StartPacket = Math.Max(1, newRequest.PacketNumber);
155 // imgrequest2.Priority = newRequest.Priority;
156 // imgrequest2.TextureID = newRequest.RequestedAssetID;
157 // imgrequest2.Priority = newRequest.Priority;
158 //
159 // //Add this download to the priority queue
160 // AddImageToQueue(imgrequest2);
161 //
162 // imgrequest2.RunUpdate();
163  
164 }
165 // else
166 // {
167 // m_log.DebugFormat(
168 // "[LL IMAGE MANAGER]: Ignoring duplicate of existing request for {0} (sequence {1}) from {2} as its request sequence {3} is not greater",
169 // newRequest.RequestedAssetID, imgrequest.LastSequence, m_client.Name, newRequest.requestSequence);
170 // }
171 }
172 }
173 else
174 {
175 if (newRequest.DiscardLevel == -1 && newRequest.Priority == 0f)
176 {
177 //m_log.DebugFormat("[TEX]: (IGN) ID={0}: D={1}, S={2}, P={3}",
178 // newRequest.RequestedAssetID, newRequest.DiscardLevel, newRequest.PacketNumber, newRequest.Priority);
179 }
180 else
181 {
182 // m_log.DebugFormat(
183 // "[LL IMAGE MANAGER]: Received request for {0}, start packet {1} from {2}",
184 // newRequest.RequestedAssetID, newRequest.PacketNumber, m_client.Name);
185  
186 //m_log.DebugFormat("[TEX]: (NEW) ID={0}: D={1}, S={2}, P={3}",
187 // newRequest.RequestedAssetID, newRequest.DiscardLevel, newRequest.PacketNumber, newRequest.Priority);
188  
189 imgrequest = new J2KImage(this);
190 imgrequest.J2KDecoder = m_j2kDecodeModule;
191 imgrequest.AssetService = m_assetCache;
192 imgrequest.AgentID = Client.AgentId;
193 imgrequest.InventoryAccessModule = Client.Scene.RequestModuleInterface<IInventoryAccessModule>();
194 imgrequest.DiscardLevel = newRequest.DiscardLevel;
195 imgrequest.StartPacket = Math.Max(1, newRequest.PacketNumber);
196 imgrequest.Priority = newRequest.Priority;
197 imgrequest.TextureID = newRequest.RequestedAssetID;
198 imgrequest.Priority = newRequest.Priority;
199  
200 //Add this download to the priority queue
201 AddImageToQueue(imgrequest);
202  
203 imgrequest.RunUpdate();
204 }
205 }
206 }
207 }
208  
209 public bool HasUpdates()
210 {
211 J2KImage image = GetHighestPriorityImage();
212  
213 return image != null && image.IsDecoded;
214 }
215  
216 public bool ProcessImageQueue(int packetsToSend)
217 {
218 int packetsSent = 0;
219  
220 while (packetsSent < packetsToSend)
221 {
222 J2KImage image = GetHighestPriorityImage();
223  
224 // If null was returned, the texture priority queue is currently empty
225 if (image == null)
226 break;
227  
228 if (image.IsDecoded)
229 {
230 int sent;
231 bool imageDone = image.SendPackets(Client, packetsToSend - packetsSent, out sent);
232 packetsSent += sent;
233  
234 // If the send is complete, destroy any knowledge of this transfer
235 if (imageDone)
236 RemoveImageFromQueue(image);
237 }
238 else
239 {
240 // TODO: This is a limitation of how LLImageManager is currently
241 // written. Undecoded textures should not be going into the priority
242 // queue, because a high priority undecoded texture will clog up the
243 // pipeline for a client
244 // m_log.DebugFormat(
245 // "[LL IMAGE MANAGER]: Exiting image queue processing early on encountering undecoded image {0}",
246 // image.TextureID);
247  
248 break;
249 }
250 }
251  
252 // if (packetsSent != 0)
253 // m_log.DebugFormat("[LL IMAGE MANAGER]: Processed {0} packets from image queue", packetsSent);
254  
255 return m_priorityQueue.Count > 0;
256 }
257  
258 /// <summary>
259 /// Faux destructor
260 /// </summary>
261 public void Close()
262 {
263 m_shuttingdown = true;
264 }
265  
266 /// <summary>
267 /// Clear the image queue.
268 /// </summary>
269 /// <returns>The number of requests cleared.</returns>
270 public int ClearImageQueue()
271 {
272 int requestsDeleted;
273  
274 lock (m_priorityQueue)
275 {
276 requestsDeleted = m_priorityQueue.Count;
277  
278 // Surprisingly, there doesn't seem to be a clear method at this time.
279 while (!m_priorityQueue.IsEmpty)
280 m_priorityQueue.DeleteMax();
281 }
282  
283 return requestsDeleted;
284 }
285  
286 /// <summary>
287 /// Returns an array containing all the images in the queue.
288 /// </summary>
289 /// <returns></returns>
290 public J2KImage[] GetImages()
291 {
292 lock (m_priorityQueue)
293 return m_priorityQueue.ToArray();
294 }
295  
296 #region Priority Queue Helpers
297  
298 private J2KImage GetHighestPriorityImage()
299 {
300 J2KImage image = null;
301  
302 lock (m_syncRoot)
303 {
304 if (m_priorityQueue.Count > 0)
305 {
306 try
307 {
308 image = m_priorityQueue.FindMax();
309 }
310 catch (Exception) { }
311 }
312 }
313 return image;
314 }
315  
316 private void AddImageToQueue(J2KImage image)
317 {
318 image.PriorityQueueHandle = null;
319  
320 lock (m_syncRoot)
321 {
322 try
323 {
324 m_priorityQueue.Add(ref image.PriorityQueueHandle, image);
325 }
326 catch (Exception) { }
327 }
328 }
329  
330 private void RemoveImageFromQueue(J2KImage image)
331 {
332 lock (m_syncRoot)
333 {
334 try
335 {
336 m_priorityQueue.Delete(image.PriorityQueueHandle);
337 }
338 catch (Exception) { }
339 }
340 }
341  
342 private void UpdateImageInQueue(J2KImage image)
343 {
344 lock (m_syncRoot)
345 {
346 try
347 {
348 m_priorityQueue.Replace(image.PriorityQueueHandle, image);
349 }
350 catch (Exception)
351 {
352 image.PriorityQueueHandle = null;
353 m_priorityQueue.Add(ref image.PriorityQueueHandle, image);
354 }
355 }
356 }
357  
358 #endregion Priority Queue Helpers
359 }
360 }