diff options
author | UbitUmarov | 2015-09-01 14:54:35 +0100 |
---|---|---|
committer | UbitUmarov | 2015-09-01 14:54:35 +0100 |
commit | 371c9dd2af01a2e7422ec901ee1f80757284a78c (patch) | |
tree | 058d2a513cacb12efcce0c0df0ae14ad135dbfe2 /OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs | |
parent | remove lixo (diff) | |
parent | dont change camera on crossings (diff) | |
download | opensim-SC-371c9dd2af01a2e7422ec901ee1f80757284a78c.zip opensim-SC-371c9dd2af01a2e7422ec901ee1f80757284a78c.tar.gz opensim-SC-371c9dd2af01a2e7422ec901ee1f80757284a78c.tar.bz2 opensim-SC-371c9dd2af01a2e7422ec901ee1f80757284a78c.tar.xz |
bad merge?
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs | 410 |
1 files changed, 410 insertions, 0 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs index f57d857..91efe8a 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs | |||
@@ -27,11 +27,14 @@ | |||
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections; | 29 | using System.Collections; |
30 | using System.Collections.Generic; | ||
30 | using System.Collections.Specialized; | 31 | using System.Collections.Specialized; |
31 | using System.Reflection; | 32 | using System.Reflection; |
32 | using System.IO; | 33 | using System.IO; |
34 | using System.Threading; | ||
33 | using System.Web; | 35 | using System.Web; |
34 | using Mono.Addins; | 36 | using Mono.Addins; |
37 | using OpenSim.Framework.Monitoring; | ||
35 | using log4net; | 38 | using log4net; |
36 | using Nini.Config; | 39 | using Nini.Config; |
37 | using OpenMetaverse; | 40 | using OpenMetaverse; |
@@ -57,12 +60,51 @@ 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 | <<<<<<< HEAD | ||
60 | private string m_URL2; | 64 | private string m_URL2; |
61 | private string m_RedirectURL = null; | 65 | private string m_RedirectURL = null; |
62 | private string m_RedirectURL2 = null; | 66 | private string m_RedirectURL2 = null; |
67 | ======= | ||
68 | |||
69 | struct aPollRequest | ||
70 | { | ||
71 | public PollServiceMeshEventArgs thepoll; | ||
72 | public UUID reqID; | ||
73 | public Hashtable request; | ||
74 | } | ||
75 | |||
76 | public class aPollResponse | ||
77 | { | ||
78 | public Hashtable response; | ||
79 | public int bytes; | ||
80 | public int lod; | ||
81 | } | ||
82 | |||
83 | |||
84 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
85 | |||
86 | private static GetMeshHandler m_getMeshHandler; | ||
87 | |||
88 | private IAssetService m_assetService = null; | ||
89 | |||
90 | private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>(); | ||
91 | private static Thread[] m_workerThreads = null; | ||
92 | |||
93 | private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue = | ||
94 | new OpenMetaverse.BlockingQueue<aPollRequest>(); | ||
95 | |||
96 | private Dictionary<UUID, PollServiceMeshEventArgs> m_pollservices = new Dictionary<UUID, PollServiceMeshEventArgs>(); | ||
97 | >>>>>>> avn/ubitvar | ||
63 | 98 | ||
64 | #region Region Module interfaceBase Members | 99 | #region Region Module interfaceBase Members |
65 | 100 | ||
101 | ~GetMeshModule() | ||
102 | { | ||
103 | foreach (Thread t in m_workerThreads) | ||
104 | Watchdog.AbortThread(t.ManagedThreadId); | ||
105 | |||
106 | } | ||
107 | |||
66 | public Type ReplaceableInterface | 108 | public Type ReplaceableInterface |
67 | { | 109 | { |
68 | get { return null; } | 110 | get { return null; } |
@@ -87,8 +129,12 @@ namespace OpenSim.Region.ClientStack.Linden | |||
87 | if (m_URL2 != string.Empty) | 129 | if (m_URL2 != string.Empty) |
88 | { | 130 | { |
89 | m_Enabled = true; | 131 | m_Enabled = true; |
132 | <<<<<<< HEAD | ||
90 | m_RedirectURL2 = config.GetString("GetMesh2RedirectURL"); | 133 | m_RedirectURL2 = config.GetString("GetMesh2RedirectURL"); |
91 | } | 134 | } |
135 | ======= | ||
136 | |||
137 | >>>>>>> avn/ubitvar | ||
92 | } | 138 | } |
93 | 139 | ||
94 | public void AddRegion(Scene pScene) | 140 | public void AddRegion(Scene pScene) |
@@ -97,6 +143,8 @@ namespace OpenSim.Region.ClientStack.Linden | |||
97 | return; | 143 | return; |
98 | 144 | ||
99 | m_scene = pScene; | 145 | m_scene = pScene; |
146 | |||
147 | m_assetService = pScene.AssetService; | ||
100 | } | 148 | } |
101 | 149 | ||
102 | public void RemoveRegion(Scene scene) | 150 | public void RemoveRegion(Scene scene) |
@@ -105,6 +153,9 @@ namespace OpenSim.Region.ClientStack.Linden | |||
105 | return; | 153 | return; |
106 | 154 | ||
107 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | 155 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; |
156 | m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps; | ||
157 | m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate; | ||
158 | |||
108 | m_scene = null; | 159 | m_scene = null; |
109 | } | 160 | } |
110 | 161 | ||
@@ -115,6 +166,27 @@ namespace OpenSim.Region.ClientStack.Linden | |||
115 | 166 | ||
116 | m_AssetService = m_scene.RequestModuleInterface<IAssetService>(); | 167 | m_AssetService = m_scene.RequestModuleInterface<IAssetService>(); |
117 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | 168 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; |
169 | // We'll reuse the same handler for all requests. | ||
170 | m_getMeshHandler = new GetMeshHandler(m_assetService); | ||
171 | m_scene.EventManager.OnDeregisterCaps += DeregisterCaps; | ||
172 | m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate; | ||
173 | |||
174 | if (m_workerThreads == null) | ||
175 | { | ||
176 | m_workerThreads = new Thread[2]; | ||
177 | |||
178 | for (uint i = 0; i < 2; i++) | ||
179 | { | ||
180 | m_workerThreads[i] = Watchdog.StartThread(DoMeshRequests, | ||
181 | String.Format("MeshWorkerThread{0}", i), | ||
182 | ThreadPriority.Normal, | ||
183 | false, | ||
184 | false, | ||
185 | null, | ||
186 | int.MaxValue); | ||
187 | } | ||
188 | } | ||
189 | |||
118 | } | 190 | } |
119 | 191 | ||
120 | 192 | ||
@@ -124,9 +196,147 @@ namespace OpenSim.Region.ClientStack.Linden | |||
124 | 196 | ||
125 | #endregion | 197 | #endregion |
126 | 198 | ||
199 | private void DoMeshRequests() | ||
200 | { | ||
201 | while (true) | ||
202 | { | ||
203 | aPollRequest poolreq = m_queue.Dequeue(); | ||
204 | |||
205 | poolreq.thepoll.Process(poolreq); | ||
206 | } | ||
207 | } | ||
208 | |||
209 | // 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. | ||
210 | public void ThrottleUpdate(ScenePresence p) | ||
211 | { | ||
212 | UUID user = p.UUID; | ||
213 | int imagethrottle = p.ControllingClient.GetAgentThrottleSilent((int)ThrottleOutPacketType.Asset); | ||
214 | PollServiceMeshEventArgs args; | ||
215 | if (m_pollservices.TryGetValue(user, out args)) | ||
216 | { | ||
217 | args.UpdateThrottle(imagethrottle, p); | ||
218 | } | ||
219 | } | ||
220 | |||
221 | private class PollServiceMeshEventArgs : PollServiceEventArgs | ||
222 | { | ||
223 | private List<Hashtable> requests = | ||
224 | new List<Hashtable>(); | ||
225 | private Dictionary<UUID, aPollResponse> responses = | ||
226 | new Dictionary<UUID, aPollResponse>(); | ||
227 | |||
228 | private Scene m_scene; | ||
229 | private MeshCapsDataThrottler m_throttler; | ||
230 | public PollServiceMeshEventArgs(string uri, UUID pId, Scene scene) : | ||
231 | base(null, uri, null, null, null, pId, int.MaxValue) | ||
232 | { | ||
233 | m_scene = scene; | ||
234 | m_throttler = new MeshCapsDataThrottler(100000, 1400000, 10000, scene, pId); | ||
235 | // x is request id, y is userid | ||
236 | HasEvents = (x, y) => | ||
237 | { | ||
238 | lock (responses) | ||
239 | { | ||
240 | bool ret = m_throttler.hasEvents(x, responses); | ||
241 | m_throttler.ProcessTime(); | ||
242 | return ret; | ||
243 | |||
244 | } | ||
245 | }; | ||
246 | GetEvents = (x, y) => | ||
247 | { | ||
248 | lock (responses) | ||
249 | { | ||
250 | try | ||
251 | { | ||
252 | return responses[x].response; | ||
253 | } | ||
254 | finally | ||
255 | { | ||
256 | m_throttler.ProcessTime(); | ||
257 | responses.Remove(x); | ||
258 | } | ||
259 | } | ||
260 | }; | ||
261 | // x is request id, y is request data hashtable | ||
262 | Request = (x, y) => | ||
263 | { | ||
264 | aPollRequest reqinfo = new aPollRequest(); | ||
265 | reqinfo.thepoll = this; | ||
266 | reqinfo.reqID = x; | ||
267 | reqinfo.request = y; | ||
268 | |||
269 | m_queue.Enqueue(reqinfo); | ||
270 | }; | ||
271 | |||
272 | // this should never happen except possible on shutdown | ||
273 | NoEvents = (x, y) => | ||
274 | { | ||
275 | /* | ||
276 | lock (requests) | ||
277 | { | ||
278 | Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString()); | ||
279 | requests.Remove(request); | ||
280 | } | ||
281 | */ | ||
282 | Hashtable response = new Hashtable(); | ||
283 | |||
284 | response["int_response_code"] = 500; | ||
285 | response["str_response_string"] = "Script timeout"; | ||
286 | response["content_type"] = "text/plain"; | ||
287 | response["keepalive"] = false; | ||
288 | response["reusecontext"] = false; | ||
289 | |||
290 | return response; | ||
291 | }; | ||
292 | } | ||
293 | |||
294 | public void Process(aPollRequest requestinfo) | ||
295 | { | ||
296 | Hashtable response; | ||
297 | |||
298 | UUID requestID = requestinfo.reqID; | ||
299 | |||
300 | // If the avatar is gone, don't bother to get the texture | ||
301 | if (m_scene.GetScenePresence(Id) == null) | ||
302 | { | ||
303 | response = new Hashtable(); | ||
304 | |||
305 | response["int_response_code"] = 500; | ||
306 | response["str_response_string"] = "Script timeout"; | ||
307 | response["content_type"] = "text/plain"; | ||
308 | response["keepalive"] = false; | ||
309 | response["reusecontext"] = false; | ||
310 | |||
311 | lock (responses) | ||
312 | responses[requestID] = new aPollResponse() { bytes = 0, response = response, lod = 0 }; | ||
313 | |||
314 | return; | ||
315 | } | ||
316 | |||
317 | response = m_getMeshHandler.Handle(requestinfo.request); | ||
318 | lock (responses) | ||
319 | { | ||
320 | responses[requestID] = new aPollResponse() | ||
321 | { | ||
322 | bytes = (int)response["int_bytes"], | ||
323 | lod = (int)response["int_lod"], | ||
324 | response = response | ||
325 | }; | ||
326 | |||
327 | } | ||
328 | m_throttler.ProcessTime(); | ||
329 | } | ||
330 | |||
331 | internal void UpdateThrottle(int pimagethrottle, ScenePresence p) | ||
332 | { | ||
333 | m_throttler.UpdateThrottle(pimagethrottle, p); | ||
334 | } | ||
335 | } | ||
127 | 336 | ||
128 | public void RegisterCaps(UUID agentID, Caps caps) | 337 | public void RegisterCaps(UUID agentID, Caps caps) |
129 | { | 338 | { |
339 | <<<<<<< HEAD | ||
130 | UUID capID = UUID.Random(); | 340 | UUID capID = UUID.Random(); |
131 | bool getMeshRegistered = false; | 341 | bool getMeshRegistered = false; |
132 | 342 | ||
@@ -140,6 +350,35 @@ namespace OpenSim.Region.ClientStack.Linden | |||
140 | caps.RegisterHandler( | 350 | caps.RegisterHandler( |
141 | "GetMesh", | 351 | "GetMesh", |
142 | new GetMeshHandler("/CAPS/" + capID + "/", m_AssetService, "GetMesh", agentID.ToString(), m_RedirectURL)); | 352 | new GetMeshHandler("/CAPS/" + capID + "/", m_AssetService, "GetMesh", agentID.ToString(), m_RedirectURL)); |
353 | ======= | ||
354 | // UUID capID = UUID.Random(); | ||
355 | if (m_URL == "localhost") | ||
356 | { | ||
357 | string capUrl = "/CAPS/" + UUID.Random() + "/"; | ||
358 | |||
359 | // Register this as a poll service | ||
360 | PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(capUrl, agentID, m_scene); | ||
361 | |||
362 | args.Type = PollServiceEventArgs.EventType.Mesh; | ||
363 | MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); | ||
364 | |||
365 | string hostName = m_scene.RegionInfo.ExternalHostName; | ||
366 | uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; | ||
367 | string protocol = "http"; | ||
368 | |||
369 | if (MainServer.Instance.UseSSL) | ||
370 | { | ||
371 | hostName = MainServer.Instance.SSLCommonName; | ||
372 | port = MainServer.Instance.SSLPort; | ||
373 | protocol = "https"; | ||
374 | } | ||
375 | caps.RegisterHandler("GetMesh", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); | ||
376 | m_pollservices[agentID] = args; | ||
377 | m_capsDict[agentID] = capUrl; | ||
378 | |||
379 | |||
380 | |||
381 | >>>>>>> avn/ubitvar | ||
143 | } | 382 | } |
144 | else | 383 | else |
145 | { | 384 | { |
@@ -164,6 +403,177 @@ namespace OpenSim.Region.ClientStack.Linden | |||
164 | caps.RegisterHandler("GetMesh2", m_URL2); | 403 | caps.RegisterHandler("GetMesh2", m_URL2); |
165 | } | 404 | } |
166 | } | 405 | } |
406 | private void DeregisterCaps(UUID agentID, Caps caps) | ||
407 | { | ||
408 | string capUrl; | ||
409 | PollServiceMeshEventArgs args; | ||
410 | if (m_capsDict.TryGetValue(agentID, out capUrl)) | ||
411 | { | ||
412 | MainServer.Instance.RemoveHTTPHandler("", capUrl); | ||
413 | m_capsDict.Remove(agentID); | ||
414 | } | ||
415 | if (m_pollservices.TryGetValue(agentID, out args)) | ||
416 | { | ||
417 | m_pollservices.Remove(agentID); | ||
418 | } | ||
419 | } | ||
420 | |||
421 | internal sealed class MeshCapsDataThrottler | ||
422 | { | ||
423 | |||
424 | private volatile int currenttime = 0; | ||
425 | private volatile int lastTimeElapsed = 0; | ||
426 | private volatile int BytesSent = 0; | ||
427 | private int Lod3 = 0; | ||
428 | private int Lod2 = 0; | ||
429 | private int Lod1 = 0; | ||
430 | private int UserSetThrottle = 0; | ||
431 | private int UDPSetThrottle = 0; | ||
432 | private int CapSetThrottle = 0; | ||
433 | private float CapThrottleDistributon = 0.30f; | ||
434 | private readonly Scene m_scene; | ||
435 | private ThrottleOutPacketType Throttle; | ||
436 | private readonly UUID User; | ||
437 | |||
438 | public MeshCapsDataThrottler(int pBytes, int max, int min, Scene pScene, UUID puser) | ||
439 | { | ||
440 | ThrottleBytes = pBytes; | ||
441 | lastTimeElapsed = Util.EnvironmentTickCount(); | ||
442 | Throttle = ThrottleOutPacketType.Asset; | ||
443 | m_scene = pScene; | ||
444 | User = puser; | ||
445 | } | ||
446 | |||
447 | |||
448 | public bool hasEvents(UUID key, Dictionary<UUID, aPollResponse> responses) | ||
449 | { | ||
450 | const float ThirtyPercent = 0.30f; | ||
451 | const float FivePercent = 0.05f; | ||
452 | PassTime(); | ||
453 | // Note, this is called IN LOCK | ||
454 | bool haskey = responses.ContainsKey(key); | ||
455 | |||
456 | if (responses.Count > 2) | ||
457 | { | ||
458 | SplitThrottle(ThirtyPercent); | ||
459 | } | ||
460 | else | ||
461 | { | ||
462 | SplitThrottle(FivePercent); | ||
463 | } | ||
464 | |||
465 | if (!haskey) | ||
466 | { | ||
467 | return false; | ||
468 | } | ||
469 | aPollResponse response; | ||
470 | if (responses.TryGetValue(key, out response)) | ||
471 | { | ||
472 | float LOD3Over = (((ThrottleBytes*CapThrottleDistributon)%50000) + 1); | ||
473 | float LOD2Over = (((ThrottleBytes*CapThrottleDistributon)%10000) + 1); | ||
474 | // Normal | ||
475 | if (BytesSent + response.bytes <= ThrottleBytes) | ||
476 | { | ||
477 | BytesSent += response.bytes; | ||
478 | |||
479 | return true; | ||
480 | } | ||
481 | // Lod3 Over Throttle protection to keep things processing even when the throttle bandwidth is set too little. | ||
482 | else if (response.bytes > ThrottleBytes && Lod3 <= ((LOD3Over < 1)? 1: LOD3Over) ) | ||
483 | { | ||
484 | Interlocked.Increment(ref Lod3); | ||
485 | BytesSent += response.bytes; | ||
486 | |||
487 | return true; | ||
488 | } | ||
489 | // Lod2 Over Throttle protection to keep things processing even when the throttle bandwidth is set too little. | ||
490 | else if (response.bytes > ThrottleBytes && Lod2 <= ((LOD2Over < 1) ? 1 : LOD2Over)) | ||
491 | { | ||
492 | Interlocked.Increment(ref Lod2); | ||
493 | BytesSent += response.bytes; | ||
494 | |||
495 | return true; | ||
496 | } | ||
497 | else | ||
498 | { | ||
499 | return false; | ||
500 | } | ||
501 | } | ||
502 | |||
503 | return haskey; | ||
504 | } | ||
505 | public void SubtractBytes(int bytes,int lod) | ||
506 | { | ||
507 | BytesSent -= bytes; | ||
508 | } | ||
509 | private void SplitThrottle(float percentMultiplier) | ||
510 | { | ||
511 | |||
512 | if (CapThrottleDistributon != percentMultiplier) // don't switch it if it's already set at the % multipler | ||
513 | { | ||
514 | CapThrottleDistributon = percentMultiplier; | ||
515 | ScenePresence p; | ||
516 | if (m_scene.TryGetScenePresence(User, out p)) // If we don't get a user they're not here anymore. | ||
517 | { | ||
518 | // AlterThrottle(UserSetThrottle, p); | ||
519 | UpdateThrottle(UserSetThrottle, p); | ||
520 | } | ||
521 | } | ||
522 | } | ||
523 | |||
524 | public void ProcessTime() | ||
525 | { | ||
526 | PassTime(); | ||
527 | } | ||
528 | |||
529 | |||
530 | private void PassTime() | ||
531 | { | ||
532 | currenttime = Util.EnvironmentTickCount(); | ||
533 | int timeElapsed = Util.EnvironmentTickCountSubtract(currenttime, lastTimeElapsed); | ||
534 | //processTimeBasedActions(responses); | ||
535 | if (currenttime - timeElapsed >= 1000) | ||
536 | { | ||
537 | lastTimeElapsed = Util.EnvironmentTickCount(); | ||
538 | BytesSent -= ThrottleBytes; | ||
539 | if (BytesSent < 0) BytesSent = 0; | ||
540 | if (BytesSent < ThrottleBytes) | ||
541 | { | ||
542 | Lod3 = 0; | ||
543 | Lod2 = 0; | ||
544 | Lod1 = 0; | ||
545 | } | ||
546 | } | ||
547 | } | ||
548 | private void AlterThrottle(int setting, ScenePresence p) | ||
549 | { | ||
550 | p.ControllingClient.SetAgentThrottleSilent((int)Throttle,setting); | ||
551 | } | ||
552 | |||
553 | public int ThrottleBytes | ||
554 | { | ||
555 | get { return CapSetThrottle; } | ||
556 | set { CapSetThrottle = value; } | ||
557 | } | ||
558 | |||
559 | internal void UpdateThrottle(int pimagethrottle, ScenePresence p) | ||
560 | { | ||
561 | // Client set throttle ! | ||
562 | UserSetThrottle = pimagethrottle; | ||
563 | CapSetThrottle = (int)(pimagethrottle*CapThrottleDistributon); | ||
564 | // UDPSetThrottle = (int) (pimagethrottle*(100 - CapThrottleDistributon)); | ||
565 | |||
566 | float udp = 1.0f - CapThrottleDistributon; | ||
567 | if(udp < 0.7f) | ||
568 | udp = 0.7f; | ||
569 | UDPSetThrottle = (int) ((float)pimagethrottle * udp); | ||
570 | if (CapSetThrottle < 4068) | ||
571 | CapSetThrottle = 4068; // at least two discovery mesh | ||
572 | p.ControllingClient.SetAgentThrottleSilent((int) Throttle, UDPSetThrottle); | ||
573 | ProcessTime(); | ||
574 | |||
575 | } | ||
576 | } | ||
167 | 577 | ||
168 | } | 578 | } |
169 | } | 579 | } |