From 1e4c65649736db82d0221b6b2aa57f7f45c7163c Mon Sep 17 00:00:00 2001 From: Melanie Date: Sun, 8 Jul 2012 10:44:53 +0200 Subject: [PATCH] Revamp map block sending to eliminate overload of the grid server connection and the sim's http client --- .../CoreModules/Hypergrid/HGWorldMapModule.cs | 4 +- .../World/WorldMap/WorldMapModule.cs | 288 ++++++++++++------ 2 files changed, 199 insertions(+), 93 deletions(-) diff --git a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs index 0c60391fe2..4f18b53311 100644 --- a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs +++ b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs @@ -90,9 +90,9 @@ namespace OpenSim.Region.CoreModules.Hypergrid } } - protected override List GetAndSendBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) + protected override List GetAndSendBlocksInternal(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) { - List mapBlocks = base.GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag); + List mapBlocks = base.GetAndSendBlocksInternal(remoteClient, minX, minY, maxX, maxY, flag); lock (m_SeenMapBlocks) { if (!m_SeenMapBlocks.ContainsKey(remoteClient.AgentId)) diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs index 88aacb9ac7..a226b78aa7 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs @@ -66,6 +66,9 @@ namespace OpenSim.Region.CoreModules.World.WorldMap private ManualResetEvent queueEvent = new ManualResetEvent(false); private Queue requests = new Queue(); + private ManualResetEvent m_mapBlockRequestEvent = new ManualResetEvent(false); + private Dictionary> m_mapBlockRequests = new Dictionary>(); + protected Scene m_scene; private List cachedMapBlocks = new List(); 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 // 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) - { - ScenePresence avatarPresence = null; + //if (m_scene.RegionInfo.RegionLocX >= 2048 || m_scene.RegionInfo.RegionLocY >= 2048) + //{ + // ScenePresence avatarPresence = null; - m_scene.TryGetScenePresence(agentID, out avatarPresence); + // m_scene.TryGetScenePresence(agentID, out avatarPresence); - if (avatarPresence != null) - { - bool lookup = false; + // if (avatarPresence != null) + // { + // bool lookup = false; - lock (cachedMapBlocks) - { - if (cachedMapBlocks.Count > 0 && ((cachedTime + 1800) > Util.UnixTimeSinceEpoch())) - { - List mapBlocks; + // lock (cachedMapBlocks) + // { + // if (cachedMapBlocks.Count > 0 && ((cachedTime + 1800) > Util.UnixTimeSinceEpoch())) + // { + // List mapBlocks; - mapBlocks = cachedMapBlocks; - avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); - } - else - { - lookup = true; - } - } - if (lookup) - { - List mapBlocks = new List(); ; + // mapBlocks = cachedMapBlocks; + // avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); + // } + // else + // { + // lookup = true; + // } + // } + // if (lookup) + // { + // List mapBlocks = new List(); ; - List 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.RegionLocY - 8) * (int)Constants.RegionSize, - (int)(m_scene.RegionInfo.RegionLocY + 8) * (int)Constants.RegionSize); - foreach (GridRegion r in regions) - { - MapBlockData block = new MapBlockData(); - MapBlockFromGridRegion(block, r, 0); - mapBlocks.Add(block); - } - avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); + // List 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.RegionLocY - 8) * (int)Constants.RegionSize, + // (int)(m_scene.RegionInfo.RegionLocY + 8) * (int)Constants.RegionSize); + // foreach (GridRegion r in regions) + // { + // MapBlockData block = new MapBlockData(); + // MapBlockFromGridRegion(block, r, 0); + // mapBlocks.Add(block); + // } + // avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); - lock (cachedMapBlocks) - cachedMapBlocks = mapBlocks; + // lock (cachedMapBlocks) + // cachedMapBlocks = mapBlocks; - cachedTime = Util.UnixTimeSinceEpoch(); - } - } - } + // cachedTime = Util.UnixTimeSinceEpoch(); + // } + // } + //} LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse(); mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse()); @@ -301,8 +304,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap protected static OSDMapLayer GetOSDMapLayerResponse() { OSDMapLayer mapLayer = new OSDMapLayer(); - mapLayer.Right = 5000; - mapLayer.Top = 5000; + mapLayer.Right = 2048; + mapLayer.Top = 2048; mapLayer.ImageID = new UUID("00000000-0000-1111-9999-000000000006"); return mapLayer; @@ -331,6 +334,11 @@ namespace OpenSim.Region.CoreModules.World.WorldMap { m_rootAgents.Remove(AgentId); } + lock (m_mapBlockRequestEvent) + { + if (m_mapBlockRequests.ContainsKey(AgentId)) + m_mapBlockRequests.Remove(AgentId); + } } #endregion @@ -353,6 +361,12 @@ namespace OpenSim.Region.CoreModules.World.WorldMap ThreadPriority.BelowNormal, true, true); + Watchdog.StartThread( + MapBlockSendThread, + string.Format("MapBlockSendThread ({0})", m_scene.RegionInfo.RegionName), + ThreadPriority.BelowNormal, + true, + true); } /// @@ -373,6 +387,22 @@ namespace OpenSim.Region.CoreModules.World.WorldMap queueEvent.Set(); 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(); + m_mapBlockRequests[UUID.Zero].Enqueue(req); + m_mapBlockRequestEvent.Set(); + } } public virtual void HandleMapItemRequest(IClientAPI remoteClient, uint flags, @@ -932,84 +962,144 @@ return; /// /// /// - 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); - if ((flag & 0x10000) != 0) // user clicked on qthe map a tile that isn't visible + List response = new List(); + + // 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 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 response = new List(); - - // 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 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) { - 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) && - (r.RegionLocY == minY * (int)Constants.RegionSize)) - { - // found it => add it to response - MapBlockData block = new MapBlockData(); - MapBlockFromGridRegion(block, r, flag); - response.Add(block); - break; - } + // found it => add it to response + MapBlockData block = new MapBlockData(); + MapBlockFromGridRegion(block, r, flag); + response.Add(block); + break; } } + } - 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 + if (response.Count == 0) { - // normal mapblock request. Use the provided values - GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag); + // 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 + GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag); + } } protected virtual List 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(); + m_mapBlockRequests[remoteClient.AgentId].Enqueue(req); + m_mapBlockRequestEvent.Set(); + } + + return new List(); + } + + protected void MapBlockSendThread() + { + while (true) + { + List thisRunData = new List(); + + m_mapBlockRequestEvent.WaitOne(); + lock (m_mapBlockRequestEvent) + { + int total = 0; + foreach (Queue 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 GetAndSendBlocksInternal(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) + { + List allBlocks = new List(); List mapBlocks = new List(); List regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, - (minX - 4) * (int)Constants.RegionSize, - (maxX + 4) * (int)Constants.RegionSize, - (minY - 4) * (int)Constants.RegionSize, - (maxY + 4) * (int)Constants.RegionSize); + minX * (int)Constants.RegionSize, + maxX * (int)Constants.RegionSize, + minY * (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) { MapBlockData block = new MapBlockData(); MapBlockFromGridRegion(block, r, flag); mapBlocks.Add(block); + allBlocks.Add(block); if (mapBlocks.Count >= 10) { remoteClient.SendMapBlock(mapBlocks, flag & 0xffff); mapBlocks.Clear(); - Thread.Sleep(1000); + Thread.Sleep(50); } } if (mapBlocks.Count > 0) remoteClient.SendMapBlock(mapBlocks, flag & 0xffff); - return mapBlocks; + return allBlocks; } protected void MapBlockFromGridRegion(MapBlockData block, GridRegion r, uint flag) @@ -1408,6 +1498,12 @@ return; { m_rootAgents.Remove(avatar.UUID); } + + lock (m_mapBlockRequestEvent) + { + if (m_mapBlockRequests.ContainsKey(avatar.UUID)) + m_mapBlockRequests.Remove(avatar.UUID); + } } public void OnRegionUp(GridRegion otherRegion) @@ -1531,4 +1627,14 @@ return; public uint itemtype; public ulong regionhandle; } + + public struct MapBlockRequestData + { + public IClientAPI client; + public int minX; + public int minY; + public int maxX; + public int maxY; + public uint flags; + } }