* 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.
This commit is contained in:
Teravus Ovares
2009-07-29 02:15:45 +00:00
parent f94985a939
commit 032aeb8b5d
11 changed files with 527 additions and 18 deletions

View File

@@ -61,7 +61,7 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue
private Dictionary<UUID, int> m_ids = new Dictionary<UUID, int>();
private Dictionary<UUID, BlockingLLSDQueue> queues = new Dictionary<UUID, BlockingLLSDQueue>();
private Dictionary<UUID, Queue<OSD>> queues = new Dictionary<UUID, Queue<OSD>>();
private Dictionary<UUID, UUID> m_QueueUUIDAvatarMapping = new Dictionary<UUID, UUID>();
private Dictionary<UUID, UUID> m_AvatarQueueUUIDMapping = new Dictionary<UUID, UUID>();
@@ -131,7 +131,7 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue
/// </summary>
/// <param name="agentId"></param>
/// <returns></returns>
private BlockingLLSDQueue TryGetQueue(UUID agentId)
private Queue<OSD> TryGetQueue(UUID agentId)
{
lock (queues)
{
@@ -141,7 +141,7 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue
"[EVENTQUEUE]: Adding new queue for agent {0} in region {1}",
agentId, m_scene.RegionInfo.RegionName);
queues[agentId] = new BlockingLLSDQueue();
queues[agentId] = new Queue<OSD>();
}
return queues[agentId];
@@ -153,7 +153,7 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue
/// </summary>
/// <param name="agentId"></param>
/// <returns></returns>
private BlockingLLSDQueue GetQueue(UUID agentId)
private Queue<OSD> GetQueue(UUID agentId)
{
lock (queues)
{
@@ -173,7 +173,7 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue
//m_log.DebugFormat("[EVENTQUEUE]: Enqueuing event for {0} in region {1}", avatarID, m_scene.RegionInfo.RegionName);
try
{
BlockingLLSDQueue queue = GetQueue(avatarID);
Queue<OSD> queue = GetQueue(avatarID);
if (queue != null)
queue.Enqueue(ev);
}
@@ -203,7 +203,7 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue
m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", AgentID, m_scene.RegionInfo.RegionName);
int count = 0;
while (queues.ContainsKey(AgentID) && queues[AgentID].Count() > 0 && count++ < 5)
while (queues.ContainsKey(AgentID) && queues[AgentID].Count > 0 && count++ < 5)
{
Thread.Sleep(1000);
}
@@ -226,7 +226,7 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue
foreach (UUID ky in removeitems)
{
m_AvatarQueueUUIDMapping.Remove(ky);
MainServer.Instance.RemoveHTTPHandler("","/CAPS/EQG/" + ky.ToString() + "/");
MainServer.Instance.RemovePollServiceHTTPHandler("","/CAPS/EQG/" + ky.ToString() + "/");
}
}
@@ -315,8 +315,8 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue
}));
// This will persist this beyond the expiry of the caps handlers
MainServer.Instance.AddHTTPHandler(
capsBase + EventQueueGetUUID.ToString() + "/", EventQueuePath2);
MainServer.Instance.AddPollServiceHTTPHandler(
capsBase + EventQueueGetUUID.ToString() + "/", EventQueuePath2, new PollServiceEventArgs(HasEvents, GetEvents, NoEvents, agentID));
Random rnd = new Random(Environment.TickCount);
lock (m_ids)
@@ -326,6 +326,73 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue
}
}
public bool HasEvents(UUID agentID)
{
Queue<OSD> queue = TryGetQueue(agentID);
if (queue.Count > 0)
return true;
else
return false;
}
public Hashtable GetEvents(UUID pAgentId, string request)
{
Queue<OSD> queue = TryGetQueue(pAgentId);
OSD element = queue.Dequeue(); // 15s timeout
int thisID = 0;
lock (m_ids)
thisID = m_ids[pAgentId];
OSDArray array = new OSDArray();
if (element == null) // didn't have an event in 15s
{
// Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say!
array.Add(EventQueueHelper.KeepAliveEvent());
m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", pAgentId, m_scene.RegionInfo.RegionName);
}
else
{
array.Add(element);
while (queue.Count > 0)
{
array.Add(queue.Dequeue());
thisID++;
}
}
OSDMap events = new OSDMap();
events.Add("events", array);
events.Add("id", new OSDInteger(thisID));
lock (m_ids)
{
m_ids[pAgentId] = thisID + 1;
}
Hashtable responsedata = new Hashtable();
responsedata["int_response_code"] = 200;
responsedata["content_type"] = "application/xml";
responsedata["keepalive"] = false;
responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(events);
return responsedata;
//m_log.DebugFormat("[EVENTQUEUE]: sending response for {0} in region {1}: {2}", agentID, m_scene.RegionInfo.RegionName, responsedata["str_response_string"]);
}
public Hashtable NoEvents()
{
Hashtable responsedata = new Hashtable();
responsedata["int_response_code"] = 502;
responsedata["content_type"] = "text/plain";
responsedata["keepalive"] = false;
responsedata["str_response_string"] = "Upstream error: ";
responsedata["error_status_text"] = "Upstream error:";
responsedata["http_protocol_version"] = "HTTP/1.0";
return responsedata;
}
public Hashtable ProcessQueue(Hashtable request, UUID agentID, Caps caps)
{
// TODO: this has to be redone to not busy-wait (and block the thread),
@@ -341,8 +408,8 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue
// m_log.DebugFormat(debug + " ]", agentID, m_scene.RegionInfo.RegionName, System.Threading.Thread.CurrentThread.Name);
// }
BlockingLLSDQueue queue = TryGetQueue(agentID);
OSD element = queue.Dequeue(15000); // 15s timeout
Queue<OSD> queue = TryGetQueue(agentID);
OSD element = queue.Dequeue(); // 15s timeout
Hashtable responsedata = new Hashtable();
@@ -381,9 +448,9 @@ namespace OpenSim.Region.CoreModules.Framework.EventQueue
else
{
array.Add(element);
while (queue.Count() > 0)
while (queue.Count > 0)
{
array.Add(queue.Dequeue(1));
array.Add(queue.Dequeue());
thisID++;
}
}