clockwerk-opensim – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 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 System.Threading;
32 using log4net;
33 using OpenMetaverse;
34 using OpenSim.Framework;
35 using OpenSim.Region.Framework.Interfaces;
36  
37 namespace OpenSim.Region.Framework.Scenes
38 {
39 class FetchHolder
40 {
41 public IClientAPI Client { get; private set; }
42 public UUID ItemID { get; private set; }
43  
44 public FetchHolder(IClientAPI client, UUID itemID)
45 {
46 Client = client;
47 ItemID = itemID;
48 }
49 }
50  
51 /// <summary>
52 /// Send FetchInventoryReply information to clients asynchronously on a single thread rather than asynchronously via
53 /// multiple threads.
54 /// </summary>
55 /// <remarks>
56 /// If the main root inventory is right-clicked on a version 1 viewer for a user with a large inventory, a very
57 /// very large number of FetchInventory requests are sent to the simulator. Each is handled on a separate thread
58 /// by the IClientAPI, but the sheer number of requests overwhelms the number of threads available and ends up
59 /// freezing the inbound packet handling.
60 ///
61 /// This class makes the first FetchInventory packet thread process the queue. If new requests come
62 /// in while it is processing, then the subsequent threads just add the requests and leave it to the original
63 /// thread to process them.
64 ///
65 /// This might slow down outbound packets but these are limited by the IClientAPI outbound queues
66 /// anyway.
67 ///
68 /// It might be possible to ignore FetchInventory requests altogether, particularly as they are redundant wrt to
69 /// FetchInventoryDescendents requests, but this would require more investigation.
70 /// </remarks>
71 public class AsyncInventorySender
72 {
73 // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
74  
75 protected Scene m_scene;
76  
77 /// <summary>
78 /// Queues fetch requests
79 /// </summary>
80 Queue<FetchHolder> m_fetchHolder = new Queue<FetchHolder>();
81  
82 /// <summary>
83 /// Signal whether a queue is currently being processed or not.
84 /// </summary>
85 protected volatile bool m_processing;
86  
87 public AsyncInventorySender(Scene scene)
88 {
89 m_processing = false;
90 m_scene = scene;
91 }
92  
93 /// <summary>
94 /// Handle a fetch inventory request from the client
95 /// </summary>
96 /// <param name="remoteClient"></param>
97 /// <param name="itemID"></param>
98 /// <param name="ownerID"></param>
99 public void HandleFetchInventory(IClientAPI remoteClient, UUID itemID, UUID ownerID)
100 {
101 lock (m_fetchHolder)
102 {
103 // m_log.DebugFormat(
104 // "[ASYNC INVENTORY SENDER]: Putting request from {0} for {1} on queue", remoteClient.Name, itemID);
105  
106 m_fetchHolder.Enqueue(new FetchHolder(remoteClient, itemID));
107 }
108  
109 if (!m_processing)
110 {
111 m_processing = true;
112 ProcessQueue();
113 }
114 }
115  
116 /// <summary>
117 /// Process the queue of fetches
118 /// </summary>
119 protected void ProcessQueue()
120 {
121 FetchHolder fh = null;
122  
123 while (true)
124 {
125 lock (m_fetchHolder)
126 {
127 // m_log.DebugFormat("[ASYNC INVENTORY SENDER]: {0} items left to process", m_fetchHolder.Count);
128  
129 if (m_fetchHolder.Count == 0)
130 {
131 m_processing = false;
132 return;
133 }
134 else
135 {
136 fh = m_fetchHolder.Dequeue();
137 }
138 }
139  
140 if (!fh.Client.IsActive)
141 continue;
142  
143 // m_log.DebugFormat(
144 // "[ASYNC INVENTORY SENDER]: Handling request from {0} for {1} on queue", fh.Client.Name, fh.ItemID);
145  
146 InventoryItemBase item = new InventoryItemBase(fh.ItemID, fh.Client.AgentId);
147 item = m_scene.InventoryService.GetItem(item);
148  
149 if (item != null)
150 fh.Client.SendInventoryItemDetails(item.Owner, item);
151  
152 // TODO: Possibly log any failure
153 }
154 }
155 }
156 }