diff options
author | Robert Adams | 2013-12-27 08:23:37 -0800 |
---|---|---|
committer | Robert Adams | 2013-12-27 08:23:37 -0800 |
commit | 01c0bbf1810d60ed5c4a31ede754fb11d843ed6a (patch) | |
tree | 5a567453bc0e7b2548a8e38cf1372c6176dcd06b /OpenSim/Region/CoreModules | |
parent | varregion: many more updates removing the constant RegionSize and replacing (diff) | |
download | opensim-SC-01c0bbf1810d60ed5c4a31ede754fb11d843ed6a.zip opensim-SC-01c0bbf1810d60ed5c4a31ede754fb11d843ed6a.tar.gz opensim-SC-01c0bbf1810d60ed5c4a31ede754fb11d843ed6a.tar.bz2 opensim-SC-01c0bbf1810d60ed5c4a31ede754fb11d843ed6a.tar.xz |
varregion: extract banned region logic into a class for cleanlyness.
Add 'not found' caching in EntityTransferModule.GetRegionContainingWorldLocation
so hitting borders and bad teleports do not continuiously hammer on the GridService.
Diffstat (limited to 'OpenSim/Region/CoreModules')
-rw-r--r-- | OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | 207 |
1 files changed, 174 insertions, 33 deletions
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index eb08257..f2850bb 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | |||
@@ -121,8 +121,53 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
121 | /// </summary> | 121 | /// </summary> |
122 | private EntityTransferStateMachine m_entityTransferStateMachine; | 122 | private EntityTransferStateMachine m_entityTransferStateMachine; |
123 | 123 | ||
124 | private ExpiringCache<UUID, ExpiringCache<ulong, DateTime>> m_bannedRegions = | 124 | // For performance, we keed a cached of banned regions so we don't keep going |
125 | new ExpiringCache<UUID, ExpiringCache<ulong, DateTime>>(); | 125 | // to the grid service. |
126 | private class BannedRegionCache | ||
127 | { | ||
128 | private ExpiringCache<UUID, ExpiringCache<ulong, DateTime>> m_bannedRegions = | ||
129 | new ExpiringCache<UUID, ExpiringCache<ulong, DateTime>>(); | ||
130 | ExpiringCache<ulong, DateTime> m_idCache; | ||
131 | DateTime m_banUntil; | ||
132 | public BannedRegionCache() | ||
133 | { | ||
134 | } | ||
135 | // Return 'true' if there is a valid ban entry for this agent in this region | ||
136 | public bool IfBanned(ulong pRegionHandle, UUID pAgentID) | ||
137 | { | ||
138 | bool ret = false; | ||
139 | if (m_bannedRegions.TryGetValue(pAgentID, out m_idCache)) | ||
140 | { | ||
141 | if (m_idCache.TryGetValue(pRegionHandle, out m_banUntil)) | ||
142 | { | ||
143 | if (DateTime.Now < m_banUntil) | ||
144 | { | ||
145 | ret = true; | ||
146 | } | ||
147 | } | ||
148 | } | ||
149 | return ret; | ||
150 | } | ||
151 | // Add this agent in this region as a banned person | ||
152 | public void Add(ulong pRegionHandle, UUID pAgentID) | ||
153 | { | ||
154 | if (!m_bannedRegions.TryGetValue(pAgentID, out m_idCache)) | ||
155 | { | ||
156 | m_idCache = new ExpiringCache<ulong, DateTime>(); | ||
157 | m_bannedRegions.Add(pAgentID, m_idCache, TimeSpan.FromSeconds(45)); | ||
158 | } | ||
159 | m_idCache.Add(pRegionHandle, DateTime.Now + TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15)); | ||
160 | } | ||
161 | // Remove the agent from the region's banned list | ||
162 | public void Remove(ulong pRegionHandle, UUID pAgentID) | ||
163 | { | ||
164 | if (m_bannedRegions.TryGetValue(pAgentID, out m_idCache)) | ||
165 | { | ||
166 | m_idCache.Remove(pRegionHandle); | ||
167 | } | ||
168 | } | ||
169 | } | ||
170 | private BannedRegionCache m_bannedRegionCache = new BannedRegionCache(); | ||
126 | 171 | ||
127 | private IEventQueue m_eqModule; | 172 | private IEventQueue m_eqModule; |
128 | private IRegionCombinerModule m_regionCombinerModule; | 173 | private IRegionCombinerModule m_regionCombinerModule; |
@@ -1393,7 +1438,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1393 | 1438 | ||
1394 | // Call the grid service to lookup the region containing the new position. | 1439 | // Call the grid service to lookup the region containing the new position. |
1395 | GridRegion neighbourRegion = GetRegionContainingWorldLocation(scene.GridService, scene.RegionInfo.ScopeID, | 1440 | GridRegion neighbourRegion = GetRegionContainingWorldLocation(scene.GridService, scene.RegionInfo.ScopeID, |
1396 | presenceWorldX, presenceWorldY); | 1441 | presenceWorldX, presenceWorldY, |
1442 | Math.Max(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY)); | ||
1397 | 1443 | ||
1398 | if (neighbourRegion != null) | 1444 | if (neighbourRegion != null) |
1399 | { | 1445 | { |
@@ -1402,24 +1448,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1402 | (float)(presenceWorldY - (double)neighbourRegion.RegionLocY), | 1448 | (float)(presenceWorldY - (double)neighbourRegion.RegionLocY), |
1403 | pos.Z); | 1449 | pos.Z); |
1404 | 1450 | ||
1405 | // Check if banned from destination region. | 1451 | if (m_bannedRegionCache.IfBanned(neighbourRegion.RegionHandle, agentID)) |
1406 | ExpiringCache<ulong, DateTime> r; | ||
1407 | DateTime banUntil; | ||
1408 | if (m_bannedRegions.TryGetValue(agentID, out r)) | ||
1409 | { | 1452 | { |
1410 | if (r.TryGetValue(neighbourRegion.RegionHandle, out banUntil)) | 1453 | neighbourRegion = null; |
1411 | { | ||
1412 | if (DateTime.Now < banUntil) | ||
1413 | { | ||
1414 | // If we're banned from the destination, we just can't go there. | ||
1415 | neighbourRegion = null; | ||
1416 | } | ||
1417 | r.Remove(neighbourRegion.RegionHandle); | ||
1418 | } | ||
1419 | } | 1454 | } |
1420 | else | 1455 | else |
1421 | { | 1456 | { |
1422 | r = null; | 1457 | // If not banned, make sure this agent is not in the list. |
1458 | m_bannedRegionCache.Remove(neighbourRegion.RegionHandle, agentID); | ||
1423 | } | 1459 | } |
1424 | 1460 | ||
1425 | // Check to see if we have access to the target region. | 1461 | // Check to see if we have access to the target region. |
@@ -1427,17 +1463,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1427 | if (neighbourRegion != null | 1463 | if (neighbourRegion != null |
1428 | && !scene.SimulationService.QueryAccess(neighbourRegion, agentID, newpos, out version, out reason)) | 1464 | && !scene.SimulationService.QueryAccess(neighbourRegion, agentID, newpos, out version, out reason)) |
1429 | { | 1465 | { |
1430 | if (r == null) | 1466 | // remember banned |
1431 | { | 1467 | m_bannedRegionCache.Add(neighbourRegion.RegionHandle, agentID); |
1432 | r = new ExpiringCache<ulong, DateTime>(); | ||
1433 | r.Add(neighbourRegion.RegionHandle, DateTime.Now + TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15)); | ||
1434 | |||
1435 | m_bannedRegions.Add(agentID, r, TimeSpan.FromSeconds(45)); | ||
1436 | } | ||
1437 | else | ||
1438 | { | ||
1439 | r.Add(neighbourRegion.RegionHandle, DateTime.Now + TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15)); | ||
1440 | } | ||
1441 | neighbourRegion = null; | 1468 | neighbourRegion = null; |
1442 | } | 1469 | } |
1443 | } | 1470 | } |
@@ -1993,14 +2020,119 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1993 | 0f); | 2020 | 0f); |
1994 | } | 2021 | } |
1995 | 2022 | ||
2023 | public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, double px, double py) | ||
2024 | { | ||
2025 | // Since we don't know how big the regions could be, we have to search a very large area | ||
2026 | // to find possible regions. | ||
2027 | return GetRegionContainingWorldLocation(pGridService, pScopeID, px, py, Constants.MaximumRegionSize); | ||
2028 | } | ||
2029 | |||
2030 | #region NotFoundLocationCache class | ||
2031 | // A collection of not found locations to make future lookups 'not found' lookups quick. | ||
2032 | // A simple expiring cache that keeps not found locations for some number of seconds. | ||
2033 | // A 'not found' location is presumed to be anywhere in the minimum sized region that | ||
2034 | // contains that point. A conservitive estimate. | ||
2035 | private class NotFoundLocationCache | ||
2036 | { | ||
2037 | private struct NotFoundLocation | ||
2038 | { | ||
2039 | public double minX, maxX, minY, maxY; | ||
2040 | public DateTime expireTime; | ||
2041 | } | ||
2042 | private List<NotFoundLocation> m_notFoundLocations = new List<NotFoundLocation>(); | ||
2043 | public NotFoundLocationCache() | ||
2044 | { | ||
2045 | } | ||
2046 | // Add an area to the lost of 'not found' places. The area is the snapped region | ||
2047 | // area around the added point. | ||
2048 | public void Add(double pX, double pY) | ||
2049 | { | ||
2050 | lock (m_notFoundLocations) | ||
2051 | { | ||
2052 | if (!LockedContains(pX, pY)) | ||
2053 | { | ||
2054 | NotFoundLocation nfl = new NotFoundLocation(); | ||
2055 | // A not found location is not found for at least a whole region sized area | ||
2056 | nfl.minX = pX - (pX % (double)Constants.RegionSize); | ||
2057 | nfl.minY = pY - (pY % (double)Constants.RegionSize); | ||
2058 | nfl.maxX = nfl.minX + (double)Constants.RegionSize; | ||
2059 | nfl.maxY = nfl.minY + (double)Constants.RegionSize; | ||
2060 | nfl.expireTime = DateTime.Now + TimeSpan.FromSeconds(30); | ||
2061 | m_notFoundLocations.Add(nfl); | ||
2062 | } | ||
2063 | } | ||
2064 | |||
2065 | } | ||
2066 | // Test to see of this point is in any of the 'not found' areas. | ||
2067 | // Return 'true' if the point is found inside the 'not found' areas. | ||
2068 | public bool Contains(double pX, double pY) | ||
2069 | { | ||
2070 | bool ret = false; | ||
2071 | lock (m_notFoundLocations) | ||
2072 | ret = LockedContains(pX, pY); | ||
2073 | return ret; | ||
2074 | } | ||
2075 | private bool LockedContains(double pX, double pY) | ||
2076 | { | ||
2077 | bool ret = false; | ||
2078 | this.DoExpiration(); | ||
2079 | foreach (NotFoundLocation nfl in m_notFoundLocations) | ||
2080 | { | ||
2081 | if (pX >= nfl.minX && pX < nfl.maxX && pY >= nfl.minY && pY < nfl.maxY) | ||
2082 | { | ||
2083 | ret = true; | ||
2084 | break; | ||
2085 | } | ||
2086 | } | ||
2087 | return ret; | ||
2088 | } | ||
2089 | private void DoExpiration() | ||
2090 | { | ||
2091 | List<NotFoundLocation> m_toRemove = null; | ||
2092 | DateTime now = DateTime.Now; | ||
2093 | foreach (NotFoundLocation nfl in m_notFoundLocations) | ||
2094 | { | ||
2095 | if (nfl.expireTime < now) | ||
2096 | { | ||
2097 | if (m_toRemove == null) | ||
2098 | m_toRemove = new List<NotFoundLocation>(); | ||
2099 | m_toRemove.Add(nfl); | ||
2100 | } | ||
2101 | } | ||
2102 | if (m_toRemove != null) | ||
2103 | { | ||
2104 | foreach (NotFoundLocation nfl in m_toRemove) | ||
2105 | m_notFoundLocations.Remove(nfl); | ||
2106 | m_toRemove.Clear(); | ||
2107 | } | ||
2108 | } | ||
2109 | } | ||
2110 | #endregion // NotFoundLocationCache class | ||
2111 | private NotFoundLocationCache m_notFoundLocationCache = new NotFoundLocationCache(); | ||
2112 | |||
1996 | // Given a world position (fractional meter coordinate), get the GridRegion info for | 2113 | // Given a world position (fractional meter coordinate), get the GridRegion info for |
1997 | // the region containing that point. | 2114 | // the region containing that point. |
1998 | // Someday this should be a method on GridService. | 2115 | // Someday this should be a method on GridService. |
2116 | // 'pSizeHint' is the size of the source region but since the destination point can be anywhere | ||
2117 | // the size of the target region is unknown thus the search area might have to be very large. | ||
1999 | // Return 'null' if no such region exists. | 2118 | // Return 'null' if no such region exists. |
2000 | public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, double px, double py) | 2119 | public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, |
2120 | double px, double py, uint pSizeHint) | ||
2001 | { | 2121 | { |
2002 | m_log.DebugFormat("{0} GetRegionContainingWorldLocation: call, XY=<{1},{2}>", LogHeader, px, py); | 2122 | m_log.DebugFormat("{0} GetRegionContainingWorldLocation: call, XY=<{1},{2}>", LogHeader, px, py); |
2003 | GridRegion ret = null; | 2123 | GridRegion ret = null; |
2124 | const double fudge = 2.0; | ||
2125 | |||
2126 | // One problem with this routine is negative results. That is, this can be called lots of times | ||
2127 | // for regions that don't exist. m_notFoundLocationCache remembers 'not found' results so they | ||
2128 | // will be quick 'not found's next time. | ||
2129 | // NotFoundLocationCache is an expiring cache so it will eventually forget about 'not found' and | ||
2130 | // thus re-ask the GridService about the location. | ||
2131 | if (m_notFoundLocationCache.Contains(px, py)) | ||
2132 | { | ||
2133 | m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found via cache. loc=<{1},{2}>", LogHeader, px, py); | ||
2134 | return null; | ||
2135 | } | ||
2004 | 2136 | ||
2005 | // As an optimization, since most regions will be legacy sized regions (256x256), first try to get | 2137 | // As an optimization, since most regions will be legacy sized regions (256x256), first try to get |
2006 | // the region at the appropriate legacy region location. | 2138 | // the region at the appropriate legacy region location. |
@@ -2018,13 +2150,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2018 | if (ret == null) | 2150 | if (ret == null) |
2019 | { | 2151 | { |
2020 | // If the simple lookup failed, search the larger area for a region that contains this point | 2152 | // If the simple lookup failed, search the larger area for a region that contains this point |
2021 | double range = (double)Constants.RegionSize * 2 + 2; | 2153 | double range = (double)pSizeHint + fudge; |
2022 | while (ret == null && range <= (Constants.MaximumRegionSize + Constants.RegionSize)) | 2154 | while (ret == null && range <= (Constants.MaximumRegionSize + Constants.RegionSize)) |
2023 | { | 2155 | { |
2024 | // Get from the grid service a list of regions that might contain this point | 2156 | // Get from the grid service a list of regions that might contain this point. |
2157 | // The region origin will be in the zero direction so only subtract the range. | ||
2025 | List<GridRegion> possibleRegions = pGridService.GetRegionRange(pScopeID, | 2158 | List<GridRegion> possibleRegions = pGridService.GetRegionRange(pScopeID, |
2026 | (int)(px - range), (int)(px + range), | 2159 | (int)(px - range), (int)(px), |
2027 | (int)(py - range), (int)(py + range)); | 2160 | (int)(py - range), (int)(py)); |
2028 | m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegions cnt={1}, range={2}", | 2161 | m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegions cnt={1}, range={2}", |
2029 | LogHeader, possibleRegions.Count, range); | 2162 | LogHeader, possibleRegions.Count, range); |
2030 | if (possibleRegions != null && possibleRegions.Count > 0) | 2163 | if (possibleRegions != null && possibleRegions.Count > 0) |
@@ -2048,6 +2181,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2048 | range *= 2; | 2181 | range *= 2; |
2049 | } | 2182 | } |
2050 | } | 2183 | } |
2184 | |||
2185 | if (ret == null) | ||
2186 | { | ||
2187 | // remember this location was not found so we can quickly not find it next time | ||
2188 | m_notFoundLocationCache.Add(px, py); | ||
2189 | m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found. Remembering loc=<{1},{2}>", LogHeader, px, py); | ||
2190 | } | ||
2191 | |||
2051 | return ret; | 2192 | return ret; |
2052 | } | 2193 | } |
2053 | 2194 | ||