diff options
Diffstat (limited to 'OpenSim/Framework/Servers/HttpServer')
-rw-r--r-- | OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs | 24 | ||||
-rw-r--r-- | OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs | 175 |
2 files changed, 120 insertions, 79 deletions
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index e1ae74e..e243002 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs | |||
@@ -113,7 +113,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
113 | 113 | ||
114 | protected IPAddress m_listenIPAddress = IPAddress.Any; | 114 | protected IPAddress m_listenIPAddress = IPAddress.Any; |
115 | 115 | ||
116 | private PollServiceRequestManager m_PollServiceManager; | 116 | public PollServiceRequestManager PollServiceRequestManager { get; private set; } |
117 | 117 | ||
118 | public uint SSLPort | 118 | public uint SSLPort |
119 | { | 119 | { |
@@ -374,7 +374,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
374 | return true; | 374 | return true; |
375 | } | 375 | } |
376 | 376 | ||
377 | private void OnRequest(object source, RequestEventArgs args) | 377 | public void OnRequest(object source, RequestEventArgs args) |
378 | { | 378 | { |
379 | RequestNumber++; | 379 | RequestNumber++; |
380 | 380 | ||
@@ -429,7 +429,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
429 | psEvArgs.Request(psreq.RequestID, keysvals); | 429 | psEvArgs.Request(psreq.RequestID, keysvals); |
430 | } | 430 | } |
431 | 431 | ||
432 | m_PollServiceManager.Enqueue(psreq); | 432 | PollServiceRequestManager.Enqueue(psreq); |
433 | } | 433 | } |
434 | else | 434 | else |
435 | { | 435 | { |
@@ -1781,10 +1781,17 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1781 | 1781 | ||
1782 | public void Start() | 1782 | public void Start() |
1783 | { | 1783 | { |
1784 | StartHTTP(); | 1784 | Start(true); |
1785 | } | 1785 | } |
1786 | 1786 | ||
1787 | private void StartHTTP() | 1787 | /// <summary> |
1788 | /// Start the http server | ||
1789 | /// </summary> | ||
1790 | /// <param name='processPollRequestsAsync'> | ||
1791 | /// If true then poll responses are performed asynchronsly. | ||
1792 | /// Option exists to allow regression tests to perform processing synchronously. | ||
1793 | /// </param> | ||
1794 | public void Start(bool performPollResponsesAsync) | ||
1788 | { | 1795 | { |
1789 | m_log.InfoFormat( | 1796 | m_log.InfoFormat( |
1790 | "[BASE HTTP SERVER]: Starting {0} server on port {1}", UseSSL ? "HTTPS" : "HTTP", Port); | 1797 | "[BASE HTTP SERVER]: Starting {0} server on port {1}", UseSSL ? "HTTPS" : "HTTP", Port); |
@@ -1822,8 +1829,9 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1822 | m_httpListener2.Start(64); | 1829 | m_httpListener2.Start(64); |
1823 | 1830 | ||
1824 | // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events | 1831 | // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events |
1825 | m_PollServiceManager = new PollServiceRequestManager(this, 3, 25000); | 1832 | PollServiceRequestManager = new PollServiceRequestManager(this, performPollResponsesAsync, 3, 25000); |
1826 | m_PollServiceManager.Start(); | 1833 | PollServiceRequestManager.Start(); |
1834 | |||
1827 | HTTPDRunning = true; | 1835 | HTTPDRunning = true; |
1828 | 1836 | ||
1829 | //HttpListenerContext context; | 1837 | //HttpListenerContext context; |
@@ -1892,7 +1900,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1892 | 1900 | ||
1893 | try | 1901 | try |
1894 | { | 1902 | { |
1895 | m_PollServiceManager.Stop(); | 1903 | PollServiceRequestManager.Stop(); |
1896 | 1904 | ||
1897 | m_httpListener2.ExceptionThrown -= httpServerException; | 1905 | m_httpListener2.ExceptionThrown -= httpServerException; |
1898 | //m_httpListener2.DisconnectHandler = null; | 1906 | //m_httpListener2.DisconnectHandler = null; |
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index 6aa5907..456acb0 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs | |||
@@ -44,6 +44,20 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
44 | { | 44 | { |
45 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 45 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
46 | 46 | ||
47 | /// <summary> | ||
48 | /// Is the poll service request manager running? | ||
49 | /// </summary> | ||
50 | /// <remarks> | ||
51 | /// Can be running either synchronously or asynchronously | ||
52 | /// </remarks> | ||
53 | public bool IsRunning { get; private set; } | ||
54 | |||
55 | /// <summary> | ||
56 | /// Is the poll service performing responses asynchronously (with its own threads) or synchronously (via | ||
57 | /// external calls)? | ||
58 | /// </summary> | ||
59 | public bool PerformResponsesAsync { get; private set; } | ||
60 | |||
47 | private readonly BaseHttpServer m_server; | 61 | private readonly BaseHttpServer m_server; |
48 | 62 | ||
49 | private BlockingQueue<PollServiceHttpRequest> m_requests = new BlockingQueue<PollServiceHttpRequest>(); | 63 | private BlockingQueue<PollServiceHttpRequest> m_requests = new BlockingQueue<PollServiceHttpRequest>(); |
@@ -52,48 +66,53 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
52 | private uint m_WorkerThreadCount = 0; | 66 | private uint m_WorkerThreadCount = 0; |
53 | private Thread[] m_workerThreads; | 67 | private Thread[] m_workerThreads; |
54 | 68 | ||
55 | private bool m_running = true; | ||
56 | |||
57 | private SmartThreadPool m_threadPool = new SmartThreadPool(20000, 12, 2); | 69 | private SmartThreadPool m_threadPool = new SmartThreadPool(20000, 12, 2); |
58 | 70 | ||
59 | // private int m_timeout = 1000; // increase timeout 250; now use the event one | 71 | // private int m_timeout = 1000; // increase timeout 250; now use the event one |
60 | 72 | ||
61 | public PollServiceRequestManager(BaseHttpServer pSrv, uint pWorkerThreadCount, int pTimeout) | 73 | public PollServiceRequestManager( |
74 | BaseHttpServer pSrv, bool performResponsesAsync, uint pWorkerThreadCount, int pTimeout) | ||
62 | { | 75 | { |
63 | m_server = pSrv; | 76 | m_server = pSrv; |
77 | PerformResponsesAsync = performResponsesAsync; | ||
64 | m_WorkerThreadCount = pWorkerThreadCount; | 78 | m_WorkerThreadCount = pWorkerThreadCount; |
65 | m_workerThreads = new Thread[m_WorkerThreadCount]; | 79 | m_workerThreads = new Thread[m_WorkerThreadCount]; |
66 | } | 80 | } |
67 | 81 | ||
68 | public void Start() | 82 | public void Start() |
69 | { | 83 | { |
70 | //startup worker threads | 84 | IsRunning = true; |
71 | for (uint i = 0; i < m_WorkerThreadCount; i++) | 85 | |
86 | if (PerformResponsesAsync) | ||
72 | { | 87 | { |
73 | m_workerThreads[i] | 88 | //startup worker threads |
74 | = Watchdog.StartThread( | 89 | for (uint i = 0; i < m_WorkerThreadCount; i++) |
75 | PoolWorkerJob, | 90 | { |
76 | string.Format("PollServiceWorkerThread{0}:{1}", i, m_server.Port), | 91 | m_workerThreads[i] |
77 | ThreadPriority.Normal, | 92 | = Watchdog.StartThread( |
78 | false, | 93 | PoolWorkerJob, |
79 | false, | 94 | string.Format("PollServiceWorkerThread{0}:{1}", i, m_server.Port), |
80 | null, | 95 | ThreadPriority.Normal, |
81 | int.MaxValue); | 96 | false, |
82 | } | 97 | false, |
98 | null, | ||
99 | int.MaxValue); | ||
100 | } | ||
83 | 101 | ||
84 | Watchdog.StartThread( | 102 | Watchdog.StartThread( |
85 | this.CheckLongPollThreads, | 103 | this.CheckLongPollThreads, |
86 | string.Format("LongPollServiceWatcherThread:{0}", m_server.Port), | 104 | string.Format("LongPollServiceWatcherThread:{0}", m_server.Port), |
87 | ThreadPriority.Normal, | 105 | ThreadPriority.Normal, |
88 | false, | 106 | false, |
89 | true, | 107 | true, |
90 | null, | 108 | null, |
91 | 1000 * 60 * 10); | 109 | 1000 * 60 * 10); |
110 | } | ||
92 | } | 111 | } |
93 | 112 | ||
94 | private void ReQueueEvent(PollServiceHttpRequest req) | 113 | private void ReQueueEvent(PollServiceHttpRequest req) |
95 | { | 114 | { |
96 | if (m_running) | 115 | if (IsRunning) |
97 | { | 116 | { |
98 | // delay the enqueueing for 100ms. There's no need to have the event | 117 | // delay the enqueueing for 100ms. There's no need to have the event |
99 | // actively on the queue | 118 | // actively on the queue |
@@ -109,7 +128,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
109 | 128 | ||
110 | public void Enqueue(PollServiceHttpRequest req) | 129 | public void Enqueue(PollServiceHttpRequest req) |
111 | { | 130 | { |
112 | if (m_running) | 131 | if (IsRunning) |
113 | { | 132 | { |
114 | if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) | 133 | if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) |
115 | { | 134 | { |
@@ -129,7 +148,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
129 | // All other types of tasks (Inventory handlers, http-in, etc) don't have the long-poll nature, | 148 | // All other types of tasks (Inventory handlers, http-in, etc) don't have the long-poll nature, |
130 | // so if they aren't ready to be served by a worker thread (no events), they are placed | 149 | // so if they aren't ready to be served by a worker thread (no events), they are placed |
131 | // directly back in the "ready-to-serve" queue by the worker thread. | 150 | // directly back in the "ready-to-serve" queue by the worker thread. |
132 | while (m_running) | 151 | while (IsRunning) |
133 | { | 152 | { |
134 | Thread.Sleep(500); | 153 | Thread.Sleep(500); |
135 | Watchdog.UpdateThread(); | 154 | Watchdog.UpdateThread(); |
@@ -137,7 +156,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
137 | // List<PollServiceHttpRequest> not_ready = new List<PollServiceHttpRequest>(); | 156 | // List<PollServiceHttpRequest> not_ready = new List<PollServiceHttpRequest>(); |
138 | lock (m_longPollRequests) | 157 | lock (m_longPollRequests) |
139 | { | 158 | { |
140 | if (m_longPollRequests.Count > 0 && m_running) | 159 | if (m_longPollRequests.Count > 0 && IsRunning) |
141 | { | 160 | { |
142 | List<PollServiceHttpRequest> ready = m_longPollRequests.FindAll(req => | 161 | List<PollServiceHttpRequest> ready = m_longPollRequests.FindAll(req => |
143 | (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id) || // there are events in this EQ | 162 | (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id) || // there are events in this EQ |
@@ -158,7 +177,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
158 | 177 | ||
159 | public void Stop() | 178 | public void Stop() |
160 | { | 179 | { |
161 | m_running = false; | 180 | IsRunning = false; |
162 | // m_timeout = -10000; // cause all to expire | 181 | // m_timeout = -10000; // cause all to expire |
163 | Thread.Sleep(1000); // let the world move | 182 | Thread.Sleep(1000); // let the world move |
164 | 183 | ||
@@ -169,7 +188,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
169 | 188 | ||
170 | lock (m_longPollRequests) | 189 | lock (m_longPollRequests) |
171 | { | 190 | { |
172 | if (m_longPollRequests.Count > 0 && m_running) | 191 | if (m_longPollRequests.Count > 0 && IsRunning) |
173 | m_longPollRequests.ForEach(req => m_requests.Enqueue(req)); | 192 | m_longPollRequests.ForEach(req => m_requests.Enqueue(req)); |
174 | } | 193 | } |
175 | 194 | ||
@@ -194,68 +213,82 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
194 | 213 | ||
195 | private void PoolWorkerJob() | 214 | private void PoolWorkerJob() |
196 | { | 215 | { |
197 | while (m_running) | 216 | while (IsRunning) |
198 | { | 217 | { |
199 | PollServiceHttpRequest req = m_requests.Dequeue(5000); | ||
200 | //m_log.WarnFormat("[YYY]: Dequeued {0}", (req == null ? "null" : req.PollServiceArgs.Type.ToString())); | ||
201 | |||
202 | Watchdog.UpdateThread(); | 218 | Watchdog.UpdateThread(); |
203 | if (req != null) | 219 | WaitPerformResponse(); |
220 | } | ||
221 | } | ||
222 | |||
223 | public void WaitPerformResponse() | ||
224 | { | ||
225 | PollServiceHttpRequest req = m_requests.Dequeue(5000); | ||
226 | // m_log.DebugFormat("[YYY]: Dequeued {0}", (req == null ? "null" : req.PollServiceArgs.Type.ToString())); | ||
227 | |||
228 | if (req != null) | ||
229 | { | ||
230 | try | ||
204 | { | 231 | { |
205 | try | 232 | if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id)) |
206 | { | 233 | { |
207 | if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id)) | 234 | Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id); |
208 | { | ||
209 | Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id); | ||
210 | 235 | ||
211 | if (responsedata == null) | 236 | if (responsedata == null) |
212 | continue; | 237 | return; |
213 | 238 | ||
214 | if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) // This is the event queue | 239 | // This is the event queue. |
240 | // Even if we're not running we can still perform responses by explicit request. | ||
241 | if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll | ||
242 | || !PerformResponsesAsync) | ||
243 | { | ||
244 | try | ||
245 | { | ||
246 | req.DoHTTPGruntWork(m_server, responsedata); | ||
247 | } | ||
248 | catch (ObjectDisposedException e) // Browser aborted before we could read body, server closed the stream | ||
249 | { | ||
250 | // Ignore it, no need to reply | ||
251 | m_log.Error(e); | ||
252 | } | ||
253 | } | ||
254 | else | ||
255 | { | ||
256 | m_threadPool.QueueWorkItem(x => | ||
215 | { | 257 | { |
216 | try | 258 | try |
217 | { | 259 | { |
218 | req.DoHTTPGruntWork(m_server, responsedata); | 260 | req.DoHTTPGruntWork(m_server, responsedata); |
219 | } | 261 | } |
220 | catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream | 262 | catch (ObjectDisposedException e) // Browser aborted before we could read body, server closed the stream |
221 | { | 263 | { |
222 | // Ignore it, no need to reply | 264 | // Ignore it, no need to reply |
265 | m_log.Error(e); | ||
223 | } | 266 | } |
224 | } | 267 | catch (Exception e) |
225 | else | ||
226 | { | ||
227 | m_threadPool.QueueWorkItem(x => | ||
228 | { | 268 | { |
229 | try | 269 | m_log.Error(e); |
230 | { | 270 | } |
231 | req.DoHTTPGruntWork(m_server, responsedata); | 271 | |
232 | } | 272 | return null; |
233 | catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream | 273 | }, null); |
234 | { | 274 | } |
235 | // Ignore it, no need to reply | 275 | } |
236 | } | 276 | else |
237 | 277 | { | |
238 | return null; | 278 | if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) |
239 | }, null); | 279 | { |
240 | } | 280 | req.DoHTTPGruntWork( |
281 | m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); | ||
241 | } | 282 | } |
242 | else | 283 | else |
243 | { | 284 | { |
244 | if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) | 285 | ReQueueEvent(req); |
245 | { | ||
246 | req.DoHTTPGruntWork( | ||
247 | m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); | ||
248 | } | ||
249 | else | ||
250 | { | ||
251 | ReQueueEvent(req); | ||
252 | } | ||
253 | } | 286 | } |
254 | } | 287 | } |
255 | catch (Exception e) | 288 | } |
256 | { | 289 | catch (Exception e) |
257 | m_log.ErrorFormat("Exception in poll service thread: " + e.ToString()); | 290 | { |
258 | } | 291 | m_log.ErrorFormat("Exception in poll service thread: " + e.ToString()); |
259 | } | 292 | } |
260 | } | 293 | } |
261 | } | 294 | } |