diff options
author | Teravus Ovares | 2009-07-29 02:15:45 +0000 |
---|---|---|
committer | Teravus Ovares | 2009-07-29 02:15:45 +0000 |
commit | 032aeb8b5d05f5f5a8ef8c6e0fe572a321717c35 (patch) | |
tree | 63d21eaa99b003b47f8eceb09e21b6c4f32ae4f7 /OpenSim | |
parent | Add the missing block to the alert message (diff) | |
download | opensim-SC_OLD-032aeb8b5d05f5f5a8ef8c6e0fe572a321717c35.zip opensim-SC_OLD-032aeb8b5d05f5f5a8ef8c6e0fe572a321717c35.tar.gz opensim-SC_OLD-032aeb8b5d05f5f5a8ef8c6e0fe572a321717c35.tar.bz2 opensim-SC_OLD-032aeb8b5d05f5f5a8ef8c6e0fe572a321717c35.tar.xz |
* Adds the ability to have a thread efficient long poll service (such as the eventqueue)
* If this doesn't melt the Http Server, this will significantly reduce the number of threads in use on regions with many users.
* Adds AddPollServiceHTTPHandler, and RemovePollServiceHTTPHandler to BaseHttpServer
* Generic enough to be used for many long poll services, not only the EventQueue.
Diffstat (limited to 'OpenSim')
8 files changed, 522 insertions, 18 deletions
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index 4532e76..369d7d4 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs | |||
@@ -64,6 +64,9 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
64 | protected Dictionary<string, GenericHTTPMethod> m_HTTPHandlers = new Dictionary<string, GenericHTTPMethod>(); | 64 | protected Dictionary<string, GenericHTTPMethod> m_HTTPHandlers = new Dictionary<string, GenericHTTPMethod>(); |
65 | protected Dictionary<string, IHttpAgentHandler> m_agentHandlers = new Dictionary<string, IHttpAgentHandler>(); | 65 | protected Dictionary<string, IHttpAgentHandler> m_agentHandlers = new Dictionary<string, IHttpAgentHandler>(); |
66 | 66 | ||
67 | protected Dictionary<string, PollServiceEventArgs> m_pollHandlers = | ||
68 | new Dictionary<string, PollServiceEventArgs>(); | ||
69 | |||
67 | protected uint m_port; | 70 | protected uint m_port; |
68 | protected uint m_sslport; | 71 | protected uint m_sslport; |
69 | protected bool m_ssl; | 72 | protected bool m_ssl; |
@@ -72,6 +75,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
72 | 75 | ||
73 | protected IPAddress m_listenIPAddress = IPAddress.Any; | 76 | protected IPAddress m_listenIPAddress = IPAddress.Any; |
74 | 77 | ||
78 | private PollServiceRequestManager m_PollServiceManager; | ||
79 | |||
75 | public uint SSLPort | 80 | public uint SSLPort |
76 | { | 81 | { |
77 | get { return m_sslport; } | 82 | get { return m_sslport; } |
@@ -189,6 +194,26 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
189 | return false; | 194 | return false; |
190 | } | 195 | } |
191 | 196 | ||
197 | public bool AddPollServiceHTTPHandler(string methodName, GenericHTTPMethod handler, PollServiceEventArgs args) | ||
198 | { | ||
199 | bool pollHandlerResult = false; | ||
200 | lock (m_pollHandlers) | ||
201 | { | ||
202 | if (!m_pollHandlers.ContainsKey( methodName)) | ||
203 | { | ||
204 | m_pollHandlers.Add(methodName,args); | ||
205 | pollHandlerResult = true; | ||
206 | |||
207 | } | ||
208 | } | ||
209 | |||
210 | if (pollHandlerResult) | ||
211 | return AddHTTPHandler(methodName, handler); | ||
212 | |||
213 | return false; | ||
214 | |||
215 | } | ||
216 | |||
192 | // Note that the agent string is provided simply to differentiate | 217 | // Note that the agent string is provided simply to differentiate |
193 | // the handlers - it is NOT required to be an actual agent header | 218 | // the handlers - it is NOT required to be an actual agent header |
194 | // value. | 219 | // value. |
@@ -230,8 +255,19 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
230 | { | 255 | { |
231 | IHttpClientContext context = (IHttpClientContext)source; | 256 | IHttpClientContext context = (IHttpClientContext)source; |
232 | IHttpRequest request = args.Request; | 257 | IHttpRequest request = args.Request; |
258 | |||
233 | 259 | ||
234 | OnHandleRequestIOThread(context,request); | 260 | PollServiceEventArgs psEvArgs; |
261 | if (TryGetPollServiceHTTPHandler(request.UriPath.ToString(), out psEvArgs)) | ||
262 | { | ||
263 | |||
264 | m_PollServiceManager.Enqueue(new PollServiceHttpRequest(psEvArgs, context, request)); | ||
265 | //DoHTTPGruntWork(psEvArgs.NoEvents(),new OSHttpResponse(new HttpResponse(context, request))); | ||
266 | } | ||
267 | else | ||
268 | { | ||
269 | OnHandleRequestIOThread(context, request); | ||
270 | } | ||
235 | 271 | ||
236 | } | 272 | } |
237 | 273 | ||
@@ -341,7 +377,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
341 | string requestBody = reader.ReadToEnd(); | 377 | string requestBody = reader.ReadToEnd(); |
342 | 378 | ||
343 | reader.Close(); | 379 | reader.Close(); |
344 | requestStream.Close(); | 380 | //requestStream.Close(); |
345 | 381 | ||
346 | Hashtable keysvals = new Hashtable(); | 382 | Hashtable keysvals = new Hashtable(); |
347 | Hashtable headervals = new Hashtable(); | 383 | Hashtable headervals = new Hashtable(); |
@@ -527,6 +563,36 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
527 | } | 563 | } |
528 | } | 564 | } |
529 | 565 | ||
566 | private bool TryGetPollServiceHTTPHandler(string handlerKey, out PollServiceEventArgs oServiceEventArgs) | ||
567 | { | ||
568 | string bestMatch = null; | ||
569 | |||
570 | lock (m_pollHandlers) | ||
571 | { | ||
572 | foreach (string pattern in m_pollHandlers.Keys) | ||
573 | { | ||
574 | if (handlerKey.StartsWith(pattern)) | ||
575 | { | ||
576 | if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length) | ||
577 | { | ||
578 | bestMatch = pattern; | ||
579 | } | ||
580 | } | ||
581 | } | ||
582 | |||
583 | if (String.IsNullOrEmpty(bestMatch)) | ||
584 | { | ||
585 | oServiceEventArgs = null; | ||
586 | return false; | ||
587 | } | ||
588 | else | ||
589 | { | ||
590 | oServiceEventArgs = m_pollHandlers[bestMatch]; | ||
591 | return true; | ||
592 | } | ||
593 | } | ||
594 | } | ||
595 | |||
530 | private bool TryGetHTTPHandler(string handlerKey, out GenericHTTPMethod HTTPHandler) | 596 | private bool TryGetHTTPHandler(string handlerKey, out GenericHTTPMethod HTTPHandler) |
531 | { | 597 | { |
532 | //m_log.DebugFormat("[BASE HTTP HANDLER]: Looking for HTTP handler for {0}", handlerKey); | 598 | //m_log.DebugFormat("[BASE HTTP HANDLER]: Looking for HTTP handler for {0}", handlerKey); |
@@ -822,7 +888,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
822 | { | 888 | { |
823 | response.Send(); | 889 | response.Send(); |
824 | response.OutputStream.Flush(); | 890 | response.OutputStream.Flush(); |
825 | response.OutputStream.Close(); | 891 | //response.OutputStream.Close(); |
826 | } | 892 | } |
827 | catch (IOException e) | 893 | catch (IOException e) |
828 | { | 894 | { |
@@ -1237,7 +1303,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1237 | } | 1303 | } |
1238 | } | 1304 | } |
1239 | 1305 | ||
1240 | private static void DoHTTPGruntWork(Hashtable responsedata, OSHttpResponse response) | 1306 | internal void DoHTTPGruntWork(Hashtable responsedata, OSHttpResponse response) |
1241 | { | 1307 | { |
1242 | //m_log.Info("[BASE HTTP SERVER]: Doing HTTP Grunt work with response"); | 1308 | //m_log.Info("[BASE HTTP SERVER]: Doing HTTP Grunt work with response"); |
1243 | int responsecode = (int)responsedata["int_response_code"]; | 1309 | int responsecode = (int)responsedata["int_response_code"]; |
@@ -1261,7 +1327,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1261 | } | 1327 | } |
1262 | //Even though only one other part of the entire code uses HTTPHandlers, we shouldn't expect this | 1328 | //Even though only one other part of the entire code uses HTTPHandlers, we shouldn't expect this |
1263 | //and should check for NullReferenceExceptions | 1329 | //and should check for NullReferenceExceptions |
1264 | 1330 | ||
1265 | if (string.IsNullOrEmpty(contentType)) | 1331 | if (string.IsNullOrEmpty(contentType)) |
1266 | { | 1332 | { |
1267 | contentType = "text/html"; | 1333 | contentType = "text/html"; |
@@ -1402,6 +1468,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1402 | //m_workerThread.Start(); | 1468 | //m_workerThread.Start(); |
1403 | //ThreadTracker.Add(m_workerThread); | 1469 | //ThreadTracker.Add(m_workerThread); |
1404 | StartHTTP(); | 1470 | StartHTTP(); |
1471 | |||
1472 | |||
1405 | } | 1473 | } |
1406 | 1474 | ||
1407 | private void StartHTTP() | 1475 | private void StartHTTP() |
@@ -1434,6 +1502,9 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1434 | m_httpListener2.RequestReceived += OnRequest; | 1502 | m_httpListener2.RequestReceived += OnRequest; |
1435 | //m_httpListener.Start(); | 1503 | //m_httpListener.Start(); |
1436 | m_httpListener2.Start(64); | 1504 | m_httpListener2.Start(64); |
1505 | |||
1506 | // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events | ||
1507 | m_PollServiceManager = new PollServiceRequestManager(this, 3, 25000); | ||
1437 | HTTPDRunning = true; | 1508 | HTTPDRunning = true; |
1438 | 1509 | ||
1439 | //HttpListenerContext context; | 1510 | //HttpListenerContext context; |
@@ -1514,6 +1585,20 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1514 | } | 1585 | } |
1515 | } | 1586 | } |
1516 | 1587 | ||
1588 | public void RemovePollServiceHTTPHandler(string httpMethod, string path) | ||
1589 | { | ||
1590 | lock (m_pollHandlers) | ||
1591 | { | ||
1592 | if (m_pollHandlers.ContainsKey(httpMethod)) | ||
1593 | { | ||
1594 | m_pollHandlers.Remove(httpMethod); | ||
1595 | } | ||
1596 | } | ||
1597 | |||
1598 | RemoveHTTPHandler(httpMethod, path); | ||
1599 | |||
1600 | } | ||
1601 | |||
1517 | public bool RemoveAgentHandler(string agent, IHttpAgentHandler handler) | 1602 | public bool RemoveAgentHandler(string agent, IHttpAgentHandler handler) |
1518 | { | 1603 | { |
1519 | try | 1604 | try |
diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs index c415dfb..9095831 100644 --- a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs | |||
@@ -74,6 +74,9 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
74 | /// </returns> | 74 | /// </returns> |
75 | bool AddHTTPHandler(string methodName, GenericHTTPMethod handler); | 75 | bool AddHTTPHandler(string methodName, GenericHTTPMethod handler); |
76 | 76 | ||
77 | |||
78 | bool AddPollServiceHTTPHandler(string methodName, GenericHTTPMethod handler, PollServiceEventArgs args); | ||
79 | |||
77 | /// <summary> | 80 | /// <summary> |
78 | /// Adds a LLSD handler, yay. | 81 | /// Adds a LLSD handler, yay. |
79 | /// </summary> | 82 | /// </summary> |
@@ -114,6 +117,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
114 | /// <param name="httpMethod"></param> | 117 | /// <param name="httpMethod"></param> |
115 | /// <param name="path"></param> | 118 | /// <param name="path"></param> |
116 | void RemoveHTTPHandler(string httpMethod, string path); | 119 | void RemoveHTTPHandler(string httpMethod, string path); |
120 | |||
121 | void RemovePollServiceHTTPHandler(string httpMethod, string path); | ||
117 | 122 | ||
118 | bool RemoveLLSDHandler(string path, LLSDMethod handler); | 123 | bool RemoveLLSDHandler(string path, LLSDMethod handler); |
119 | 124 | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs new file mode 100644 index 0000000..fed490e --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs | |||
@@ -0,0 +1,53 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using OpenMetaverse; | ||
31 | namespace OpenSim.Framework.Servers.HttpServer | ||
32 | { | ||
33 | public delegate bool HasEventsMethod(UUID pId); | ||
34 | |||
35 | public delegate Hashtable GetEventsMethod(UUID pId, string request); | ||
36 | |||
37 | public delegate Hashtable NoEventsMethod(); | ||
38 | |||
39 | public class PollServiceEventArgs : EventArgs | ||
40 | { | ||
41 | public HasEventsMethod HasEvents; | ||
42 | public GetEventsMethod GetEvents; | ||
43 | public NoEventsMethod NoEvents; | ||
44 | public UUID Id; | ||
45 | public PollServiceEventArgs(HasEventsMethod pHasEvents, GetEventsMethod pGetEvents, NoEventsMethod pNoEvents,UUID pId) | ||
46 | { | ||
47 | HasEvents = pHasEvents; | ||
48 | GetEvents = pGetEvents; | ||
49 | NoEvents = pNoEvents; | ||
50 | Id = pId; | ||
51 | } | ||
52 | } | ||
53 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs new file mode 100644 index 0000000..ff7c1e8 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs | |||
@@ -0,0 +1,48 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using HttpServer; | ||
30 | |||
31 | namespace OpenSim.Framework.Servers.HttpServer | ||
32 | { | ||
33 | |||
34 | public class PollServiceHttpRequest | ||
35 | { | ||
36 | public readonly PollServiceEventArgs PollServiceArgs; | ||
37 | public readonly IHttpClientContext HttpContext; | ||
38 | public readonly IHttpRequest Request; | ||
39 | public readonly int RequestTime; | ||
40 | public PollServiceHttpRequest(PollServiceEventArgs pPollServiceArgs, IHttpClientContext pHttpContext, IHttpRequest pRequest) | ||
41 | { | ||
42 | PollServiceArgs = pPollServiceArgs; | ||
43 | HttpContext = pHttpContext; | ||
44 | Request = pRequest; | ||
45 | RequestTime = System.Environment.TickCount; | ||
46 | } | ||
47 | } | ||
48 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs new file mode 100644 index 0000000..7f632cf --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs | |||
@@ -0,0 +1,145 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Threading; | ||
31 | using HttpServer; | ||
32 | |||
33 | namespace OpenSim.Framework.Servers.HttpServer | ||
34 | { | ||
35 | public class PollServiceRequestManager | ||
36 | { | ||
37 | private readonly BaseHttpServer m_server; | ||
38 | private static Queue m_requests = Queue.Synchronized(new Queue()); | ||
39 | private uint m_WorkerThreadCount = 0; | ||
40 | private Thread[] m_workerThreads; | ||
41 | private PollServiceWorkerThread[] m_PollServiceWorkerThreads; | ||
42 | private Thread m_watcherThread; | ||
43 | private bool m_running = true; | ||
44 | |||
45 | |||
46 | |||
47 | public PollServiceRequestManager(BaseHttpServer pSrv, uint pWorkerThreadCount, int pTimeout) | ||
48 | { | ||
49 | m_server = pSrv; | ||
50 | m_WorkerThreadCount = pWorkerThreadCount; | ||
51 | m_workerThreads = new Thread[m_WorkerThreadCount]; | ||
52 | m_PollServiceWorkerThreads = new PollServiceWorkerThread[m_WorkerThreadCount]; | ||
53 | m_watcherThread = new Thread(ThreadStart); | ||
54 | |||
55 | |||
56 | //startup worker threads | ||
57 | for (uint i=0;i<m_WorkerThreadCount;i++) | ||
58 | { | ||
59 | m_PollServiceWorkerThreads[i] = new PollServiceWorkerThread(m_server, pTimeout); | ||
60 | m_PollServiceWorkerThreads[i].ReQueue += ReQueueEvent; | ||
61 | |||
62 | m_workerThreads[i] = new Thread( m_PollServiceWorkerThreads[i].ThreadStart); | ||
63 | m_workerThreads[i].Name = String.Format("PollServiceWorkerThread{0}",i); | ||
64 | //Can't add to thread Tracker here Referencing OpenSim.Framework creates circular reference | ||
65 | m_workerThreads[i].Start(); | ||
66 | |||
67 | } | ||
68 | //start watcher threads | ||
69 | m_watcherThread.Name = "PollServiceWatcherThread"; | ||
70 | m_watcherThread.Start(); | ||
71 | |||
72 | |||
73 | } | ||
74 | |||
75 | internal void ReQueueEvent(PollServiceHttpRequest req) | ||
76 | { | ||
77 | // Do accounting stuff here | ||
78 | Enqueue(req); | ||
79 | } | ||
80 | |||
81 | public void Enqueue(PollServiceHttpRequest req) | ||
82 | { | ||
83 | lock (m_requests) | ||
84 | m_requests.Enqueue(req); | ||
85 | } | ||
86 | |||
87 | public void ThreadStart(object o) | ||
88 | { | ||
89 | while (m_running) | ||
90 | { | ||
91 | ProcessQueuedRequests(); | ||
92 | Thread.Sleep(1000); | ||
93 | } | ||
94 | } | ||
95 | |||
96 | private void ProcessQueuedRequests() | ||
97 | { | ||
98 | lock (m_requests) | ||
99 | { | ||
100 | if (m_requests.Count == 0) | ||
101 | return; | ||
102 | |||
103 | int reqperthread = (int) (m_requests.Count/m_WorkerThreadCount) + 1; | ||
104 | // For Each WorkerThread | ||
105 | for (int tc = 0; tc < m_WorkerThreadCount && m_requests.Count > 0; tc++) | ||
106 | { | ||
107 | //Loop over number of requests each thread handles. | ||
108 | for (int i=0;i<reqperthread && m_requests.Count > 0;i++) | ||
109 | { | ||
110 | try | ||
111 | { | ||
112 | m_PollServiceWorkerThreads[tc].Enqueue((PollServiceHttpRequest)m_requests.Dequeue()); | ||
113 | } | ||
114 | catch (InvalidOperationException) | ||
115 | { | ||
116 | // The queue is empty, we did our calculations wrong! | ||
117 | return; | ||
118 | } | ||
119 | |||
120 | } | ||
121 | } | ||
122 | } | ||
123 | |||
124 | } | ||
125 | |||
126 | |||
127 | |||
128 | ~PollServiceRequestManager() | ||
129 | { | ||
130 | foreach (object o in m_requests) | ||
131 | { | ||
132 | PollServiceHttpRequest req = (PollServiceHttpRequest) o; | ||
133 | m_server.DoHTTPGruntWork(req.PollServiceArgs.NoEvents(), new OSHttpResponse(new HttpResponse(req.HttpContext, req.Request))); | ||
134 | } | ||
135 | |||
136 | m_requests.Clear(); | ||
137 | |||
138 | foreach (Thread t in m_workerThreads) | ||
139 | { | ||
140 | t.Abort(); | ||
141 | } | ||
142 | m_running = false; | ||
143 | } | ||
144 | } | ||
145 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs new file mode 100644 index 0000000..4c0be78 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs | |||
@@ -0,0 +1,100 @@ | |||
1 | using System; | ||
2 | using System.Collections; | ||
3 | using System.Collections.Generic; | ||
4 | /* | ||
5 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
6 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions are met: | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in the | ||
14 | * documentation and/or other materials provided with the distribution. | ||
15 | * * Neither the name of the OpenSimulator Project nor the | ||
16 | * names of its contributors may be used to endorse or promote products | ||
17 | * derived from this software without specific prior written permission. | ||
18 | * | ||
19 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
20 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
21 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
22 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
23 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
24 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
25 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
26 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
28 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
29 | */ | ||
30 | |||
31 | using System.IO; | ||
32 | using System.Text; | ||
33 | using HttpServer; | ||
34 | using OpenMetaverse; | ||
35 | |||
36 | namespace OpenSim.Framework.Servers.HttpServer | ||
37 | { | ||
38 | public delegate void ReQueuePollServiceItem(PollServiceHttpRequest req); | ||
39 | |||
40 | public class PollServiceWorkerThread | ||
41 | { | ||
42 | public event ReQueuePollServiceItem ReQueue; | ||
43 | |||
44 | private readonly BaseHttpServer m_server; | ||
45 | private BlockingQueue<PollServiceHttpRequest> m_request; | ||
46 | private bool m_running = true; | ||
47 | private int m_timeout = 25000; | ||
48 | |||
49 | |||
50 | |||
51 | public PollServiceWorkerThread(BaseHttpServer pSrv, int pTimeout) | ||
52 | { | ||
53 | m_request = new BlockingQueue<PollServiceHttpRequest>(); | ||
54 | m_server = pSrv; | ||
55 | m_timeout = pTimeout; | ||
56 | } | ||
57 | |||
58 | public void ThreadStart(object o) | ||
59 | { | ||
60 | Run(); | ||
61 | } | ||
62 | |||
63 | public void Run() | ||
64 | { | ||
65 | while (m_running) | ||
66 | { | ||
67 | PollServiceHttpRequest req = m_request.Dequeue(); | ||
68 | if (req.PollServiceArgs.HasEvents(req.PollServiceArgs.Id)) | ||
69 | { | ||
70 | StreamReader str = new StreamReader(req.Request.Body); | ||
71 | |||
72 | Hashtable responsedata = req.PollServiceArgs.GetEvents(req.PollServiceArgs.Id, str.ReadToEnd()); | ||
73 | m_server.DoHTTPGruntWork(responsedata, | ||
74 | new OSHttpResponse(new HttpResponse(req.HttpContext, req.Request))); | ||
75 | } | ||
76 | else | ||
77 | { | ||
78 | if ((Environment.TickCount - req.RequestTime) > m_timeout) | ||
79 | { | ||
80 | m_server.DoHTTPGruntWork(req.PollServiceArgs.NoEvents(), | ||
81 | new OSHttpResponse(new HttpResponse(req.HttpContext, req.Request))); | ||
82 | } | ||
83 | else | ||
84 | { | ||
85 | ReQueuePollServiceItem reQueueItem = ReQueue; | ||
86 | if (reQueueItem != null) | ||
87 | reQueueItem(req); | ||
88 | } | ||
89 | } | ||
90 | } | ||
91 | |||
92 | |||
93 | } | ||
94 | |||
95 | internal void Enqueue(PollServiceHttpRequest pPollServiceHttpRequest) | ||
96 | { | ||
97 | m_request.Enqueue(pPollServiceHttpRequest); | ||
98 | } | ||
99 | } | ||
100 | } | ||
diff --git a/OpenSim/Framework/Servers/Tests/OSHttpTests.cs b/OpenSim/Framework/Servers/Tests/OSHttpTests.cs index f7f0afa..a6a90dc 100644 --- a/OpenSim/Framework/Servers/Tests/OSHttpTests.cs +++ b/OpenSim/Framework/Servers/Tests/OSHttpTests.cs | |||
@@ -67,6 +67,7 @@ namespace OpenSim.Framework.Servers.Tests | |||
67 | public void Send(byte[] buffer) {} | 67 | public void Send(byte[] buffer) {} |
68 | public void Send(byte[] buffer, int offset, int size) {} | 68 | public void Send(byte[] buffer, int offset, int size) {} |
69 | public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body, string contentType) {} | 69 | public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body, string contentType) {} |
70 | public void Close() { } | ||
70 | 71 | ||
71 | public event EventHandler<DisconnectedEventArgs> Disconnected = delegate { }; | 72 | public event EventHandler<DisconnectedEventArgs> Disconnected = delegate { }; |
72 | /// <summary> | 73 | /// <summary> |
diff --git a/OpenSim/Region/CoreModules/Framework/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/CoreModules/Framework/EventQueue/EventQueueGetModule.cs index 81ea267..81b47be 100644 --- a/OpenSim/Region/CoreModules/Framework/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EventQueue/EventQueueGetModule.cs | |||
@@ -61,7 +61,7 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue | |||
61 | 61 | ||
62 | private Dictionary<UUID, int> m_ids = new Dictionary<UUID, int>(); | 62 | private Dictionary<UUID, int> m_ids = new Dictionary<UUID, int>(); |
63 | 63 | ||
64 | private Dictionary<UUID, BlockingLLSDQueue> queues = new Dictionary<UUID, BlockingLLSDQueue>(); | 64 | private Dictionary<UUID, Queue<OSD>> queues = new Dictionary<UUID, Queue<OSD>>(); |
65 | private Dictionary<UUID, UUID> m_QueueUUIDAvatarMapping = new Dictionary<UUID, UUID>(); | 65 | private Dictionary<UUID, UUID> m_QueueUUIDAvatarMapping = new Dictionary<UUID, UUID>(); |
66 | private Dictionary<UUID, UUID> m_AvatarQueueUUIDMapping = new Dictionary<UUID, UUID>(); | 66 | private Dictionary<UUID, UUID> m_AvatarQueueUUIDMapping = new Dictionary<UUID, UUID>(); |
67 | 67 | ||
@@ -131,7 +131,7 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue | |||
131 | /// </summary> | 131 | /// </summary> |
132 | /// <param name="agentId"></param> | 132 | /// <param name="agentId"></param> |
133 | /// <returns></returns> | 133 | /// <returns></returns> |
134 | private BlockingLLSDQueue TryGetQueue(UUID agentId) | 134 | private Queue<OSD> TryGetQueue(UUID agentId) |
135 | { | 135 | { |
136 | lock (queues) | 136 | lock (queues) |
137 | { | 137 | { |
@@ -141,7 +141,7 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue | |||
141 | "[EVENTQUEUE]: Adding new queue for agent {0} in region {1}", | 141 | "[EVENTQUEUE]: Adding new queue for agent {0} in region {1}", |
142 | agentId, m_scene.RegionInfo.RegionName); | 142 | agentId, m_scene.RegionInfo.RegionName); |
143 | 143 | ||
144 | queues[agentId] = new BlockingLLSDQueue(); | 144 | queues[agentId] = new Queue<OSD>(); |
145 | } | 145 | } |
146 | 146 | ||
147 | return queues[agentId]; | 147 | return queues[agentId]; |
@@ -153,7 +153,7 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue | |||
153 | /// </summary> | 153 | /// </summary> |
154 | /// <param name="agentId"></param> | 154 | /// <param name="agentId"></param> |
155 | /// <returns></returns> | 155 | /// <returns></returns> |
156 | private BlockingLLSDQueue GetQueue(UUID agentId) | 156 | private Queue<OSD> GetQueue(UUID agentId) |
157 | { | 157 | { |
158 | lock (queues) | 158 | lock (queues) |
159 | { | 159 | { |
@@ -173,7 +173,7 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue | |||
173 | //m_log.DebugFormat("[EVENTQUEUE]: Enqueuing event for {0} in region {1}", avatarID, m_scene.RegionInfo.RegionName); | 173 | //m_log.DebugFormat("[EVENTQUEUE]: Enqueuing event for {0} in region {1}", avatarID, m_scene.RegionInfo.RegionName); |
174 | try | 174 | try |
175 | { | 175 | { |
176 | BlockingLLSDQueue queue = GetQueue(avatarID); | 176 | Queue<OSD> queue = GetQueue(avatarID); |
177 | if (queue != null) | 177 | if (queue != null) |
178 | queue.Enqueue(ev); | 178 | queue.Enqueue(ev); |
179 | } | 179 | } |
@@ -203,7 +203,7 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue | |||
203 | m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", AgentID, m_scene.RegionInfo.RegionName); | 203 | m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", AgentID, m_scene.RegionInfo.RegionName); |
204 | 204 | ||
205 | int count = 0; | 205 | int count = 0; |
206 | while (queues.ContainsKey(AgentID) && queues[AgentID].Count() > 0 && count++ < 5) | 206 | while (queues.ContainsKey(AgentID) && queues[AgentID].Count > 0 && count++ < 5) |
207 | { | 207 | { |
208 | Thread.Sleep(1000); | 208 | Thread.Sleep(1000); |
209 | } | 209 | } |
@@ -226,7 +226,7 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue | |||
226 | foreach (UUID ky in removeitems) | 226 | foreach (UUID ky in removeitems) |
227 | { | 227 | { |
228 | m_AvatarQueueUUIDMapping.Remove(ky); | 228 | m_AvatarQueueUUIDMapping.Remove(ky); |
229 | MainServer.Instance.RemoveHTTPHandler("","/CAPS/EQG/" + ky.ToString() + "/"); | 229 | MainServer.Instance.RemovePollServiceHTTPHandler("","/CAPS/EQG/" + ky.ToString() + "/"); |
230 | } | 230 | } |
231 | 231 | ||
232 | } | 232 | } |
@@ -315,8 +315,8 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue | |||
315 | })); | 315 | })); |
316 | 316 | ||
317 | // This will persist this beyond the expiry of the caps handlers | 317 | // This will persist this beyond the expiry of the caps handlers |
318 | MainServer.Instance.AddHTTPHandler( | 318 | MainServer.Instance.AddPollServiceHTTPHandler( |
319 | capsBase + EventQueueGetUUID.ToString() + "/", EventQueuePath2); | 319 | capsBase + EventQueueGetUUID.ToString() + "/", EventQueuePath2, new PollServiceEventArgs(HasEvents, GetEvents, NoEvents, agentID)); |
320 | 320 | ||
321 | Random rnd = new Random(Environment.TickCount); | 321 | Random rnd = new Random(Environment.TickCount); |
322 | lock (m_ids) | 322 | lock (m_ids) |
@@ -326,6 +326,73 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue | |||
326 | } | 326 | } |
327 | } | 327 | } |
328 | 328 | ||
329 | public bool HasEvents(UUID agentID) | ||
330 | { | ||
331 | Queue<OSD> queue = TryGetQueue(agentID); | ||
332 | if (queue.Count > 0) | ||
333 | return true; | ||
334 | else | ||
335 | return false; | ||
336 | |||
337 | } | ||
338 | |||
339 | public Hashtable GetEvents(UUID pAgentId, string request) | ||
340 | { | ||
341 | Queue<OSD> queue = TryGetQueue(pAgentId); | ||
342 | OSD element = queue.Dequeue(); // 15s timeout | ||
343 | |||
344 | |||
345 | |||
346 | int thisID = 0; | ||
347 | lock (m_ids) | ||
348 | thisID = m_ids[pAgentId]; | ||
349 | |||
350 | OSDArray array = new OSDArray(); | ||
351 | if (element == null) // didn't have an event in 15s | ||
352 | { | ||
353 | // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say! | ||
354 | array.Add(EventQueueHelper.KeepAliveEvent()); | ||
355 | m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", pAgentId, m_scene.RegionInfo.RegionName); | ||
356 | } | ||
357 | else | ||
358 | { | ||
359 | array.Add(element); | ||
360 | while (queue.Count > 0) | ||
361 | { | ||
362 | array.Add(queue.Dequeue()); | ||
363 | thisID++; | ||
364 | } | ||
365 | } | ||
366 | |||
367 | OSDMap events = new OSDMap(); | ||
368 | events.Add("events", array); | ||
369 | |||
370 | events.Add("id", new OSDInteger(thisID)); | ||
371 | lock (m_ids) | ||
372 | { | ||
373 | m_ids[pAgentId] = thisID + 1; | ||
374 | } | ||
375 | Hashtable responsedata = new Hashtable(); | ||
376 | responsedata["int_response_code"] = 200; | ||
377 | responsedata["content_type"] = "application/xml"; | ||
378 | responsedata["keepalive"] = false; | ||
379 | responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(events); | ||
380 | return responsedata; | ||
381 | //m_log.DebugFormat("[EVENTQUEUE]: sending response for {0} in region {1}: {2}", agentID, m_scene.RegionInfo.RegionName, responsedata["str_response_string"]); | ||
382 | } | ||
383 | |||
384 | public Hashtable NoEvents() | ||
385 | { | ||
386 | Hashtable responsedata = new Hashtable(); | ||
387 | responsedata["int_response_code"] = 502; | ||
388 | responsedata["content_type"] = "text/plain"; | ||
389 | responsedata["keepalive"] = false; | ||
390 | responsedata["str_response_string"] = "Upstream error: "; | ||
391 | responsedata["error_status_text"] = "Upstream error:"; | ||
392 | responsedata["http_protocol_version"] = "HTTP/1.0"; | ||
393 | return responsedata; | ||
394 | } | ||
395 | |||
329 | public Hashtable ProcessQueue(Hashtable request, UUID agentID, Caps caps) | 396 | public Hashtable ProcessQueue(Hashtable request, UUID agentID, Caps caps) |
330 | { | 397 | { |
331 | // TODO: this has to be redone to not busy-wait (and block the thread), | 398 | // TODO: this has to be redone to not busy-wait (and block the thread), |
@@ -341,8 +408,8 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue | |||
341 | // m_log.DebugFormat(debug + " ]", agentID, m_scene.RegionInfo.RegionName, System.Threading.Thread.CurrentThread.Name); | 408 | // m_log.DebugFormat(debug + " ]", agentID, m_scene.RegionInfo.RegionName, System.Threading.Thread.CurrentThread.Name); |
342 | // } | 409 | // } |
343 | 410 | ||
344 | BlockingLLSDQueue queue = TryGetQueue(agentID); | 411 | Queue<OSD> queue = TryGetQueue(agentID); |
345 | OSD element = queue.Dequeue(15000); // 15s timeout | 412 | OSD element = queue.Dequeue(); // 15s timeout |
346 | 413 | ||
347 | Hashtable responsedata = new Hashtable(); | 414 | Hashtable responsedata = new Hashtable(); |
348 | 415 | ||
@@ -381,9 +448,9 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue | |||
381 | else | 448 | else |
382 | { | 449 | { |
383 | array.Add(element); | 450 | array.Add(element); |
384 | while (queue.Count() > 0) | 451 | while (queue.Count > 0) |
385 | { | 452 | { |
386 | array.Add(queue.Dequeue(1)); | 453 | array.Add(queue.Dequeue()); |
387 | thisID++; | 454 | thisID++; |
388 | } | 455 | } |
389 | } | 456 | } |