aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--OpenSim/Framework/Communications/Limit/IRequestLimitStrategy.cs68
-rw-r--r--OpenSim/Framework/Communications/Limit/RepeatLimitStrategy.cs113
-rw-r--r--OpenSim/Region/Environment/Modules/UserTextureDownloadService.cs90
3 files changed, 211 insertions, 60 deletions
diff --git a/OpenSim/Framework/Communications/Limit/IRequestLimitStrategy.cs b/OpenSim/Framework/Communications/Limit/IRequestLimitStrategy.cs
new file mode 100644
index 0000000..ded9ffc
--- /dev/null
+++ b/OpenSim/Framework/Communications/Limit/IRequestLimitStrategy.cs
@@ -0,0 +1,68 @@
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 OpenSim 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;
29
30namespace OpenSim.Framework.Communications.Limit
31{
32 /// <summary>
33 /// Interface for strategies that can limit requests from the client. Currently only used in the
34 /// texture modules to deal with repeated requests for certain textures. However, limiting strategies
35 /// could be used with other requests.
36 /// </summary>
37 public interface IRequestLimitStrategy<TId>
38 {
39 /// <summary>
40 /// Should the request be allowed? If the id is not monitored, then the request is always allowed.
41 /// Otherwise, the strategy criteria will be applied.
42 /// </summary>
43 /// <param name="id"></param>
44 /// <returns></returns>
45 bool AllowRequest(TId id);
46
47 /// <summary>
48 /// Has the request been refused just once?
49 /// </summary>
50 /// <returns>False if the request has not yet been refused, or if the request has been refused more
51 /// than once.</returns>
52 bool IsFirstRefusal(TId id);
53
54 /// <summary>
55 /// Start monitoring for future AllowRequest calls. If the id is already monitored, then monitoring
56 /// continues.
57 /// </summary>
58 /// <param name="id"></param>
59 void MonitorRequests(TId id);
60
61 /// <summary>
62 /// Is the id being monitored?
63 /// </summary>
64 /// <param name="uuid"> </param>
65 /// <returns></returns>
66 bool IsMonitoringRequests(TId id);
67 }
68}
diff --git a/OpenSim/Framework/Communications/Limit/RepeatLimitStrategy.cs b/OpenSim/Framework/Communications/Limit/RepeatLimitStrategy.cs
new file mode 100644
index 0000000..6dd0fa1
--- /dev/null
+++ b/OpenSim/Framework/Communications/Limit/RepeatLimitStrategy.cs
@@ -0,0 +1,113 @@
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 OpenSim 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;
30
31namespace OpenSim.Framework.Communications.Limit
32{
33 /// <summary>
34 /// Limit requests by discarding them after they've been repeated a certain number of times.
35 /// </summary>
36 public class RepeatLimitStrategy<TId> : IRequestLimitStrategy<TId>
37 {
38 private static readonly log4net.ILog m_log
39 = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
40
41 /// <summary>
42 /// Record each asset request that we're notified about.
43 /// </summary>
44 private readonly Dictionary<TId, int> requestCounts = new Dictionary<TId, int>();
45
46 /// <summary>
47 /// The maximum number of requests that can be made before we drop subsequent requests.
48 /// </summary>
49 private readonly int m_maxRequests;
50 public int MaxRequests
51 {
52 get { return m_maxRequests; }
53 }
54
55 /// <summary></summary>
56 /// <param name="maxRequests">The maximum number of requests that may be served before all further
57 /// requests are dropped.</param>
58 public RepeatLimitStrategy(int maxRequests)
59 {
60 m_maxRequests = maxRequests;
61 }
62
63 /// <summary>
64 /// <see cref="IRequestLimitStrategy"/>
65 /// </summary>
66 public bool AllowRequest(TId id)
67 {
68 if (requestCounts.ContainsKey(id))
69 {
70 requestCounts[id] += 1;
71
72 if (requestCounts[id] > m_maxRequests)
73 {
74 return false;
75 }
76 }
77
78 return true;
79 }
80
81 /// <summary>
82 /// <see cref="IRequestLimitStrategy"/>
83 /// </summary>
84 public bool IsFirstRefusal(TId id)
85 {
86 if (m_maxRequests + 1 == requestCounts[id])
87 {
88 return true;
89 }
90
91 return false;
92 }
93
94 /// <summary>
95 /// <see cref="IRequestLimitStrategy"/>
96 /// </summary>
97 public void MonitorRequests(TId id)
98 {
99 if (!IsMonitoringRequests(id))
100 {
101 requestCounts.Add(id, 1);
102 }
103 }
104
105 /// <summary>
106 /// <see cref="IRequestLimitStrategy"/>
107 /// </summary>
108 public bool IsMonitoringRequests(TId id)
109 {
110 return requestCounts.ContainsKey(id);
111 }
112 }
113}
diff --git a/OpenSim/Region/Environment/Modules/UserTextureDownloadService.cs b/OpenSim/Region/Environment/Modules/UserTextureDownloadService.cs
index 4fdec65..a688cc8 100644
--- a/OpenSim/Region/Environment/Modules/UserTextureDownloadService.cs
+++ b/OpenSim/Region/Environment/Modules/UserTextureDownloadService.cs
@@ -32,6 +32,7 @@ using libsecondlife;
32using libsecondlife.Packets; 32using libsecondlife.Packets;
33 33
34using OpenSim.Framework; 34using OpenSim.Framework;
35using OpenSim.Framework.Communications.Limit;
35using OpenSim.Framework.Console; 36using OpenSim.Framework.Console;
36using OpenSim.Region.Environment.Interfaces; 37using OpenSim.Region.Environment.Interfaces;
37using OpenSim.Region.Environment.Scenes; 38using OpenSim.Region.Environment.Scenes;
@@ -54,27 +55,29 @@ namespace OpenSim.Region.Environment.Modules
54 private static readonly int MAX_ALLOWED_TEXTURE_REQUESTS = 5; 55 private static readonly int MAX_ALLOWED_TEXTURE_REQUESTS = 5;
55 56
56 /// <summary> 57 /// <summary>
57 /// Holds texture senders before they have received the appropriate texture from the asset cache. 58 /// We're going to limit repeated requests for the same missing texture.
58 /// </summary> 59 /// XXX This is really a temporary solution to deal with the situation where a client continually requests
59 private readonly Dictionary<LLUUID, TextureSender> m_textureSenders = new Dictionary<LLUUID, TextureSender>(); 60 /// the same missing textures
61 /// </summary>
62 private readonly IRequestLimitStrategy<LLUUID> missingTextureLimitStrategy
63 = new RepeatLimitStrategy<LLUUID>(MAX_ALLOWED_TEXTURE_REQUESTS);
60 64
61 /// <summary> 65 /// <summary>
62 /// Texture Senders are placed in this queue once they have received their texture from the asset 66 /// XXX Also going to limit repeated requests for found textures.
63 /// cache. Another module actually invokes the send.
64 /// </summary> 67 /// </summary>
65 private readonly BlockingQueue<ITextureSender> m_sharedSendersQueue; 68 private readonly IRequestLimitStrategy<LLUUID> foundTextureLimitStrategy
69 = new RepeatLimitStrategy<LLUUID>(MAX_ALLOWED_TEXTURE_REQUESTS);
66 70
67 /// <summary> 71 /// <summary>
68 /// We're going to record when we get a request for a particular missing texture for each client 72 /// Holds texture senders before they have received the appropriate texture from the asset cache.
69 /// XXX This is really a temporary solution to deal with the situation where a client continually requests
70 /// the same missing textures
71 /// </summary> 73 /// </summary>
72 private readonly Dictionary<LLUUID, int> missingTextureRequestCounts = new Dictionary<LLUUID, int>(); 74 private readonly Dictionary<LLUUID, TextureSender> m_textureSenders = new Dictionary<LLUUID, TextureSender>();
73 75
74 /// <summary> 76 /// <summary>
75 /// XXX Also going to record all the textures found and dispatched 77 /// Texture Senders are placed in this queue once they have received their texture from the asset
78 /// cache. Another module actually invokes the send.
76 /// </summary> 79 /// </summary>
77 private readonly Dictionary<LLUUID, int> dispatchedTextureRequestCounts = new Dictionary<LLUUID, int>(); 80 private readonly BlockingQueue<ITextureSender> m_sharedSendersQueue;
78 81
79 private readonly Scene m_scene; 82 private readonly Scene m_scene;
80 83
@@ -109,50 +112,21 @@ namespace OpenSim.Region.Environment.Modules
109 textureSender.UpdateRequest(e.DiscardLevel, e.PacketNumber); 112 textureSender.UpdateRequest(e.DiscardLevel, e.PacketNumber);
110 } 113 }
111 else 114 else
112 { 115 {
113 // If we've already told the client we're missing the texture, then don't ask the 116 if (!foundTextureLimitStrategy.AllowRequest(e.RequestedAssetID))
114 // asset server for it again - record the fact that it's missing instead.
115 // XXX This is to reduce (but not resolve) a current problem where some clients keep
116 // requesting the same textures
117 if (missingTextureRequestCounts.ContainsKey(e.RequestedAssetID))
118 { 117 {
119 missingTextureRequestCounts[e.RequestedAssetID] += 1; 118 return;
120
121 if (missingTextureRequestCounts[e.RequestedAssetID] > MAX_ALLOWED_TEXTURE_REQUESTS)
122 {
123 if (MAX_ALLOWED_TEXTURE_REQUESTS + 1 == missingTextureRequestCounts[e.RequestedAssetID])
124 {
125 m_log.DebugFormat(
126 "[USER TEXTURE DOWNLOAD SERVICE]: Dropping requests for notified missing texture {0} for {1} since we have received more than {2} requests",
127 e.RequestedAssetID, m_client.AgentId, MAX_ALLOWED_TEXTURE_REQUESTS);
128 }
129
130 return;
131 }
132 } 119 }
133 else 120 else if (!missingTextureLimitStrategy.AllowRequest(e.RequestedAssetID))
134 { 121 {
135 // If we keep receiving requests for textures we've already served to the client, 122 if (missingTextureLimitStrategy.IsFirstRefusal(e.RequestedAssetID))
136 // then stop sending them. This is a short term approach approach to the problem
137 // of clients which keep requesting the same texture - the long term approach
138 // will be to treat the cause (and possibly more generally cap the request
139 // queues as well/instead)
140 if (dispatchedTextureRequestCounts.ContainsKey(e.RequestedAssetID))
141 { 123 {
142 dispatchedTextureRequestCounts[e.RequestedAssetID] += 1; 124 m_log.DebugFormat(
143 125 "[USER TEXTURE DOWNLOAD SERVICE]: Dropping requests for notified missing texture {0} for client {1} since we have received more than {1} requests",
144 if (dispatchedTextureRequestCounts[e.RequestedAssetID] > MAX_ALLOWED_TEXTURE_REQUESTS) 126 e.RequestedAssetID, m_client.AgentId, MAX_ALLOWED_TEXTURE_REQUESTS);
145 { 127 }
146// if (MAX_ALLOWED_TEXTURE_REQUESTS + 1 == dispatchedTextureRequestCounts[e.RequestedAssetID]) 128
147// { 129 return;
148// m_log.DebugFormat(
149// "[USER TEXTURE DOWNLOAD SERVICE]: Dropping further requests for dispatched/queued texture {0} for {1} since we have received more than {2} requests",
150// e.RequestedAssetID, m_client.AgentId, MAX_ALLOWED_TEXTURE_REQUESTS);
151// }
152
153 return;
154 }
155 }
156 } 130 }
157 131
158 m_scene.AddPendingDownloads(1); 132 m_scene.AddPendingDownloads(1);
@@ -197,9 +171,9 @@ namespace OpenSim.Region.Environment.Modules
197 // Needs investigation. 171 // Needs investigation.
198 if (texture == null || texture.Data == null) 172 if (texture == null || texture.Data == null)
199 { 173 {
200 if (!missingTextureRequestCounts.ContainsKey(textureID)) 174 if (!missingTextureLimitStrategy.IsMonitoringRequests(textureID))
201 { 175 {
202 missingTextureRequestCounts.Add(textureID, 1); 176 missingTextureLimitStrategy.MonitorRequests(textureID);
203 177
204 m_log.DebugFormat( 178 m_log.DebugFormat(
205 "[USER TEXTURE DOWNLOAD SERVICE]: Queueing first TextureNotFoundSender for {0}, client {1}", 179 "[USER TEXTURE DOWNLOAD SERVICE]: Queueing first TextureNotFoundSender for {0}, client {1}",
@@ -216,11 +190,7 @@ namespace OpenSim.Region.Environment.Modules
216 textureSender.TextureReceived(texture); 190 textureSender.TextureReceived(texture);
217 EnqueueTextureSender(textureSender); 191 EnqueueTextureSender(textureSender);
218 192
219 // Record the fact that we've put this texture in for dispatch 193 foundTextureLimitStrategy.MonitorRequests(textureID);
220 if (!dispatchedTextureRequestCounts.ContainsKey(textureID))
221 {
222 dispatchedTextureRequestCounts.Add(textureID, 1);
223 }
224 } 194 }
225 } 195 }
226 196