aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs')
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs190
1 files changed, 173 insertions, 17 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
index d1a1583..dd87671 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
@@ -47,9 +47,6 @@ using OpenSim.Framework.Monitoring;
47namespace OpenSim.Region.ClientStack.Linden 47namespace OpenSim.Region.ClientStack.Linden
48{ 48{
49 49
50 /// <summary>
51 /// This module implements both WebFetchTextureDescendents and FetchTextureDescendents2 capabilities.
52 /// </summary>
53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetTextureModule")] 50 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetTextureModule")]
54 public class GetTextureModule : INonSharedRegionModule 51 public class GetTextureModule : INonSharedRegionModule
55 { 52 {
@@ -61,6 +58,13 @@ namespace OpenSim.Region.ClientStack.Linden
61 public Hashtable request; 58 public Hashtable request;
62 } 59 }
63 60
61 public class aPollResponse
62 {
63 public Hashtable response;
64 public int bytes;
65 }
66
67
64 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 68 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
65 69
66 private Scene m_scene; 70 private Scene m_scene;
@@ -75,6 +79,8 @@ namespace OpenSim.Region.ClientStack.Linden
75 private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue = 79 private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue =
76 new OpenMetaverse.BlockingQueue<aPollRequest>(); 80 new OpenMetaverse.BlockingQueue<aPollRequest>();
77 81
82 private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>();
83
78 #region ISharedRegionModule Members 84 #region ISharedRegionModule Members
79 85
80 public void Initialise(IConfigSource source) 86 public void Initialise(IConfigSource source)
@@ -91,6 +97,7 @@ namespace OpenSim.Region.ClientStack.Linden
91 { 97 {
92 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 98 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
93 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps; 99 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
100 m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate;
94 m_scene = null; 101 m_scene = null;
95 } 102 }
96 103
@@ -101,6 +108,7 @@ namespace OpenSim.Region.ClientStack.Linden
101 108
102 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 109 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
103 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps; 110 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
111 m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate;
104 112
105 if (m_workerThreads == null) 113 if (m_workerThreads == null)
106 { 114 {
@@ -118,6 +126,56 @@ namespace OpenSim.Region.ClientStack.Linden
118 } 126 }
119 } 127 }
120 } 128 }
129 private int ExtractImageThrottle(byte[] pthrottles)
130 {
131
132 byte[] adjData;
133 int pos = 0;
134
135 if (!BitConverter.IsLittleEndian)
136 {
137 byte[] newData = new byte[7 * 4];
138 Buffer.BlockCopy(pthrottles, 0, newData, 0, 7 * 4);
139
140 for (int i = 0; i < 7; i++)
141 Array.Reverse(newData, i * 4, 4);
142
143 adjData = newData;
144 }
145 else
146 {
147 adjData = pthrottles;
148 }
149
150 // 0.125f converts from bits to bytes
151 //int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
152 //pos += 4;
153 // int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
154 //pos += 4;
155 // int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
156 // pos += 4;
157 // int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
158 // pos += 4;
159 // int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
160 // pos += 4;
161 pos = pos + 20;
162 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); //pos += 4;
163 //int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
164 return texture;
165 }
166
167 // Now we know when the throttle is changed by the client in the case of a root agent or by a neighbor region in the case of a child agent.
168 public void ThrottleUpdate(ScenePresence p)
169 {
170 byte[] throttles = p.ControllingClient.GetThrottlesPacked(1);
171 UUID user = p.UUID;
172 int imagethrottle = ExtractImageThrottle(throttles);
173 PollServiceTextureEventArgs args;
174 if (m_pollservices.TryGetValue(user,out args))
175 {
176 args.UpdateThrottle(imagethrottle);
177 }
178 }
121 179
122 public void PostInitialise() 180 public void PostInitialise()
123 { 181 {
@@ -145,20 +203,25 @@ namespace OpenSim.Region.ClientStack.Linden
145 { 203 {
146 private List<Hashtable> requests = 204 private List<Hashtable> requests =
147 new List<Hashtable>(); 205 new List<Hashtable>();
148 private Dictionary<UUID, Hashtable> responses = 206 private Dictionary<UUID, aPollResponse> responses =
149 new Dictionary<UUID, Hashtable>(); 207 new Dictionary<UUID, aPollResponse>();
150 208
151 private Scene m_scene; 209 private Scene m_scene;
152 210 private CapsDataThrottler m_throttler = new CapsDataThrottler(100000, 1400000,10000);
153 public PollServiceTextureEventArgs(UUID pId, Scene scene) : 211 public PollServiceTextureEventArgs(UUID pId, Scene scene) :
154 base(null, null, null, null, pId, int.MaxValue) 212 base(null, null, null, null, pId, int.MaxValue)
155 { 213 {
156 m_scene = scene; 214 m_scene = scene;
157 215 // x is request id, y is userid
158 HasEvents = (x, y) => 216 HasEvents = (x, y) =>
159 { 217 {
160 lock (responses) 218 lock (responses)
161 return responses.ContainsKey(x); 219 {
220 bool ret = m_throttler.hasEvents(x, responses);
221 m_throttler.ProcessTime();
222 return ret;
223
224 }
162 }; 225 };
163 GetEvents = (x, y) => 226 GetEvents = (x, y) =>
164 { 227 {
@@ -166,7 +229,7 @@ namespace OpenSim.Region.ClientStack.Linden
166 { 229 {
167 try 230 try
168 { 231 {
169 return responses[x]; 232 return responses[x].response;
170 } 233 }
171 finally 234 finally
172 { 235 {
@@ -174,14 +237,14 @@ namespace OpenSim.Region.ClientStack.Linden
174 } 237 }
175 } 238 }
176 }; 239 };
177 240 // x is request id, y is request data hashtable
178 Request = (x, y) => 241 Request = (x, y) =>
179 { 242 {
180 aPollRequest reqinfo = new aPollRequest(); 243 aPollRequest reqinfo = new aPollRequest();
181 reqinfo.thepoll = this; 244 reqinfo.thepoll = this;
182 reqinfo.reqID = x; 245 reqinfo.reqID = x;
183 reqinfo.request = y; 246 reqinfo.request = y;
184 247
185 m_queue.Enqueue(reqinfo); 248 m_queue.Enqueue(reqinfo);
186 }; 249 };
187 250
@@ -223,16 +286,29 @@ namespace OpenSim.Region.ClientStack.Linden
223 response["content_type"] = "text/plain"; 286 response["content_type"] = "text/plain";
224 response["keepalive"] = false; 287 response["keepalive"] = false;
225 response["reusecontext"] = false; 288 response["reusecontext"] = false;
226 289
227 lock (responses) 290 lock (responses)
228 responses[requestID] = response; 291 responses[requestID] = new aPollResponse() {bytes = 0, response = response};
229 292
230 return; 293 return;
231 } 294 }
232 295
233 response = m_getTextureHandler.Handle(requestinfo.request); 296 response = m_getTextureHandler.Handle(requestinfo.request);
234 lock (responses) 297 lock (responses)
235 responses[requestID] = response; 298 {
299 responses[requestID] = new aPollResponse()
300 {
301 bytes = (int) response["int_bytes"],
302 response = response
303 };
304
305 }
306 m_throttler.ProcessTime();
307 }
308
309 internal void UpdateThrottle(int pimagethrottle)
310 {
311 m_throttler.ThrottleBytes = pimagethrottle;
236 } 312 }
237 } 313 }
238 314
@@ -257,19 +333,23 @@ namespace OpenSim.Region.ClientStack.Linden
257 protocol = "https"; 333 protocol = "https";
258 } 334 }
259 caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); 335 caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
260 336 m_pollservices.Add(agentID, args);
261 m_capsDict[agentID] = capUrl; 337 m_capsDict[agentID] = capUrl;
262 } 338 }
263 339
264 private void DeregisterCaps(UUID agentID, Caps caps) 340 private void DeregisterCaps(UUID agentID, Caps caps)
265 { 341 {
266 string capUrl; 342 string capUrl;
267 343 PollServiceTextureEventArgs args;
268 if (m_capsDict.TryGetValue(agentID, out capUrl)) 344 if (m_capsDict.TryGetValue(agentID, out capUrl))
269 { 345 {
270 MainServer.Instance.RemoveHTTPHandler("", capUrl); 346 MainServer.Instance.RemoveHTTPHandler("", capUrl);
271 m_capsDict.Remove(agentID); 347 m_capsDict.Remove(agentID);
272 } 348 }
349 if (m_pollservices.TryGetValue(agentID, out args))
350 {
351 m_pollservices.Remove(agentID);
352 }
273 } 353 }
274 354
275 private void DoTextureRequests() 355 private void DoTextureRequests()
@@ -281,5 +361,81 @@ namespace OpenSim.Region.ClientStack.Linden
281 poolreq.thepoll.Process(poolreq); 361 poolreq.thepoll.Process(poolreq);
282 } 362 }
283 } 363 }
364 internal sealed class CapsDataThrottler
365 {
366
367 private volatile int currenttime = 0;
368 private volatile int lastTimeElapsed = 0;
369 private volatile int BytesSent = 0;
370 private int oversizedImages = 0;
371 public CapsDataThrottler(int pBytes, int max, int min)
372 {
373 ThrottleBytes = pBytes;
374 lastTimeElapsed = Util.EnvironmentTickCount();
375 }
376 public bool hasEvents(UUID key, Dictionary<UUID, GetTextureModule.aPollResponse> responses)
377 {
378 PassTime();
379 // Note, this is called IN LOCK
380 bool haskey = responses.ContainsKey(key);
381 if (!haskey)
382 {
383 return false;
384 }
385 GetTextureModule.aPollResponse response;
386 if (responses.TryGetValue(key, out response))
387 {
388
389 // Normal
390 if (BytesSent + response.bytes <= ThrottleBytes)
391 {
392 BytesSent += response.bytes;
393 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + 1000, unlockyn = false };
394 //m_actions.Add(timeBasedAction);
395 return true;
396 }
397 // Big textures
398 else if (response.bytes > ThrottleBytes && oversizedImages <= ((ThrottleBytes % 50000) + 1))
399 {
400 Interlocked.Increment(ref oversizedImages);
401 BytesSent += response.bytes;
402 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + (((response.bytes % ThrottleBytes)+1)*1000) , unlockyn = false };
403 //m_actions.Add(timeBasedAction);
404 return true;
405 }
406 else
407 {
408 return false;
409 }
410 }
411
412 return haskey;
413 }
414 public void ProcessTime()
415 {
416 PassTime();
417 }
418
419
420 private void PassTime()
421 {
422 currenttime = Util.EnvironmentTickCount();
423 int timeElapsed = Util.EnvironmentTickCountSubtract(currenttime, lastTimeElapsed);
424 //processTimeBasedActions(responses);
425 if (Util.EnvironmentTickCountSubtract(currenttime, timeElapsed) >= 1000)
426 {
427 lastTimeElapsed = Util.EnvironmentTickCount();
428 BytesSent -= ThrottleBytes;
429 if (BytesSent < 0) BytesSent = 0;
430 if (BytesSent < ThrottleBytes)
431 {
432 oversizedImages = 0;
433 }
434 }
435 }
436 public int ThrottleBytes;
437 }
284 } 438 }
439
440
285} 441}