From 470019b52a72de1a8777933ce3254cde87e184f9 Mon Sep 17 00:00:00 2001 From: Melanie Date: Sat, 7 Jul 2012 19:59:55 +0200 Subject: Change semantics of FromXML on vehicle data to make the serializer a bit cleaner --- OpenSim/Region/Framework/Scenes/SOPVehicle.cs | 15 ++++++++++++++- .../Scenes/Serialization/SceneObjectSerializer.cs | 11 +++++------ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SOPVehicle.cs b/OpenSim/Region/Framework/Scenes/SOPVehicle.cs index e2ef77b..41e8944 100644 --- a/OpenSim/Region/Framework/Scenes/SOPVehicle.cs +++ b/OpenSim/Region/Framework/Scenes/SOPVehicle.cs @@ -599,7 +599,20 @@ namespace OpenSim.Region.Framework.Scenes return v; } - public void FromXml2(XmlTextReader _reader, out bool errors) + public static SOPVehicle FromXml2(XmlTextReader reader) + { + SOPVehicle vehicle = new SOPVehicle(); + + bool errors = false; + + vehicle.FromXml2(reader, out errors); + if (errors) + return null; + + return vehicle; + } + + private void FromXml2(XmlTextReader _reader, out bool errors) { errors = false; reader = _reader; diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index c7e4c3e..abca14f 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs @@ -623,12 +623,9 @@ namespace OpenSim.Region.Framework.Scenes.Serialization private static void ProcessVehicle(SceneObjectPart obj, XmlTextReader reader) { - bool errors = false; - SOPVehicle _vehicle = new SOPVehicle(); + SOPVehicle vehicle = SOPVehicle.FromXml2(reader); - _vehicle.FromXml2(reader, out errors); - - if (errors) + if (vehicle == null) { obj.VehicleParams = null; m_log.DebugFormat( @@ -636,7 +633,9 @@ namespace OpenSim.Region.Framework.Scenes.Serialization obj.Name, obj.UUID); } else - obj.VehicleParams = _vehicle; + { + obj.VehicleParams = vehicle; + } } private static void ProcessShape(SceneObjectPart obj, XmlTextReader reader) -- cgit v1.1 From d3b778ebbe617a37a32c866101c75284dad8f15a Mon Sep 17 00:00:00 2001 From: Melanie Date: Sun, 8 Jul 2012 06:06:33 +0200 Subject: Address map lag issue seen with non-avination viewers --- .../CoreModules/World/WorldMap/MapSearchModule.cs | 161 +++++----- .../CoreModules/World/WorldMap/WorldMapModule.cs | 357 ++++++++++----------- .../Server/Handlers/Map/MapGetServerConnector.cs | 15 +- 3 files changed, 271 insertions(+), 262 deletions(-) diff --git a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs index 4e6bfb8..2417b1a 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs @@ -86,90 +86,93 @@ namespace OpenSim.Region.CoreModules.World.WorldMap private void OnMapNameRequest(IClientAPI remoteClient, string mapName, uint flags) { - if (mapName.Length < 2) + Util.FireAndForget(x => { - remoteClient.SendAlertMessage("Use a search string with at least 2 characters"); - return; - } + if (mapName.Length < 2) + { + remoteClient.SendAlertMessage("Use a search string with at least 2 characters"); + return; + } - //m_log.DebugFormat("MAP NAME=({0})", mapName); - - // Hack to get around the fact that ll V3 now drops the port from the - // map name. See https://jira.secondlife.com/browse/VWR-28570 - // - // Caller, use this magic form instead: - // secondlife://http|!!mygrid.com|8002|Region+Name/128/128 - // or url encode if possible. - // the hacks we do with this viewer... - // - string mapNameOrig = mapName; - if (mapName.Contains("|")) - mapName = mapName.Replace('|', ':'); - if (mapName.Contains("+")) - mapName = mapName.Replace('+', ' '); - if (mapName.Contains("!")) - mapName = mapName.Replace('!', '/'); - - // try to fetch from GridServer - List regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20); -// if (regionInfos.Count == 0) -// remoteClient.SendAlertMessage("Hyperlink could not be established."); - - //m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions", mapName, regionInfos.Count); - List blocks = new List(); - - MapBlockData data; - if (regionInfos.Count > 0) - { - foreach (GridRegion info in regionInfos) + //m_log.DebugFormat("MAP NAME=({0})", mapName); + + // Hack to get around the fact that ll V3 now drops the port from the + // map name. See https://jira.secondlife.com/browse/VWR-28570 + // + // Caller, use this magic form instead: + // secondlife://http|!!mygrid.com|8002|Region+Name/128/128 + // or url encode if possible. + // the hacks we do with this viewer... + // + string mapNameOrig = mapName; + if (mapName.Contains("|")) + mapName = mapName.Replace('|', ':'); + if (mapName.Contains("+")) + mapName = mapName.Replace('+', ' '); + if (mapName.Contains("!")) + mapName = mapName.Replace('!', '/'); + + // try to fetch from GridServer + List regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20); + // if (regionInfos.Count == 0) + // remoteClient.SendAlertMessage("Hyperlink could not be established."); + + //m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions", mapName, regionInfos.Count); + List blocks = new List(); + + MapBlockData data; + if (regionInfos.Count > 0) { - data = new MapBlockData(); - data.Agents = 0; - data.Access = info.Access; - if (flags == 2) // V2 sends this - data.MapImageId = UUID.Zero; - else - data.MapImageId = info.TerrainImage; - // ugh! V2-3 is very sensitive about the result being - // exactly the same as the requested name - if (regionInfos.Count == 1 && mapNameOrig.Contains("|") || mapNameOrig.Contains("+")) - data.Name = mapNameOrig; - else - data.Name = info.RegionName; - data.RegionFlags = 0; // TODO not used? - data.WaterHeight = 0; // not used - data.X = (ushort)(info.RegionLocX / Constants.RegionSize); - data.Y = (ushort)(info.RegionLocY / Constants.RegionSize); - blocks.Add(data); + foreach (GridRegion info in regionInfos) + { + data = new MapBlockData(); + data.Agents = 0; + data.Access = info.Access; + if (flags == 2) // V2 sends this + data.MapImageId = UUID.Zero; + else + data.MapImageId = info.TerrainImage; + // ugh! V2-3 is very sensitive about the result being + // exactly the same as the requested name + if (regionInfos.Count == 1 && mapNameOrig.Contains("|") || mapNameOrig.Contains("+")) + data.Name = mapNameOrig; + else + data.Name = info.RegionName; + data.RegionFlags = 0; // TODO not used? + data.WaterHeight = 0; // not used + data.X = (ushort)(info.RegionLocX / Constants.RegionSize); + data.Y = (ushort)(info.RegionLocY / Constants.RegionSize); + blocks.Add(data); + } } - } - // final block, closing the search result - data = new MapBlockData(); - data.Agents = 0; - data.Access = 255; - data.MapImageId = UUID.Zero; - data.Name = mapName; - data.RegionFlags = 0; - data.WaterHeight = 0; // not used - data.X = 0; - data.Y = 0; - blocks.Add(data); - - // flags are agent flags sent from the viewer. - // they have different values depending on different viewers, apparently - remoteClient.SendMapBlock(blocks, flags); - - // send extra user messages for V3 - // because the UI is very confusing - // while we don't fix the hard-coded urls - if (flags == 2) - { - if (regionInfos.Count == 0) - remoteClient.SendAgentAlertMessage("No regions found with that name.", true); - else if (regionInfos.Count == 1) - remoteClient.SendAgentAlertMessage("Region found!", false); - } + // final block, closing the search result + data = new MapBlockData(); + data.Agents = 0; + data.Access = 255; + data.MapImageId = UUID.Zero; + data.Name = mapName; + data.RegionFlags = 0; + data.WaterHeight = 0; // not used + data.X = 0; + data.Y = 0; + blocks.Add(data); + + // flags are agent flags sent from the viewer. + // they have different values depending on different viewers, apparently + remoteClient.SendMapBlock(blocks, flags); + + // send extra user messages for V3 + // because the UI is very confusing + // while we don't fix the hard-coded urls + if (flags == 2) + { + if (regionInfos.Count == 0) + remoteClient.SendAgentAlertMessage("No regions found with that name.", true); + else if (regionInfos.Count == 1) + remoteClient.SendAgentAlertMessage("Region found!", false); + } + }); } // private Scene GetClientScene(IClientAPI client) diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs index 899e5ea..721ac5c 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs @@ -63,7 +63,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap private static readonly UUID STOP_UUID = UUID.Random(); private static readonly string m_mapLayerPath = "0001/"; - private OpenSim.Framework.BlockingQueue requests = new OpenSim.Framework.BlockingQueue(); + private ManualResetEvent queueEvent = new ManualResetEvent(false); + private Queue requests = new Queue(); protected Scene m_scene; private List cachedMapBlocks = new List(); @@ -71,7 +72,6 @@ namespace OpenSim.Region.CoreModules.World.WorldMap private int blacklistTimeout = 10*60*1000; // 10 minutes private byte[] myMapImageJPEG; protected volatile bool m_Enabled = false; - private Dictionary m_openRequests = new Dictionary(); private Dictionary m_blacklistedurls = new Dictionary(); private Dictionary m_blacklistedregions = new Dictionary(); private Dictionary m_cachedRegionMapItemsAddress = new Dictionary(); @@ -368,7 +368,11 @@ namespace OpenSim.Region.CoreModules.World.WorldMap st.itemtype=0; st.regionhandle=0; - requests.Enqueue(st); + lock (requests) + { + queueEvent.Set(); + requests.Enqueue(st); + } } public virtual void HandleMapItemRequest(IClientAPI remoteClient, uint flags, @@ -519,12 +523,26 @@ namespace OpenSim.Region.CoreModules.World.WorldMap /// public void process() { - const int MAX_ASYNC_REQUESTS = 20; + const int MAX_ASYNC_REQUESTS = 5; try { while (true) { - MapRequestState st = requests.Dequeue(1000); + MapRequestState st = new MapRequestState(); + bool valid = false; + queueEvent.WaitOne(); + lock (requests) + { + if (requests.Count > 0) + { + st = requests.Dequeue(); + valid = true; + } + if (requests.Count == 0) + queueEvent.Reset(); + } + if (!valid) + continue; // end gracefully if (st.agentID == STOP_UUID) @@ -541,14 +559,11 @@ namespace OpenSim.Region.CoreModules.World.WorldMap if (dorequest && !m_blacklistedregions.ContainsKey(st.regionhandle)) { - while (nAsyncRequests >= MAX_ASYNC_REQUESTS) // hit the break - Thread.Sleep(80); +// while (nAsyncRequests >= MAX_ASYNC_REQUESTS) // hit the break +// Thread.Sleep(500); - RequestMapItemsDelegate d = RequestMapItemsAsync; - d.BeginInvoke(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle, RequestMapItemsCompleted, null); - //OSDMap response = RequestMapItemsAsync(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle); - //RequestMapItemsCompleted(response); Interlocked.Increment(ref nAsyncRequests); + RequestMapItemsAsync(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle); } } @@ -570,110 +585,10 @@ namespace OpenSim.Region.CoreModules.World.WorldMap /// public void EnqueueMapItemRequest(MapRequestState state) { - requests.Enqueue(state); - } - - /// - /// Sends the mapitem response to the IClientAPI - /// - /// The OSDMap Response for the mapitem - private void RequestMapItemsCompleted(IAsyncResult iar) - { - AsyncResult result = (AsyncResult)iar; - RequestMapItemsDelegate icon = (RequestMapItemsDelegate)result.AsyncDelegate; - - OSDMap response = (OSDMap)icon.EndInvoke(iar); - - Interlocked.Decrement(ref nAsyncRequests); - - if (!response.ContainsKey("requestID")) - return; - - UUID requestID = response["requestID"].AsUUID(); - - if (requestID != UUID.Zero) + lock (requests) { - MapRequestState mrs = new MapRequestState(); - mrs.agentID = UUID.Zero; - lock (m_openRequests) - { - if (m_openRequests.ContainsKey(requestID)) - { - mrs = m_openRequests[requestID]; - m_openRequests.Remove(requestID); - } - } - - if (mrs.agentID != UUID.Zero) - { - ScenePresence av = null; - m_scene.TryGetScenePresence(mrs.agentID, out av); - if (av != null) - { - if (response.ContainsKey(mrs.itemtype.ToString())) - { - List returnitems = new List(); - OSDArray itemarray = (OSDArray)response[mrs.itemtype.ToString()]; - for (int i = 0; i < itemarray.Count; i++) - { - OSDMap mapitem = (OSDMap)itemarray[i]; - mapItemReply mi = new mapItemReply(); - mi.x = (uint)mapitem["X"].AsInteger(); - mi.y = (uint)mapitem["Y"].AsInteger(); - mi.id = mapitem["ID"].AsUUID(); - mi.Extra = mapitem["Extra"].AsInteger(); - mi.Extra2 = mapitem["Extra2"].AsInteger(); - mi.name = mapitem["Name"].AsString(); - returnitems.Add(mi); - } - av.ControllingClient.SendMapItemReply(returnitems.ToArray(), mrs.itemtype, mrs.flags); - } - - // Service 7 (MAP_ITEM_LAND_FOR_SALE) - uint itemtype = 7; - - if (response.ContainsKey(itemtype.ToString())) - { - List returnitems = new List(); - OSDArray itemarray = (OSDArray)response[itemtype.ToString()]; - for (int i = 0; i < itemarray.Count; i++) - { - OSDMap mapitem = (OSDMap)itemarray[i]; - mapItemReply mi = new mapItemReply(); - mi.x = (uint)mapitem["X"].AsInteger(); - mi.y = (uint)mapitem["Y"].AsInteger(); - mi.id = mapitem["ID"].AsUUID(); - mi.Extra = mapitem["Extra"].AsInteger(); - mi.Extra2 = mapitem["Extra2"].AsInteger(); - mi.name = mapitem["Name"].AsString(); - returnitems.Add(mi); - } - av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, mrs.flags); - } - - // Service 1 (MAP_ITEM_TELEHUB) - itemtype = 1; - - if (response.ContainsKey(itemtype.ToString())) - { - List returnitems = new List(); - OSDArray itemarray = (OSDArray)response[itemtype.ToString()]; - for (int i = 0; i < itemarray.Count; i++) - { - OSDMap mapitem = (OSDMap)itemarray[i]; - mapItemReply mi = new mapItemReply(); - mi.x = (uint)mapitem["X"].AsInteger(); - mi.y = (uint)mapitem["Y"].AsInteger(); - mi.id = mapitem["ID"].AsUUID(); - mi.Extra = mapitem["Extra"].AsInteger(); - mi.Extra2 = mapitem["Extra2"].AsInteger(); - mi.name = mapitem["Name"].AsString(); - returnitems.Add(mi); - } - av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, mrs.flags); - } - } - } + queueEvent.Set(); + requests.Enqueue(state); } } @@ -700,8 +615,6 @@ namespace OpenSim.Region.CoreModules.World.WorldMap EnqueueMapItemRequest(st); } - private delegate OSDMap RequestMapItemsDelegate(UUID id, uint flags, - uint EstateID, bool godlike, uint itemtype, ulong regionhandle); /// /// Does the actual remote mapitem request /// This should be called from an asynchronous thread @@ -716,7 +629,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap /// passed in from packet /// Region we're looking up /// - private OSDMap RequestMapItemsAsync(UUID id, uint flags, + private void RequestMapItemsAsync(UUID id, uint flags, uint EstateID, bool godlike, uint itemtype, ulong regionhandle) { // m_log.DebugFormat("[WORLDMAP]: RequestMapItemsAsync; region handle: {0} {1}", regionhandle, itemtype); @@ -739,7 +652,10 @@ namespace OpenSim.Region.CoreModules.World.WorldMap } if (blacklisted) - return new OSDMap(); + { + Interlocked.Decrement(ref nAsyncRequests); + return; + } UUID requestID = UUID.Random(); lock (m_cachedRegionMapItemsAddress) @@ -747,6 +663,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap if (m_cachedRegionMapItemsAddress.ContainsKey(regionhandle)) httpserver = m_cachedRegionMapItemsAddress[regionhandle]; } + if (httpserver.Length == 0) { uint x = 0, y = 0; @@ -791,18 +708,10 @@ namespace OpenSim.Region.CoreModules.World.WorldMap // Can't find the http server if (httpserver.Length == 0 || blacklisted) - return new OSDMap(); - - MapRequestState mrs = new MapRequestState(); - mrs.agentID = id; - mrs.EstateID = EstateID; - mrs.flags = flags; - mrs.godlike = godlike; - mrs.itemtype=itemtype; - mrs.regionhandle = regionhandle; - - lock (m_openRequests) - m_openRequests.Add(requestID, mrs); + { + Interlocked.Decrement(ref nAsyncRequests); + return; + } WebRequest mapitemsrequest = null; try @@ -812,7 +721,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap catch (Exception e) { m_log.DebugFormat("[WORLD MAP]: Access to {0} failed with {1}", httpserver, e); - return new OSDMap(); + Interlocked.Decrement(ref nAsyncRequests); + return; } mapitemsrequest.Method = "POST"; @@ -826,6 +736,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap OSDMap responseMap = new OSDMap(); responseMap["requestID"] = OSD.FromUUID(requestID); +return; Stream os = null; try { // send the Post @@ -837,7 +748,6 @@ namespace OpenSim.Region.CoreModules.World.WorldMap catch (WebException ex) { m_log.WarnFormat("[WORLD MAP]: Bad send on GetMapItems {0}", ex.Message); - responseMap["connect"] = OSD.FromBoolean(false); lock (m_blacklistedurls) { if (!m_blacklistedurls.ContainsKey(httpserver)) @@ -846,13 +756,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap m_log.WarnFormat("[WORLD MAP]: Blacklisted {0}", httpserver); - return responseMap; + Interlocked.Decrement(ref nAsyncRequests); + return; } catch { m_log.DebugFormat("[WORLD MAP]: RequestMapItems failed for {0}", httpserver); - responseMap["connect"] = OSD.FromBoolean(false); - return responseMap; + Interlocked.Decrement(ref nAsyncRequests); + return; } finally { @@ -873,12 +784,12 @@ namespace OpenSim.Region.CoreModules.World.WorldMap } else { - return new OSDMap(); + Interlocked.Decrement(ref nAsyncRequests); + return; } } catch (WebException) { - responseMap["connect"] = OSD.FromBoolean(false); lock (m_blacklistedurls) { if (!m_blacklistedurls.ContainsKey(httpserver)) @@ -887,19 +798,20 @@ namespace OpenSim.Region.CoreModules.World.WorldMap m_log.WarnFormat("[WORLD MAP]: Blacklisted {0}", httpserver); - return responseMap; + Interlocked.Decrement(ref nAsyncRequests); + return; } catch { m_log.DebugFormat("[WORLD MAP]: RequestMapItems failed for {0}", httpserver); - responseMap["connect"] = OSD.FromBoolean(false); lock (m_blacklistedregions) { if (!m_blacklistedregions.ContainsKey(regionhandle)) m_blacklistedregions.Add(regionhandle, Environment.TickCount); } - return responseMap; + Interlocked.Decrement(ref nAsyncRequests); + return; } finally { @@ -918,14 +830,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap catch (Exception ex) { m_log.InfoFormat("[WORLD MAP]: exception on parse of RequestMapItems reply from {0}: {1}", httpserver, ex.Message); - responseMap["connect"] = OSD.FromBoolean(false); lock (m_blacklistedregions) { if (!m_blacklistedregions.ContainsKey(regionhandle)) m_blacklistedregions.Add(regionhandle, Environment.TickCount); } - return responseMap; + Interlocked.Decrement(ref nAsyncRequests); + return; } } @@ -939,7 +851,78 @@ namespace OpenSim.Region.CoreModules.World.WorldMap } } - return responseMap; + Interlocked.Decrement(ref nAsyncRequests); + + if (id != UUID.Zero) + { + ScenePresence av = null; + m_scene.TryGetScenePresence(id, out av); + if (av != null) + { + if (responseMap.ContainsKey(itemtype.ToString())) + { + List returnitems = new List(); + OSDArray itemarray = (OSDArray)responseMap[itemtype.ToString()]; + for (int i = 0; i < itemarray.Count; i++) + { + OSDMap mapitem = (OSDMap)itemarray[i]; + mapItemReply mi = new mapItemReply(); + mi.x = (uint)mapitem["X"].AsInteger(); + mi.y = (uint)mapitem["Y"].AsInteger(); + mi.id = mapitem["ID"].AsUUID(); + mi.Extra = mapitem["Extra"].AsInteger(); + mi.Extra2 = mapitem["Extra2"].AsInteger(); + mi.name = mapitem["Name"].AsString(); + returnitems.Add(mi); + } + av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, flags); + } + + // Service 7 (MAP_ITEM_LAND_FOR_SALE) + itemtype = 7; + + if (responseMap.ContainsKey(itemtype.ToString())) + { + List returnitems = new List(); + OSDArray itemarray = (OSDArray)responseMap[itemtype.ToString()]; + for (int i = 0; i < itemarray.Count; i++) + { + OSDMap mapitem = (OSDMap)itemarray[i]; + mapItemReply mi = new mapItemReply(); + mi.x = (uint)mapitem["X"].AsInteger(); + mi.y = (uint)mapitem["Y"].AsInteger(); + mi.id = mapitem["ID"].AsUUID(); + mi.Extra = mapitem["Extra"].AsInteger(); + mi.Extra2 = mapitem["Extra2"].AsInteger(); + mi.name = mapitem["Name"].AsString(); + returnitems.Add(mi); + } + av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, flags); + } + + // Service 1 (MAP_ITEM_TELEHUB) + itemtype = 1; + + if (responseMap.ContainsKey(itemtype.ToString())) + { + List returnitems = new List(); + OSDArray itemarray = (OSDArray)responseMap[itemtype.ToString()]; + for (int i = 0; i < itemarray.Count; i++) + { + OSDMap mapitem = (OSDMap)itemarray[i]; + mapItemReply mi = new mapItemReply(); + mi.x = (uint)mapitem["X"].AsInteger(); + mi.y = (uint)mapitem["Y"].AsInteger(); + mi.id = mapitem["ID"].AsUUID(); + mi.Extra = mapitem["Extra"].AsInteger(); + mi.Extra2 = mapitem["Extra2"].AsInteger(); + mi.name = mapitem["Name"].AsString(); + returnitems.Add(mi); + } + av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, flags); + } + } + } } /// @@ -951,53 +934,56 @@ namespace OpenSim.Region.CoreModules.World.WorldMap /// public virtual void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) { - //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 + Util.FireAndForget(x => { - 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) + //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 { - foreach (GridRegion r in regions) + 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) { - if ((r.RegionLocX == minX * (int)Constants.RegionSize) && - (r.RegionLocY == minY * (int)Constants.RegionSize)) + foreach (GridRegion r in regions) { - // found it => add it to response - MapBlockData block = new MapBlockData(); - MapBlockFromGridRegion(block, r, flag); - response.Add(block); - break; + 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; + } } } - } - 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 { - // 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); + // normal mapblock request. Use the provided values + GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag); } - // 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) @@ -1013,8 +999,15 @@ namespace OpenSim.Region.CoreModules.World.WorldMap MapBlockData block = new MapBlockData(); MapBlockFromGridRegion(block, r, flag); mapBlocks.Add(block); + if (mapBlocks.Count >= 20) + { + remoteClient.SendMapBlock(mapBlocks, flag & 0xffff); + mapBlocks.Clear(); + Thread.Sleep(1000); + } } - remoteClient.SendMapBlock(mapBlocks, flag & 0xffff); + if (mapBlocks.Count > 0) + remoteClient.SendMapBlock(mapBlocks, flag & 0xffff); return mapBlocks; } diff --git a/OpenSim/Server/Handlers/Map/MapGetServerConnector.cs b/OpenSim/Server/Handlers/Map/MapGetServerConnector.cs index fb85d1c..4502b7d 100644 --- a/OpenSim/Server/Handlers/Map/MapGetServerConnector.cs +++ b/OpenSim/Server/Handlers/Map/MapGetServerConnector.cs @@ -29,6 +29,7 @@ using System; using System.IO; using System.Net; using System.Reflection; +using System.Threading; using Nini.Config; using log4net; @@ -70,6 +71,8 @@ namespace OpenSim.Server.Handlers.MapImage class MapServerGetHandler : BaseStreamHandler { + public static ManualResetEvent ev = new ManualResetEvent(true); + // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private IMapImageService m_MapService; @@ -82,8 +85,13 @@ namespace OpenSim.Server.Handlers.MapImage public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { - byte[] result = new byte[0]; + ev.WaitOne(); + lock (ev) + { + ev.Reset(); + } + byte[] result = new byte[0]; string format = string.Empty; result = m_MapService.GetMapTile(path.Trim('/'), out format); if (result.Length > 0) @@ -100,6 +108,11 @@ namespace OpenSim.Server.Handlers.MapImage httpResponse.ContentType = "text/plain"; } + lock (ev) + { + ev.Set(); + } + return result; } -- cgit v1.1 From 73c5a6e66637b9f5f0d7dc3f4bf4c9818223b3e9 Mon Sep 17 00:00:00 2001 From: Melanie Date: Sun, 8 Jul 2012 07:42:40 +0200 Subject: Instead of sending 20 records in 2 packets, send just one as we intended in the first place. --- OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs index 721ac5c..88aacb9 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs @@ -999,7 +999,7 @@ return; MapBlockData block = new MapBlockData(); MapBlockFromGridRegion(block, r, flag); mapBlocks.Add(block); - if (mapBlocks.Count >= 20) + if (mapBlocks.Count >= 10) { remoteClient.SendMapBlock(mapBlocks, flag & 0xffff); mapBlocks.Clear(); -- cgit v1.1 From 1e4c65649736db82d0221b6b2aa57f7f45c7163c Mon Sep 17 00:00:00 2001 From: Melanie Date: Sun, 8 Jul 2012 10:44:53 +0200 Subject: Revamp map block sending to eliminate overload of the grid server connection and the sim's http client --- .../CoreModules/Hypergrid/HGWorldMapModule.cs | 4 +- .../CoreModules/World/WorldMap/WorldMapModule.cs | 298 ++++++++++++++------- 2 files changed, 204 insertions(+), 98 deletions(-) diff --git a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs index 0c60391..4f18b53 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 88aacb9..a226b78 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; - - m_scene.TryGetScenePresence(agentID, out avatarPresence); - - if (avatarPresence != null) - { - bool lookup = false; - - 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(); ; - - 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; - - cachedTime = Util.UnixTimeSinceEpoch(); - } - } - } + //if (m_scene.RegionInfo.RegionLocX >= 2048 || m_scene.RegionInfo.RegionLocY >= 2048) + //{ + // ScenePresence avatarPresence = null; + + // m_scene.TryGetScenePresence(agentID, out avatarPresence); + + // if (avatarPresence != null) + // { + // bool lookup = false; + + // 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(); ; + + // 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; + + // 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) + 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 + 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) { - // 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); + if (q.Count > 0) + thisRunData.Add(q.Dequeue()); + + total += q.Count; } - // The lower 16 bits are an unsigned int16 - remoteClient.SendMapBlock(response, flag & 0xffff); + + if (total == 0) + m_mapBlockRequestEvent.Reset(); } - else + + foreach (MapBlockRequestData req in thisRunData) { - // normal mapblock request. Use the provided values - GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag); + // 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 GetAndSendBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) + 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; + } } -- cgit v1.1