aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorTeravus Ovares2008-10-08 11:53:35 +0000
committerTeravus Ovares2008-10-08 11:53:35 +0000
commit2c5497fa3ae7c132b9c8c3022d65fbd9efab2844 (patch)
tree50ca201cf3457b020fb27ebaeee43aec78f16897
parentwarning squashing (diff)
downloadopensim-SC-2c5497fa3ae7c132b9c8c3022d65fbd9efab2844.zip
opensim-SC-2c5497fa3ae7c132b9c8c3022d65fbd9efab2844.tar.gz
opensim-SC-2c5497fa3ae7c132b9c8c3022d65fbd9efab2844.tar.bz2
opensim-SC-2c5497fa3ae7c132b9c8c3022d65fbd9efab2844.tar.xz
* Re-enables map item requests.
* Puts remote requests in a single worker thread * Worker thread only starts when there are agents to serve * When there are no agents to serve, it shuts down * A good example of how to deal with threads in non-shared modules so they don't end up consuming threads per regions
-rw-r--r--OpenSim/Region/Environment/Modules/World/WorldMap/WorldMapModule.cs312
1 files changed, 261 insertions, 51 deletions
diff --git a/OpenSim/Region/Environment/Modules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/Environment/Modules/World/WorldMap/WorldMapModule.cs
index 215f3fa..9b4a997 100644
--- a/OpenSim/Region/Environment/Modules/World/WorldMap/WorldMapModule.cs
+++ b/OpenSim/Region/Environment/Modules/World/WorldMap/WorldMapModule.cs
@@ -33,6 +33,7 @@ using System.Drawing.Imaging;
33using System.IO; 33using System.IO;
34using System.Net; 34using System.Net;
35using System.Reflection; 35using System.Reflection;
36using System.Threading;
36using OpenMetaverse; 37using OpenMetaverse;
37using OpenMetaverse.Imaging; 38using OpenMetaverse.Imaging;
38using OpenMetaverse.StructuredData; 39using OpenMetaverse.StructuredData;
@@ -60,6 +61,8 @@ namespace OpenSim.Region.Environment.Modules.World.WorldMap
60 61
61 private static readonly string m_mapLayerPath = "0001/"; 62 private static readonly string m_mapLayerPath = "0001/";
62 63
64 private OpenSim.Framework.BlockingQueue<MapRequestState> requests = new OpenSim.Framework.BlockingQueue<MapRequestState>();
65
63 //private IConfig m_config; 66 //private IConfig m_config;
64 private Scene m_scene; 67 private Scene m_scene;
65 private List<MapBlockData> cachedMapBlocks = new List<MapBlockData>(); 68 private List<MapBlockData> cachedMapBlocks = new List<MapBlockData>();
@@ -67,7 +70,11 @@ namespace OpenSim.Region.Environment.Modules.World.WorldMap
67 private byte[] myMapImageJPEG; 70 private byte[] myMapImageJPEG;
68 private bool m_Enabled = false; 71 private bool m_Enabled = false;
69 private Dictionary<UUID, MapRequestState> m_openRequests = new Dictionary<UUID, MapRequestState>(); 72 private Dictionary<UUID, MapRequestState> m_openRequests = new Dictionary<UUID, MapRequestState>();
70 73 private Dictionary<string, int> m_blacklistedurls = new Dictionary<string, int>();
74 private Dictionary<ulong, int> m_blacklistedregions = new Dictionary<ulong, int>();
75 private Dictionary<ulong, string> m_cachedRegionMapItemsAddress = new Dictionary<ulong, string>();
76 private Thread mapItemReqThread;
77 private volatile bool threadrunning = false;
71 78
72 //private int CacheRegionsDistance = 256; 79 //private int CacheRegionsDistance = 256;
73 80
@@ -93,12 +100,15 @@ namespace OpenSim.Region.Environment.Modules.World.WorldMap
93 100
94 m_scene.AddHTTPHandler(regionimage, OnHTTPGetMapImage); 101 m_scene.AddHTTPHandler(regionimage, OnHTTPGetMapImage);
95 m_scene.AddLLSDHandler("/MAP/MapItems/" + scene.RegionInfo.RegionHandle.ToString(),HandleRemoteMapItemRequest); 102 m_scene.AddLLSDHandler("/MAP/MapItems/" + scene.RegionInfo.RegionHandle.ToString(),HandleRemoteMapItemRequest);
96 //QuadTree.Subdivide(); 103
97 //QuadTree.Subdivide();
98 104
99 scene.EventManager.OnRegisterCaps += OnRegisterCaps; 105 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
100 scene.EventManager.OnNewClient += OnNewClient; 106 scene.EventManager.OnNewClient += OnNewClient;
101 scene.EventManager.OnClientClosed += ClientLoggedOut; 107 scene.EventManager.OnClientClosed += ClientLoggedOut;
108 scene.EventManager.OnMakeChildAgent += MakeChildAgent;
109 scene.EventManager.OnAvatarEnteringNewParcel += AvatarEnteringParcel;
110
111
102 } 112 }
103 public void PostInitialise() 113 public void PostInitialise()
104 { 114 {
@@ -220,33 +230,80 @@ namespace OpenSim.Region.Environment.Modules.World.WorldMap
220 } 230 }
221 #region EventHandlers 231 #region EventHandlers
222 232
223 233 /// <summary>
234 /// Registered for event
235 /// </summary>
236 /// <param name="client"></param>
224 private void OnNewClient(IClientAPI client) 237 private void OnNewClient(IClientAPI client)
225 { 238 {
226 // All friends establishment protocol goes over instant message
227 // There's no way to send a message from the sim
228 // to a user to 'add a friend' without causing dialog box spam
229 //
230 // The base set of friends are added when the user signs on in their XMLRPC response
231 // Generated by LoginService. The friends are retreived from the database by the UserManager
232
233 // Subscribe to instant messages
234
235 //client.OnInstantMessage += OnInstantMessage;
236 //client.OnApproveFriendRequest += OnApprovedFriendRequest;
237 //client.OnDenyFriendRequest += OnDenyFriendRequest;
238 //client.OnTerminateFriendship += OnTerminateFriendship;
239
240 //doFriendListUpdateOnline(client.AgentId);
241 client.OnRequestMapBlocks += RequestMapBlocks; 239 client.OnRequestMapBlocks += RequestMapBlocks;
242 client.OnMapItemRequest += HandleMapItemRequest; 240 client.OnMapItemRequest += HandleMapItemRequest;
243 } 241 }
242
243 /// <summary>
244 /// Client logged out, check to see if there are any more root agents in the simulator
245 /// If not, stop the mapItemRequest Thread
246 /// Event handler
247 /// </summary>
248 /// <param name="AgentId">AgentID that logged out</param>
244 private void ClientLoggedOut(UUID AgentId) 249 private void ClientLoggedOut(UUID AgentId)
245 { 250 {
251
252 List<ScenePresence> presences = m_scene.GetAvatars();
253 int rootcount = 0;
254 for (int i=0;i<presences.Count;i++)
255 {
256 if (presences[i] != null)
257 {
258 if (!presences[i].IsChildAgent)
259 rootcount++;
260 }
261 }
262 if (rootcount <= 1)
263 StopThread();
264
246 265
247 } 266 }
248 #endregion 267 #endregion
249 268
269 /// <summary>
270 /// Starts the MapItemRequest Thread
271 /// Note that this only gets started when there are actually agents in the region
272 /// Additionally, it gets stopped when there are none.
273 /// </summary>
274 /// <param name="o"></param>
275 private void StartThread(object o)
276 {
277 if (threadrunning) return;
278
279 m_log.Warn("[WorldMap]: Starting remote MapItem request thread");
280 threadrunning = true;
281 mapItemReqThread = new Thread(new ThreadStart(process));
282 mapItemReqThread.IsBackground = true;
283 mapItemReqThread.Name = "MapItemRequestThread";
284 mapItemReqThread.Priority = ThreadPriority.BelowNormal;
285 mapItemReqThread.SetApartmentState(ApartmentState.MTA);
286 mapItemReqThread.Start();
287 ThreadTracker.Add(mapItemReqThread);
288 }
289
290 /// <summary>
291 /// Enqueues a 'stop thread' MapRequestState. Causes the MapItemRequest thread to end
292 /// </summary>
293 private void StopThread()
294 {
295 MapRequestState st = new MapRequestState();
296 st.agentID=UUID.Zero;
297 st.EstateID=0;
298 st.flags=0;
299 st.godlike=false;
300 st.itemtype=0;
301 st.regionhandle=0;
302
303 requests.Enqueue(st);
304 }
305
306
250 public virtual void HandleMapItemRequest(IClientAPI remoteClient, uint flags, 307 public virtual void HandleMapItemRequest(IClientAPI remoteClient, uint flags,
251 uint EstateID, bool godlike, uint itemtype, ulong regionhandle) 308 uint EstateID, bool godlike, uint itemtype, ulong regionhandle)
252 { 309 {
@@ -257,6 +314,7 @@ namespace OpenSim.Region.Environment.Modules.World.WorldMap
257 { 314 {
258 if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle) 315 if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle)
259 { 316 {
317 // Local Map Item Request
260 List<ScenePresence> avatars = m_scene.GetAvatars(); 318 List<ScenePresence> avatars = m_scene.GetAvatars();
261 int tc = System.Environment.TickCount; 319 int tc = System.Environment.TickCount;
262 List<mapItemReply> mapitems = new List<mapItemReply>(); 320 List<mapItemReply> mapitems = new List<mapItemReply>();
@@ -295,29 +353,62 @@ namespace OpenSim.Region.Environment.Modules.World.WorldMap
295 } 353 }
296 else 354 else
297 { 355 {
298 //RegionInfo mreg = m_scene.SceneGridService.RequestNeighbouringRegionInfo(regionhandle); 356 // Remote Map Item Request
299 //if (mreg != null) 357
300 //{ 358
301 // string httpserver = "http://" + mreg.ExternalEndPoint.Address.ToString() + ":" + mreg.HttpPort + "/MAP/MapItems/" + regionhandle.ToString(); 359 // ensures that the blockingqueue doesn't get borked if the GetAgents() timing changes.
302 360 // Note that we only start up a remote mapItem Request thread if there's users who could
303 // RequestMapItems(httpserver,remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle); 361 // be making requests
304 362 if (!threadrunning)
305 //} 363 {
364 m_log.Warn("[WorldMap]: Starting new remote request thread manually. This means that AvatarEnteringParcel never fired! This needs to be fixed! Don't Mantis this, as the developers can see it in this message");
365 StartThread(new object());
366 }
367
368 RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle);
369
306 } 370 }
307 } 371 }
308 372
309 } 373 }
310 374
311 public delegate LLSDMap RequestMapItemsDelegate(string httpserver, UUID id, uint flags, 375 /// <summary>
312 uint EstateID, bool godlike, uint itemtype, ulong regionhandle); 376 /// Processing thread main() loop for doing remote mapitem requests
377 /// </summary>
378 public void process()
379 {
380 while (true)
381 {
382 MapRequestState st = requests.Dequeue();
383
384 // end gracefully
385 if (st.agentID == UUID.Zero)
386 {
387 ThreadTracker.Remove(mapItemReqThread);
388 break;
389 }
390 LLSDMap response = RequestMapItemsAsync("", st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle);
391 RequestMapItemsCompleted(response);
392 }
393 threadrunning = false;
394 m_log.Warn("[WorldMap]: Remote request thread exiting");
395 }
313 396
314 private void RequestMapItemsCompleted(IAsyncResult iar) 397 /// <summary>
398 /// Enqueues the map item request into the processing thread
399 /// </summary>
400 /// <param name="state"></param>
401 public void EnqueueMapItemRequest(MapRequestState state)
315 { 402 {
316 403 requests.Enqueue(state);
317 RequestMapItemsDelegate icon = (RequestMapItemsDelegate)iar.AsyncState; 404 }
318 LLSDMap response = icon.EndInvoke(iar);
319
320 405
406 /// <summary>
407 /// Sends the mapitem response to the IClientAPI
408 /// </summary>
409 /// <param name="response">The LLSDMap Response for the mapitem</param>
410 private void RequestMapItemsCompleted(LLSDMap response)
411 {
321 412
322 UUID requestID = response["requestID"].AsUUID(); 413 UUID requestID = response["requestID"].AsUUID();
323 414
@@ -364,19 +455,99 @@ namespace OpenSim.Region.Environment.Modules.World.WorldMap
364 } 455 }
365 } 456 }
366 } 457 }
458
459 /// <summary>
460 /// Enqueue the MapItem request for remote processing
461 /// </summary>
462 /// <param name="httpserver">blank string, we discover this in the process</param>
463 /// <param name="id">Agent ID that we are making this request on behalf</param>
464 /// <param name="flags">passed in from packet</param>
465 /// <param name="EstateID">passed in from packet</param>
466 /// <param name="godlike">passed in from packet</param>
467 /// <param name="itemtype">passed in from packet</param>
468 /// <param name="regionhandle">Region we're looking up</param>
367 public void RequestMapItems(string httpserver, UUID id, uint flags, 469 public void RequestMapItems(string httpserver, UUID id, uint flags,
368 uint EstateID, bool godlike, uint itemtype, ulong regionhandle) 470 uint EstateID, bool godlike, uint itemtype, ulong regionhandle)
369 { 471 {
370 //m_log.Info("[INTER]: " + debugRegionName + ": SceneCommunicationService: Sending InterRegion Notification that region is up " + region.RegionName); 472 MapRequestState st = new MapRequestState();
371 RequestMapItemsDelegate d = RequestMapItemsAsync; 473 st.agentID = id;
372 d.BeginInvoke(httpserver, id,flags,EstateID,godlike,itemtype,regionhandle,RequestMapItemsCompleted, d); 474 st.flags = flags;
373 //bool val = m_commsProvider.InterRegion.RegionUp(new SerializableRegionInfo(region)); 475 st.EstateID = EstateID;
476 st.godlike = godlike;
477 st.itemtype = itemtype;
478 st.regionhandle = regionhandle;
479 EnqueueMapItemRequest(st);
480
374 } 481 }
482
483 /// <summary>
484 /// Does the actual remote mapitem request
485 /// This should be called from an asynchronous thread
486 /// Request failures get blacklisted until region restart so we don't
487 /// continue to spend resources trying to contact regions that are down.
488 /// </summary>
489 /// <param name="httpserver">blank string, we discover this in the process</param>
490 /// <param name="id">Agent ID that we are making this request on behalf</param>
491 /// <param name="flags">passed in from packet</param>
492 /// <param name="EstateID">passed in from packet</param>
493 /// <param name="godlike">passed in from packet</param>
494 /// <param name="itemtype">passed in from packet</param>
495 /// <param name="regionhandle">Region we're looking up</param>
496 /// <returns></returns>
375 private LLSDMap RequestMapItemsAsync(string httpserver, UUID id, uint flags, 497 private LLSDMap RequestMapItemsAsync(string httpserver, UUID id, uint flags,
376 uint EstateID, bool godlike, uint itemtype, ulong regionhandle) 498 uint EstateID, bool godlike, uint itemtype, ulong regionhandle)
377 { 499 {
500 bool blacklisted = false;
501 lock (m_blacklistedregions)
502 {
503 if (m_blacklistedregions.ContainsKey(regionhandle))
504 blacklisted = true;
505
506 }
507
508 if (blacklisted)
509 return new LLSDMap();
510
378 UUID requestID = UUID.Random(); 511 UUID requestID = UUID.Random();
379 512 lock (m_cachedRegionMapItemsAddress)
513 {
514 if (m_cachedRegionMapItemsAddress.ContainsKey(regionhandle))
515 httpserver = m_cachedRegionMapItemsAddress[regionhandle];
516 }
517 if (httpserver.Length == 0)
518 {
519 RegionInfo mreg = m_scene.SceneGridService.RequestNeighbouringRegionInfo(regionhandle);
520 if (mreg != null)
521 {
522 httpserver = "http://" + mreg.ExternalEndPoint.Address.ToString() + ":" + mreg.HttpPort + "/MAP/MapItems/" + regionhandle.ToString();
523 lock (m_cachedRegionMapItemsAddress)
524 {
525 if (!m_cachedRegionMapItemsAddress.ContainsKey(regionhandle))
526 m_cachedRegionMapItemsAddress.Add(regionhandle, httpserver);
527 }
528 }
529 else
530 {
531 lock (m_blacklistedregions)
532 {
533 if (!m_blacklistedregions.ContainsKey(regionhandle))
534 m_blacklistedregions.Add(regionhandle, System.Environment.TickCount);
535 }
536 m_log.WarnFormat("[WorldMap]: Blacklisted region {0}", regionhandle.ToString());
537 }
538 }
539
540 blacklisted = false;
541 lock (m_blacklistedurls)
542 {
543 if (m_blacklistedurls.ContainsKey(httpserver))
544 blacklisted = true;
545 }
546
547 // Can't find the http server
548 if (httpserver.Length == 0 || blacklisted)
549 return new LLSDMap();
550
380 MapRequestState mrs = new MapRequestState(); 551 MapRequestState mrs = new MapRequestState();
381 mrs.agentID = id; 552 mrs.agentID = id;
382 mrs.EstateID = EstateID; 553 mrs.EstateID = EstateID;
@@ -413,30 +584,43 @@ namespace OpenSim.Region.Environment.Modules.World.WorldMap
413 { 584 {
414 m_log.InfoFormat("[WorldMap] Bad send on GetMapItems {0}", ex.Message); 585 m_log.InfoFormat("[WorldMap] Bad send on GetMapItems {0}", ex.Message);
415 responseMap["connect"] = LLSD.FromBoolean(false); 586 responseMap["connect"] = LLSD.FromBoolean(false);
587 lock (m_blacklistedurls)
588 {
589 if (!m_blacklistedurls.ContainsKey(httpserver))
590 m_blacklistedurls.Add(httpserver, System.Environment.TickCount);
591 }
592
593 m_log.WarnFormat("[WorldMap]: Blacklisted {0}", httpserver);
416 594
417 return responseMap; 595 return responseMap;
418 } 596 }
419 597
420 //m_log.Info("[OGP] waiting for a reply after rez avatar send");
421 string response_mapItems_reply = null; 598 string response_mapItems_reply = null;
422 { // get the response 599 { // get the response
423 try 600 try
424 { 601 {
425 WebResponse webResponse = mapitemsrequest.GetResponse(); 602 WebResponse webResponse = mapitemsrequest.GetResponse();
426 if (webResponse == null) 603 if (webResponse != null)
427 { 604 {
428 //m_log.Info("[OGP:] Null reply on rez_avatar post"); 605 StreamReader sr = new StreamReader(webResponse.GetResponseStream());
606 response_mapItems_reply = sr.ReadToEnd().Trim();
607 }
608 else
609 {
610 return new LLSDMap();
429 } 611 }
430
431 StreamReader sr = new StreamReader(webResponse.GetResponseStream());
432 response_mapItems_reply = sr.ReadToEnd().Trim();
433 //m_log.InfoFormat("[OGP]: rez_avatar reply was {0} ", response_mapItems_reply);
434
435 } 612 }
436 catch (WebException) 613 catch (WebException)
437 { 614 {
438 //m_log.InfoFormat("[OGP]: exception on read after send of rez avatar {0}", ex.Message); 615
439 responseMap["connect"] = LLSD.FromBoolean(false); 616 responseMap["connect"] = LLSD.FromBoolean(false);
617 lock (m_blacklistedurls)
618 {
619 if (!m_blacklistedurls.ContainsKey(httpserver))
620 m_blacklistedurls.Add(httpserver, System.Environment.TickCount);
621 }
622
623 m_log.WarnFormat("[WorldMap]: Blacklisted {0}", httpserver);
440 624
441 return responseMap; 625 return responseMap;
442 } 626 }
@@ -655,7 +839,34 @@ namespace OpenSim.Region.Environment.Modules.World.WorldMap
655 } 839 }
656 return responsemap; 840 return responsemap;
657 } 841 }
842
843 private void AvatarEnteringParcel(ScenePresence avatar, int localLandID, UUID regionID)
844 {
845 // You may ask, why this is in a threadpool to start with..
846 // The reason is so we don't cause the thread to freeze waiting
847 // for the 1 second it costs to start a thread manually.
848
849 if (!threadrunning)
850 ThreadPool.QueueUserWorkItem(new WaitCallback(this.StartThread));
851 }
852
853 private void MakeChildAgent(ScenePresence avatar)
854 {
855 List<ScenePresence> presences = m_scene.GetAvatars();
856 int rootcount = 0;
857 for (int i = 0; i < presences.Count; i++)
858 {
859 if (presences[i] != null)
860 {
861 if (!presences[i].IsChildAgent)
862 rootcount++;
863 }
864 }
865 if (rootcount <= 1)
866 StopThread();
867 }
658 } 868 }
869
659 public struct MapRequestState 870 public struct MapRequestState
660 { 871 {
661 public UUID agentID; 872 public UUID agentID;
@@ -665,6 +876,5 @@ namespace OpenSim.Region.Environment.Modules.World.WorldMap
665 public uint itemtype; 876 public uint itemtype;
666 public ulong regionhandle; 877 public ulong regionhandle;
667 } 878 }
668 879
669
670} 880}