aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/Framework/EntityTransfer
diff options
context:
space:
mode:
authorRobert Adams2013-12-27 08:23:37 -0800
committerRobert Adams2013-12-27 08:23:37 -0800
commit01c0bbf1810d60ed5c4a31ede754fb11d843ed6a (patch)
tree5a567453bc0e7b2548a8e38cf1372c6176dcd06b /OpenSim/Region/CoreModules/Framework/EntityTransfer
parentvarregion: many more updates removing the constant RegionSize and replacing (diff)
downloadopensim-SC_OLD-01c0bbf1810d60ed5c4a31ede754fb11d843ed6a.zip
opensim-SC_OLD-01c0bbf1810d60ed5c4a31ede754fb11d843ed6a.tar.gz
opensim-SC_OLD-01c0bbf1810d60ed5c4a31ede754fb11d843ed6a.tar.bz2
opensim-SC_OLD-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/Framework/EntityTransfer')
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs207
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