From 60325f81d81f41ca6a23465468afa940aae397dd Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 15 Jul 2013 10:29:42 -0700 Subject: [PATCH 01/55] This might address the following observed exception: 17:14:28 - [APPLICATION]: APPLICATION EXCEPTION DETECTED: System.UnhandledExceptionEventArgs Exception: System.InvalidOperationException: Operation is not valid due to the current state of the object at System.Collections.Generic.Queue`1[OpenSim.Region.ClientStack.Linden.WebFetchInvDescModule+aPollRequest].Peek () [0x00011] in /root/install/mono-3.1.0/mono/mcs/class/System/System.Collections.Generic/Queue.cs:158 at System.Collections.Generic.Queue`1[OpenSim.Region.ClientStack.Linden.WebFetchInvDescModule+aPollRequest].Dequeue () [0x00000] in /root/install/mono-3.1.0/mono/mcs/class/System/System.Collections.Generic/Queue.cs:140 at OpenSim.Framework.DoubleQueue`1[OpenSim.Region.ClientStack.Linden.WebFetchInvDescModule+aPollRequest].Dequeue (TimeSpan wait, OpenSim.Region.ClientStack.Linden.aPollRequest& res) [0x0004e] in /home/avacon/opensim_2013-07-14/OpenSim/Framework/Util.cs:2297 --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index cafe103135..8cfc4d4b86 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2293,7 +2293,7 @@ namespace OpenSim.Framework { if (m_highQueue.Count > 0) res = m_highQueue.Dequeue(); - else + else if (m_lowQueue.Count > 0) res = m_lowQueue.Dequeue(); if (m_highQueue.Count == 0 && m_lowQueue.Count == 0) From ac73e702935dd4607c13aaec3095940fba7932ca Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 15 Jul 2013 11:27:49 -0700 Subject: [PATCH 02/55] Trying to hunt the CPU spikes recently experienced. Revert "Comment out old inbound UDP throttling hack. This would cause the UDP" This reverts commit 38e6da5522a53c7f65eac64ae7b0af929afb1ae6. --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 85270a6e2d..e20a1946d1 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1615,7 +1615,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP { IncomingPacket incomingPacket = null; - /* // HACK: This is a test to try and rate limit packet handling on Mono. // If it works, a more elegant solution can be devised if (Util.FireAndForgetCount() < 2) @@ -1623,7 +1622,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping"); Thread.Sleep(30); } - */ if (packetInbox.Dequeue(100, ref incomingPacket)) { From fbb01bd28064cde3e00ddf2a0cc4ce87ddd4cb6e Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 15 Jul 2013 11:37:49 -0700 Subject: [PATCH 03/55] Protect against null requests --- .../GridServiceThrottleModule.cs | 10 ++++++---- .../UserManagement/UserManagementModule.cs | 18 ++++++++++-------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs index f1eb1ad3a9..fd4d48ae2b 100644 --- a/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs @@ -140,11 +140,13 @@ namespace OpenSim.Region.CoreModules.Framework Watchdog.UpdateThread(); GridRegionRequest request = m_RequestQueue.Dequeue(); - GridRegion r = m_scenes[0].GridService.GetRegionByUUID(UUID.Zero, request.regionID); - - if (r != null && r.RegionHandle != 0) - request.client.SendRegionHandle(request.regionID, r.RegionHandle); + if (request != null) + { + GridRegion r = m_scenes[0].GridService.GetRegionByUUID(UUID.Zero, request.regionID); + if (r != null && r.RegionHandle != 0) + request.client.SendRegionHandle(request.regionID, r.RegionHandle); + } } } } diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index a5280939fc..507329eb59 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -681,17 +681,19 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement Watchdog.UpdateThread(); NameRequest request = m_RequestQueue.Dequeue(); - string[] names; - bool foundRealName = TryGetUserNames(request.uuid, out names); - - if (names.Length == 2) + if (request != null) { - if (!foundRealName) - m_log.DebugFormat("[USER MANAGEMENT MODULE]: Sending {0} {1} for {2} to {3} since no bound name found", names[0], names[1], request.uuid, request.client.Name); + string[] names; + bool foundRealName = TryGetUserNames(request.uuid, out names); - request.client.SendNameReply(request.uuid, names[0], names[1]); + if (names.Length == 2) + { + if (!foundRealName) + m_log.DebugFormat("[USER MANAGEMENT MODULE]: Sending {0} {1} for {2} to {3} since no bound name found", names[0], names[1], request.uuid, request.client.Name); + + request.client.SendNameReply(request.uuid, names[0], names[1]); + } } - } } From 864f15ce4dfd412df8442a26429b9dd7a2bf9e12 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 15 Jul 2013 11:52:26 -0700 Subject: [PATCH 04/55] Revert the revert Revert "Trying to hunt the CPU spikes recently experienced." This reverts commit ac73e702935dd4607c13aaec3095940fba7932ca. --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index e20a1946d1..85270a6e2d 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1615,6 +1615,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { IncomingPacket incomingPacket = null; + /* // HACK: This is a test to try and rate limit packet handling on Mono. // If it works, a more elegant solution can be devised if (Util.FireAndForgetCount() < 2) @@ -1622,6 +1623,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping"); Thread.Sleep(30); } + */ if (packetInbox.Dequeue(100, ref incomingPacket)) { From b060ce96d93a33298b59392210af4d336e0d171b Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 15 Jul 2013 12:05:31 -0700 Subject: [PATCH 05/55] Puts RequestImage (UDP) back to asyn -- CPU spike hunt --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 79c80a7032..f57e069779 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -5373,7 +5373,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false); AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false); AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false); - AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage, false); + AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage); AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest, false); AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest); AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer); From 687c1a420a6f3c254eb7104fee40a79fc6a39e1d Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 15 Jul 2013 12:33:31 -0700 Subject: [PATCH 06/55] Guard against null ref --- .../Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index b90df17622..5b0859b69c 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs @@ -351,7 +351,8 @@ namespace OpenSim.Region.ClientStack.Linden aPollRequest poolreq = m_queue.Dequeue(); - poolreq.thepoll.Process(poolreq); + if (poolreq != null && poolreq.thepoll != null) + poolreq.thepoll.Process(poolreq); } } } From 68fbf7eebb12bcd22c3e3308a838c5c2e9b1c47f Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 15 Jul 2013 12:34:10 -0700 Subject: [PATCH 07/55] Revert "Puts RequestImage (UDP) back to asyn -- CPU spike hunt" This reverts commit b060ce96d93a33298b59392210af4d336e0d171b. --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index f57e069779..79c80a7032 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -5373,7 +5373,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false); AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false); AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false); - AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage); + AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage, false); AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest, false); AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest); AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer); From 1b7b664c8696531fec26378d1386362d8a3da55e Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 15 Jul 2013 23:22:39 +0100 Subject: [PATCH 08/55] Add request received/handling stats for caps which are served by http poll handlers. This adds explicit cap poll handler supporting to the Caps classes rather than relying on callers to do the complicated coding. Other refactoring was required to get logic into the right places to support this. --- OpenSim/Capabilities/Caps.cs | 97 +++++++++++++++++-- OpenSim/Framework/Console/RemoteConsole.cs | 2 +- .../Servers/HttpServer/BaseHttpServer.cs | 2 + .../HttpServer/PollServiceEventArgs.cs | 14 +++ .../HttpServer/PollServiceHttpRequest.cs | 45 +++++++++ .../HttpServer/PollServiceRequestManager.cs | 58 ++--------- .../Linden/Caps/BunchOfCaps/BunchOfCaps.cs | 13 +-- .../Caps/EventQueue/EventQueueGetModule.cs | 2 +- .../Linden/Caps/WebFetchInvDescModule.cs | 64 ++++++------ .../Framework/Caps/CapabilitiesModule.cs | 92 ++++++++++++++---- .../Scripting/LSLHttp/UrlModule.cs | 6 +- 11 files changed, 268 insertions(+), 127 deletions(-) diff --git a/OpenSim/Capabilities/Caps.cs b/OpenSim/Capabilities/Caps.cs index 6c95d8b06c..bbf3b27c51 100644 --- a/OpenSim/Capabilities/Caps.cs +++ b/OpenSim/Capabilities/Caps.cs @@ -63,7 +63,11 @@ namespace OpenSim.Framework.Capabilities public string CapsObjectPath { get { return m_capsObjectPath; } } private CapsHandlers m_capsHandlers; - private Dictionary m_externalCapsHandlers; + + private Dictionary m_pollServiceHandlers + = new Dictionary(); + + private Dictionary m_externalCapsHandlers = new Dictionary(); private IHttpServer m_httpListener; private UUID m_agentID; @@ -132,7 +136,6 @@ namespace OpenSim.Framework.Capabilities m_agentID = agent; m_capsHandlers = new CapsHandlers(httpServer, httpListen, httpPort, (httpServer == null) ? false : httpServer.UseSSL); - m_externalCapsHandlers = new Dictionary(); m_regionName = regionName; } @@ -147,6 +150,27 @@ namespace OpenSim.Framework.Capabilities m_capsHandlers[capName] = handler; } + public void RegisterPollHandler(string capName, PollServiceEventArgs pollServiceHandler) + { + m_pollServiceHandlers.Add(capName, pollServiceHandler); + + m_httpListener.AddPollServiceHTTPHandler(pollServiceHandler.Url, pollServiceHandler); + +// uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; +// string protocol = "http"; +// string hostName = m_httpListenerHostName; +// +// if (MainServer.Instance.UseSSL) +// { +// hostName = MainServer.Instance.SSLCommonName; +// port = MainServer.Instance.SSLPort; +// protocol = "https"; +// } + +// RegisterHandler( +// capName, String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, pollServiceHandler.Url)); + } + /// /// Register an external handler. The service for this capability is somewhere else /// given by the URL. @@ -163,13 +187,70 @@ namespace OpenSim.Framework.Capabilities /// public void DeregisterHandlers() { - if (m_capsHandlers != null) + foreach (string capsName in m_capsHandlers.Caps) { - foreach (string capsName in m_capsHandlers.Caps) - { - m_capsHandlers.Remove(capsName); - } + m_capsHandlers.Remove(capsName); + } + + foreach (PollServiceEventArgs handler in m_pollServiceHandlers.Values) + { + m_httpListener.RemovePollServiceHTTPHandler("", handler.Url); } } + + public bool TryGetPollHandler(string name, out PollServiceEventArgs pollHandler) + { + return m_pollServiceHandlers.TryGetValue(name, out pollHandler); + } + + public Dictionary GetPollHandlers() + { + return new Dictionary(m_pollServiceHandlers); + } + + /// + /// Return an LLSD-serializable Hashtable describing the + /// capabilities and their handler details. + /// + /// If true, then exclude the seed cap. + public Hashtable GetCapsDetails(bool excludeSeed, List requestedCaps) + { + Hashtable caps = CapsHandlers.GetCapsDetails(excludeSeed, requestedCaps); + + lock (m_pollServiceHandlers) + { + foreach (KeyValuePair kvp in m_pollServiceHandlers) + { + if (!requestedCaps.Contains(kvp.Key)) + continue; + + string hostName = m_httpListenerHostName; + uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; + string protocol = "http"; + + if (MainServer.Instance.UseSSL) + { + hostName = MainServer.Instance.SSLCommonName; + port = MainServer.Instance.SSLPort; + protocol = "https"; + } + // + // caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); + + caps[kvp.Key] = string.Format("{0}://{1}:{2}{3}", protocol, hostName, port, kvp.Value.Url); + } + } + + // Add the external too + foreach (KeyValuePair kvp in ExternalCapsHandlers) + { + if (!requestedCaps.Contains(kvp.Key)) + continue; + + caps[kvp.Key] = kvp.Value; + } + + return caps; + } } -} +} \ No newline at end of file diff --git a/OpenSim/Framework/Console/RemoteConsole.cs b/OpenSim/Framework/Console/RemoteConsole.cs index 3e3c2b3758..8ad7b0daa9 100644 --- a/OpenSim/Framework/Console/RemoteConsole.cs +++ b/OpenSim/Framework/Console/RemoteConsole.cs @@ -234,7 +234,7 @@ namespace OpenSim.Framework.Console string uri = "/ReadResponses/" + sessionID.ToString() + "/"; m_Server.AddPollServiceHTTPHandler( - uri, new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, sessionID,25000)); // 25 secs timeout + uri, new PollServiceEventArgs(null, uri, HasEvents, GetEvents, NoEvents, sessionID,25000)); // 25 secs timeout XmlDocument xmldoc = new XmlDocument(); XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index 6863e0e37b..c4e569d6ee 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs @@ -387,6 +387,8 @@ namespace OpenSim.Framework.Servers.HttpServer if (TryGetPollServiceHTTPHandler(request.UriPath.ToString(), out psEvArgs)) { + psEvArgs.RequestsReceived++; + PollServiceHttpRequest psreq = new PollServiceHttpRequest(psEvArgs, context, request); if (psEvArgs.Request != null) diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs index 3079a7e52d..020bfd5baf 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs @@ -55,12 +55,26 @@ namespace OpenSim.Framework.Servers.HttpServer Inventory = 2 } + public string Url { get; set; } + + /// + /// Number of requests received for this poll service. + /// + public int RequestsReceived { get; set; } + + /// + /// Number of requests handled by this poll service. + /// + public int RequestsHandled { get; set; } + public PollServiceEventArgs( RequestMethod pRequest, + string pUrl, HasEventsMethod pHasEvents, GetEventsMethod pGetEvents, NoEventsMethod pNoEvents, UUID pId, int pTimeOutms) { Request = pRequest; + Url = pUrl; HasEvents = pHasEvents; GetEvents = pGetEvents; NoEvents = pNoEvents; diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs index 723530ae15..6aa94794ee 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs @@ -26,13 +26,19 @@ */ using System; +using System.Collections; +using System.Reflection; +using System.Text; using HttpServer; +using log4net; using OpenMetaverse; namespace OpenSim.Framework.Servers.HttpServer { public class PollServiceHttpRequest { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + public readonly PollServiceEventArgs PollServiceArgs; public readonly IHttpClientContext HttpContext; public readonly IHttpRequest Request; @@ -48,5 +54,44 @@ namespace OpenSim.Framework.Servers.HttpServer RequestTime = System.Environment.TickCount; RequestID = UUID.Random(); } + + internal void DoHTTPGruntWork(BaseHttpServer server, Hashtable responsedata) + { + OSHttpResponse response + = new OSHttpResponse(new HttpResponse(HttpContext, Request), HttpContext); + + byte[] buffer = server.DoHTTPGruntWork(responsedata, response); + + response.SendChunked = false; + response.ContentLength64 = buffer.Length; + response.ContentEncoding = Encoding.UTF8; + + try + { + response.OutputStream.Write(buffer, 0, buffer.Length); + } + catch (Exception ex) + { + m_log.Warn(string.Format("[POLL SERVICE WORKER THREAD]: Error ", ex)); + } + finally + { + //response.OutputStream.Close(); + try + { + response.OutputStream.Flush(); + response.Send(); + + //if (!response.KeepAlive && response.ReuseContext) + // response.FreeContext(); + } + catch (Exception e) + { + m_log.Warn(String.Format("[POLL SERVICE WORKER THREAD]: Error ", e)); + } + + PollServiceArgs.RequestsHandled++; + } + } } } \ No newline at end of file diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index aee3e3cca7..1b9010acf0 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -157,8 +157,7 @@ namespace OpenSim.Framework.Servers.HttpServer { foreach (PollServiceHttpRequest req in m_retryRequests) { - DoHTTPGruntWork(m_server,req, - req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); + req.DoHTTPGruntWork(m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); } } catch @@ -179,8 +178,8 @@ namespace OpenSim.Framework.Servers.HttpServer try { wreq = m_requests.Dequeue(0); - DoHTTPGruntWork(m_server,wreq, - wreq.PollServiceArgs.NoEvents(wreq.RequestID, wreq.PollServiceArgs.Id)); + wreq.DoHTTPGruntWork( + m_server, wreq.PollServiceArgs.NoEvents(wreq.RequestID, wreq.PollServiceArgs.Id)); } catch { @@ -214,7 +213,7 @@ namespace OpenSim.Framework.Servers.HttpServer { try { - DoHTTPGruntWork(m_server, req, responsedata); + req.DoHTTPGruntWork(m_server, responsedata); } catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream { @@ -227,7 +226,7 @@ namespace OpenSim.Framework.Servers.HttpServer { try { - DoHTTPGruntWork(m_server, req, responsedata); + req.DoHTTPGruntWork(m_server, responsedata); } catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream { @@ -242,8 +241,8 @@ namespace OpenSim.Framework.Servers.HttpServer { if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) { - DoHTTPGruntWork(m_server, req, - req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); + req.DoHTTPGruntWork( + m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); } else { @@ -258,46 +257,5 @@ namespace OpenSim.Framework.Servers.HttpServer } } } - - // DoHTTPGruntWork changed, not sending response - // do the same work around as core - - internal static void DoHTTPGruntWork(BaseHttpServer server, PollServiceHttpRequest req, Hashtable responsedata) - { - OSHttpResponse response - = new OSHttpResponse(new HttpResponse(req.HttpContext, req.Request), req.HttpContext); - - byte[] buffer = server.DoHTTPGruntWork(responsedata, response); - - response.SendChunked = false; - response.ContentLength64 = buffer.Length; - response.ContentEncoding = Encoding.UTF8; - - try - { - response.OutputStream.Write(buffer, 0, buffer.Length); - } - catch (Exception ex) - { - m_log.Warn(string.Format("[POLL SERVICE WORKER THREAD]: Error ", ex)); - } - finally - { - //response.OutputStream.Close(); - try - { - response.OutputStream.Flush(); - response.Send(); - - //if (!response.KeepAlive && response.ReuseContext) - // response.FreeContext(); - } - catch (Exception e) - { - m_log.Warn(String.Format("[POLL SERVICE WORKER THREAD]: Error ", e)); - } - } - } } -} - +} \ No newline at end of file diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs index 5c6bc1c002..1d4c7f0897 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs @@ -285,18 +285,7 @@ namespace OpenSim.Region.ClientStack.Linden foreach (OSD c in capsRequested) validCaps.Add(c.AsString()); - Hashtable caps = m_HostCapsObj.CapsHandlers.GetCapsDetails(true, validCaps); - - // Add the external too - foreach (KeyValuePair kvp in m_HostCapsObj.ExternalCapsHandlers) - { - if (!validCaps.Contains(kvp.Key)) - continue; - - caps[kvp.Key] = kvp.Value; - } - - string result = LLSDHelpers.SerialiseLLSDReply(caps); + string result = LLSDHelpers.SerialiseLLSDReply(m_HostCapsObj.GetCapsDetails(true, validCaps)); //m_log.DebugFormat("[CAPS] CapsRequest {0}", result); diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index 50bfda1b77..ca38a97578 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs @@ -377,7 +377,7 @@ namespace OpenSim.Region.ClientStack.Linden // TODO: Add EventQueueGet name/description for diagnostics MainServer.Instance.AddPollServiceHTTPHandler( eventQueueGetPath, - new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, agentID, 40000)); + new PollServiceEventArgs(null, eventQueueGetPath, HasEvents, GetEvents, NoEvents, agentID, 40000)); // m_log.DebugFormat( // "[EVENT QUEUE GET MODULE]: Registered EQG handler {0} for {1} in {2}", diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index b90df17622..86a0298eb4 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs @@ -77,7 +77,6 @@ namespace OpenSim.Region.ClientStack.Linden private static WebFetchInvDescHandler m_webFetchHandler; - private Dictionary m_capsDict = new Dictionary(); private static Thread[] m_workerThreads = null; private static DoubleQueue m_queue = @@ -114,7 +113,6 @@ namespace OpenSim.Region.ClientStack.Linden return; m_scene.EventManager.OnRegisterCaps -= RegisterCaps; - m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps; foreach (Thread t in m_workerThreads) Watchdog.AbortThread(t.ManagedThreadId); @@ -134,7 +132,6 @@ namespace OpenSim.Region.ClientStack.Linden m_webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService); m_scene.EventManager.OnRegisterCaps += RegisterCaps; - m_scene.EventManager.OnDeregisterCaps += DeregisterCaps; if (m_workerThreads == null) { @@ -177,8 +174,8 @@ namespace OpenSim.Region.ClientStack.Linden private Scene m_scene; - public PollServiceInventoryEventArgs(Scene scene, UUID pId) : - base(null, null, null, null, pId, int.MaxValue) + public PollServiceInventoryEventArgs(Scene scene, string url, UUID pId) : + base(null, url, null, null, null, pId, int.MaxValue) { m_scene = scene; @@ -308,40 +305,39 @@ namespace OpenSim.Region.ClientStack.Linden if (m_fetchInventoryDescendents2Url == "") return; - string capUrl = "/CAPS/" + UUID.Random() + "/"; - // Register this as a poll service - PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(m_scene, agentID); - + PollServiceInventoryEventArgs args + = new PollServiceInventoryEventArgs(m_scene, "/CAPS/" + UUID.Random() + "/", agentID); args.Type = PollServiceEventArgs.EventType.Inventory; - MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); - string hostName = m_scene.RegionInfo.ExternalHostName; - uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; - string protocol = "http"; - - if (MainServer.Instance.UseSSL) - { - hostName = MainServer.Instance.SSLCommonName; - port = MainServer.Instance.SSLPort; - protocol = "https"; - } + caps.RegisterPollHandler("FetchInventoryDescendents2", args); - caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); - - m_capsDict[agentID] = capUrl; +// MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); +// +// string hostName = m_scene.RegionInfo.ExternalHostName; +// uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; +// string protocol = "http"; +// +// if (MainServer.Instance.UseSSL) +// { +// hostName = MainServer.Instance.SSLCommonName; +// port = MainServer.Instance.SSLPort; +// protocol = "https"; +// } +// +// caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); } - private void DeregisterCaps(UUID agentID, Caps caps) - { - string capUrl; - - if (m_capsDict.TryGetValue(agentID, out capUrl)) - { - MainServer.Instance.RemoveHTTPHandler("", capUrl); - m_capsDict.Remove(agentID); - } - } +// private void DeregisterCaps(UUID agentID, Caps caps) +// { +// string capUrl; +// +// if (m_capsDict.TryGetValue(agentID, out capUrl)) +// { +// MainServer.Instance.RemoveHTTPHandler("", capUrl); +// m_capsDict.Remove(agentID); +// } +// } private void DoInventoryRequests() { @@ -355,4 +351,4 @@ namespace OpenSim.Region.ClientStack.Linden } } } -} +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs index bd60611d3d..ad1c4ce406 100644 --- a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs @@ -80,7 +80,7 @@ namespace OpenSim.Region.CoreModules.Framework MainConsole.Instance.Commands.AddCommand( "Comms", false, "show caps stats by user", - "show caps stats [ ]", + "show caps stats by user [ ]", "Shows statistics on capabilities use by user.", "If a user name is given, then prints a detailed breakdown of caps use ordered by number of requests received.", HandleShowCapsStatsByUserCommand); @@ -285,27 +285,31 @@ namespace OpenSim.Region.CoreModules.Framework if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) return; - StringBuilder caps = new StringBuilder(); - caps.AppendFormat("Region {0}:\n", m_scene.RegionInfo.RegionName); + StringBuilder capsReport = new StringBuilder(); + capsReport.AppendFormat("Region {0}:\n", m_scene.RegionInfo.RegionName); lock (m_capsObjects) { foreach (KeyValuePair kvp in m_capsObjects) { - caps.AppendFormat("** User {0}:\n", kvp.Key); + capsReport.AppendFormat("** User {0}:\n", kvp.Key); + Caps caps = kvp.Value; - for (IDictionaryEnumerator kvp2 = kvp.Value.CapsHandlers.GetCapsDetails(false, null).GetEnumerator(); kvp2.MoveNext(); ) + for (IDictionaryEnumerator kvp2 = caps.CapsHandlers.GetCapsDetails(false, null).GetEnumerator(); kvp2.MoveNext(); ) { Uri uri = new Uri(kvp2.Value.ToString()); - caps.AppendFormat(m_showCapsCommandFormat, kvp2.Key, uri.PathAndQuery); + capsReport.AppendFormat(m_showCapsCommandFormat, kvp2.Key, uri.PathAndQuery); } - foreach (KeyValuePair kvp3 in kvp.Value.ExternalCapsHandlers) - caps.AppendFormat(m_showCapsCommandFormat, kvp3.Key, kvp3.Value); + foreach (KeyValuePair kvp2 in caps.GetPollHandlers()) + capsReport.AppendFormat(m_showCapsCommandFormat, kvp2.Key, kvp2.Value.Url); + + foreach (KeyValuePair kvp3 in caps.ExternalCapsHandlers) + capsReport.AppendFormat(m_showCapsCommandFormat, kvp3.Key, kvp3.Value); } } - MainConsole.Instance.Output(caps.ToString()); + MainConsole.Instance.Output(capsReport.ToString()); } private void HandleShowCapsStatsByCapCommand(string module, string[] cmdParams) @@ -362,7 +366,16 @@ namespace OpenSim.Region.CoreModules.Framework { receivedStats[sp.Name] = reqHandler.RequestsReceived; handledStats[sp.Name] = reqHandler.RequestsHandled; - } + } + else + { + PollServiceEventArgs pollHandler = null; + if (caps.TryGetPollHandler(capName, out pollHandler)) + { + receivedStats[sp.Name] = pollHandler.RequestsReceived; + handledStats[sp.Name] = pollHandler.RequestsHandled; + } + } } ); @@ -391,11 +404,9 @@ namespace OpenSim.Region.CoreModules.Framework Caps caps = m_scene.CapsModule.GetCapsForUser(sp.UUID); if (caps == null) - return; + return; - Dictionary capsHandlers = caps.CapsHandlers.GetCapsHandlers(); - - foreach (IRequestHandler reqHandler in capsHandlers.Values) + foreach (IRequestHandler reqHandler in caps.CapsHandlers.GetCapsHandlers().Values) { string reqName = reqHandler.Name ?? ""; @@ -410,6 +421,23 @@ namespace OpenSim.Region.CoreModules.Framework handledStats[reqName] += reqHandler.RequestsHandled; } } + + foreach (KeyValuePair kvp in caps.GetPollHandlers()) + { + string name = kvp.Key; + PollServiceEventArgs pollHandler = kvp.Value; + + if (!receivedStats.ContainsKey(name)) + { + receivedStats[name] = pollHandler.RequestsReceived; + handledStats[name] = pollHandler.RequestsHandled; + } + else + { + receivedStats[name] += pollHandler.RequestsReceived; + handledStats[name] += pollHandler.RequestsHandled; + } + } } ); @@ -468,12 +496,16 @@ namespace OpenSim.Region.CoreModules.Framework if (caps == null) return; - Dictionary capsHandlers = caps.CapsHandlers.GetCapsHandlers(); + List capRows = new List(); - foreach (IRequestHandler reqHandler in capsHandlers.Values.OrderByDescending(rh => rh.RequestsReceived)) - { - cdt.AddRow(reqHandler.Name, reqHandler.RequestsReceived, reqHandler.RequestsHandled); - } + foreach (IRequestHandler reqHandler in caps.CapsHandlers.GetCapsHandlers().Values) + capRows.Add(new CapTableRow(reqHandler.Name, reqHandler.RequestsReceived, reqHandler.RequestsHandled)); + + foreach (KeyValuePair kvp in caps.GetPollHandlers()) + capRows.Add(new CapTableRow(kvp.Key, kvp.Value.RequestsReceived, kvp.Value.RequestsHandled)); + + foreach (CapTableRow ctr in capRows.OrderByDescending(ctr => ctr.RequestsReceived)) + cdt.AddRow(ctr.Name, ctr.RequestsReceived, ctr.RequestsHandled); sb.Append(cdt.ToString()); } @@ -505,6 +537,14 @@ namespace OpenSim.Region.CoreModules.Framework totalRequestsReceived += reqHandler.RequestsReceived; totalRequestsHandled += reqHandler.RequestsHandled; } + + Dictionary capsPollHandlers = caps.GetPollHandlers(); + + foreach (PollServiceEventArgs handler in capsPollHandlers.Values) + { + totalRequestsReceived += handler.RequestsReceived; + totalRequestsHandled += handler.RequestsHandled; + } cdt.AddRow(sp.Name, sp.IsChildAgent ? "child" : "root", totalRequestsReceived, totalRequestsHandled); } @@ -512,5 +552,19 @@ namespace OpenSim.Region.CoreModules.Framework sb.Append(cdt.ToString()); } + + private class CapTableRow + { + public string Name { get; set; } + public int RequestsReceived { get; set; } + public int RequestsHandled { get; set; } + + public CapTableRow(string name, int requestsReceived, int requestsHandled) + { + Name = name; + RequestsReceived = requestsReceived; + RequestsHandled = requestsHandled; + } + } } } \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs index def8162b2f..99a3122e1d 100644 --- a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs @@ -235,7 +235,8 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp string uri = "/lslhttp/" + urlcode.ToString() + "/"; - PollServiceEventArgs args = new PollServiceEventArgs(HttpRequestHandler, HasEvents, GetEvents, NoEvents, urlcode, 25000); + PollServiceEventArgs args + = new PollServiceEventArgs(HttpRequestHandler, uri, HasEvents, GetEvents, NoEvents, urlcode, 25000); args.Type = PollServiceEventArgs.EventType.LslHttp; m_HttpServer.AddPollServiceHTTPHandler(uri, args); @@ -280,7 +281,8 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp string uri = "/lslhttps/" + urlcode.ToString() + "/"; - PollServiceEventArgs args = new PollServiceEventArgs(HttpRequestHandler, HasEvents, GetEvents, NoEvents, urlcode, 25000); + PollServiceEventArgs args + = new PollServiceEventArgs(HttpRequestHandler, uri, HasEvents, GetEvents, NoEvents, urlcode, 25000); args.Type = PollServiceEventArgs.EventType.LslHttp; m_HttpsServer.AddPollServiceHTTPHandler(uri, args); From e8e073aa97a8f756f42b242dd1cfcd05beb4d8ef Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 16 Jul 2013 00:05:45 +0100 Subject: [PATCH 09/55] Simplify EventQueue cap setup so that it is also stat monitored. Curiously, the number of requests received is always one greater than that shown as handled - needs investigation --- .../Caps/EventQueue/EventQueueGetModule.cs | 74 ++++++++----------- 1 file changed, 29 insertions(+), 45 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index ca38a97578..1835a72a4a 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs @@ -252,29 +252,32 @@ namespace OpenSim.Region.ClientStack.Linden List removeitems = new List(); lock (m_AvatarQueueUUIDMapping) - { - foreach (UUID ky in m_AvatarQueueUUIDMapping.Keys) - { -// m_log.DebugFormat("[EVENTQUEUE]: Found key {0} in m_AvatarQueueUUIDMapping while looking for {1}", ky, AgentID); - if (ky == agentID) - { - removeitems.Add(ky); - } - } + m_AvatarQueueUUIDMapping.Remove(agentID); - foreach (UUID ky in removeitems) - { - UUID eventQueueGetUuid = m_AvatarQueueUUIDMapping[ky]; - m_AvatarQueueUUIDMapping.Remove(ky); - - string eqgPath = GenerateEqgCapPath(eventQueueGetUuid); - MainServer.Instance.RemovePollServiceHTTPHandler("", eqgPath); - -// m_log.DebugFormat( -// "[EVENT QUEUE GET MODULE]: Removed EQG handler {0} for {1} in {2}", -// eqgPath, agentID, m_scene.RegionInfo.RegionName); - } - } +// lock (m_AvatarQueueUUIDMapping) +// { +// foreach (UUID ky in m_AvatarQueueUUIDMapping.Keys) +// { +//// m_log.DebugFormat("[EVENTQUEUE]: Found key {0} in m_AvatarQueueUUIDMapping while looking for {1}", ky, AgentID); +// if (ky == agentID) +// { +// removeitems.Add(ky); +// } +// } +// +// foreach (UUID ky in removeitems) +// { +// UUID eventQueueGetUuid = m_AvatarQueueUUIDMapping[ky]; +// m_AvatarQueueUUIDMapping.Remove(ky); +// +// string eqgPath = GenerateEqgCapPath(eventQueueGetUuid); +// MainServer.Instance.RemovePollServiceHTTPHandler("", eqgPath); +// +//// m_log.DebugFormat( +//// "[EVENT QUEUE GET MODULE]: Removed EQG handler {0} for {1} in {2}", +//// eqgPath, agentID, m_scene.RegionInfo.RegionName); +// } +// } UUID searchval = UUID.Zero; @@ -359,29 +362,10 @@ namespace OpenSim.Region.ClientStack.Linden m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID); } - string eventQueueGetPath = GenerateEqgCapPath(eventQueueGetUUID); - - // Register this as a caps handler - // FIXME: Confusingly, we need to register separate as a capability so that the client is told about - // EventQueueGet when it receive capability information, but then we replace the rest handler immediately - // afterwards with the poll service. So for now, we'll pass a null instead to simplify code reading, but - // really it should be possible to directly register the poll handler as a capability. - caps.RegisterHandler( - "EventQueueGet", new RestHTTPHandler("POST", eventQueueGetPath, null, "EventQueueGet", null)); -// delegate(Hashtable m_dhttpMethod) -// { -// return ProcessQueue(m_dhttpMethod, agentID, caps); -// })); - - // This will persist this beyond the expiry of the caps handlers - // TODO: Add EventQueueGet name/description for diagnostics - MainServer.Instance.AddPollServiceHTTPHandler( - eventQueueGetPath, - new PollServiceEventArgs(null, eventQueueGetPath, HasEvents, GetEvents, NoEvents, agentID, 40000)); - -// m_log.DebugFormat( -// "[EVENT QUEUE GET MODULE]: Registered EQG handler {0} for {1} in {2}", -// eventQueueGetPath, agentID, m_scene.RegionInfo.RegionName); + caps.RegisterPollHandler( + "EventQueueGet", + new PollServiceEventArgs( + null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, 40000)); Random rnd = new Random(Environment.TickCount); lock (m_ids) From 42e2a0d66eaa7e322bce817e9e2cc9a288de167b Mon Sep 17 00:00:00 2001 From: dahlia Date: Tue, 16 Jul 2013 01:12:56 -0700 Subject: [PATCH 10/55] MSDN documentation is unclear about whether exiting a lock() block will trigger a Monitor.Wait() to exit, so avoid some locks that don't actually affect the state of the internal queues in the BlockingQueue class. --- OpenSim/Framework/BlockingQueue.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index 365816109b..cc016b07c3 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -58,7 +58,7 @@ namespace OpenSim.Framework { lock (m_queueSync) { - if (m_queue.Count < 1 && m_pqueue.Count < 1) + while (m_queue.Count < 1 && m_pqueue.Count < 1) { Monitor.Wait(m_queueSync); } @@ -91,6 +91,9 @@ namespace OpenSim.Framework public bool Contains(T item) { + if (m_queue.Count < 1 && m_pqueue.Count < 1) + return false; + lock (m_queueSync) { if (m_pqueue.Contains(item)) @@ -101,14 +104,14 @@ namespace OpenSim.Framework public int Count() { - lock (m_queueSync) - { - return m_queue.Count+m_pqueue.Count; - } + return m_queue.Count+m_pqueue.Count; } public T[] GetQueueArray() { + if (m_queue.Count < 1 && m_pqueue.Count < 1) + return new T[0]; + lock (m_queueSync) { return m_queue.ToArray(); From 70aa77f520060a27df1fb7fbdf39685ff866dcf8 Mon Sep 17 00:00:00 2001 From: dahlia Date: Tue, 16 Jul 2013 01:31:09 -0700 Subject: [PATCH 11/55] add locking to internal queue in WebFetchInvDescModule; lack of which caused a random crash in a load test yesterday --- .../Linden/Caps/WebFetchInvDescModule.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index 164adeb2d4..4ff617fbd7 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs @@ -254,10 +254,13 @@ namespace OpenSim.Region.ClientStack.Linden } } - if (highPriority) - m_queue.EnqueueHigh(reqinfo); - else - m_queue.EnqueueLow(reqinfo); + lock (m_queue) + { + if (highPriority) + m_queue.EnqueueHigh(reqinfo); + else + m_queue.EnqueueLow(reqinfo); + } }; NoEvents = (x, y) => @@ -345,7 +348,9 @@ namespace OpenSim.Region.ClientStack.Linden { Watchdog.UpdateThread(); - aPollRequest poolreq = m_queue.Dequeue(); + aPollRequest poolreq = null; + lock (m_queue) + poolreq = m_queue.Dequeue(); if (poolreq != null && poolreq.thepoll != null) poolreq.thepoll.Process(poolreq); From 6dd454240fb962a408c979060701531f0f458e8e Mon Sep 17 00:00:00 2001 From: dahlia Date: Tue, 16 Jul 2013 02:03:01 -0700 Subject: [PATCH 12/55] revert last commit which seems to conflict with DoubleQueue internals. The random crash might be in DoubleQueue instead. See http://pastebin.com/XhNBNqsc --- .../Linden/Caps/WebFetchInvDescModule.cs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index 4ff617fbd7..164adeb2d4 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs @@ -254,13 +254,10 @@ namespace OpenSim.Region.ClientStack.Linden } } - lock (m_queue) - { - if (highPriority) - m_queue.EnqueueHigh(reqinfo); - else - m_queue.EnqueueLow(reqinfo); - } + if (highPriority) + m_queue.EnqueueHigh(reqinfo); + else + m_queue.EnqueueLow(reqinfo); }; NoEvents = (x, y) => @@ -348,9 +345,7 @@ namespace OpenSim.Region.ClientStack.Linden { Watchdog.UpdateThread(); - aPollRequest poolreq = null; - lock (m_queue) - poolreq = m_queue.Dequeue(); + aPollRequest poolreq = m_queue.Dequeue(); if (poolreq != null && poolreq.thepoll != null) poolreq.thepoll.Process(poolreq); From 5a01ffa5150edf4c4f8b4675d8c8c2b2c6ec0684 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 16 Jul 2013 07:15:14 -0700 Subject: [PATCH 13/55] High CPU hunt: try a different blocking queue, DoubleQueue --- .../Framework/GridServiceThrottle/GridServiceThrottleModule.cs | 3 ++- .../Framework/UserManagement/UserManagementModule.cs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs index fd4d48ae2b..a069317e38 100644 --- a/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs @@ -49,7 +49,8 @@ namespace OpenSim.Region.CoreModules.Framework private readonly List m_scenes = new List(); - private OpenSim.Framework.BlockingQueue m_RequestQueue = new OpenSim.Framework.BlockingQueue(); + //private OpenSim.Framework.BlockingQueue m_RequestQueue = new OpenSim.Framework.BlockingQueue(); + private OpenSim.Framework.DoubleQueue m_RequestQueue = new OpenSim.Framework.DoubleQueue(); public void Initialise(IConfigSource config) { diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 507329eb59..ffb8bda9d8 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -60,6 +60,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement protected Dictionary m_UserCache = new Dictionary(); // Throttle the name requests + //private OpenSim.Framework.BlockingQueue m_RequestQueue = new OpenSim.Framework.BlockingQueue(); private OpenSim.Framework.BlockingQueue m_RequestQueue = new OpenSim.Framework.BlockingQueue(); From 6da50d34dfb321e71b5242ab8d82a9801da5d05b Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 16 Jul 2013 07:19:13 -0700 Subject: [PATCH 14/55] Actually use DoubleQueue in UserManagement/UserManagementModule --- .../Framework/UserManagement/UserManagementModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index ffb8bda9d8..9f5e4ae1f2 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -61,7 +61,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement // Throttle the name requests //private OpenSim.Framework.BlockingQueue m_RequestQueue = new OpenSim.Framework.BlockingQueue(); - private OpenSim.Framework.BlockingQueue m_RequestQueue = new OpenSim.Framework.BlockingQueue(); + private OpenSim.Framework.DoubleQueue m_RequestQueue = new OpenSim.Framework.DoubleQueue(); #region ISharedRegionModule From e0f0b88dece110ca10208a2f826f9e360a9d7826 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 16 Jul 2013 13:01:39 -0700 Subject: [PATCH 15/55] In the pursuit of using less CPU: now trying to avoid blocking queues altogether. Instead, this uses a timer. No sure if it's better or worse, but worth the try. --- .../GridServiceThrottleModule.cs | 71 ++++++++++++++++--- .../UserManagement/UserManagementModule.cs | 64 +++++++++++++++-- 2 files changed, 120 insertions(+), 15 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs index a069317e38..83be644142 100644 --- a/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs @@ -48,18 +48,26 @@ namespace OpenSim.Region.CoreModules.Framework MethodBase.GetCurrentMethod().DeclaringType); private readonly List m_scenes = new List(); + private System.Timers.Timer m_timer = new System.Timers.Timer(); //private OpenSim.Framework.BlockingQueue m_RequestQueue = new OpenSim.Framework.BlockingQueue(); - private OpenSim.Framework.DoubleQueue m_RequestQueue = new OpenSim.Framework.DoubleQueue(); + // private OpenSim.Framework.DoubleQueue m_RequestQueue = new OpenSim.Framework.DoubleQueue(); + private Queue m_RequestQueue = new Queue(); public void Initialise(IConfigSource config) { - Watchdog.StartThread( - ProcessQueue, - "GridServiceRequestThread", - ThreadPriority.BelowNormal, - true, - false); + m_timer = new System.Timers.Timer(); + m_timer.AutoReset = false; + m_timer.Interval = 15000; // 15 secs at first + m_timer.Elapsed += ProcessQueue; + m_timer.Start(); + + //Watchdog.StartThread( + // ProcessQueue, + // "GridServiceRequestThread", + // ThreadPriority.BelowNormal, + // true, + // false); } public void AddRegion(Scene scene) @@ -89,6 +97,16 @@ namespace OpenSim.Region.CoreModules.Framework client.OnRegionHandleRequest += OnRegionHandleRequest; } + //void OnMakeRootAgent(ScenePresence obj) + //{ + // lock (m_timer) + // { + // m_timer.Stop(); + // m_timer.Interval = 1000; + // m_timer.Start(); + // } + //} + public void PostInitialise() { } @@ -118,7 +136,8 @@ namespace OpenSim.Region.CoreModules.Framework } GridRegionRequest request = new GridRegionRequest(client, regionID); - m_RequestQueue.Enqueue(request); + lock (m_RequestQueue) + m_RequestQueue.Enqueue(request); } @@ -134,6 +153,41 @@ namespace OpenSim.Region.CoreModules.Framework return false; } + private bool AreThereRootAgents() + { + foreach (Scene s in m_scenes) + { + if (s.GetRootAgentCount() > 0) + return true; + } + + return false; + } + + private void ProcessQueue(object sender, System.Timers.ElapsedEventArgs e) + { + while (m_RequestQueue.Count > 0) + { + GridRegionRequest request = null; + lock (m_RequestQueue) + request = m_RequestQueue.Dequeue(); + if (request != null) + { + GridRegion r = m_scenes[0].GridService.GetRegionByUUID(UUID.Zero, request.regionID); + + if (r != null && r.RegionHandle != 0) + request.client.SendRegionHandle(request.regionID, r.RegionHandle); + } + } + + if (AreThereRootAgents()) + m_timer.Interval = 1000; // 1 sec + else + m_timer.Interval = 10000; // 10 secs + + m_timer.Start(); + } + private void ProcessQueue() { while (true) @@ -150,6 +204,7 @@ namespace OpenSim.Region.CoreModules.Framework } } } + } class GridRegionRequest diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 9f5e4ae1f2..61c1e70c1b 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -61,8 +61,10 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement // Throttle the name requests //private OpenSim.Framework.BlockingQueue m_RequestQueue = new OpenSim.Framework.BlockingQueue(); - private OpenSim.Framework.DoubleQueue m_RequestQueue = new OpenSim.Framework.DoubleQueue(); + //private OpenSim.Framework.DoubleQueue m_RequestQueue = new OpenSim.Framework.DoubleQueue(); + private Queue m_RequestQueue = new Queue(); + private System.Timers.Timer m_timer; #region ISharedRegionModule @@ -599,12 +601,18 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement protected void Init() { RegisterConsoleCmds(); - Watchdog.StartThread( - ProcessQueue, - "NameRequestThread", - ThreadPriority.BelowNormal, - true, - false); + //Watchdog.StartThread( + // ProcessQueue, + // "NameRequestThread", + // ThreadPriority.BelowNormal, + // true, + // false); + + m_timer = new System.Timers.Timer(); + m_timer.AutoReset = false; + m_timer.Interval = 15000; // 15 secs at first + m_timer.Elapsed += ProcessQueue; + m_timer.Start(); } @@ -698,6 +706,48 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } } + private bool AreThereRootAgents() + { + foreach (Scene s in m_Scenes) + { + if (s.GetRootAgentCount() > 0) + return true; + } + + return false; + } + + private void ProcessQueue(object sender, System.Timers.ElapsedEventArgs e) + { + while (m_RequestQueue.Count > 0) + { + NameRequest request = null; + lock (m_RequestQueue) + request = m_RequestQueue.Dequeue(); + + if (request != null) + { + string[] names; + bool foundRealName = TryGetUserNames(request.uuid, out names); + + if (names.Length == 2) + { + if (!foundRealName) + m_log.DebugFormat("[USER MANAGEMENT MODULE]: Sending {0} {1} for {2} to {3} since no bound name found", names[0], names[1], request.uuid, request.client.Name); + + request.client.SendNameReply(request.uuid, names[0], names[1]); + } + } + } + + if (AreThereRootAgents()) + m_timer.Interval = 1000; // 1 sec + else + m_timer.Interval = 10000; // 10 secs + + m_timer.Start(); + + } } class NameRequest From 21a09ad3ad42b24bce4fc04c6bcd6f7d9a80af08 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 16 Jul 2013 21:54:00 +0100 Subject: [PATCH 16/55] Revert "MSDN documentation is unclear about whether exiting a lock() block will trigger a Monitor.Wait() to exit, so avoid some locks that don't actually affect the state of the internal queues in the BlockingQueue class." This reverts commit 42e2a0d66eaa7e322bce817e9e2cc9a288de167b Reverting because unfortunately this introduces race conditions because Contains(), Count() and GetQueueArray() may now end up returning the wrong result if another thread performs a simultaneous update on m_queue. Code such as PollServiceRequestManager.Stop() relies on the count being correct otherwise a request may be lost. Also, though some of the internal queue methods do not affect state, they are not thread-safe and could return the wrong result generating the same problem lock() generates Monitor.Enter() and Monitor.Exit() under the covers. Monitor.Exit() does not cause Monitor.Wait() to exist, only Pulse() and PulseAll() will do this Reverted with agreement. --- OpenSim/Framework/BlockingQueue.cs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index cc016b07c3..365816109b 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -58,7 +58,7 @@ namespace OpenSim.Framework { lock (m_queueSync) { - while (m_queue.Count < 1 && m_pqueue.Count < 1) + if (m_queue.Count < 1 && m_pqueue.Count < 1) { Monitor.Wait(m_queueSync); } @@ -91,9 +91,6 @@ namespace OpenSim.Framework public bool Contains(T item) { - if (m_queue.Count < 1 && m_pqueue.Count < 1) - return false; - lock (m_queueSync) { if (m_pqueue.Contains(item)) @@ -104,14 +101,14 @@ namespace OpenSim.Framework public int Count() { - return m_queue.Count+m_pqueue.Count; + lock (m_queueSync) + { + return m_queue.Count+m_pqueue.Count; + } } public T[] GetQueueArray() { - if (m_queue.Count < 1 && m_pqueue.Count < 1) - return new T[0]; - lock (m_queueSync) { return m_queue.ToArray(); From 50b8ab60f2d4d8a2cc7024012fc1333be7635276 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 16 Jul 2013 23:00:07 +0100 Subject: [PATCH 17/55] Revert "Revert "MSDN documentation is unclear about whether exiting a lock() block will trigger a Monitor.Wait() to exit, so avoid some locks that don't actually affect the state of the internal queues in the BlockingQueue class."" This reverts commit 21a09ad3ad42b24bce4fc04c6bcd6f7d9a80af08. After more analysis and discussion, it is apparant that the Count(), Contains() and GetQueueArray() cannot be made thread-safe anyway without external locking And this change appears to have a positive impact on performance. I still believe that Monitor.Exit() will not release any thread for Monitor.Wait(), as per http://msdn.microsoft.com/en-gb/library/vstudio/system.threading.monitor.exit%28v=vs.100%29.aspx so this should in theory make no difference, though mono implementation issues could possibly be coming into play. --- OpenSim/Framework/BlockingQueue.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index 365816109b..cc016b07c3 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -58,7 +58,7 @@ namespace OpenSim.Framework { lock (m_queueSync) { - if (m_queue.Count < 1 && m_pqueue.Count < 1) + while (m_queue.Count < 1 && m_pqueue.Count < 1) { Monitor.Wait(m_queueSync); } @@ -91,6 +91,9 @@ namespace OpenSim.Framework public bool Contains(T item) { + if (m_queue.Count < 1 && m_pqueue.Count < 1) + return false; + lock (m_queueSync) { if (m_pqueue.Contains(item)) @@ -101,14 +104,14 @@ namespace OpenSim.Framework public int Count() { - lock (m_queueSync) - { - return m_queue.Count+m_pqueue.Count; - } + return m_queue.Count+m_pqueue.Count; } public T[] GetQueueArray() { + if (m_queue.Count < 1 && m_pqueue.Count < 1) + return new T[0]; + lock (m_queueSync) { return m_queue.ToArray(); From cbc3576ee2ee0afc7cbf66d4d782dfaee9bbdcda Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 16 Jul 2013 23:14:53 +0100 Subject: [PATCH 18/55] minor: Add warning method doc about possibly inconsistent results returned from BlockingQueue.Contains(), Count() and GetQueueArray() --- OpenSim/Framework/BlockingQueue.cs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index cc016b07c3..aef1192364 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -89,6 +89,12 @@ namespace OpenSim.Framework } } + /// + /// Indicate whether this queue contains the given item. + /// + /// + /// This method is not thread-safe. Do not rely on the result without consistent external locking. + /// public bool Contains(T item) { if (m_queue.Count < 1 && m_pqueue.Count < 1) @@ -102,11 +108,23 @@ namespace OpenSim.Framework } } + /// + /// Return a count of the number of requests on this queue. + /// + /// + /// This method is not thread-safe. Do not rely on the result without consistent external locking. + /// public int Count() { - return m_queue.Count+m_pqueue.Count; + return m_queue.Count + m_pqueue.Count; } + /// + /// Return the array of items on this queue. + /// + /// + /// This method is not thread-safe. Do not rely on the result without consistent external locking. + /// public T[] GetQueueArray() { if (m_queue.Count < 1 && m_pqueue.Count < 1) From 3fbd2c54bc7357ea61b3a8b0c56473ae6a5a3260 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 16 Jul 2013 17:04:32 -0700 Subject: [PATCH 19/55] Eliminated the UserManagement/UserManagementModule throttle thread. Made the other one generic, taking any continuation. --- .../GridServiceThrottleModule.cs | 166 ++++++++-------- .../UserManagement/UserManagementModule.cs | 177 ++++++------------ 2 files changed, 151 insertions(+), 192 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs index 83be644142..d805fd3200 100644 --- a/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs @@ -42,7 +42,7 @@ using GridRegion = OpenSim.Services.Interfaces.GridRegion; namespace OpenSim.Region.CoreModules.Framework { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GridServiceThrottleModule")] - public class GridServiceThrottleModule : ISharedRegionModule + public class ServiceThrottleModule : ISharedRegionModule, IServiceThrottleModule { private static readonly ILog m_log = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); @@ -52,12 +52,16 @@ namespace OpenSim.Region.CoreModules.Framework //private OpenSim.Framework.BlockingQueue m_RequestQueue = new OpenSim.Framework.BlockingQueue(); // private OpenSim.Framework.DoubleQueue m_RequestQueue = new OpenSim.Framework.DoubleQueue(); - private Queue m_RequestQueue = new Queue(); + //private Queue m_RequestQueue = new Queue(); + private Queue m_RequestQueue = new Queue(); + + #region ISharedRegionModule public void Initialise(IConfigSource config) { m_timer = new System.Timers.Timer(); m_timer.AutoReset = false; + m_timer.Enabled = true; m_timer.Interval = 15000; // 15 secs at first m_timer.Elapsed += ProcessQueue; m_timer.Start(); @@ -75,7 +79,9 @@ namespace OpenSim.Region.CoreModules.Framework lock (m_scenes) { m_scenes.Add(scene); + scene.RegisterModuleInterface(this); scene.EventManager.OnNewClient += OnNewClient; + scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; } } @@ -92,21 +98,6 @@ namespace OpenSim.Region.CoreModules.Framework } } - void OnNewClient(IClientAPI client) - { - client.OnRegionHandleRequest += OnRegionHandleRequest; - } - - //void OnMakeRootAgent(ScenePresence obj) - //{ - // lock (m_timer) - // { - // m_timer.Stop(); - // m_timer.Interval = 1000; - // m_timer.Start(); - // } - //} - public void PostInitialise() { } @@ -117,7 +108,7 @@ namespace OpenSim.Region.CoreModules.Framework public string Name { - get { return "GridServiceThrottleModule"; } + get { return "ServiceThrottleModule"; } } public Type ReplaceableInterface @@ -125,9 +116,31 @@ namespace OpenSim.Region.CoreModules.Framework get { return null; } } + #endregion ISharedRegionMOdule + + #region Events + + void OnNewClient(IClientAPI client) + { + client.OnRegionHandleRequest += OnRegionHandleRequest; + } + + void OnMakeRootAgent(ScenePresence obj) + { + lock (m_timer) + { + if (!m_timer.Enabled) + { + m_timer.Interval = 1000; + m_timer.Enabled = true; + m_timer.Start(); + } + } + } + public void OnRegionHandleRequest(IClientAPI client, UUID regionID) { - //m_log.DebugFormat("[GRIDSERVICE THROTTLE]: RegionHandleRequest {0}", regionID); + //m_log.DebugFormat("[SERVICE THROTTLE]: RegionHandleRequest {0}", regionID); ulong handle = 0; if (IsLocalRegionHandle(regionID, out handle)) { @@ -135,12 +148,65 @@ namespace OpenSim.Region.CoreModules.Framework return; } - GridRegionRequest request = new GridRegionRequest(client, regionID); + Action action = delegate + { + GridRegion r = m_scenes[0].GridService.GetRegionByUUID(UUID.Zero, regionID); + + if (r != null && r.RegionHandle != 0) + client.SendRegionHandle(regionID, r.RegionHandle); + }; + lock (m_RequestQueue) - m_RequestQueue.Enqueue(request); + m_RequestQueue.Enqueue(action); } + #endregion Events + + #region IServiceThrottleModule + + public void Enqueue(Action continuation) + { + m_RequestQueue.Enqueue(continuation); + } + + #endregion IServiceThrottleModule + + #region Process Continuation Queue + + private void ProcessQueue(object sender, System.Timers.ElapsedEventArgs e) + { + m_log.DebugFormat("[YYY]: Process queue with {0} continuations", m_RequestQueue.Count); + + while (m_RequestQueue.Count > 0) + { + Action continuation = null; + lock (m_RequestQueue) + continuation = m_RequestQueue.Dequeue(); + + if (continuation != null) + continuation(); + } + + if (AreThereRootAgents()) + { + lock (m_timer) + { + m_timer.Interval = 1000; // 1 sec + m_timer.Enabled = true; + m_timer.Start(); + } + } + else + lock (m_timer) + m_timer.Enabled = false; + + } + + #endregion Process Continuation Queue + + #region Misc + private bool IsLocalRegionHandle(UUID regionID, out ulong regionHandle) { regionHandle = 0; @@ -157,65 +223,15 @@ namespace OpenSim.Region.CoreModules.Framework { foreach (Scene s in m_scenes) { - if (s.GetRootAgentCount() > 0) - return true; + foreach (ScenePresence sp in s.GetScenePresences()) + if (!sp.IsChildAgent) + return true; } return false; } - private void ProcessQueue(object sender, System.Timers.ElapsedEventArgs e) - { - while (m_RequestQueue.Count > 0) - { - GridRegionRequest request = null; - lock (m_RequestQueue) - request = m_RequestQueue.Dequeue(); - if (request != null) - { - GridRegion r = m_scenes[0].GridService.GetRegionByUUID(UUID.Zero, request.regionID); - - if (r != null && r.RegionHandle != 0) - request.client.SendRegionHandle(request.regionID, r.RegionHandle); - } - } - - if (AreThereRootAgents()) - m_timer.Interval = 1000; // 1 sec - else - m_timer.Interval = 10000; // 10 secs - - m_timer.Start(); - } - - private void ProcessQueue() - { - while (true) - { - Watchdog.UpdateThread(); - - GridRegionRequest request = m_RequestQueue.Dequeue(); - if (request != null) - { - GridRegion r = m_scenes[0].GridService.GetRegionByUUID(UUID.Zero, request.regionID); - - if (r != null && r.RegionHandle != 0) - request.client.SendRegionHandle(request.regionID, r.RegionHandle); - } - } - } - + #endregion Misc } - class GridRegionRequest - { - public IClientAPI client; - public UUID regionID; - - public GridRegionRequest(IClientAPI c, UUID r) - { - client = c; - regionID = r; - } - } } diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 61c1e70c1b..73b59d329e 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -56,16 +56,10 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement protected bool m_Enabled; protected List m_Scenes = new List(); + protected IServiceThrottleModule m_ServiceThrottle; // The cache protected Dictionary m_UserCache = new Dictionary(); - // Throttle the name requests - //private OpenSim.Framework.BlockingQueue m_RequestQueue = new OpenSim.Framework.BlockingQueue(); - //private OpenSim.Framework.DoubleQueue m_RequestQueue = new OpenSim.Framework.DoubleQueue(); - private Queue m_RequestQueue = new Queue(); - - private System.Timers.Timer m_timer; - #region ISharedRegionModule public void Initialise(IConfigSource config) @@ -118,6 +112,8 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement public void RegionLoaded(Scene s) { + if (m_Enabled && m_ServiceThrottle == null) + m_ServiceThrottle = s.RequestModuleInterface(); } public void PostInitialise() @@ -157,7 +153,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement client.OnAvatarPickerRequest -= new AvatarPickerRequest(HandleAvatarPickerRequest); } - void HandleUUIDNameRequest(UUID uuid, IClientAPI remote_client) + void HandleUUIDNameRequest(UUID uuid, IClientAPI client) { // m_log.DebugFormat( // "[USER MANAGEMENT MODULE]: Handling request for name binding of UUID {0} from {1}", @@ -165,12 +161,33 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement if (m_Scenes[0].LibraryService != null && (m_Scenes[0].LibraryService.LibraryRootFolder.Owner == uuid)) { - remote_client.SendNameReply(uuid, "Mr", "OpenSim"); + client.SendNameReply(uuid, "Mr", "OpenSim"); } else { - NameRequest request = new NameRequest(remote_client, uuid); - m_RequestQueue.Enqueue(request); + string[] names = new string[2]; + if (TryGetUserNamesFromCache(uuid, names)) + { + client.SendNameReply(uuid, names[0], names[1]); + return; + } + + // Not found in cache, get it from services + m_ServiceThrottle.Enqueue(delegate + { + m_log.DebugFormat("[YYY]: Name request {0}", uuid); + bool foundRealName = TryGetUserNamesFromServices(uuid, names); + + if (names.Length == 2) + { + if (!foundRealName) + m_log.DebugFormat("[USER MANAGEMENT MODULE]: Sending {0} {1} for {2} to {3} since no bound name found", names[0], names[1], uuid, client.Name); + else + m_log.DebugFormat("[YYY]: Found user {0} {1} for uuid {2}", names[0], names[1], uuid); + + client.SendNameReply(uuid, names[0], names[1]); + } + }); } } @@ -286,15 +303,27 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } /// - /// Try to get the names bound to the given uuid. + /// /// - /// True if the name was found, false if not. - /// - /// The array of names if found. If not found, then names[0] = "Unknown" and names[1] = "User" - private bool TryGetUserNames(UUID uuid, out string[] names) + /// + /// Caller please provide a properly instantiated array for names, string[2] + /// + private bool TryGetUserNames(UUID uuid, string[] names) { - names = new string[2]; + if (names == null) + names = new string[2]; + if (TryGetUserNamesFromCache(uuid, names)) + return true; + + if (TryGetUserNamesFromServices(uuid, names)) + return true; + + return false; + } + + private bool TryGetUserNamesFromCache(UUID uuid, string[] names) + { lock (m_UserCache) { if (m_UserCache.ContainsKey(uuid)) @@ -306,6 +335,17 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } } + return false; + } + + /// + /// Try to get the names bound to the given uuid, from the services. + /// + /// True if the name was found, false if not. + /// + /// The array of names if found. If not found, then names[0] = "Unknown" and names[1] = "User" + private bool TryGetUserNamesFromServices(UUID uuid, string[] names) + { UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(UUID.Zero, uuid); if (account != null) @@ -390,18 +430,11 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement public string GetUserName(UUID uuid) { - string[] names; - TryGetUserNames(uuid, out names); + string[] names = new string[2]; + TryGetUserNames(uuid, names); - if (names.Length == 2) - { - string firstname = names[0]; - string lastname = names[1]; + return names[0] + " " + names[1]; - return firstname + " " + lastname; - } - - return "(hippos)"; } public string GetUserHomeURL(UUID userID) @@ -601,19 +634,6 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement protected void Init() { RegisterConsoleCmds(); - //Watchdog.StartThread( - // ProcessQueue, - // "NameRequestThread", - // ThreadPriority.BelowNormal, - // true, - // false); - - m_timer = new System.Timers.Timer(); - m_timer.AutoReset = false; - m_timer.Interval = 15000; // 15 secs at first - m_timer.Elapsed += ProcessQueue; - m_timer.Start(); - } protected void RegisterConsoleCmds() @@ -683,83 +703,6 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement MainConsole.Instance.Output(cdt.ToString()); } - private void ProcessQueue() - { - while (true) - { - Watchdog.UpdateThread(); - - NameRequest request = m_RequestQueue.Dequeue(); - if (request != null) - { - string[] names; - bool foundRealName = TryGetUserNames(request.uuid, out names); - - if (names.Length == 2) - { - if (!foundRealName) - m_log.DebugFormat("[USER MANAGEMENT MODULE]: Sending {0} {1} for {2} to {3} since no bound name found", names[0], names[1], request.uuid, request.client.Name); - - request.client.SendNameReply(request.uuid, names[0], names[1]); - } - } - } - } - - private bool AreThereRootAgents() - { - foreach (Scene s in m_Scenes) - { - if (s.GetRootAgentCount() > 0) - return true; - } - - return false; - } - - private void ProcessQueue(object sender, System.Timers.ElapsedEventArgs e) - { - while (m_RequestQueue.Count > 0) - { - NameRequest request = null; - lock (m_RequestQueue) - request = m_RequestQueue.Dequeue(); - - if (request != null) - { - string[] names; - bool foundRealName = TryGetUserNames(request.uuid, out names); - - if (names.Length == 2) - { - if (!foundRealName) - m_log.DebugFormat("[USER MANAGEMENT MODULE]: Sending {0} {1} for {2} to {3} since no bound name found", names[0], names[1], request.uuid, request.client.Name); - - request.client.SendNameReply(request.uuid, names[0], names[1]); - } - } - } - - if (AreThereRootAgents()) - m_timer.Interval = 1000; // 1 sec - else - m_timer.Interval = 10000; // 10 secs - - m_timer.Start(); - - } - } - - class NameRequest - { - public IClientAPI client; - public UUID uuid; - - public NameRequest(IClientAPI c, UUID n) - { - client = c; - uuid = n; - } } } \ No newline at end of file From 99a600753e2013a5e5c4649da78bc5b871461c8e Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 16 Jul 2013 17:06:17 -0700 Subject: [PATCH 20/55] Changed the name to ServiceThrottle/ServiceThrottleModule in order to reflect its more generic nature. --- .../ServiceThrottleModule.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename OpenSim/Region/CoreModules/Framework/{GridServiceThrottle/GridServiceThrottleModule.cs => ServiceThrottle/ServiceThrottleModule.cs} (100%) diff --git a/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs similarity index 100% rename from OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs rename to OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs From a006caabbcfe6e2a2b4a6118d217d3bd9abd4d99 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 16 Jul 2013 17:06:54 -0700 Subject: [PATCH 21/55] Added IServiceThrottleModule.cs --- .../Framework/Interfaces/IServiceThrottleModule.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 OpenSim/Region/Framework/Interfaces/IServiceThrottleModule.cs diff --git a/OpenSim/Region/Framework/Interfaces/IServiceThrottleModule.cs b/OpenSim/Region/Framework/Interfaces/IServiceThrottleModule.cs new file mode 100644 index 0000000000..bb6a8b4ffa --- /dev/null +++ b/OpenSim/Region/Framework/Interfaces/IServiceThrottleModule.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; + +namespace OpenSim.Region.Framework.Interfaces +{ + public interface IServiceThrottleModule + { + void Enqueue(Action continuation); + } + +} From 9f578cf0c83ba56d5a999df7411f4065fc17d24b Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 16 Jul 2013 17:18:11 -0700 Subject: [PATCH 22/55] Deleted a couple of verbose messages --- .../Framework/ServiceThrottle/ServiceThrottleModule.cs | 2 +- .../Framework/UserManagement/UserManagementModule.cs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs index d805fd3200..553e4caa29 100644 --- a/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs @@ -176,7 +176,7 @@ namespace OpenSim.Region.CoreModules.Framework private void ProcessQueue(object sender, System.Timers.ElapsedEventArgs e) { - m_log.DebugFormat("[YYY]: Process queue with {0} continuations", m_RequestQueue.Count); + //m_log.DebugFormat("[YYY]: Process queue with {0} continuations", m_RequestQueue.Count); while (m_RequestQueue.Count > 0) { diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 73b59d329e..da28a530f5 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -175,15 +175,13 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement // Not found in cache, get it from services m_ServiceThrottle.Enqueue(delegate { - m_log.DebugFormat("[YYY]: Name request {0}", uuid); + //m_log.DebugFormat("[YYY]: Name request {0}", uuid); bool foundRealName = TryGetUserNamesFromServices(uuid, names); if (names.Length == 2) { if (!foundRealName) m_log.DebugFormat("[USER MANAGEMENT MODULE]: Sending {0} {1} for {2} to {3} since no bound name found", names[0], names[1], uuid, client.Name); - else - m_log.DebugFormat("[YYY]: Found user {0} {1} for uuid {2}", names[0], names[1], uuid); client.SendNameReply(uuid, names[0], names[1]); } From 9f129938c9c75bb4513b0b93248985100fe0e921 Mon Sep 17 00:00:00 2001 From: Dan Lake Date: Tue, 16 Jul 2013 17:43:36 -0700 Subject: [PATCH 23/55] Attachments module only registers when enabled. This enables alternative attachments module implementations. All calls to Scene.AttachmentsModule are checking for null. Ideally, if we support disabling attachments then we need a null attachments module to register with the scene. --- .../CoreModules/Avatar/Attachments/AttachmentsModule.cs | 6 ++++-- OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs | 6 ++++-- .../RegionCombinerIndividualEventForwarder.cs | 6 ++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index f69ec21c58..2f5a76f747 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -74,10 +74,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments public void AddRegion(Scene scene) { m_scene = scene; - m_scene.RegisterModuleInterface(this); - if (Enabled) { + // Only register module with scene if it is enabled. All callers check for a null attachments module. + // Ideally, there should be a null attachments module for when this core attachments module has been + // disabled. Registering only when enabled allows for other attachments module implementations. + m_scene.RegisterModuleInterface(this); m_scene.EventManager.OnNewClient += SubscribeToClientEvents; m_scene.EventManager.OnStartScript += (localID, itemID) => HandleScriptStateChange(localID, true); m_scene.EventManager.OnStopScript += (localID, itemID) => HandleScriptStateChange(localID, false); diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs index 7d46d92613..69189b3d1e 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs @@ -116,7 +116,8 @@ namespace OpenSim.Region.OptionalModules.World.NPC return false; // Delete existing npc attachments - scene.AttachmentsModule.DeleteAttachmentsFromScene(npc, false); + if(scene.AttachmentsModule != null) + scene.AttachmentsModule.DeleteAttachmentsFromScene(npc, false); // XXX: We can't just use IAvatarFactoryModule.SetAppearance() yet // since it doesn't transfer attachments @@ -125,7 +126,8 @@ namespace OpenSim.Region.OptionalModules.World.NPC npc.Appearance = npcAppearance; // Rez needed npc attachments - scene.AttachmentsModule.RezAttachments(npc); + if (scene.AttachmentsModule != null) + scene.AttachmentsModule.RezAttachments(npc); IAvatarFactoryModule module = scene.RequestModuleInterface(); diff --git a/OpenSim/Region/RegionCombinerModule/RegionCombinerIndividualEventForwarder.cs b/OpenSim/Region/RegionCombinerModule/RegionCombinerIndividualEventForwarder.cs index f424e7f42c..83732e205d 100644 --- a/OpenSim/Region/RegionCombinerModule/RegionCombinerIndividualEventForwarder.cs +++ b/OpenSim/Region/RegionCombinerModule/RegionCombinerIndividualEventForwarder.cs @@ -51,7 +51,8 @@ namespace OpenSim.Region.RegionCombinerModule m_virtScene.UnSubscribeToClientPrimEvents(client); m_virtScene.UnSubscribeToClientPrimRezEvents(client); m_virtScene.UnSubscribeToClientInventoryEvents(client); - ((AttachmentsModule)m_virtScene.AttachmentsModule).UnsubscribeFromClientEvents(client); + if(m_virtScene.AttachmentsModule != null) + ((AttachmentsModule)m_virtScene.AttachmentsModule).UnsubscribeFromClientEvents(client); //m_virtScene.UnSubscribeToClientTeleportEvents(client); m_virtScene.UnSubscribeToClientScriptEvents(client); @@ -66,7 +67,8 @@ namespace OpenSim.Region.RegionCombinerModule client.OnRezObject += LocalRezObject; m_rootScene.SubscribeToClientInventoryEvents(client); - ((AttachmentsModule)m_rootScene.AttachmentsModule).SubscribeToClientEvents(client); + if (m_rootScene.AttachmentsModule != null) + ((AttachmentsModule)m_rootScene.AttachmentsModule).SubscribeToClientEvents(client); //m_rootScene.SubscribeToClientTeleportEvents(client); m_rootScene.SubscribeToClientScriptEvents(client); From d4720bd721b518efbc681df2f4e7d1ca35aa0f3c Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 16 Jul 2013 17:53:05 -0700 Subject: [PATCH 24/55] Added config var to fiddle with the Interval for the service throttle thread --- .../Framework/ServiceThrottle/ServiceThrottleModule.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs index 553e4caa29..a3ca6d69d0 100644 --- a/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs @@ -54,11 +54,14 @@ namespace OpenSim.Region.CoreModules.Framework // private OpenSim.Framework.DoubleQueue m_RequestQueue = new OpenSim.Framework.DoubleQueue(); //private Queue m_RequestQueue = new Queue(); private Queue m_RequestQueue = new Queue(); + private int m_Interval; #region ISharedRegionModule public void Initialise(IConfigSource config) { + m_Interval = Util.GetConfigVarFromSections(config, "Interval", new string[] { "ServiceThrottle" }, 2000); + m_timer = new System.Timers.Timer(); m_timer.AutoReset = false; m_timer.Enabled = true; @@ -131,7 +134,7 @@ namespace OpenSim.Region.CoreModules.Framework { if (!m_timer.Enabled) { - m_timer.Interval = 1000; + m_timer.Interval = m_Interval; m_timer.Enabled = true; m_timer.Start(); } From 5f27aaa6ddb857dbfbbe0219d0e29c42ad903375 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 16 Jul 2013 18:22:42 -0700 Subject: [PATCH 25/55] UserManagementModule: in the continuation, call the method that also looks up the cache, because the resource may be here in the meantime --- .../Framework/UserManagement/UserManagementModule.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index da28a530f5..e8bdcc9692 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -172,11 +172,11 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement return; } - // Not found in cache, get it from services + // Not found in cache, queue continuation m_ServiceThrottle.Enqueue(delegate { //m_log.DebugFormat("[YYY]: Name request {0}", uuid); - bool foundRealName = TryGetUserNamesFromServices(uuid, names); + bool foundRealName = TryGetUserNames(uuid, names); if (names.Length == 2) { From 9432f3c94d0b0345132e5ff9eaf966b96cf218c2 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 16 Jul 2013 19:04:30 -0700 Subject: [PATCH 26/55] Improvements to the ServiceThrottleModule: added a category and an itemid to the interface, so that duplicate requests aren't enqueued more than once. --- .../ServiceThrottle/ServiceThrottleModule.cs | 35 ++++++++++++++----- .../UserManagement/UserManagementModule.cs | 2 +- .../Interfaces/IServiceThrottleModule.cs | 10 +++++- bin/OpenSimDefaults.ini | 4 +++ 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs index a3ca6d69d0..1554b3ed8c 100644 --- a/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs @@ -50,17 +50,15 @@ namespace OpenSim.Region.CoreModules.Framework private readonly List m_scenes = new List(); private System.Timers.Timer m_timer = new System.Timers.Timer(); - //private OpenSim.Framework.BlockingQueue m_RequestQueue = new OpenSim.Framework.BlockingQueue(); - // private OpenSim.Framework.DoubleQueue m_RequestQueue = new OpenSim.Framework.DoubleQueue(); - //private Queue m_RequestQueue = new Queue(); private Queue m_RequestQueue = new Queue(); + private Dictionary> m_Pending = new Dictionary>(); private int m_Interval; #region ISharedRegionModule public void Initialise(IConfigSource config) { - m_Interval = Util.GetConfigVarFromSections(config, "Interval", new string[] { "ServiceThrottle" }, 2000); + m_Interval = Util.GetConfigVarFromSections(config, "Interval", new string[] { "ServiceThrottle" }, 5000); m_timer = new System.Timers.Timer(); m_timer.AutoReset = false; @@ -159,18 +157,37 @@ namespace OpenSim.Region.CoreModules.Framework client.SendRegionHandle(regionID, r.RegionHandle); }; - lock (m_RequestQueue) - m_RequestQueue.Enqueue(action); - + Enqueue("region", regionID.ToString(), action); } #endregion Events #region IServiceThrottleModule - public void Enqueue(Action continuation) + public void Enqueue(string category, string itemid, Action continuation) { - m_RequestQueue.Enqueue(continuation); + lock (m_RequestQueue) + { + if (m_Pending.ContainsKey(category)) + { + if (m_Pending[category].Contains(itemid)) + // Don't enqueue, it's already pending + return; + } + else + m_Pending.Add(category, new List()); + + m_Pending[category].Add(itemid); + + m_RequestQueue.Enqueue(delegate + { + continuation(); + lock (m_RequestQueue) + { + m_Pending[category].Remove(itemid); + } + }); + } } #endregion IServiceThrottleModule diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index e8bdcc9692..a91adfab13 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -173,7 +173,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } // Not found in cache, queue continuation - m_ServiceThrottle.Enqueue(delegate + m_ServiceThrottle.Enqueue("name", uuid.ToString(), delegate { //m_log.DebugFormat("[YYY]: Name request {0}", uuid); bool foundRealName = TryGetUserNames(uuid, names); diff --git a/OpenSim/Region/Framework/Interfaces/IServiceThrottleModule.cs b/OpenSim/Region/Framework/Interfaces/IServiceThrottleModule.cs index bb6a8b4ffa..198256fdde 100644 --- a/OpenSim/Region/Framework/Interfaces/IServiceThrottleModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IServiceThrottleModule.cs @@ -5,7 +5,15 @@ namespace OpenSim.Region.Framework.Interfaces { public interface IServiceThrottleModule { - void Enqueue(Action continuation); + /// + /// Enqueue a continuation meant to get a resource from elsewhere. + /// As usual with CPS, caller beware: if that continuation is a never-ending computation, + /// the whole thread will be blocked, and no requests are processed + /// + /// Category of the resource (e.g. name, region) + /// The resource identifier + /// The continuation to be executed + void Enqueue(string category, string itemid, Action continuation); } } diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 4a3104ee81..8079632368 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -1727,5 +1727,9 @@ MaxStringSpace = 0 ;; {MaxDistance} {} {Cut-off distance at which sounds will not be sent to users} {100.0} MaxDistance = 100.0 +[ServiceThrottle] + ;; Default time interval (in ms) for the throttle service thread to wake up + Interval = 5000 + [Modules] Include-modules = "addon-modules/*/config/*.ini" From 894554faf61fe8ae02c1348612845ae2553efbd4 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 16 Jul 2013 20:28:48 -0700 Subject: [PATCH 27/55] Removed the MapItems thread. Redirected the map items requests to the services throttle thread. Didn't change anything in how that processor is implemented, for better or for worse. --- .../ServiceThrottle/ServiceThrottleModule.cs | 5 +- .../World/WorldMap/WorldMapModule.cs | 49 ++++++++++++++++--- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs index 1554b3ed8c..a70261e938 100644 --- a/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs @@ -181,11 +181,10 @@ namespace OpenSim.Region.CoreModules.Framework m_RequestQueue.Enqueue(delegate { - continuation(); lock (m_RequestQueue) - { m_Pending[category].Remove(itemid); - } + + continuation(); }); } } diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs index c50ab64ad6..a26a5f03e9 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs @@ -81,6 +81,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap private List m_rootAgents = new List(); private volatile bool threadrunning = false; + private IServiceThrottleModule m_ServiceThrottle; + //private int CacheRegionsDistance = 256; #region INonSharedRegionModule Members @@ -131,6 +133,10 @@ namespace OpenSim.Region.CoreModules.World.WorldMap public virtual void RegionLoaded (Scene scene) { + if (!m_Enabled) + return; + + m_ServiceThrottle = scene.RequestModuleInterface(); } @@ -170,13 +176,13 @@ namespace OpenSim.Region.CoreModules.World.WorldMap m_scene.EventManager.OnMakeRootAgent += MakeRootAgent; m_scene.EventManager.OnRegionUp += OnRegionUp; - StartThread(new object()); +// StartThread(new object()); } // this has to be called with a lock on m_scene protected virtual void RemoveHandlers() { - StopThread(); +// StopThread(); m_scene.EventManager.OnRegionUp -= OnRegionUp; m_scene.EventManager.OnMakeRootAgent -= MakeRootAgent; @@ -526,7 +532,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap /// public void process() { - const int MAX_ASYNC_REQUESTS = 20; + //const int MAX_ASYNC_REQUESTS = 20; try { while (true) @@ -571,13 +577,44 @@ namespace OpenSim.Region.CoreModules.World.WorldMap Watchdog.RemoveThread(); } + const int MAX_ASYNC_REQUESTS = 20; + /// - /// Enqueues the map item request into the processing thread + /// Enqueues the map item request into the services throttle processing thread /// /// - public void EnqueueMapItemRequest(MapRequestState state) + public void EnqueueMapItemRequest(MapRequestState st) { - requests.Enqueue(state); + + m_ServiceThrottle.Enqueue("map-item", st.regionhandle.ToString() + st.agentID.ToString(), delegate + { + if (st.agentID != UUID.Zero) + { + bool dorequest = true; + lock (m_rootAgents) + { + if (!m_rootAgents.Contains(st.agentID)) + dorequest = false; + } + + if (dorequest && !m_blacklistedregions.ContainsKey(st.regionhandle)) + { + if (nAsyncRequests >= MAX_ASYNC_REQUESTS) // hit the break + { + // AH!!! Recursive ! + // Put this request back in the queue and return + EnqueueMapItemRequest(st); + return; + } + + RequestMapItemsDelegate d = RequestMapItemsAsync; + d.BeginInvoke(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle, RequestMapItemsCompleted, null); + //OSDMap response = RequestMapItemsAsync(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle); + //RequestMapItemsCompleted(response); + Interlocked.Increment(ref nAsyncRequests); + } + } + }); } /// From 2c8bf4aaa66a4cc9fc8fd9f89825e7cd1b43f3d6 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 17 Jul 2013 10:19:44 -0700 Subject: [PATCH 28/55] BulletSim: fix small bug where everything looked like it was colliding before the first simulator step. --- .../Region/Physics/BulletSPlugin/BSPhysObject.cs | 13 +++++++------ OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 3 +++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index a41eaf8617..fc4545f4e3 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -103,9 +103,10 @@ public abstract class BSPhysObject : PhysicsActor CollisionsLastTickStep = -1; SubscribedEventsMs = 0; - CollidingStep = 0; - CollidingGroundStep = 0; - CollisionAccumulation = 0; + // Crazy values that will never be true + CollidingStep = BSScene.NotASimulationStep; + CollidingGroundStep = BSScene.NotASimulationStep; + CollisionAccumulation = BSScene.NotASimulationStep; ColliderIsMoving = false; CollisionScore = 0; @@ -349,7 +350,7 @@ public abstract class BSPhysObject : PhysicsActor if (value) CollidingStep = PhysScene.SimulationStep; else - CollidingStep = 0; + CollidingStep = BSScene.NotASimulationStep; } } public override bool CollidingGround { @@ -359,7 +360,7 @@ public abstract class BSPhysObject : PhysicsActor if (value) CollidingGroundStep = PhysScene.SimulationStep; else - CollidingGroundStep = 0; + CollidingGroundStep = BSScene.NotASimulationStep; } } public override bool CollidingObj { @@ -368,7 +369,7 @@ public abstract class BSPhysObject : PhysicsActor if (value) CollidingObjectStep = PhysScene.SimulationStep; else - CollidingObjectStep = 0; + CollidingObjectStep = BSScene.NotASimulationStep; } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 214271b247..41aca3b2a7 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -97,6 +97,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters internal long m_simulationStep = 0; // The current simulation step. public long SimulationStep { get { return m_simulationStep; } } + // A number to use for SimulationStep that is probably not any step value + // Used by the collision code (which remembers the step when a collision happens) to remember not any simulation step. + public static long NotASimulationStep = -1234; internal float LastTimeStep { get; private set; } // The simulation time from the last invocation of Simulate() From e46459ef21e1ee5ceaeca70365a7c881d33b09ce Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 11:19:36 -0700 Subject: [PATCH 29/55] Cleared up much confusion in PollServiceRequestManager. Here's the history: When Melanie added the web fetch inventory throttle to core, she made the long poll requests (EQs) effectively be handled on an active loop. All those requests, if they existed, were being constantly dequeued, checked for events (which most often they didn't have), and requeued again. This was an active loop thread on a 100ms cycle! This fixes the issue. Now the inventory requests, if they aren't ready to be served, are placed directly back in the queue, but the long poll requests aren't placed there until there are events ready to be sent or timeout has been reached. This puts the LongPollServiceWatcherThread back to 1sec cycle, as it was before. --- OpenSim/Framework/BlockingQueue.cs | 2 +- .../HttpServer/PollServiceEventArgs.cs | 4 +- .../HttpServer/PollServiceRequestManager.cs | 79 ++++++++----------- .../Caps/EventQueue/EventQueueGetModule.cs | 8 +- 4 files changed, 41 insertions(+), 52 deletions(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index aef1192364..e607e648e9 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -76,7 +76,7 @@ namespace OpenSim.Framework { lock (m_queueSync) { - if (m_queue.Count < 1 && m_pqueue.Count < 1) + while (m_queue.Count < 1 && m_pqueue.Count < 1) { Monitor.Wait(m_queueSync, msTimeout); } diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs index 020bfd5baf..947710094d 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs @@ -50,7 +50,7 @@ namespace OpenSim.Framework.Servers.HttpServer public enum EventType : int { - Normal = 0, + LongPoll = 0, LslHttp = 1, Inventory = 2 } @@ -80,7 +80,7 @@ namespace OpenSim.Framework.Servers.HttpServer NoEvents = pNoEvents; Id = pId; TimeOutms = pTimeOutms; - Type = EventType.Normal; + Type = EventType.LongPoll; } } } diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index 1b9010acf0..4cb551cd19 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -47,12 +47,11 @@ namespace OpenSim.Framework.Servers.HttpServer private readonly BaseHttpServer m_server; private BlockingQueue m_requests = new BlockingQueue(); - private static Queue m_slowRequests = new Queue(); - private static Queue m_retryRequests = new Queue(); + private static Queue m_longPollRequests = new Queue(); private uint m_WorkerThreadCount = 0; private Thread[] m_workerThreads; - private Thread m_retrysThread; + private Thread m_longPollThread; private bool m_running = true; private int slowCount = 0; @@ -84,9 +83,9 @@ namespace OpenSim.Framework.Servers.HttpServer int.MaxValue); } - m_retrysThread = Watchdog.StartThread( - this.CheckRetries, - string.Format("PollServiceWatcherThread:{0}", m_server.Port), + m_longPollThread = Watchdog.StartThread( + this.CheckLongPollThreads, + string.Format("LongPollServiceWatcherThread:{0}", m_server.Port), ThreadPriority.Normal, false, true, @@ -97,48 +96,47 @@ namespace OpenSim.Framework.Servers.HttpServer private void ReQueueEvent(PollServiceHttpRequest req) { if (m_running) - { - lock (m_retryRequests) - m_retryRequests.Enqueue(req); - } + m_requests.Enqueue(req); } public void Enqueue(PollServiceHttpRequest req) { if (m_running) { - if (req.PollServiceArgs.Type != PollServiceEventArgs.EventType.Normal) + if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) { - m_requests.Enqueue(req); + lock (m_longPollRequests) + m_longPollRequests.Enqueue(req); } else - { - lock (m_slowRequests) - m_slowRequests.Enqueue(req); - } + m_requests.Enqueue(req); } } - private void CheckRetries() + private void CheckLongPollThreads() { + // The only purpose of this thread is to check the EQs for events. + // If there are events, that thread will be placed in the "ready-to-serve" queue, m_requests. + // If there are no events, that thread will be back to its "waiting" queue, m_longPollRequests. + // All other types of tasks (Inventory handlers) don't have the long-poll nature, + // so if they aren't ready to be served by a worker thread (no events), they are placed + // directly back in the "ready-to-serve" queue by the worker thread. while (m_running) { - Thread.Sleep(100); // let the world move .. back to faster rate + Thread.Sleep(1000); Watchdog.UpdateThread(); - lock (m_retryRequests) - { - while (m_retryRequests.Count > 0 && m_running) - m_requests.Enqueue(m_retryRequests.Dequeue()); - } - slowCount++; - if (slowCount >= 10) - { - slowCount = 0; - lock (m_slowRequests) + PollServiceHttpRequest req; + lock (m_longPollRequests) + { + while (m_longPollRequests.Count > 0 && m_running) { - while (m_slowRequests.Count > 0 && m_running) - m_requests.Enqueue(m_slowRequests.Dequeue()); + req = m_longPollRequests.Dequeue(); + if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id) || // there are events in this EQ + (Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) // no events, but timeout + m_requests.Enqueue(req); + else + m_longPollRequests.Enqueue(req); } } } @@ -153,24 +151,12 @@ namespace OpenSim.Framework.Servers.HttpServer foreach (Thread t in m_workerThreads) Watchdog.AbortThread(t.ManagedThreadId); - try - { - foreach (PollServiceHttpRequest req in m_retryRequests) - { - req.DoHTTPGruntWork(m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); - } - } - catch - { - } - PollServiceHttpRequest wreq; - m_retryRequests.Clear(); - lock (m_slowRequests) + lock (m_longPollRequests) { - while (m_slowRequests.Count > 0 && m_running) - m_requests.Enqueue(m_slowRequests.Dequeue()); + while (m_longPollRequests.Count > 0 && m_running) + m_requests.Enqueue(m_longPollRequests.Dequeue()); } while (m_requests.Count() > 0) @@ -196,6 +182,7 @@ namespace OpenSim.Framework.Servers.HttpServer while (m_running) { PollServiceHttpRequest req = m_requests.Dequeue(5000); + //m_log.WarnFormat("[YYY]: Dequeued {0}", (req == null ? "null" : req.PollServiceArgs.Type.ToString())); Watchdog.UpdateThread(); if (req != null) @@ -209,7 +196,7 @@ namespace OpenSim.Framework.Servers.HttpServer if (responsedata == null) continue; - if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.Normal) // This is the event queue + if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) // This is the event queue { try { diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index 1835a72a4a..f0445ff3c3 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs @@ -364,8 +364,7 @@ namespace OpenSim.Region.ClientStack.Linden caps.RegisterPollHandler( "EventQueueGet", - new PollServiceEventArgs( - null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, 40000)); + new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, 40000)); Random rnd = new Random(Environment.TickCount); lock (m_ids) @@ -383,7 +382,10 @@ namespace OpenSim.Region.ClientStack.Linden Queue queue = GetQueue(agentID); if (queue != null) lock (queue) + { + //m_log.WarnFormat("POLLED FOR EVENTS BY {0} in {1} -- {2}", agentID, m_scene.RegionInfo.RegionName, queue.Count); return queue.Count > 0; + } return false; } @@ -406,7 +408,7 @@ namespace OpenSim.Region.ClientStack.Linden public Hashtable GetEvents(UUID requestID, UUID pAgentId) { if (DebugLevel >= 2) - m_log.DebugFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName); + m_log.WarnFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName); Queue queue = TryGetQueue(pAgentId); OSD element; From 0f5b616fb0ebf9207b3cc81771622ed1290ea7d6 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 12:02:00 -0700 Subject: [PATCH 30/55] Didn't mean to commit this change in BlockingQueue.cs --- OpenSim/Framework/BlockingQueue.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index e607e648e9..aef1192364 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -76,7 +76,7 @@ namespace OpenSim.Framework { lock (m_queueSync) { - while (m_queue.Count < 1 && m_pqueue.Count < 1) + if (m_queue.Count < 1 && m_pqueue.Count < 1) { Monitor.Wait(m_queueSync, msTimeout); } From f4317dc26d670c853d0ea64b401b00f718f09474 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 12:57:34 -0700 Subject: [PATCH 31/55] Putting the requests back in the queue while testing for count >0 is not the smartest move... --- .../Servers/HttpServer/PollServiceRequestManager.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index 4cb551cd19..c50df5abf4 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -126,18 +126,22 @@ namespace OpenSim.Framework.Servers.HttpServer Thread.Sleep(1000); Watchdog.UpdateThread(); - PollServiceHttpRequest req; + List not_ready = new List(); lock (m_longPollRequests) { while (m_longPollRequests.Count > 0 && m_running) { - req = m_longPollRequests.Dequeue(); + PollServiceHttpRequest req = m_longPollRequests.Dequeue(); if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id) || // there are events in this EQ (Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) // no events, but timeout m_requests.Enqueue(req); else - m_longPollRequests.Enqueue(req); + not_ready.Add(req); } + + foreach (PollServiceHttpRequest req in not_ready) + m_longPollRequests.Enqueue(req); + } } } From af792bc7f2504e9ccf1c8ae7568919785dc397c9 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 13:23:29 -0700 Subject: [PATCH 32/55] Do the same trick that dahlia did for Dequeue(timeout) --- OpenSim/Framework/BlockingQueue.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index aef1192364..fb74a24784 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -76,9 +76,10 @@ namespace OpenSim.Framework { lock (m_queueSync) { - if (m_queue.Count < 1 && m_pqueue.Count < 1) + bool timedout = false; + while (m_queue.Count < 1 && m_pqueue.Count < 1 && !timedout) { - Monitor.Wait(m_queueSync, msTimeout); + timedout = Monitor.Wait(m_queueSync, msTimeout); } if (m_pqueue.Count > 0) From 1d3deda10cf85abd68a5f904d6698ae597a67cc0 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 13:26:15 -0700 Subject: [PATCH 33/55] I confuse myself. Let's try this variable name instead. --- OpenSim/Framework/BlockingQueue.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index fb74a24784..3e90fac569 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -76,10 +76,10 @@ namespace OpenSim.Framework { lock (m_queueSync) { - bool timedout = false; - while (m_queue.Count < 1 && m_pqueue.Count < 1 && !timedout) + bool success = true; + while (m_queue.Count < 1 && m_pqueue.Count < 1 && success) { - timedout = Monitor.Wait(m_queueSync, msTimeout); + success = Monitor.Wait(m_queueSync, msTimeout); } if (m_pqueue.Count > 0) From 5f95f4d78e8c7d17b8ba866907156fe6d4444c04 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 14:09:04 -0700 Subject: [PATCH 34/55] Now trying DoubleQueue instead of BlockingQueue for the PollServiceRequestManager. --- .../Framework/Servers/HttpServer/PollServiceRequestManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index c50df5abf4..bad28e47d2 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -46,7 +46,7 @@ namespace OpenSim.Framework.Servers.HttpServer private readonly BaseHttpServer m_server; - private BlockingQueue m_requests = new BlockingQueue(); + private DoubleQueue m_requests = new DoubleQueue(); private static Queue m_longPollRequests = new Queue(); private uint m_WorkerThreadCount = 0; @@ -163,7 +163,7 @@ namespace OpenSim.Framework.Servers.HttpServer m_requests.Enqueue(m_longPollRequests.Dequeue()); } - while (m_requests.Count() > 0) + while (m_requests.Count > 0) { try { From 5232ab0496eb4fe6903a0fd328974ac69df29ad8 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 14:36:55 -0700 Subject: [PATCH 35/55] This is a completely unreasonable thing to do, effectively defying the purpose of BlockingQueues. Trying this, to see the effect on CPU. --- .../HttpServer/PollServiceRequestManager.cs | 94 +++++++++++-------- 1 file changed, 53 insertions(+), 41 deletions(-) diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index bad28e47d2..b8f57436cd 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -46,7 +46,7 @@ namespace OpenSim.Framework.Servers.HttpServer private readonly BaseHttpServer m_server; - private DoubleQueue m_requests = new DoubleQueue(); + private BlockingQueue m_requests = new BlockingQueue(); private static Queue m_longPollRequests = new Queue(); private uint m_WorkerThreadCount = 0; @@ -163,7 +163,7 @@ namespace OpenSim.Framework.Servers.HttpServer m_requests.Enqueue(m_longPollRequests.Dequeue()); } - while (m_requests.Count > 0) + while (m_requests.Count() > 0) { try { @@ -185,35 +185,33 @@ namespace OpenSim.Framework.Servers.HttpServer { while (m_running) { - PollServiceHttpRequest req = m_requests.Dequeue(5000); - //m_log.WarnFormat("[YYY]: Dequeued {0}", (req == null ? "null" : req.PollServiceArgs.Type.ToString())); - Watchdog.UpdateThread(); - if (req != null) + + PollServiceHttpRequest req = null; + lock (m_requests) { - try + if (m_requests.Count() > 0) + req = m_requests.Dequeue(); + } + if (req == null) + Thread.Sleep(100); + else + { + //PollServiceHttpRequest req = m_requests.Dequeue(5000); + //m_log.WarnFormat("[YYY]: Dequeued {0}", (req == null ? "null" : req.PollServiceArgs.Type.ToString())); + + if (req != null) { - if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id)) + try { - Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id); - - if (responsedata == null) - continue; - - if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) // This is the event queue + if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id)) { - try - { - req.DoHTTPGruntWork(m_server, responsedata); - } - catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream - { - // Ignore it, no need to reply - } - } - else - { - m_threadPool.QueueWorkItem(x => + Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id); + + if (responsedata == null) + continue; + + if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) // This is the event queue { try { @@ -223,27 +221,41 @@ namespace OpenSim.Framework.Servers.HttpServer { // Ignore it, no need to reply } + } + else + { + m_threadPool.QueueWorkItem(x => + { + try + { + req.DoHTTPGruntWork(m_server, responsedata); + } + catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream + { + // Ignore it, no need to reply + } - return null; - }, null); - } - } - else - { - if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) - { - req.DoHTTPGruntWork( - m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); + return null; + }, null); + } } else { - ReQueueEvent(req); + if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) + { + req.DoHTTPGruntWork( + m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); + } + else + { + ReQueueEvent(req); + } } } - } - catch (Exception e) - { - m_log.ErrorFormat("Exception in poll service thread: " + e.ToString()); + catch (Exception e) + { + m_log.ErrorFormat("Exception in poll service thread: " + e.ToString()); + } } } } From 5c54eb30eddf5ff17769eaa11ab9c5a9ac79caa3 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 15:02:54 -0700 Subject: [PATCH 36/55] Revert "This is a completely unreasonable thing to do, effectively defying the purpose of BlockingQueues. Trying this, to see the effect on CPU." This reverts commit 5232ab0496eb4fe6903a0fd328974ac69df29ad8. --- .../HttpServer/PollServiceRequestManager.cs | 94 ++++++++----------- 1 file changed, 41 insertions(+), 53 deletions(-) diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index b8f57436cd..bad28e47d2 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -46,7 +46,7 @@ namespace OpenSim.Framework.Servers.HttpServer private readonly BaseHttpServer m_server; - private BlockingQueue m_requests = new BlockingQueue(); + private DoubleQueue m_requests = new DoubleQueue(); private static Queue m_longPollRequests = new Queue(); private uint m_WorkerThreadCount = 0; @@ -163,7 +163,7 @@ namespace OpenSim.Framework.Servers.HttpServer m_requests.Enqueue(m_longPollRequests.Dequeue()); } - while (m_requests.Count() > 0) + while (m_requests.Count > 0) { try { @@ -185,33 +185,35 @@ namespace OpenSim.Framework.Servers.HttpServer { while (m_running) { + PollServiceHttpRequest req = m_requests.Dequeue(5000); + //m_log.WarnFormat("[YYY]: Dequeued {0}", (req == null ? "null" : req.PollServiceArgs.Type.ToString())); + Watchdog.UpdateThread(); - - PollServiceHttpRequest req = null; - lock (m_requests) + if (req != null) { - if (m_requests.Count() > 0) - req = m_requests.Dequeue(); - } - if (req == null) - Thread.Sleep(100); - else - { - //PollServiceHttpRequest req = m_requests.Dequeue(5000); - //m_log.WarnFormat("[YYY]: Dequeued {0}", (req == null ? "null" : req.PollServiceArgs.Type.ToString())); - - if (req != null) + try { - try + if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id)) { - if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id)) + Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id); + + if (responsedata == null) + continue; + + if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) // This is the event queue { - Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id); - - if (responsedata == null) - continue; - - if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) // This is the event queue + try + { + req.DoHTTPGruntWork(m_server, responsedata); + } + catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream + { + // Ignore it, no need to reply + } + } + else + { + m_threadPool.QueueWorkItem(x => { try { @@ -221,41 +223,27 @@ namespace OpenSim.Framework.Servers.HttpServer { // Ignore it, no need to reply } - } - else - { - m_threadPool.QueueWorkItem(x => - { - try - { - req.DoHTTPGruntWork(m_server, responsedata); - } - catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream - { - // Ignore it, no need to reply - } - return null; - }, null); - } + return null; + }, null); + } + } + else + { + if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) + { + req.DoHTTPGruntWork( + m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); } else { - if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) - { - req.DoHTTPGruntWork( - m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); - } - else - { - ReQueueEvent(req); - } + ReQueueEvent(req); } } - catch (Exception e) - { - m_log.ErrorFormat("Exception in poll service thread: " + e.ToString()); - } + } + catch (Exception e) + { + m_log.ErrorFormat("Exception in poll service thread: " + e.ToString()); } } } From 519dba9a69a02980e09268671c030017001a2cd4 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 15:03:16 -0700 Subject: [PATCH 37/55] Revert "Now trying DoubleQueue instead of BlockingQueue for the PollServiceRequestManager." This reverts commit 5f95f4d78e8c7d17b8ba866907156fe6d4444c04. --- .../Framework/Servers/HttpServer/PollServiceRequestManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index bad28e47d2..c50df5abf4 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -46,7 +46,7 @@ namespace OpenSim.Framework.Servers.HttpServer private readonly BaseHttpServer m_server; - private DoubleQueue m_requests = new DoubleQueue(); + private BlockingQueue m_requests = new BlockingQueue(); private static Queue m_longPollRequests = new Queue(); private uint m_WorkerThreadCount = 0; @@ -163,7 +163,7 @@ namespace OpenSim.Framework.Servers.HttpServer m_requests.Enqueue(m_longPollRequests.Dequeue()); } - while (m_requests.Count > 0) + while (m_requests.Count() > 0) { try { From 52dc7b2a96a28798d55d07d79d003ce5e3d35216 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 15:03:40 -0700 Subject: [PATCH 38/55] Revert "I confuse myself. Let's try this variable name instead." This reverts commit 1d3deda10cf85abd68a5f904d6698ae597a67cc0. --- OpenSim/Framework/BlockingQueue.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index 3e90fac569..fb74a24784 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -76,10 +76,10 @@ namespace OpenSim.Framework { lock (m_queueSync) { - bool success = true; - while (m_queue.Count < 1 && m_pqueue.Count < 1 && success) + bool timedout = false; + while (m_queue.Count < 1 && m_pqueue.Count < 1 && !timedout) { - success = Monitor.Wait(m_queueSync, msTimeout); + timedout = Monitor.Wait(m_queueSync, msTimeout); } if (m_pqueue.Count > 0) From 5495df74436d6c0039a1500d979a964b003abfdf Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 15:04:12 -0700 Subject: [PATCH 39/55] Revert "Do the same trick that dahlia did for Dequeue(timeout)" This reverts commit af792bc7f2504e9ccf1c8ae7568919785dc397c9. --- OpenSim/Framework/BlockingQueue.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index fb74a24784..aef1192364 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -76,10 +76,9 @@ namespace OpenSim.Framework { lock (m_queueSync) { - bool timedout = false; - while (m_queue.Count < 1 && m_pqueue.Count < 1 && !timedout) + if (m_queue.Count < 1 && m_pqueue.Count < 1) { - timedout = Monitor.Wait(m_queueSync, msTimeout); + Monitor.Wait(m_queueSync, msTimeout); } if (m_pqueue.Count > 0) From 71278919575b0e0222cdbe3c0cefa5919f9a75bc Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 15:04:27 -0700 Subject: [PATCH 40/55] Revert "Putting the requests back in the queue while testing for count >0 is not the smartest move..." This reverts commit f4317dc26d670c853d0ea64b401b00f718f09474. --- .../Servers/HttpServer/PollServiceRequestManager.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index c50df5abf4..4cb551cd19 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -126,22 +126,18 @@ namespace OpenSim.Framework.Servers.HttpServer Thread.Sleep(1000); Watchdog.UpdateThread(); - List not_ready = new List(); + PollServiceHttpRequest req; lock (m_longPollRequests) { while (m_longPollRequests.Count > 0 && m_running) { - PollServiceHttpRequest req = m_longPollRequests.Dequeue(); + req = m_longPollRequests.Dequeue(); if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id) || // there are events in this EQ (Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) // no events, but timeout m_requests.Enqueue(req); else - not_ready.Add(req); + m_longPollRequests.Enqueue(req); } - - foreach (PollServiceHttpRequest req in not_ready) - m_longPollRequests.Enqueue(req); - } } } From fda91d93dad1fa6f901e8db5829aa8b70477c97e Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 15:05:16 -0700 Subject: [PATCH 41/55] Revert "Didn't mean to commit this change in BlockingQueue.cs" This reverts commit 0f5b616fb0ebf9207b3cc81771622ed1290ea7d6. --- OpenSim/Framework/BlockingQueue.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index aef1192364..e607e648e9 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -76,7 +76,7 @@ namespace OpenSim.Framework { lock (m_queueSync) { - if (m_queue.Count < 1 && m_pqueue.Count < 1) + while (m_queue.Count < 1 && m_pqueue.Count < 1) { Monitor.Wait(m_queueSync, msTimeout); } From f64f07e7c5b115d4005462d976fb60727c6d1cd1 Mon Sep 17 00:00:00 2001 From: Dan Lake Date: Wed, 17 Jul 2013 14:55:48 -0700 Subject: [PATCH 42/55] command line kick user now uses exact name match instead of substring search to avoid kicking the wrong user or multiple wrong users. --- OpenSim/Region/Application/OpenSim.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 6ff7f012fa..b071df84fa 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -423,8 +423,8 @@ namespace OpenSim { RegionInfo regionInfo = presence.Scene.RegionInfo; - if (presence.Firstname.ToLower().Contains(mainParams[2].ToLower()) && - presence.Lastname.ToLower().Contains(mainParams[3].ToLower())) + if (presence.Firstname.ToLower().Equals(mainParams[2].ToLower()) && + presence.Lastname.ToLower().Equals(mainParams[3].ToLower())) { MainConsole.Instance.Output( String.Format( @@ -438,6 +438,7 @@ namespace OpenSim presence.ControllingClient.Kick("\nThe OpenSim manager kicked you out.\n"); presence.Scene.IncomingCloseAgent(presence.UUID, force); + break; } } From fa2370b32ee57a07f27501152c3c705a883b13d8 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 15:05:36 -0700 Subject: [PATCH 43/55] Revert "Cleared up much confusion in PollServiceRequestManager. Here's the history:" This reverts commit e46459ef21e1ee5ceaeca70365a7c881d33b09ce. --- OpenSim/Framework/BlockingQueue.cs | 2 +- .../HttpServer/PollServiceEventArgs.cs | 4 +- .../HttpServer/PollServiceRequestManager.cs | 83 +++++++++++-------- .../Caps/EventQueue/EventQueueGetModule.cs | 8 +- 4 files changed, 54 insertions(+), 43 deletions(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index e607e648e9..aef1192364 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -76,7 +76,7 @@ namespace OpenSim.Framework { lock (m_queueSync) { - while (m_queue.Count < 1 && m_pqueue.Count < 1) + if (m_queue.Count < 1 && m_pqueue.Count < 1) { Monitor.Wait(m_queueSync, msTimeout); } diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs index 947710094d..020bfd5baf 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs @@ -50,7 +50,7 @@ namespace OpenSim.Framework.Servers.HttpServer public enum EventType : int { - LongPoll = 0, + Normal = 0, LslHttp = 1, Inventory = 2 } @@ -80,7 +80,7 @@ namespace OpenSim.Framework.Servers.HttpServer NoEvents = pNoEvents; Id = pId; TimeOutms = pTimeOutms; - Type = EventType.LongPoll; + Type = EventType.Normal; } } } diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index 4cb551cd19..1b9010acf0 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -47,11 +47,12 @@ namespace OpenSim.Framework.Servers.HttpServer private readonly BaseHttpServer m_server; private BlockingQueue m_requests = new BlockingQueue(); - private static Queue m_longPollRequests = new Queue(); + private static Queue m_slowRequests = new Queue(); + private static Queue m_retryRequests = new Queue(); private uint m_WorkerThreadCount = 0; private Thread[] m_workerThreads; - private Thread m_longPollThread; + private Thread m_retrysThread; private bool m_running = true; private int slowCount = 0; @@ -83,9 +84,9 @@ namespace OpenSim.Framework.Servers.HttpServer int.MaxValue); } - m_longPollThread = Watchdog.StartThread( - this.CheckLongPollThreads, - string.Format("LongPollServiceWatcherThread:{0}", m_server.Port), + m_retrysThread = Watchdog.StartThread( + this.CheckRetries, + string.Format("PollServiceWatcherThread:{0}", m_server.Port), ThreadPriority.Normal, false, true, @@ -96,47 +97,48 @@ namespace OpenSim.Framework.Servers.HttpServer private void ReQueueEvent(PollServiceHttpRequest req) { if (m_running) - m_requests.Enqueue(req); + { + lock (m_retryRequests) + m_retryRequests.Enqueue(req); + } } public void Enqueue(PollServiceHttpRequest req) { if (m_running) { - if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) + if (req.PollServiceArgs.Type != PollServiceEventArgs.EventType.Normal) { - lock (m_longPollRequests) - m_longPollRequests.Enqueue(req); + m_requests.Enqueue(req); } else - m_requests.Enqueue(req); + { + lock (m_slowRequests) + m_slowRequests.Enqueue(req); + } } } - private void CheckLongPollThreads() + private void CheckRetries() { - // The only purpose of this thread is to check the EQs for events. - // If there are events, that thread will be placed in the "ready-to-serve" queue, m_requests. - // If there are no events, that thread will be back to its "waiting" queue, m_longPollRequests. - // All other types of tasks (Inventory handlers) don't have the long-poll nature, - // so if they aren't ready to be served by a worker thread (no events), they are placed - // directly back in the "ready-to-serve" queue by the worker thread. while (m_running) { - Thread.Sleep(1000); + Thread.Sleep(100); // let the world move .. back to faster rate Watchdog.UpdateThread(); - - PollServiceHttpRequest req; - lock (m_longPollRequests) + lock (m_retryRequests) { - while (m_longPollRequests.Count > 0 && m_running) + while (m_retryRequests.Count > 0 && m_running) + m_requests.Enqueue(m_retryRequests.Dequeue()); + } + slowCount++; + if (slowCount >= 10) + { + slowCount = 0; + + lock (m_slowRequests) { - req = m_longPollRequests.Dequeue(); - if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id) || // there are events in this EQ - (Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) // no events, but timeout - m_requests.Enqueue(req); - else - m_longPollRequests.Enqueue(req); + while (m_slowRequests.Count > 0 && m_running) + m_requests.Enqueue(m_slowRequests.Dequeue()); } } } @@ -151,12 +153,24 @@ namespace OpenSim.Framework.Servers.HttpServer foreach (Thread t in m_workerThreads) Watchdog.AbortThread(t.ManagedThreadId); - PollServiceHttpRequest wreq; - - lock (m_longPollRequests) + try { - while (m_longPollRequests.Count > 0 && m_running) - m_requests.Enqueue(m_longPollRequests.Dequeue()); + foreach (PollServiceHttpRequest req in m_retryRequests) + { + req.DoHTTPGruntWork(m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); + } + } + catch + { + } + + PollServiceHttpRequest wreq; + m_retryRequests.Clear(); + + lock (m_slowRequests) + { + while (m_slowRequests.Count > 0 && m_running) + m_requests.Enqueue(m_slowRequests.Dequeue()); } while (m_requests.Count() > 0) @@ -182,7 +196,6 @@ namespace OpenSim.Framework.Servers.HttpServer while (m_running) { PollServiceHttpRequest req = m_requests.Dequeue(5000); - //m_log.WarnFormat("[YYY]: Dequeued {0}", (req == null ? "null" : req.PollServiceArgs.Type.ToString())); Watchdog.UpdateThread(); if (req != null) @@ -196,7 +209,7 @@ namespace OpenSim.Framework.Servers.HttpServer if (responsedata == null) continue; - if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) // This is the event queue + if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.Normal) // This is the event queue { try { diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index f0445ff3c3..1835a72a4a 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs @@ -364,7 +364,8 @@ namespace OpenSim.Region.ClientStack.Linden caps.RegisterPollHandler( "EventQueueGet", - new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, 40000)); + new PollServiceEventArgs( + null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, 40000)); Random rnd = new Random(Environment.TickCount); lock (m_ids) @@ -382,10 +383,7 @@ namespace OpenSim.Region.ClientStack.Linden Queue queue = GetQueue(agentID); if (queue != null) lock (queue) - { - //m_log.WarnFormat("POLLED FOR EVENTS BY {0} in {1} -- {2}", agentID, m_scene.RegionInfo.RegionName, queue.Count); return queue.Count > 0; - } return false; } @@ -408,7 +406,7 @@ namespace OpenSim.Region.ClientStack.Linden public Hashtable GetEvents(UUID requestID, UUID pAgentId) { if (DebugLevel >= 2) - m_log.WarnFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName); + m_log.DebugFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName); Queue queue = TryGetQueue(pAgentId); OSD element; From 077be8b496f00c82353de02be192d2dcd920d6b3 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 18 Jul 2013 01:23:33 +0100 Subject: [PATCH 44/55] Fix what apepars to be a bug in DoubleQueue.Enqueue(Queue q, T data) where the q parmater is ignored and everyghig is always placed on m_lowQueue. No actual impact presently since nothing ends up calling EnqueueHigh() --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 8cfc4d4b86..a39d860564 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2253,7 +2253,7 @@ namespace OpenSim.Framework { lock (m_syncRoot) { - m_lowQueue.Enqueue(data); + q.Enqueue(data); m_s.WaitOne(0); m_s.Release(); } From 6572847518646f3f46959f613e602efc16210dcf Mon Sep 17 00:00:00 2001 From: Dan Lake Date: Thu, 18 Jul 2013 02:28:07 -0700 Subject: [PATCH 45/55] Added MinPoolThreads to ini [Startup] section to control SmartThreadPool. --- OpenSim/Framework/Util.cs | 8 +++++--- OpenSim/Region/Application/OpenSim.cs | 4 +++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 8cfc4d4b86..27100e66d9 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1779,10 +1779,12 @@ namespace OpenSim.Framework FireAndForget(callback, null); } - public static void InitThreadPool(int maxThreads) + public static void InitThreadPool(int minThreads, int maxThreads) { if (maxThreads < 2) throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2"); + if (minThreads > maxThreads || minThreads < 2) + throw new ArgumentOutOfRangeException("minThreads", "minThreads must be greater than 2 and less than or equal to maxThreads"); if (m_ThreadPool != null) throw new InvalidOperationException("SmartThreadPool is already initialized"); @@ -1790,7 +1792,7 @@ namespace OpenSim.Framework startInfo.ThreadPoolName = "Util"; startInfo.IdleTimeout = 2000; startInfo.MaxWorkerThreads = maxThreads; - startInfo.MinWorkerThreads = 2; + startInfo.MinWorkerThreads = minThreads; m_ThreadPool = new SmartThreadPool(startInfo); } @@ -1865,7 +1867,7 @@ namespace OpenSim.Framework break; case FireAndForgetMethod.SmartThreadPool: if (m_ThreadPool == null) - InitThreadPool(15); + InitThreadPool(2, 15); m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj); break; case FireAndForgetMethod.Thread: diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index b071df84fa..9dcc8dac22 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -86,6 +86,7 @@ namespace OpenSim IConfig startupConfig = Config.Configs["Startup"]; IConfig networkConfig = Config.Configs["Network"]; + int stpMinThreads = 2; int stpMaxThreads = 15; if (startupConfig != null) @@ -112,12 +113,13 @@ namespace OpenSim if (!String.IsNullOrEmpty(asyncCallMethodStr) && Utils.EnumTryParse(asyncCallMethodStr, out asyncCallMethod)) Util.FireAndForgetMethod = asyncCallMethod; + stpMinThreads = startupConfig.GetInt("MinPoolThreads", 15); stpMaxThreads = startupConfig.GetInt("MaxPoolThreads", 15); m_consolePrompt = startupConfig.GetString("ConsolePrompt", @"Region (\R) "); } if (Util.FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) - Util.InitThreadPool(stpMaxThreads); + Util.InitThreadPool(stpMinThreads, stpMaxThreads); m_log.Info("[OPENSIM MAIN]: Using async_call_method " + Util.FireAndForgetMethod); } From 9e35b069a43942285214ff485c8f5ffb53e7c5ec Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 18 Jul 2013 12:23:27 -0700 Subject: [PATCH 46/55] Reverting the reverts I did yesterday. cpu-branch has now been successfully tested, and I'm merging back those changes, which proved to be good. Revert "Revert "Cleared up much confusion in PollServiceRequestManager. Here's the history:"" This reverts commit fa2370b32ee57a07f27501152c3c705a883b13d8. --- OpenSim/Framework/BlockingQueue.cs | 2 +- .../HttpServer/PollServiceEventArgs.cs | 4 +- .../HttpServer/PollServiceRequestManager.cs | 79 ++++++++----------- .../Caps/EventQueue/EventQueueGetModule.cs | 8 +- 4 files changed, 41 insertions(+), 52 deletions(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index aef1192364..e607e648e9 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -76,7 +76,7 @@ namespace OpenSim.Framework { lock (m_queueSync) { - if (m_queue.Count < 1 && m_pqueue.Count < 1) + while (m_queue.Count < 1 && m_pqueue.Count < 1) { Monitor.Wait(m_queueSync, msTimeout); } diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs index 020bfd5baf..947710094d 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs @@ -50,7 +50,7 @@ namespace OpenSim.Framework.Servers.HttpServer public enum EventType : int { - Normal = 0, + LongPoll = 0, LslHttp = 1, Inventory = 2 } @@ -80,7 +80,7 @@ namespace OpenSim.Framework.Servers.HttpServer NoEvents = pNoEvents; Id = pId; TimeOutms = pTimeOutms; - Type = EventType.Normal; + Type = EventType.LongPoll; } } } diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index 1b9010acf0..4cb551cd19 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -47,12 +47,11 @@ namespace OpenSim.Framework.Servers.HttpServer private readonly BaseHttpServer m_server; private BlockingQueue m_requests = new BlockingQueue(); - private static Queue m_slowRequests = new Queue(); - private static Queue m_retryRequests = new Queue(); + private static Queue m_longPollRequests = new Queue(); private uint m_WorkerThreadCount = 0; private Thread[] m_workerThreads; - private Thread m_retrysThread; + private Thread m_longPollThread; private bool m_running = true; private int slowCount = 0; @@ -84,9 +83,9 @@ namespace OpenSim.Framework.Servers.HttpServer int.MaxValue); } - m_retrysThread = Watchdog.StartThread( - this.CheckRetries, - string.Format("PollServiceWatcherThread:{0}", m_server.Port), + m_longPollThread = Watchdog.StartThread( + this.CheckLongPollThreads, + string.Format("LongPollServiceWatcherThread:{0}", m_server.Port), ThreadPriority.Normal, false, true, @@ -97,48 +96,47 @@ namespace OpenSim.Framework.Servers.HttpServer private void ReQueueEvent(PollServiceHttpRequest req) { if (m_running) - { - lock (m_retryRequests) - m_retryRequests.Enqueue(req); - } + m_requests.Enqueue(req); } public void Enqueue(PollServiceHttpRequest req) { if (m_running) { - if (req.PollServiceArgs.Type != PollServiceEventArgs.EventType.Normal) + if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) { - m_requests.Enqueue(req); + lock (m_longPollRequests) + m_longPollRequests.Enqueue(req); } else - { - lock (m_slowRequests) - m_slowRequests.Enqueue(req); - } + m_requests.Enqueue(req); } } - private void CheckRetries() + private void CheckLongPollThreads() { + // The only purpose of this thread is to check the EQs for events. + // If there are events, that thread will be placed in the "ready-to-serve" queue, m_requests. + // If there are no events, that thread will be back to its "waiting" queue, m_longPollRequests. + // All other types of tasks (Inventory handlers) don't have the long-poll nature, + // so if they aren't ready to be served by a worker thread (no events), they are placed + // directly back in the "ready-to-serve" queue by the worker thread. while (m_running) { - Thread.Sleep(100); // let the world move .. back to faster rate + Thread.Sleep(1000); Watchdog.UpdateThread(); - lock (m_retryRequests) - { - while (m_retryRequests.Count > 0 && m_running) - m_requests.Enqueue(m_retryRequests.Dequeue()); - } - slowCount++; - if (slowCount >= 10) - { - slowCount = 0; - lock (m_slowRequests) + PollServiceHttpRequest req; + lock (m_longPollRequests) + { + while (m_longPollRequests.Count > 0 && m_running) { - while (m_slowRequests.Count > 0 && m_running) - m_requests.Enqueue(m_slowRequests.Dequeue()); + req = m_longPollRequests.Dequeue(); + if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id) || // there are events in this EQ + (Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) // no events, but timeout + m_requests.Enqueue(req); + else + m_longPollRequests.Enqueue(req); } } } @@ -153,24 +151,12 @@ namespace OpenSim.Framework.Servers.HttpServer foreach (Thread t in m_workerThreads) Watchdog.AbortThread(t.ManagedThreadId); - try - { - foreach (PollServiceHttpRequest req in m_retryRequests) - { - req.DoHTTPGruntWork(m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); - } - } - catch - { - } - PollServiceHttpRequest wreq; - m_retryRequests.Clear(); - lock (m_slowRequests) + lock (m_longPollRequests) { - while (m_slowRequests.Count > 0 && m_running) - m_requests.Enqueue(m_slowRequests.Dequeue()); + while (m_longPollRequests.Count > 0 && m_running) + m_requests.Enqueue(m_longPollRequests.Dequeue()); } while (m_requests.Count() > 0) @@ -196,6 +182,7 @@ namespace OpenSim.Framework.Servers.HttpServer while (m_running) { PollServiceHttpRequest req = m_requests.Dequeue(5000); + //m_log.WarnFormat("[YYY]: Dequeued {0}", (req == null ? "null" : req.PollServiceArgs.Type.ToString())); Watchdog.UpdateThread(); if (req != null) @@ -209,7 +196,7 @@ namespace OpenSim.Framework.Servers.HttpServer if (responsedata == null) continue; - if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.Normal) // This is the event queue + if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) // This is the event queue { try { diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index 1835a72a4a..f0445ff3c3 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs @@ -364,8 +364,7 @@ namespace OpenSim.Region.ClientStack.Linden caps.RegisterPollHandler( "EventQueueGet", - new PollServiceEventArgs( - null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, 40000)); + new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, 40000)); Random rnd = new Random(Environment.TickCount); lock (m_ids) @@ -383,7 +382,10 @@ namespace OpenSim.Region.ClientStack.Linden Queue queue = GetQueue(agentID); if (queue != null) lock (queue) + { + //m_log.WarnFormat("POLLED FOR EVENTS BY {0} in {1} -- {2}", agentID, m_scene.RegionInfo.RegionName, queue.Count); return queue.Count > 0; + } return false; } @@ -406,7 +408,7 @@ namespace OpenSim.Region.ClientStack.Linden public Hashtable GetEvents(UUID requestID, UUID pAgentId) { if (DebugLevel >= 2) - m_log.DebugFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName); + m_log.WarnFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName); Queue queue = TryGetQueue(pAgentId); OSD element; From ad198a714ca4a659110b1aea2e7bb5dea34a7d13 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 18 Jul 2013 12:24:43 -0700 Subject: [PATCH 47/55] Revert "Revert "Didn't mean to commit this change in BlockingQueue.cs"" This reverts commit fda91d93dad1fa6f901e8db5829aa8b70477c97e. --- OpenSim/Framework/BlockingQueue.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index e607e648e9..aef1192364 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -76,7 +76,7 @@ namespace OpenSim.Framework { lock (m_queueSync) { - while (m_queue.Count < 1 && m_pqueue.Count < 1) + if (m_queue.Count < 1 && m_pqueue.Count < 1) { Monitor.Wait(m_queueSync, msTimeout); } From 552b85d33d4dc465d84fccb0c6e14c2f45213716 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 18 Jul 2013 12:25:04 -0700 Subject: [PATCH 48/55] Revert "Revert "Putting the requests back in the queue while testing for count >0 is not the smartest move..."" This reverts commit 71278919575b0e0222cdbe3c0cefa5919f9a75bc. --- .../Servers/HttpServer/PollServiceRequestManager.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index 4cb551cd19..c50df5abf4 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -126,18 +126,22 @@ namespace OpenSim.Framework.Servers.HttpServer Thread.Sleep(1000); Watchdog.UpdateThread(); - PollServiceHttpRequest req; + List not_ready = new List(); lock (m_longPollRequests) { while (m_longPollRequests.Count > 0 && m_running) { - req = m_longPollRequests.Dequeue(); + PollServiceHttpRequest req = m_longPollRequests.Dequeue(); if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id) || // there are events in this EQ (Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) // no events, but timeout m_requests.Enqueue(req); else - m_longPollRequests.Enqueue(req); + not_ready.Add(req); } + + foreach (PollServiceHttpRequest req in not_ready) + m_longPollRequests.Enqueue(req); + } } } From a22a4db5cec02637b7653870d09b69c810d7dfe9 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 18 Jul 2013 12:25:22 -0700 Subject: [PATCH 49/55] Revert "Revert "Do the same trick that dahlia did for Dequeue(timeout)"" This reverts commit 5495df74436d6c0039a1500d979a964b003abfdf. --- OpenSim/Framework/BlockingQueue.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index aef1192364..fb74a24784 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -76,9 +76,10 @@ namespace OpenSim.Framework { lock (m_queueSync) { - if (m_queue.Count < 1 && m_pqueue.Count < 1) + bool timedout = false; + while (m_queue.Count < 1 && m_pqueue.Count < 1 && !timedout) { - Monitor.Wait(m_queueSync, msTimeout); + timedout = Monitor.Wait(m_queueSync, msTimeout); } if (m_pqueue.Count > 0) From 71b1511db5c697a2748c87adafe94db8ce408a8d Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 18 Jul 2013 12:25:47 -0700 Subject: [PATCH 50/55] Revert "Revert "I confuse myself. Let's try this variable name instead."" This reverts commit 52dc7b2a96a28798d55d07d79d003ce5e3d35216. --- OpenSim/Framework/BlockingQueue.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index fb74a24784..3e90fac569 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -76,10 +76,10 @@ namespace OpenSim.Framework { lock (m_queueSync) { - bool timedout = false; - while (m_queue.Count < 1 && m_pqueue.Count < 1 && !timedout) + bool success = true; + while (m_queue.Count < 1 && m_pqueue.Count < 1 && success) { - timedout = Monitor.Wait(m_queueSync, msTimeout); + success = Monitor.Wait(m_queueSync, msTimeout); } if (m_pqueue.Count > 0) From d9d995914c5fba00d4ccaf66b899384c8ea3d5eb Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 18 Jul 2013 01:17:46 +0100 Subject: [PATCH 51/55] try Hacking in an AutoResetEvent to control the outgoing UDP loop instead of a continuous loop with sleeps. Does appear to have a cpu impact but may need further tweaking --- .../ClientStack/Linden/UDP/LLClientView.cs | 20 +++++++++++++++++++ .../ClientStack/Linden/UDP/LLUDPServer.cs | 10 ++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 79c80a7032..7229d7c15e 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -3776,6 +3776,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP ResendPrimUpdate(update); } +// OpenSim.Framework.Lazy> objectUpdateBlocks = new OpenSim.Framework.Lazy>(); +// OpenSim.Framework.Lazy> compressedUpdateBlocks = new OpenSim.Framework.Lazy>(); +// OpenSim.Framework.Lazy> terseUpdateBlocks = new OpenSim.Framework.Lazy>(); +// OpenSim.Framework.Lazy> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy>(); +// +// OpenSim.Framework.Lazy> objectUpdates = new OpenSim.Framework.Lazy>(); +// OpenSim.Framework.Lazy> compressedUpdates = new OpenSim.Framework.Lazy>(); +// OpenSim.Framework.Lazy> terseUpdates = new OpenSim.Framework.Lazy>(); +// OpenSim.Framework.Lazy> terseAgentUpdates = new OpenSim.Framework.Lazy>(); + + private void ProcessEntityUpdates(int maxUpdates) { OpenSim.Framework.Lazy> objectUpdateBlocks = new OpenSim.Framework.Lazy>(); @@ -3788,6 +3799,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP OpenSim.Framework.Lazy> terseUpdates = new OpenSim.Framework.Lazy>(); OpenSim.Framework.Lazy> terseAgentUpdates = new OpenSim.Framework.Lazy>(); +// objectUpdateBlocks.Value.Clear(); +// compressedUpdateBlocks.Value.Clear(); +// terseUpdateBlocks.Value.Clear(); +// terseAgentUpdateBlocks.Value.Clear(); +// objectUpdates.Value.Clear(); +// compressedUpdates.Value.Clear(); +// terseUpdates.Value.Clear(); +// terseAgentUpdates.Value.Clear(); + // Check to see if this is a flush if (maxUpdates <= 0) { diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 85270a6e2d..54cafb2bdf 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -806,8 +806,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP } PacketPool.Instance.ReturnPacket(packet); + m_dataPresentEvent.Set(); + } + private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false); + /// /// Start the process of sending a packet to the client. /// @@ -1658,6 +1662,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Action generic every round Action clientPacketHandler = ClientOutgoingPacketHandler; +// while (true) while (base.IsRunningOutbound) { try @@ -1718,8 +1723,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP // If nothing was sent, sleep for the minimum amount of time before a // token bucket could get more tokens - if (!m_packetSent) - Thread.Sleep((int)TickCountResolution); + //if (!m_packetSent) + // Thread.Sleep((int)TickCountResolution); + m_dataPresentEvent.WaitOne(100); Watchdog.UpdateThread(); } From b5062ae7ee4067158f255a0d62fb87b8eaf9d1d6 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 18 Jul 2013 13:30:04 -0700 Subject: [PATCH 52/55] Changed the timoeut of EQ 502s (no events) to 50 secs. The viewer post requests timeout in 60 secs. There's plenty of room for improvement in handling the EQs. Some other time... --- .../Servers/HttpServer/PollServiceRequestManager.cs | 2 +- .../Linden/Caps/EventQueue/EventQueueGetModule.cs | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index c50df5abf4..e8110795a8 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -118,7 +118,7 @@ namespace OpenSim.Framework.Servers.HttpServer // The only purpose of this thread is to check the EQs for events. // If there are events, that thread will be placed in the "ready-to-serve" queue, m_requests. // If there are no events, that thread will be back to its "waiting" queue, m_longPollRequests. - // All other types of tasks (Inventory handlers) don't have the long-poll nature, + // All other types of tasks (Inventory handlers, http-in, etc) don't have the long-poll nature, // so if they aren't ready to be served by a worker thread (no events), they are placed // directly back in the "ready-to-serve" queue by the worker thread. while (m_running) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index f0445ff3c3..c5e28ad349 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs @@ -65,6 +65,13 @@ namespace OpenSim.Region.ClientStack.Linden /// public int DebugLevel { get; set; } + // Viewer post requests timeout in 60 secs + // https://bitbucket.org/lindenlab/viewer-release/src/421c20423df93d650cc305dc115922bb30040999/indra/llmessage/llhttpclient.cpp?at=default#cl-44 + // + private const int VIEWER_TIMEOUT = 60 * 1000; + // Just to be safe, we work on a 10 sec shorter cycle + private const int SERVER_EQ_TIME_NO_EVENTS = VIEWER_TIMEOUT - (10 * 1000); + protected Scene m_scene; private Dictionary m_ids = new Dictionary(); @@ -363,8 +370,8 @@ namespace OpenSim.Region.ClientStack.Linden } caps.RegisterPollHandler( - "EventQueueGet", - new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, 40000)); + "EventQueueGet", + new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, SERVER_EQ_TIME_NO_EVENTS)); Random rnd = new Random(Environment.TickCount); lock (m_ids) From edef7472d1060435334d7803728517d559a717e7 Mon Sep 17 00:00:00 2001 From: Dan Lake Date: Thu, 18 Jul 2013 13:33:50 -0700 Subject: [PATCH 53/55] Enable storing of environment settings in NullSimulationData --- OpenSim/Data/Null/NullSimulationData.cs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/OpenSim/Data/Null/NullSimulationData.cs b/OpenSim/Data/Null/NullSimulationData.cs index 4979cf6d61..d11ad72f4e 100644 --- a/OpenSim/Data/Null/NullSimulationData.cs +++ b/OpenSim/Data/Null/NullSimulationData.cs @@ -77,20 +77,34 @@ namespace OpenSim.Data.Null } #region Environment Settings + + private Dictionary EnvironmentSettings = new Dictionary(); + public string LoadRegionEnvironmentSettings(UUID regionUUID) { - //This connector doesn't support the Environment module yet + lock (EnvironmentSettings) + { + if (EnvironmentSettings.ContainsKey(regionUUID)) + return EnvironmentSettings[regionUUID]; + } return string.Empty; } public void StoreRegionEnvironmentSettings(UUID regionUUID, string settings) { - //This connector doesn't support the Environment module yet + lock (EnvironmentSettings) + { + EnvironmentSettings[regionUUID] = settings; + } } public void RemoveRegionEnvironmentSettings(UUID regionUUID) { - //This connector doesn't support the Environment module yet + lock (EnvironmentSettings) + { + if (EnvironmentSettings.ContainsKey(regionUUID)) + EnvironmentSettings.Remove(regionUUID); + } } #endregion From 1d65b0d80296a672c8023293aee7d0a01bad4066 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 18 Jul 2013 19:09:55 -0700 Subject: [PATCH 54/55] BulletSim: add position resetting for stationary avatars so they don't move around when standing on a stationary object. Create proper linkage between BSCharacter and its actor by generating a UpdatedProperties event the same way BSPrim does. --- .../Physics/BulletSPlugin/BSActorAvatarMove.cs | 17 ++++++++++++++++- .../Region/Physics/BulletSPlugin/BSCharacter.cs | 8 ++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs index 928b350645..0f11c4a158 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs @@ -130,6 +130,7 @@ public class BSActorAvatarMove : BSActor SetVelocityAndTarget(m_controllingPrim.RawVelocity, m_controllingPrim.TargetVelocity, true /* inTaintTime */); m_physicsScene.BeforeStep += Mover; + m_controllingPrim.OnPreUpdateProperty += Process_OnPreUpdateProperty; m_walkingUpStairs = 0; } @@ -139,6 +140,7 @@ public class BSActorAvatarMove : BSActor { if (m_velocityMotor != null) { + m_controllingPrim.OnPreUpdateProperty -= Process_OnPreUpdateProperty; m_physicsScene.BeforeStep -= Mover; m_velocityMotor = null; } @@ -197,7 +199,7 @@ public class BSActorAvatarMove : BSActor { if (m_controllingPrim.Flying) { - // Flying and not collising and velocity nearly zero. + // Flying and not colliding and velocity nearly zero. m_controllingPrim.ZeroMotion(true /* inTaintTime */); } } @@ -266,6 +268,19 @@ public class BSActorAvatarMove : BSActor } } + // Called just as the property update is received from the physics engine. + // Do any mode necessary for avatar movement. + private void Process_OnPreUpdateProperty(ref EntityProperties entprop) + { + // Don't change position if standing on a stationary object. + if (m_controllingPrim.IsStationary) + { + entprop.Position = m_controllingPrim.RawPosition; + m_physicsScene.PE.SetTranslation(m_controllingPrim.PhysBody, entprop.Position, entprop.Rotation); + } + + } + // Decide if the character is colliding with a low object and compute a force to pop the // avatar up so it can walk up and over the low objects. private OMV.Vector3 WalkUpStairs() diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index c9e3ca0ead..59e7f5ffbe 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -709,10 +709,10 @@ public sealed class BSCharacter : BSPhysObject // the world that things have changed. public override void UpdateProperties(EntityProperties entprop) { - // Don't change position if standing on a stationary object. - if (!IsStationary) - RawPosition = entprop.Position; + // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator. + TriggerPreUpdatePropertyAction(ref entprop); + RawPosition = entprop.Position; RawOrientation = entprop.Rotation; // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar @@ -740,7 +740,7 @@ public sealed class BSCharacter : BSPhysObject // Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. - // base.RequestPhysicsterseUpdate(); + // PhysScene.PostUpdate(this); DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", LocalID, RawPosition, RawOrientation, RawVelocity, _acceleration, _rotationalVelocity); From c1705236c7b0fe779c52b56a4531eb036817de89 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 19 Jul 2013 20:24:56 -0700 Subject: [PATCH 55/55] Fix HGTravelStore.migrations in SQLite (mantis #6709) --- .../SQLite/Resources/HGTravelStore.migrations | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/OpenSim/Data/SQLite/Resources/HGTravelStore.migrations b/OpenSim/Data/SQLite/Resources/HGTravelStore.migrations index 2e73caa9d2..02612ce13a 100644 --- a/OpenSim/Data/SQLite/Resources/HGTravelStore.migrations +++ b/OpenSim/Data/SQLite/Resources/HGTravelStore.migrations @@ -1,18 +1,18 @@ -:VERSION 1 # -------------------------- +:VERSION 2 # -------------------------- BEGIN; -CREATE TABLE hg_traveling_data ( +CREATE TABLE hg_traveling_data( SessionID VARCHAR(36) NOT NULL, UserID VARCHAR(36) NOT NULL, - GridExternalName VARCHAR(255) NOT NULL DEFAULT '', - ServiceToken VARCHAR(255) NOT NULL DEFAULT '', - ClientIPAddress VARCHAR(16) NOT NULL DEFAULT '', - MyIPAddress VARCHAR(16) NOT NULL DEFAULT '', - TMStamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (`SessionID`), - KEY (`UserID`) -) ENGINE=InnoDB; + GridExternalName VARCHAR(255) NOT NULL DEFAULT "", + ServiceToken VARCHAR(255) NOT NULL DEFAULT "", + ClientIPAddress VARCHAR(16) NOT NULL DEFAULT "", + MyIPAddress VARCHAR(16) NOT NULL DEFAULT "", + TMStamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY(SessionID), + UNIQUE(UserID) +); COMMIT;