aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
authorTeravus Ovares2009-07-29 02:15:45 +0000
committerTeravus Ovares2009-07-29 02:15:45 +0000
commit032aeb8b5d05f5f5a8ef8c6e0fe572a321717c35 (patch)
tree63d21eaa99b003b47f8eceb09e21b6c4f32ae4f7 /OpenSim
parentAdd the missing block to the alert message (diff)
downloadopensim-SC-032aeb8b5d05f5f5a8ef8c6e0fe572a321717c35.zip
opensim-SC-032aeb8b5d05f5f5a8ef8c6e0fe572a321717c35.tar.gz
opensim-SC-032aeb8b5d05f5f5a8ef8c6e0fe572a321717c35.tar.bz2
opensim-SC-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')
-rw-r--r--OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs95
-rw-r--r--OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs5
-rw-r--r--OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs53
-rw-r--r--OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs48
-rw-r--r--OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs145
-rw-r--r--OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs100
-rw-r--r--OpenSim/Framework/Servers/Tests/OSHttpTests.cs1
-rw-r--r--OpenSim/Region/CoreModules/Framework/EventQueue/EventQueueGetModule.cs93
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
28using System;
29using System.Collections;
30using OpenMetaverse;
31namespace 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
28using System;
29using HttpServer;
30
31namespace 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
28using System;
29using System.Collections;
30using System.Threading;
31using HttpServer;
32
33namespace 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 @@
1using System;
2using System.Collections;
3using 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
31using System.IO;
32using System.Text;
33using HttpServer;
34using OpenMetaverse;
35
36namespace 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 }