aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorteravus2012-11-09 23:55:30 -0500
committerteravus2012-11-09 23:55:30 -0500
commitcda127e30f0049cda21137363e4d759fd7fd4959 (patch)
tree426814e4aa4c63eb5bd8c2f920bfa9aedeecd930
parentThis implements the Caps throttler. After some testing, the system seemed ... (diff)
downloadopensim-SC-cda127e30f0049cda21137363e4d759fd7fd4959.zip
opensim-SC-cda127e30f0049cda21137363e4d759fd7fd4959.tar.gz
opensim-SC-cda127e30f0049cda21137363e4d759fd7fd4959.tar.bz2
opensim-SC-cda127e30f0049cda21137363e4d759fd7fd4959.tar.xz
* Prep work switching the GetMeshModule over to a poll service.
* This still has the image throttler in it.. as is... so it's not suitable for live yet.... The throttler keeps track of the task throttle but doesn't balance the UDP throttle yet.
-rw-r--r--OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs131
-rw-r--r--OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs3
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs362
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs121
4 files changed, 538 insertions, 79 deletions
diff --git a/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs b/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs
index 720640e..d29bed9 100644
--- a/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs
+++ b/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs
@@ -45,16 +45,53 @@ namespace OpenSim.Capabilities.Handlers
45{ 45{
46 public class GetMeshHandler 46 public class GetMeshHandler
47 { 47 {
48// private static readonly ILog m_log = 48 private static readonly ILog m_log =
49// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 49 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50 50
51 private IAssetService m_assetService; 51 private IAssetService m_assetService;
52 52
53 public const string DefaultFormat = "vnd.ll.mesh";
54
53 public GetMeshHandler(IAssetService assService) 55 public GetMeshHandler(IAssetService assService)
54 { 56 {
55 m_assetService = assService; 57 m_assetService = assService;
56 } 58 }
59 public Hashtable Handle(Hashtable request)
60 {
61 Hashtable ret = new Hashtable();
62 ret["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound;
63 ret["content_type"] = "text/plain";
64 ret["keepalive"] = false;
65 ret["reusecontext"] = false;
66 ret["int_bytes"] = 0;
67 string MeshStr = (string)request["mesh_id"];
68
69
70 //m_log.DebugFormat("[GETMESH]: called {0}", MeshStr);
71
72 if (m_assetService == null)
73 {
74 m_log.Error("[GETMESH]: Cannot fetch mesh " + MeshStr + " without an asset service");
75 }
76
77 UUID meshID;
78 if (!String.IsNullOrEmpty(MeshStr) && UUID.TryParse(MeshStr, out meshID))
79 {
80 // m_log.DebugFormat("[GETMESH]: Received request for mesh id {0}", meshID);
57 81
82
83 ret = ProcessGetMesh(request, UUID.Zero, null);
84
85
86 }
87 else
88 {
89 m_log.Warn("[GETMESH]: Failed to parse a mesh_id from GetMesh request: " + (string)request["uri"]);
90 }
91
92
93 return ret;
94 }
58 public Hashtable ProcessGetMesh(Hashtable request, UUID AgentId, Caps cap) 95 public Hashtable ProcessGetMesh(Hashtable request, UUID AgentId, Caps cap)
59 { 96 {
60 Hashtable responsedata = new Hashtable(); 97 Hashtable responsedata = new Hashtable();
@@ -86,9 +123,78 @@ namespace OpenSim.Capabilities.Handlers
86 { 123 {
87 if (mesh.Type == (SByte)AssetType.Mesh) 124 if (mesh.Type == (SByte)AssetType.Mesh)
88 { 125 {
89 responsedata["str_response_string"] = Convert.ToBase64String(mesh.Data); 126
90 responsedata["content_type"] = "application/vnd.ll.mesh"; 127 Hashtable headers = new Hashtable();
91 responsedata["int_response_code"] = 200; 128 responsedata["headers"] = headers;
129
130 string range = String.Empty;
131
132 if (((Hashtable)request["headers"])["range"] != null)
133 range = (string)((Hashtable)request["headers"])["range"];
134
135 else if (((Hashtable)request["headers"])["Range"] != null)
136 range = (string)((Hashtable)request["headers"])["Range"];
137
138 if (!String.IsNullOrEmpty(range)) // Mesh Asset LOD // Physics
139 {
140 // Range request
141 int start, end;
142 if (TryParseRange(range, out start, out end))
143 {
144 // Before clamping start make sure we can satisfy it in order to avoid
145 // sending back the last byte instead of an error status
146 if (start >= mesh.Data.Length)
147 {
148 responsedata["int_response_code"] = 404; //501; //410; //404;
149 responsedata["content_type"] = "text/plain";
150 responsedata["keepalive"] = false;
151 responsedata["str_response_string"] = "This range doesnt exist.";
152 return responsedata;
153 }
154 else
155 {
156 end = Utils.Clamp(end, 0, mesh.Data.Length - 1);
157 start = Utils.Clamp(start, 0, end);
158 int len = end - start + 1;
159
160 //m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID);
161
162
163
164 if (start == 0 && len == mesh.Data.Length) // well redudante maybe
165 {
166 responsedata["int_response_code"] = (int) System.Net.HttpStatusCode.OK;
167 responsedata["bin_response_data"] = mesh.Data;
168 responsedata["int_bytes"] = mesh.Data.Length;
169 }
170 else
171 {
172 responsedata["int_response_code"] =
173 (int) System.Net.HttpStatusCode.PartialContent;
174 headers["Content-Range"] = String.Format("bytes {0}-{1}/{2}", start, end,
175 mesh.Data.Length);
176
177 byte[] d = new byte[len];
178 Array.Copy(mesh.Data, start, d, 0, len);
179 responsedata["bin_response_data"] = d;
180 responsedata["int_bytes"] = len;
181 }
182 }
183 }
184 else
185 {
186 m_log.Warn("[GETMESH]: Failed to parse a range from GetMesh request, sending full asset: " + (string)request["uri"]);
187 responsedata["str_response_string"] = Convert.ToBase64String(mesh.Data);
188 responsedata["content_type"] = "application/vnd.ll.mesh";
189 responsedata["int_response_code"] = 200;
190 }
191 }
192 else
193 {
194 responsedata["str_response_string"] = Convert.ToBase64String(mesh.Data);
195 responsedata["content_type"] = "application/vnd.ll.mesh";
196 responsedata["int_response_code"] = 200;
197 }
92 } 198 }
93 // Optionally add additional mesh types here 199 // Optionally add additional mesh types here
94 else 200 else
@@ -112,5 +218,20 @@ namespace OpenSim.Capabilities.Handlers
112 218
113 return responsedata; 219 return responsedata;
114 } 220 }
221 private bool TryParseRange(string header, out int start, out int end)
222 {
223 if (header.StartsWith("bytes="))
224 {
225 string[] rangeValues = header.Substring(6).Split('-');
226 if (rangeValues.Length == 2)
227 {
228 if (Int32.TryParse(rangeValues[0], out start) && Int32.TryParse(rangeValues[1], out end))
229 return true;
230 }
231 }
232
233 start = end = 0;
234 return false;
235 }
115 } 236 }
116} \ No newline at end of file 237} \ No newline at end of file
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs
index d0a37d0..c19ac32 100644
--- a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs
+++ b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs
@@ -53,7 +53,8 @@ namespace OpenSim.Framework.Servers.HttpServer
53 Normal = 0, 53 Normal = 0,
54 LslHttp = 1, 54 LslHttp = 1,
55 Inventory = 2, 55 Inventory = 2,
56 Texture = 3 56 Texture = 3,
57 Mesh = 4
57 } 58 }
58 59
59 public PollServiceEventArgs( 60 public PollServiceEventArgs(
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
index 0d7b1fc..8deff81 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
@@ -27,11 +27,14 @@
27 27
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic;
30using System.Collections.Specialized; 31using System.Collections.Specialized;
31using System.Reflection; 32using System.Reflection;
32using System.IO; 33using System.IO;
34using System.Threading;
33using System.Web; 35using System.Web;
34using Mono.Addins; 36using Mono.Addins;
37using OpenSim.Framework.Monitoring;
35using log4net; 38using log4net;
36using Nini.Config; 39using Nini.Config;
37using OpenMetaverse; 40using OpenMetaverse;
@@ -57,8 +60,42 @@ namespace OpenSim.Region.ClientStack.Linden
57 private IAssetService m_AssetService; 60 private IAssetService m_AssetService;
58 private bool m_Enabled = true; 61 private bool m_Enabled = true;
59 private string m_URL; 62 private string m_URL;
63 struct aPollRequest
64 {
65 public PollServiceMeshEventArgs thepoll;
66 public UUID reqID;
67 public Hashtable request;
68 }
69
70 public class aPollResponse
71 {
72 public Hashtable response;
73 public int bytes;
74 }
75
76
77 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
78
79 private static GetMeshHandler m_getMeshHandler;
80
81 private IAssetService m_assetService = null;
82
83 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
84 private static Thread[] m_workerThreads = null;
85
86 private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue =
87 new OpenMetaverse.BlockingQueue<aPollRequest>();
88
89 private Dictionary<UUID, PollServiceMeshEventArgs> m_pollservices = new Dictionary<UUID, PollServiceMeshEventArgs>();
60 90
61 #region IRegionModuleBase Members 91 #region ISharedRegionModule Members
92
93 ~GetMeshModule()
94 {
95 foreach (Thread t in m_workerThreads)
96 Watchdog.AbortThread(t.ManagedThreadId);
97
98 }
62 99
63 public Type ReplaceableInterface 100 public Type ReplaceableInterface
64 { 101 {
@@ -83,6 +120,8 @@ namespace OpenSim.Region.ClientStack.Linden
83 return; 120 return;
84 121
85 m_scene = pScene; 122 m_scene = pScene;
123
124 m_assetService = pScene.AssetService;
86 } 125 }
87 126
88 public void RemoveRegion(Scene scene) 127 public void RemoveRegion(Scene scene)
@@ -91,6 +130,9 @@ namespace OpenSim.Region.ClientStack.Linden
91 return; 130 return;
92 131
93 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 132 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
133 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
134 m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate;
135
94 m_scene = null; 136 m_scene = null;
95 } 137 }
96 138
@@ -101,6 +143,27 @@ namespace OpenSim.Region.ClientStack.Linden
101 143
102 m_AssetService = m_scene.RequestModuleInterface<IAssetService>(); 144 m_AssetService = m_scene.RequestModuleInterface<IAssetService>();
103 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 145 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
146 // We'll reuse the same handler for all requests.
147 m_getMeshHandler = new GetMeshHandler(m_assetService);
148 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
149 m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate;
150
151 if (m_workerThreads == null)
152 {
153 m_workerThreads = new Thread[2];
154
155 for (uint i = 0; i < 2; i++)
156 {
157 m_workerThreads[i] = Watchdog.StartThread(DoMeshRequests,
158 String.Format("MeshWorkerThread{0}", i),
159 ThreadPriority.Normal,
160 false,
161 false,
162 null,
163 int.MaxValue);
164 }
165 }
166
104 } 167 }
105 168
106 169
@@ -110,25 +173,209 @@ namespace OpenSim.Region.ClientStack.Linden
110 173
111 #endregion 174 #endregion
112 175
176 private void DoMeshRequests()
177 {
178 while (true)
179 {
180 aPollRequest poolreq = m_queue.Dequeue();
181
182 poolreq.thepoll.Process(poolreq);
183 }
184 }
185
186 // 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.
187 public void ThrottleUpdate(ScenePresence p)
188 {
189 byte[] throttles = p.ControllingClient.GetThrottlesPacked(1);
190 UUID user = p.UUID;
191 int imagethrottle = ExtractTaskThrottle(throttles);
192 PollServiceMeshEventArgs args;
193 if (m_pollservices.TryGetValue(user, out args))
194 {
195 args.UpdateThrottle(imagethrottle);
196 }
197 }
198
199 private int ExtractTaskThrottle(byte[] pthrottles)
200 {
201
202 byte[] adjData;
203 int pos = 0;
204
205 if (!BitConverter.IsLittleEndian)
206 {
207 byte[] newData = new byte[7 * 4];
208 Buffer.BlockCopy(pthrottles, 0, newData, 0, 7 * 4);
209
210 for (int i = 0; i < 7; i++)
211 Array.Reverse(newData, i * 4, 4);
212
213 adjData = newData;
214 }
215 else
216 {
217 adjData = pthrottles;
218 }
219
220 // 0.125f converts from bits to bytes
221 //int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
222 //pos += 4;
223 // int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
224 //pos += 4;
225 // int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
226 // pos += 4;
227 // int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
228 // pos += 4;
229 pos += 16;
230 int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
231 // pos += 4;
232 //int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); //pos += 4;
233 //int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
234 return task;
235 }
236
237 private class PollServiceMeshEventArgs : PollServiceEventArgs
238 {
239 private List<Hashtable> requests =
240 new List<Hashtable>();
241 private Dictionary<UUID, aPollResponse> responses =
242 new Dictionary<UUID, aPollResponse>();
243
244 private Scene m_scene;
245 private CapsDataThrottler m_throttler = new CapsDataThrottler(100000, 1400000, 10000);
246 public PollServiceMeshEventArgs(UUID pId, Scene scene) :
247 base(null, null, null, null, pId, int.MaxValue)
248 {
249 m_scene = scene;
250 // x is request id, y is userid
251 HasEvents = (x, y) =>
252 {
253 lock (responses)
254 {
255 bool ret = m_throttler.hasEvents(x, responses);
256 m_throttler.ProcessTime();
257 return ret;
258
259 }
260 };
261 GetEvents = (x, y) =>
262 {
263 lock (responses)
264 {
265 try
266 {
267 return responses[x].response;
268 }
269 finally
270 {
271 responses.Remove(x);
272 }
273 }
274 };
275 // x is request id, y is request data hashtable
276 Request = (x, y) =>
277 {
278 aPollRequest reqinfo = new aPollRequest();
279 reqinfo.thepoll = this;
280 reqinfo.reqID = x;
281 reqinfo.request = y;
282
283 m_queue.Enqueue(reqinfo);
284 };
285
286 // this should never happen except possible on shutdown
287 NoEvents = (x, y) =>
288 {
289 /*
290 lock (requests)
291 {
292 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
293 requests.Remove(request);
294 }
295 */
296 Hashtable response = new Hashtable();
297
298 response["int_response_code"] = 500;
299 response["str_response_string"] = "Script timeout";
300 response["content_type"] = "text/plain";
301 response["keepalive"] = false;
302 response["reusecontext"] = false;
303
304 return response;
305 };
306 }
307
308 public void Process(aPollRequest requestinfo)
309 {
310 Hashtable response;
311
312 UUID requestID = requestinfo.reqID;
313
314 // If the avatar is gone, don't bother to get the texture
315 if (m_scene.GetScenePresence(Id) == null)
316 {
317 response = new Hashtable();
318
319 response["int_response_code"] = 500;
320 response["str_response_string"] = "Script timeout";
321 response["content_type"] = "text/plain";
322 response["keepalive"] = false;
323 response["reusecontext"] = false;
324
325 lock (responses)
326 responses[requestID] = new aPollResponse() { bytes = 0, response = response };
327
328 return;
329 }
330
331 response = m_getMeshHandler.Handle(requestinfo.request);
332 lock (responses)
333 {
334 responses[requestID] = new aPollResponse()
335 {
336 bytes = (int)response["int_bytes"],
337 response = response
338 };
339
340 }
341 m_throttler.ProcessTime();
342 }
343
344 internal void UpdateThrottle(int pimagethrottle)
345 {
346 m_throttler.ThrottleBytes = pimagethrottle;
347 }
348 }
113 349
114 public void RegisterCaps(UUID agentID, Caps caps) 350 public void RegisterCaps(UUID agentID, Caps caps)
115 { 351 {
116// UUID capID = UUID.Random(); 352// UUID capID = UUID.Random();
117
118 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture));
119 if (m_URL == "localhost") 353 if (m_URL == "localhost")
120 { 354 {
121// m_log.DebugFormat("[GETMESH]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); 355 string capUrl = "/CAPS/" + UUID.Random() + "/";
122 GetMeshHandler gmeshHandler = new GetMeshHandler(m_AssetService); 356
123 IRequestHandler reqHandler 357 // Register this as a poll service
124 = new RestHTTPHandler( 358 PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(agentID, m_scene);
125 "GET", 359
126 "/CAPS/" + UUID.Random(), 360 args.Type = PollServiceEventArgs.EventType.Mesh;
127 httpMethod => gmeshHandler.ProcessGetMesh(httpMethod, UUID.Zero, null), 361 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
128 "GetMesh", 362
129 agentID.ToString()); 363 string hostName = m_scene.RegionInfo.ExternalHostName;
364 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
365 string protocol = "http";
130 366
131 caps.RegisterHandler("GetMesh", reqHandler); 367 if (MainServer.Instance.UseSSL)
368 {
369 hostName = MainServer.Instance.SSLCommonName;
370 port = MainServer.Instance.SSLPort;
371 protocol = "https";
372 }
373 caps.RegisterHandler("GetMesh", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
374 m_pollservices.Add(agentID, args);
375 m_capsDict[agentID] = capUrl;
376
377
378
132 } 379 }
133 else 380 else
134 { 381 {
@@ -136,6 +383,95 @@ namespace OpenSim.Region.ClientStack.Linden
136 caps.RegisterHandler("GetMesh", m_URL); 383 caps.RegisterHandler("GetMesh", m_URL);
137 } 384 }
138 } 385 }
386 private void DeregisterCaps(UUID agentID, Caps caps)
387 {
388 string capUrl;
389 PollServiceMeshEventArgs args;
390 if (m_capsDict.TryGetValue(agentID, out capUrl))
391 {
392 MainServer.Instance.RemoveHTTPHandler("", capUrl);
393 m_capsDict.Remove(agentID);
394 }
395 if (m_pollservices.TryGetValue(agentID, out args))
396 {
397 m_pollservices.Remove(agentID);
398 }
399 }
400
401 internal sealed class CapsDataThrottler
402 {
403
404 private volatile int currenttime = 0;
405 private volatile int lastTimeElapsed = 0;
406 private volatile int BytesSent = 0;
407 private int oversizedImages = 0;
408 public CapsDataThrottler(int pBytes, int max, int min)
409 {
410 ThrottleBytes = pBytes;
411 lastTimeElapsed = Util.EnvironmentTickCount();
412 }
413 public bool hasEvents(UUID key, Dictionary<UUID, aPollResponse> responses)
414 {
415 PassTime();
416 // Note, this is called IN LOCK
417 bool haskey = responses.ContainsKey(key);
418 if (!haskey)
419 {
420 return false;
421 }
422 aPollResponse response;
423 if (responses.TryGetValue(key, out response))
424 {
425
426 // Normal
427 if (BytesSent + response.bytes <= ThrottleBytes)
428 {
429 BytesSent += response.bytes;
430 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + 1000, unlockyn = false };
431 //m_actions.Add(timeBasedAction);
432 return true;
433 }
434 // Big textures
435 else if (response.bytes > ThrottleBytes && oversizedImages <= ((ThrottleBytes % 50000) + 1))
436 {
437 Interlocked.Increment(ref oversizedImages);
438 BytesSent += response.bytes;
439 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + (((response.bytes % ThrottleBytes)+1)*1000) , unlockyn = false };
440 //m_actions.Add(timeBasedAction);
441 return true;
442 }
443 else
444 {
445 return false;
446 }
447 }
448
449 return haskey;
450 }
451 public void ProcessTime()
452 {
453 PassTime();
454 }
455
456
457 private void PassTime()
458 {
459 currenttime = Util.EnvironmentTickCount();
460 int timeElapsed = Util.EnvironmentTickCountSubtract(currenttime, lastTimeElapsed);
461 //processTimeBasedActions(responses);
462 if (Util.EnvironmentTickCountSubtract(currenttime, timeElapsed) >= 1000)
463 {
464 lastTimeElapsed = Util.EnvironmentTickCount();
465 BytesSent -= ThrottleBytes;
466 if (BytesSent < 0) BytesSent = 0;
467 if (BytesSent < ThrottleBytes)
468 {
469 oversizedImages = 0;
470 }
471 }
472 }
473 public int ThrottleBytes;
474 }
139 475
140 } 476 }
141} 477}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
index 8cba6c8..c8c709a 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
@@ -364,80 +364,81 @@ namespace OpenSim.Region.ClientStack.Linden
364 poolreq.thepoll.Process(poolreq); 364 poolreq.thepoll.Process(poolreq);
365 } 365 }
366 } 366 }
367 } 367 internal sealed class CapsDataThrottler
368
369 internal sealed class CapsDataThrottler
370 {
371
372 private volatile int currenttime = 0;
373 private volatile int lastTimeElapsed = 0;
374 private volatile int BytesSent = 0;
375 private int oversizedImages = 0;
376 public CapsDataThrottler(int pBytes, int max, int min)
377 {
378 ThrottleBytes = pBytes;
379 lastTimeElapsed = Util.EnvironmentTickCount();
380 }
381 public bool hasEvents(UUID key, Dictionary<UUID, GetTextureModule.aPollResponse> responses)
382 { 368 {
383 PassTime(); 369
384 // Note, this is called IN LOCK 370 private volatile int currenttime = 0;
385 bool haskey = responses.ContainsKey(key); 371 private volatile int lastTimeElapsed = 0;
386 if (!haskey) 372 private volatile int BytesSent = 0;
373 private int oversizedImages = 0;
374 public CapsDataThrottler(int pBytes, int max, int min)
387 { 375 {
388 return false; 376 ThrottleBytes = pBytes;
377 lastTimeElapsed = Util.EnvironmentTickCount();
389 } 378 }
390 GetTextureModule.aPollResponse response; 379 public bool hasEvents(UUID key, Dictionary<UUID, GetTextureModule.aPollResponse> responses)
391 if (responses.TryGetValue(key,out response))
392 { 380 {
393 381 PassTime();
394 // Normal 382 // Note, this is called IN LOCK
395 if (BytesSent + response.bytes <= ThrottleBytes) 383 bool haskey = responses.ContainsKey(key);
384 if (!haskey)
396 { 385 {
397 BytesSent += response.bytes; 386 return false;
398 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + 1000, unlockyn = false };
399 //m_actions.Add(timeBasedAction);
400 return true;
401 }
402 // Big textures
403 else if (response.bytes > ThrottleBytes && oversizedImages <= ((ThrottleBytes%50000) + 1))
404 {
405 Interlocked.Increment(ref oversizedImages);
406 BytesSent += response.bytes;
407 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + (((response.bytes % ThrottleBytes)+1)*1000) , unlockyn = false };
408 //m_actions.Add(timeBasedAction);
409 return true;
410 } 387 }
411 else 388 GetTextureModule.aPollResponse response;
389 if (responses.TryGetValue(key, out response))
412 { 390 {
413 return false; 391
392 // Normal
393 if (BytesSent + response.bytes <= ThrottleBytes)
394 {
395 BytesSent += response.bytes;
396 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + 1000, unlockyn = false };
397 //m_actions.Add(timeBasedAction);
398 return true;
399 }
400 // Big textures
401 else if (response.bytes > ThrottleBytes && oversizedImages <= ((ThrottleBytes % 50000) + 1))
402 {
403 Interlocked.Increment(ref oversizedImages);
404 BytesSent += response.bytes;
405 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + (((response.bytes % ThrottleBytes)+1)*1000) , unlockyn = false };
406 //m_actions.Add(timeBasedAction);
407 return true;
408 }
409 else
410 {
411 return false;
412 }
414 } 413 }
414
415 return haskey;
416 }
417 public void ProcessTime()
418 {
419 PassTime();
415 } 420 }
416 421
417 return haskey; 422
418 } 423 private void PassTime()
419 public void ProcessTime()
420 {
421 PassTime();
422 }
423
424
425 private void PassTime()
426 {
427 currenttime = Util.EnvironmentTickCount();
428 int timeElapsed = Util.EnvironmentTickCountSubtract(currenttime, lastTimeElapsed);
429 //processTimeBasedActions(responses);
430 if (Util.EnvironmentTickCountSubtract(currenttime, timeElapsed) >= 1000)
431 { 424 {
432 lastTimeElapsed = Util.EnvironmentTickCount(); 425 currenttime = Util.EnvironmentTickCount();
433 BytesSent -= ThrottleBytes; 426 int timeElapsed = Util.EnvironmentTickCountSubtract(currenttime, lastTimeElapsed);
434 if (BytesSent < 0) BytesSent = 0; 427 //processTimeBasedActions(responses);
435 if (BytesSent < ThrottleBytes) 428 if (Util.EnvironmentTickCountSubtract(currenttime, timeElapsed) >= 1000)
436 { 429 {
437 oversizedImages = 0; 430 lastTimeElapsed = Util.EnvironmentTickCount();
431 BytesSent -= ThrottleBytes;
432 if (BytesSent < 0) BytesSent = 0;
433 if (BytesSent < ThrottleBytes)
434 {
435 oversizedImages = 0;
436 }
438 } 437 }
439 } 438 }
439 public int ThrottleBytes;
440 } 440 }
441 public int ThrottleBytes;
442 } 441 }
442
443
443} 444}