Revamp map block sending to eliminate overload of the grid server connection
and the sim's http clientavinationmerge
parent
73c5a6e666
commit
1e4c656497
|
@ -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))
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue