Revamp map block sending to eliminate overload of the grid server connection

and the sim's http client
avinationmerge
Melanie 2012-07-08 10:44:53 +02:00
parent 73c5a6e666
commit 1e4c656497
2 changed files with 199 additions and 93 deletions

View File

@ -90,9 +90,9 @@ namespace OpenSim.Region.CoreModules.Hypergrid
} }
} }
protected override List<MapBlockData> GetAndSendBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) protected override List<MapBlockData> GetAndSendBlocksInternal(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag)
{ {
List<MapBlockData> mapBlocks = base.GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag); List<MapBlockData> mapBlocks = base.GetAndSendBlocksInternal(remoteClient, minX, minY, maxX, maxY, flag);
lock (m_SeenMapBlocks) lock (m_SeenMapBlocks)
{ {
if (!m_SeenMapBlocks.ContainsKey(remoteClient.AgentId)) if (!m_SeenMapBlocks.ContainsKey(remoteClient.AgentId))

View File

@ -66,6 +66,9 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
private ManualResetEvent queueEvent = new ManualResetEvent(false); private ManualResetEvent queueEvent = new ManualResetEvent(false);
private Queue<MapRequestState> requests = new Queue<MapRequestState>(); private Queue<MapRequestState> requests = new Queue<MapRequestState>();
private ManualResetEvent m_mapBlockRequestEvent = new ManualResetEvent(false);
private Dictionary<UUID, Queue<MapBlockRequestData>> m_mapBlockRequests = new Dictionary<UUID, Queue<MapBlockRequestData>>();
protected Scene m_scene; protected Scene m_scene;
private List<MapBlockData> cachedMapBlocks = new List<MapBlockData>(); private List<MapBlockData> cachedMapBlocks = new List<MapBlockData>();
private int cachedTime = 0; private int cachedTime = 0;
@ -227,54 +230,54 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
// 6/8/2011 -- I'm adding an explicit 2048 check, so that we never forget that there is // 6/8/2011 -- I'm adding an explicit 2048 check, so that we never forget that there is
// a hack here, and so that regions below 4096 don't get spammed with unnecessary map blocks. // a hack here, and so that regions below 4096 don't get spammed with unnecessary map blocks.
if (m_scene.RegionInfo.RegionLocX >= 2048 || m_scene.RegionInfo.RegionLocY >= 2048) //if (m_scene.RegionInfo.RegionLocX >= 2048 || m_scene.RegionInfo.RegionLocY >= 2048)
{ //{
ScenePresence avatarPresence = null; // ScenePresence avatarPresence = null;
m_scene.TryGetScenePresence(agentID, out avatarPresence); // m_scene.TryGetScenePresence(agentID, out avatarPresence);
if (avatarPresence != null) // if (avatarPresence != null)
{ // {
bool lookup = false; // bool lookup = false;
lock (cachedMapBlocks) // lock (cachedMapBlocks)
{ // {
if (cachedMapBlocks.Count > 0 && ((cachedTime + 1800) > Util.UnixTimeSinceEpoch())) // if (cachedMapBlocks.Count > 0 && ((cachedTime + 1800) > Util.UnixTimeSinceEpoch()))
{ // {
List<MapBlockData> mapBlocks; // List<MapBlockData> mapBlocks;
mapBlocks = cachedMapBlocks; // mapBlocks = cachedMapBlocks;
avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); // avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0);
} // }
else // else
{ // {
lookup = true; // lookup = true;
} // }
} // }
if (lookup) // if (lookup)
{ // {
List<MapBlockData> mapBlocks = new List<MapBlockData>(); ; // List<MapBlockData> mapBlocks = new List<MapBlockData>(); ;
List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, // List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
(int)(m_scene.RegionInfo.RegionLocX - 8) * (int)Constants.RegionSize, // (int)(m_scene.RegionInfo.RegionLocX - 8) * (int)Constants.RegionSize,
(int)(m_scene.RegionInfo.RegionLocX + 8) * (int)Constants.RegionSize, // (int)(m_scene.RegionInfo.RegionLocX + 8) * (int)Constants.RegionSize,
(int)(m_scene.RegionInfo.RegionLocY - 8) * (int)Constants.RegionSize, // (int)(m_scene.RegionInfo.RegionLocY - 8) * (int)Constants.RegionSize,
(int)(m_scene.RegionInfo.RegionLocY + 8) * (int)Constants.RegionSize); // (int)(m_scene.RegionInfo.RegionLocY + 8) * (int)Constants.RegionSize);
foreach (GridRegion r in regions) // foreach (GridRegion r in regions)
{ // {
MapBlockData block = new MapBlockData(); // MapBlockData block = new MapBlockData();
MapBlockFromGridRegion(block, r, 0); // MapBlockFromGridRegion(block, r, 0);
mapBlocks.Add(block); // mapBlocks.Add(block);
} // }
avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); // avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0);
lock (cachedMapBlocks) // lock (cachedMapBlocks)
cachedMapBlocks = mapBlocks; // cachedMapBlocks = mapBlocks;
cachedTime = Util.UnixTimeSinceEpoch(); // cachedTime = Util.UnixTimeSinceEpoch();
} // }
} // }
} //}
LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse(); LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse();
mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse()); mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse());
@ -301,8 +304,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
protected static OSDMapLayer GetOSDMapLayerResponse() protected static OSDMapLayer GetOSDMapLayerResponse()
{ {
OSDMapLayer mapLayer = new OSDMapLayer(); OSDMapLayer mapLayer = new OSDMapLayer();
mapLayer.Right = 5000; mapLayer.Right = 2048;
mapLayer.Top = 5000; mapLayer.Top = 2048;
mapLayer.ImageID = new UUID("00000000-0000-1111-9999-000000000006"); mapLayer.ImageID = new UUID("00000000-0000-1111-9999-000000000006");
return mapLayer; return mapLayer;
@ -331,6 +334,11 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
{ {
m_rootAgents.Remove(AgentId); m_rootAgents.Remove(AgentId);
} }
lock (m_mapBlockRequestEvent)
{
if (m_mapBlockRequests.ContainsKey(AgentId))
m_mapBlockRequests.Remove(AgentId);
}
} }
#endregion #endregion
@ -353,6 +361,12 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
ThreadPriority.BelowNormal, ThreadPriority.BelowNormal,
true, true,
true); true);
Watchdog.StartThread(
MapBlockSendThread,
string.Format("MapBlockSendThread ({0})", m_scene.RegionInfo.RegionName),
ThreadPriority.BelowNormal,
true,
true);
} }
/// <summary> /// <summary>
@ -373,6 +387,22 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
queueEvent.Set(); queueEvent.Set();
requests.Enqueue(st); requests.Enqueue(st);
} }
MapBlockRequestData req = new MapBlockRequestData();
req.client = null;
req.minX = 0;
req.maxX = 0;
req.minY = 0;
req.maxY = 0;
req.flags = 0;
lock (m_mapBlockRequestEvent)
{
m_mapBlockRequests[UUID.Zero] = new Queue<MapBlockRequestData>();
m_mapBlockRequests[UUID.Zero].Enqueue(req);
m_mapBlockRequestEvent.Set();
}
} }
public virtual void HandleMapItemRequest(IClientAPI remoteClient, uint flags, public virtual void HandleMapItemRequest(IClientAPI remoteClient, uint flags,
@ -932,84 +962,144 @@ return;
/// <param name="minY"></param> /// <param name="minY"></param>
/// <param name="maxX"></param> /// <param name="maxX"></param>
/// <param name="maxY"></param> /// <param name="maxY"></param>
public virtual void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) public void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag)
{ {
Util.FireAndForget(x => //m_log.ErrorFormat("[YYY] RequestMapBlocks {0}={1}={2}={3} {4}", minX, minY, maxX, maxY, flag);
if ((flag & 0x10000) != 0) // user clicked on qthe map a tile that isn't visible
{ {
//m_log.ErrorFormat("[YYY] RequestMapBlocks {0}={1}={2}={3} {4}", minX, minY, maxX, maxY, flag); List<MapBlockData> response = new List<MapBlockData>();
if ((flag & 0x10000) != 0) // user clicked on qthe map a tile that isn't visible
// this should return one mapblock at most. It is triggered by a click
// on an unloaded square.
// But make sure: Look whether the one we requested is in there
List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
minX * (int)Constants.RegionSize,
maxX * (int)Constants.RegionSize,
minY * (int)Constants.RegionSize,
maxY * (int)Constants.RegionSize);
if (regions != null)
{ {
List<MapBlockData> response = new List<MapBlockData>(); foreach (GridRegion r in regions)
// this should return one mapblock at most. It is triggered by a click
// on an unloaded square.
// But make sure: Look whether the one we requested is in there
List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
minX * (int)Constants.RegionSize,
maxX * (int)Constants.RegionSize,
minY * (int)Constants.RegionSize,
maxY * (int)Constants.RegionSize);
if (regions != null)
{ {
foreach (GridRegion r in regions) if ((r.RegionLocX == minX * (int)Constants.RegionSize) &&
(r.RegionLocY == minY * (int)Constants.RegionSize))
{ {
if ((r.RegionLocX == minX * (int)Constants.RegionSize) && // found it => add it to response
(r.RegionLocY == minY * (int)Constants.RegionSize)) MapBlockData block = new MapBlockData();
{ MapBlockFromGridRegion(block, r, flag);
// found it => add it to response response.Add(block);
MapBlockData block = new MapBlockData(); break;
MapBlockFromGridRegion(block, r, flag);
response.Add(block);
break;
}
} }
} }
}
if (response.Count == 0) if (response.Count == 0)
{
// response still empty => couldn't find the map-tile the user clicked on => tell the client
MapBlockData block = new MapBlockData();
block.X = (ushort)minX;
block.Y = (ushort)minY;
block.Access = 254; // means 'simulator is offline'
response.Add(block);
}
// The lower 16 bits are an unsigned int16
remoteClient.SendMapBlock(response, flag & 0xffff);
}
else
{ {
// normal mapblock request. Use the provided values // response still empty => couldn't find the map-tile the user clicked on => tell the client
GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag); MapBlockData block = new MapBlockData();
block.X = (ushort)minX;
block.Y = (ushort)minY;
block.Access = 254; // means 'simulator is offline'
response.Add(block);
} }
}); // The lower 16 bits are an unsigned int16
remoteClient.SendMapBlock(response, flag & 0xffff);
}
else
{
// normal mapblock request. Use the provided values
GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag);
}
} }
protected virtual List<MapBlockData> GetAndSendBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) protected virtual List<MapBlockData> GetAndSendBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag)
{ {
MapBlockRequestData req = new MapBlockRequestData();
req.client = remoteClient;
req.minX = minX;
req.maxX = maxX;
req.minY = minY;
req.maxY = maxY;
req.flags = flag;
lock (m_mapBlockRequestEvent)
{
if (!m_mapBlockRequests.ContainsKey(remoteClient.AgentId))
m_mapBlockRequests[remoteClient.AgentId] = new Queue<MapBlockRequestData>();
m_mapBlockRequests[remoteClient.AgentId].Enqueue(req);
m_mapBlockRequestEvent.Set();
}
return new List<MapBlockData>();
}
protected void MapBlockSendThread()
{
while (true)
{
List<MapBlockRequestData> thisRunData = new List<MapBlockRequestData>();
m_mapBlockRequestEvent.WaitOne();
lock (m_mapBlockRequestEvent)
{
int total = 0;
foreach (Queue<MapBlockRequestData> q in m_mapBlockRequests.Values)
{
if (q.Count > 0)
thisRunData.Add(q.Dequeue());
total += q.Count;
}
if (total == 0)
m_mapBlockRequestEvent.Reset();
}
foreach (MapBlockRequestData req in thisRunData)
{
// Null client stops thread
if (req.client == null)
return;
GetAndSendBlocksInternal(req.client, req.minX, req.minY, req.maxX, req.maxY, req.flags);
}
Thread.Sleep(50);
}
}
protected virtual List<MapBlockData> GetAndSendBlocksInternal(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag)
{
List<MapBlockData> allBlocks = new List<MapBlockData>();
List<MapBlockData> mapBlocks = new List<MapBlockData>(); List<MapBlockData> mapBlocks = new List<MapBlockData>();
List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
(minX - 4) * (int)Constants.RegionSize, minX * (int)Constants.RegionSize,
(maxX + 4) * (int)Constants.RegionSize, maxX * (int)Constants.RegionSize,
(minY - 4) * (int)Constants.RegionSize, minY * (int)Constants.RegionSize,
(maxY + 4) * (int)Constants.RegionSize); maxY * (int)Constants.RegionSize);
// (minX - 4) * (int)Constants.RegionSize,
// (maxX + 4) * (int)Constants.RegionSize,
// (minY - 4) * (int)Constants.RegionSize,
// (maxY + 4) * (int)Constants.RegionSize);
foreach (GridRegion r in regions) foreach (GridRegion r in regions)
{ {
MapBlockData block = new MapBlockData(); MapBlockData block = new MapBlockData();
MapBlockFromGridRegion(block, r, flag); MapBlockFromGridRegion(block, r, flag);
mapBlocks.Add(block); mapBlocks.Add(block);
allBlocks.Add(block);
if (mapBlocks.Count >= 10) if (mapBlocks.Count >= 10)
{ {
remoteClient.SendMapBlock(mapBlocks, flag & 0xffff); remoteClient.SendMapBlock(mapBlocks, flag & 0xffff);
mapBlocks.Clear(); mapBlocks.Clear();
Thread.Sleep(1000); Thread.Sleep(50);
} }
} }
if (mapBlocks.Count > 0) if (mapBlocks.Count > 0)
remoteClient.SendMapBlock(mapBlocks, flag & 0xffff); remoteClient.SendMapBlock(mapBlocks, flag & 0xffff);
return mapBlocks; return allBlocks;
} }
protected void MapBlockFromGridRegion(MapBlockData block, GridRegion r, uint flag) protected void MapBlockFromGridRegion(MapBlockData block, GridRegion r, uint flag)
@ -1408,6 +1498,12 @@ return;
{ {
m_rootAgents.Remove(avatar.UUID); m_rootAgents.Remove(avatar.UUID);
} }
lock (m_mapBlockRequestEvent)
{
if (m_mapBlockRequests.ContainsKey(avatar.UUID))
m_mapBlockRequests.Remove(avatar.UUID);
}
} }
public void OnRegionUp(GridRegion otherRegion) public void OnRegionUp(GridRegion otherRegion)
@ -1531,4 +1627,14 @@ return;
public uint itemtype; public uint itemtype;
public ulong regionhandle; public ulong regionhandle;
} }
public struct MapBlockRequestData
{
public IClientAPI client;
public int minX;
public int minY;
public int maxX;
public int maxY;
public uint flags;
}
} }