aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid
diff options
context:
space:
mode:
authoronefang2019-05-19 21:24:15 +1000
committeronefang2019-05-19 21:24:15 +1000
commit5e4d6cab00cb29cd088ab7b62ab13aff103b64cb (patch)
treea9fbc62df9eb2d1d9ba2698d8552eae71eca20d8 /OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid
parentAdd a build script. (diff)
downloadopensim-SC_OLD-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.zip
opensim-SC_OLD-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.tar.gz
opensim-SC_OLD-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.tar.bz2
opensim-SC_OLD-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.tar.xz
Dump OpenSim 0.9.0.1 into it's own branch.
Diffstat (limited to 'OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid')
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs164
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionCache.cs102
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionInfoCache.cs965
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs154
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs6
5 files changed, 1070 insertions, 321 deletions
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs
index 1f782f5..d220568 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs
@@ -51,7 +51,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
51 private static string LogHeader = "[LOCAL GRID SERVICE CONNECTOR]"; 51 private static string LogHeader = "[LOCAL GRID SERVICE CONNECTOR]";
52 52
53 private IGridService m_GridService; 53 private IGridService m_GridService;
54 private Dictionary<UUID, RegionCache> m_LocalCache = new Dictionary<UUID, RegionCache>(); 54 private RegionInfoCache m_RegionInfoCache;
55 private HashSet<Scene> m_scenes = new HashSet<Scene>();
55 56
56 private bool m_Enabled; 57 private bool m_Enabled;
57 58
@@ -63,12 +64,18 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
63 public LocalGridServicesConnector(IConfigSource source) 64 public LocalGridServicesConnector(IConfigSource source)
64 { 65 {
65 m_log.DebugFormat("{0} LocalGridServicesConnector instantiated directly.", LogHeader); 66 m_log.DebugFormat("{0} LocalGridServicesConnector instantiated directly.", LogHeader);
66 InitialiseService(source); 67 InitialiseService(source, null);
68 }
69
70 public LocalGridServicesConnector(IConfigSource source, RegionInfoCache regionInfoCache)
71 {
72 m_log.DebugFormat("{0} LocalGridServicesConnector instantiated directly with cache.", LogHeader);
73 InitialiseService(source, regionInfoCache);
67 } 74 }
68 75
69 #region ISharedRegionModule 76 #region ISharedRegionModule
70 77
71 public Type ReplaceableInterface 78 public Type ReplaceableInterface
72 { 79 {
73 get { return null; } 80 get { return null; }
74 } 81 }
@@ -86,19 +93,24 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
86 string name = moduleConfig.GetString("GridServices", ""); 93 string name = moduleConfig.GetString("GridServices", "");
87 if (name == Name) 94 if (name == Name)
88 { 95 {
89 InitialiseService(source); 96 if(InitialiseService(source, null))
90 m_log.Info("[LOCAL GRID SERVICE CONNECTOR]: Local grid connector enabled"); 97 m_log.Info("[LOCAL GRID SERVICE CONNECTOR]: Local grid connector enabled");
91 } 98 }
92 } 99 }
93 } 100 }
94 101
95 private void InitialiseService(IConfigSource source) 102 private bool InitialiseService(IConfigSource source, RegionInfoCache ric)
96 { 103 {
104 if(ric == null && m_RegionInfoCache == null)
105 m_RegionInfoCache = new RegionInfoCache();
106 else
107 m_RegionInfoCache = ric;
108
97 IConfig config = source.Configs["GridService"]; 109 IConfig config = source.Configs["GridService"];
98 if (config == null) 110 if (config == null)
99 { 111 {
100 m_log.Error("[LOCAL GRID SERVICE CONNECTOR]: GridService missing from OpenSim.ini"); 112 m_log.Error("[LOCAL GRID SERVICE CONNECTOR]: GridService missing from OpenSim.ini");
101 return; 113 return false;
102 } 114 }
103 115
104 string serviceDll = config.GetString("LocalServiceModule", String.Empty); 116 string serviceDll = config.GetString("LocalServiceModule", String.Empty);
@@ -106,7 +118,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
106 if (serviceDll == String.Empty) 118 if (serviceDll == String.Empty)
107 { 119 {
108 m_log.Error("[LOCAL GRID SERVICE CONNECTOR]: No LocalServiceModule named in section GridService"); 120 m_log.Error("[LOCAL GRID SERVICE CONNECTOR]: No LocalServiceModule named in section GridService");
109 return; 121 return false;
110 } 122 }
111 123
112 Object[] args = new Object[] { source }; 124 Object[] args = new Object[] { source };
@@ -117,19 +129,15 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
117 if (m_GridService == null) 129 if (m_GridService == null)
118 { 130 {
119 m_log.Error("[LOCAL GRID SERVICE CONNECTOR]: Can't load grid service"); 131 m_log.Error("[LOCAL GRID SERVICE CONNECTOR]: Can't load grid service");
120 return; 132 return false;
121 } 133 }
122 134
123 m_Enabled = true; 135 m_Enabled = true;
136 return true;
124 } 137 }
125 138
126 public void PostInitialise() 139 public void PostInitialise()
127 { 140 {
128 // FIXME: We will still add this command even if we aren't enabled since RemoteGridServiceConnector
129 // will have instantiated us directly.
130 MainConsole.Instance.Commands.AddCommand("Regions", false, "show neighbours",
131 "show neighbours",
132 "Shows the local regions' neighbours", HandleShowNeighboursCommand);
133 } 141 }
134 142
135 public void Close() 143 public void Close()
@@ -141,15 +149,17 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
141 if (!m_Enabled) 149 if (!m_Enabled)
142 return; 150 return;
143 151
144 scene.RegisterModuleInterface<IGridService>(this); 152 lock(m_scenes)
145
146 lock (m_LocalCache)
147 { 153 {
148 if (m_LocalCache.ContainsKey(scene.RegionInfo.RegionID)) 154 if(!m_scenes.Contains(scene))
149 m_log.ErrorFormat("[LOCAL GRID SERVICE CONNECTOR]: simulator seems to have more than one region with the same UUID. Please correct this!"); 155 m_scenes.Add(scene);
150 else
151 m_LocalCache.Add(scene.RegionInfo.RegionID, new RegionCache(scene));
152 } 156 }
157 scene.RegisterModuleInterface<IGridService>(this);
158
159 GridRegion r = new GridRegion(scene.RegionInfo);
160 m_RegionInfoCache.CacheLocal(r);
161
162 scene.EventManager.OnRegionUp += OnRegionUp;
153 } 163 }
154 164
155 public void RemoveRegion(Scene scene) 165 public void RemoveRegion(Scene scene)
@@ -157,11 +167,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
157 if (!m_Enabled) 167 if (!m_Enabled)
158 return; 168 return;
159 169
160 lock (m_LocalCache) 170 lock(m_scenes)
161 { 171 {
162 m_LocalCache[scene.RegionInfo.RegionID].Clear(); 172 if(m_scenes.Contains(scene))
163 m_LocalCache.Remove(scene.RegionInfo.RegionID); 173 m_scenes.Remove(scene);
164 } 174 }
175
176 m_RegionInfoCache.Remove(scene.RegionInfo.ScopeID, scene.RegionInfo.RegionHandle);
177 scene.EventManager.OnRegionUp -= OnRegionUp;
165 } 178 }
166 179
167 public void RegionLoaded(Scene scene) 180 public void RegionLoaded(Scene scene)
@@ -172,6 +185,15 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
172 185
173 #region IGridService 186 #region IGridService
174 187
188 private void OnRegionUp(GridRegion region)
189 {
190 // This shouldn't happen
191 if (region == null)
192 return;
193
194 m_RegionInfoCache.CacheNearNeighbour(region.ScopeID, region);
195 }
196
175 public string RegisterRegion(UUID scopeID, GridRegion regionInfo) 197 public string RegisterRegion(UUID scopeID, GridRegion regionInfo)
176 { 198 {
177 return m_GridService.RegisterRegion(scopeID, regionInfo); 199 return m_GridService.RegisterRegion(scopeID, regionInfo);
@@ -184,12 +206,20 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
184 206
185 public List<GridRegion> GetNeighbours(UUID scopeID, UUID regionID) 207 public List<GridRegion> GetNeighbours(UUID scopeID, UUID regionID)
186 { 208 {
187 return m_GridService.GetNeighbours(scopeID, regionID); 209 return m_GridService.GetNeighbours(scopeID, regionID);
188 } 210 }
189 211
190 public GridRegion GetRegionByUUID(UUID scopeID, UUID regionID) 212 public GridRegion GetRegionByUUID(UUID scopeID, UUID regionID)
191 { 213 {
192 return m_GridService.GetRegionByUUID(scopeID, regionID); 214 bool inCache = false;
215 GridRegion rinfo = m_RegionInfoCache.Get(scopeID,regionID,out inCache);
216 if (inCache)
217 return rinfo;
218
219 rinfo = m_GridService.GetRegionByUUID(scopeID, regionID);
220 if(rinfo != null)
221 m_RegionInfoCache.Cache(scopeID, rinfo);
222 return rinfo;
193 } 223 }
194 224
195 // Get a region given its base coordinates. 225 // Get a region given its base coordinates.
@@ -197,59 +227,30 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
197 // be the base coordinate of the region. 227 // be the base coordinate of the region.
198 public GridRegion GetRegionByPosition(UUID scopeID, int x, int y) 228 public GridRegion GetRegionByPosition(UUID scopeID, int x, int y)
199 { 229 {
200 GridRegion region = null;
201 uint regionX = Util.WorldToRegionLoc((uint)x);
202 uint regionY = Util.WorldToRegionLoc((uint)y);
203 230
204 // Sanity check 231 bool inCache = false;
205 if ((Util.RegionToWorldLoc(regionX) != (uint)x) || (Util.RegionToWorldLoc(regionY) != (uint)y)) 232 GridRegion rinfo = m_RegionInfoCache.Get(scopeID, (uint)x, (uint)y, out inCache);
206 { 233 if (inCache)
207 m_log.WarnFormat("{0} GetRegionByPosition. Bad position requested: not the base of the region. Requested Pos=<{1},{2}>, Should Be=<{3},{4}>", 234 return rinfo;
208 LogHeader, x, y, Util.RegionToWorldLoc(regionX), Util.RegionToWorldLoc(regionY));
209 }
210
211 // First see if it's a neighbour, even if it isn't on this sim.
212 // Neighbour data is cached in memory, so this is fast
213
214 lock (m_LocalCache)
215 {
216 foreach (RegionCache rcache in m_LocalCache.Values)
217 {
218 region = rcache.GetRegionByPosition(x, y);
219 if (region != null)
220 {
221 m_log.DebugFormat("{0} GetRegionByPosition. Found region {1} in cache (of region {2}). Pos=<{3},{4}>",
222 LogHeader, region.RegionName, rcache.RegionName,
223 Util.WorldToRegionLoc((uint)region.RegionLocX), Util.WorldToRegionLoc((uint)region.RegionLocY));
224 break;
225 }
226 }
227 }
228 235
229 // Then try on this sim (may be a lookup in DB if this is using MySql). 236 // Then try on this sim (may be a lookup in DB if this is using MySql).
230 if (region == null) 237 rinfo = m_GridService.GetRegionByPosition(scopeID, x, y);
231 { 238 if(rinfo != null)
232 region = m_GridService.GetRegionByPosition(scopeID, x, y); 239 m_RegionInfoCache.Cache(scopeID, rinfo);
233 240 return rinfo;
234 if (region == null)
235 {
236 m_log.DebugFormat("{0} GetRegionByPosition. Region not found by grid service. Pos=<{1},{2}>",
237 LogHeader, regionX, regionY);
238 }
239 else
240 {
241 m_log.DebugFormat("{0} GetRegionByPosition. Got region {1} from grid service. Pos=<{2},{3}>",
242 LogHeader, region.RegionName,
243 Util.WorldToRegionLoc((uint)region.RegionLocX), Util.WorldToRegionLoc((uint)region.RegionLocY));
244 }
245 }
246
247 return region;
248 } 241 }
249 242
250 public GridRegion GetRegionByName(UUID scopeID, string regionName) 243 public GridRegion GetRegionByName(UUID scopeID, string regionName)
251 { 244 {
252 return m_GridService.GetRegionByName(scopeID, regionName); 245 bool inCache = false;
246 GridRegion rinfo = m_RegionInfoCache.Get(scopeID, regionName, out inCache);
247 if (inCache)
248 return rinfo;
249
250 rinfo = m_GridService.GetRegionByName(scopeID, regionName);
251 if(rinfo != null)
252 m_RegionInfoCache.Cache(scopeID, rinfo);
253 return rinfo;
253 } 254 }
254 255
255 public List<GridRegion> GetRegionsByName(UUID scopeID, string name, int maxNumber) 256 public List<GridRegion> GetRegionsByName(UUID scopeID, string name, int maxNumber)
@@ -281,7 +282,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
281 { 282 {
282 return m_GridService.GetHyperlinks(scopeID); 283 return m_GridService.GetHyperlinks(scopeID);
283 } 284 }
284 285
285 public int GetRegionFlags(UUID scopeID, UUID regionID) 286 public int GetRegionFlags(UUID scopeID, UUID regionID)
286 { 287 {
287 return m_GridService.GetRegionFlags(scopeID, regionID); 288 return m_GridService.GetRegionFlags(scopeID, regionID);
@@ -294,22 +295,5 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
294 295
295 #endregion 296 #endregion
296 297
297 public void HandleShowNeighboursCommand(string module, string[] cmdparams)
298 {
299 System.Text.StringBuilder caps = new System.Text.StringBuilder();
300
301 lock (m_LocalCache)
302 {
303 foreach (KeyValuePair<UUID, RegionCache> kvp in m_LocalCache)
304 {
305 caps.AppendFormat("*** Neighbours of {0} ({1}) ***\n", kvp.Value.RegionName, kvp.Key);
306 List<GridRegion> regions = kvp.Value.GetNeighbours();
307 foreach (GridRegion r in regions)
308 caps.AppendFormat(" {0} @ {1}-{2}\n", r.RegionName, Util.WorldToRegionLoc((uint)r.RegionLocX), Util.WorldToRegionLoc((uint)r.RegionLocY));
309 }
310 }
311
312 MainConsole.Instance.Output(caps.ToString());
313 }
314 } 298 }
315} 299}
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionCache.cs
deleted file mode 100644
index ae76288..0000000
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionCache.cs
+++ /dev/null
@@ -1,102 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31
32using OpenSim.Framework;
33using OpenSim.Region.Framework.Scenes;
34using OpenSim.Services.Interfaces;
35using GridRegion = OpenSim.Services.Interfaces.GridRegion;
36
37using OpenMetaverse;
38using log4net;
39
40namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
41{
42 public class RegionCache
43 {
44 private static readonly ILog m_log =
45 LogManager.GetLogger(
46 MethodBase.GetCurrentMethod().DeclaringType);
47
48 private Scene m_scene;
49 private Dictionary<ulong, GridRegion> m_neighbours = new Dictionary<ulong, GridRegion>();
50
51 public string RegionName
52 {
53 get { return m_scene.RegionInfo.RegionName; }
54 }
55
56 public RegionCache(Scene s)
57 {
58 m_scene = s;
59 m_scene.EventManager.OnRegionUp += OnRegionUp;
60 }
61
62 private void OnRegionUp(GridRegion otherRegion)
63 {
64 // This shouldn't happen
65 if (otherRegion == null)
66 return;
67
68 m_log.DebugFormat("[REGION CACHE]: (on region {0}) Region {1} is up @ {2}-{3}",
69 m_scene.RegionInfo.RegionName, otherRegion.RegionName, Util.WorldToRegionLoc((uint)otherRegion.RegionLocX), Util.WorldToRegionLoc((uint)otherRegion.RegionLocY));
70
71 m_neighbours[otherRegion.RegionHandle] = otherRegion;
72 }
73
74 public void Clear()
75 {
76 m_scene.EventManager.OnRegionUp -= OnRegionUp;
77 m_neighbours.Clear();
78 }
79
80 public List<GridRegion> GetNeighbours()
81 {
82 return new List<GridRegion>(m_neighbours.Values);
83 }
84
85 // Get a region given its base coordinates (in meters).
86 // NOTE: this is NOT 'get a region by some point in the region'. The coordinate MUST
87 // be the base coordinate of the region.
88 // The snapping is technically unnecessary but is harmless because regions are always
89 // multiples of the legacy region size (256).
90 public GridRegion GetRegionByPosition(int x, int y)
91 {
92 uint xsnap = (uint)(x / Constants.RegionSize) * Constants.RegionSize;
93 uint ysnap = (uint)(y / Constants.RegionSize) * Constants.RegionSize;
94 ulong handle = Util.RegionWorldLocToHandle(xsnap, ysnap);
95
96 if (m_neighbours.ContainsKey(handle))
97 return m_neighbours[handle];
98
99 return null;
100 }
101 }
102}
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionInfoCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionInfoCache.cs
index be8a9a2..f6fff58 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionInfoCache.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionInfoCache.cs
@@ -26,6 +26,8 @@
26 */ 26 */
27using System; 27using System;
28using System.Reflection; 28using System.Reflection;
29using System.Threading;
30using System.Runtime.InteropServices;
29using System.Collections.Generic; 31using System.Collections.Generic;
30using OpenSim.Framework; 32using OpenSim.Framework;
31using OpenSim.Services.Interfaces; 33using OpenSim.Services.Interfaces;
@@ -37,82 +39,68 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
37{ 39{
38 public class RegionInfoCache 40 public class RegionInfoCache
39 { 41 {
40 private const double CACHE_EXPIRATION_SECONDS = 300.0; // 5 minutes 42 private const float CACHE_EXPIRATION_SECONDS = 120; // 2 minutes opensim regions change a lot
41 43
42// private static readonly ILog m_log = 44// private static readonly ILog m_log =
43// LogManager.GetLogger( 45// LogManager.GetLogger(
44// MethodBase.GetCurrentMethod().DeclaringType); 46// MethodBase.GetCurrentMethod().DeclaringType);
45 47
46 internal struct ScopedRegionUUID 48 private static RegionsExpiringCache m_Cache;
49 private int numberInstances;
50
51 public RegionInfoCache()
47 { 52 {
48 public UUID m_scopeID; 53 if(m_Cache == null)
49 public UUID m_regionID; 54 m_Cache = new RegionsExpiringCache();
50 public ScopedRegionUUID(UUID scopeID, UUID regionID) 55 numberInstances++;
51 {
52 m_scopeID = scopeID;
53 m_regionID = regionID;
54 }
55 } 56 }
56 57
57 internal struct ScopedRegionName 58 public void Cache(GridRegion rinfo)
58 { 59 {
59 public UUID m_scopeID; 60 if (rinfo != null)
60 public string m_name; 61 this.Cache(rinfo.ScopeID, rinfo);
61 public ScopedRegionName(UUID scopeID, string name)
62 {
63 m_scopeID = scopeID;
64 m_name = name;
65 }
66 } 62 }
67 63
68 internal struct ScopedRegionPosition 64 public void Cache(UUID scopeID, GridRegion rinfo)
69 { 65 {
70 public UUID m_scopeID; 66 if (rinfo == null)
71 public ulong m_regionHandle; 67 return;
72 public ScopedRegionPosition(UUID scopeID, ulong handle)
73 {
74 m_scopeID = scopeID;
75 m_regionHandle = handle;
76 }
77 }
78 68
79 private ExpiringCache<ScopedRegionUUID, GridRegion> m_UUIDCache; 69 m_Cache.AddOrUpdate(scopeID, rinfo, CACHE_EXPIRATION_SECONDS);
80 private ExpiringCache<ScopedRegionName, ScopedRegionUUID> m_NameCache; 70 }
81 private ExpiringCache<ScopedRegionPosition, GridRegion> m_PositionCache;
82 71
83 public RegionInfoCache() 72 public void CacheLocal(GridRegion rinfo)
84 { 73 {
85 m_UUIDCache = new ExpiringCache<ScopedRegionUUID, GridRegion>(); 74 if (rinfo == null)
86 m_NameCache = new ExpiringCache<ScopedRegionName, ScopedRegionUUID>(); 75 return;
87 m_PositionCache = new ExpiringCache<ScopedRegionPosition, GridRegion>(); 76
77 m_Cache.AddOrUpdate(rinfo.ScopeID, rinfo, 1e7f);
88 } 78 }
89 79
90 public void Cache(GridRegion rinfo) 80 public void CacheNearNeighbour(UUID scopeID, GridRegion rinfo)
91 { 81 {
92 if (rinfo != null) 82 if (rinfo == null)
93 this.Cache(rinfo.ScopeID,rinfo.RegionID,rinfo); 83 return;
84
85 m_Cache.AddOrUpdate(scopeID, rinfo, CACHE_EXPIRATION_SECONDS);
94 } 86 }
95 87
96 public void Cache(UUID scopeID, UUID regionID, GridRegion rinfo) 88 public void Cache(UUID scopeID, GridRegion rinfo, float expireSeconds)
97 { 89 {
98 // for now, do not cache negative results; this is because
99 // we need to figure out how to handle regions coming online
100 // in a timely way
101 if (rinfo == null) 90 if (rinfo == null)
102 return; 91 return;
103
104 ScopedRegionUUID id = new ScopedRegionUUID(scopeID,regionID);
105
106 // Cache even null accounts
107 m_UUIDCache.AddOrUpdate(id, rinfo, CACHE_EXPIRATION_SECONDS);
108 if (rinfo != null)
109 {
110 ScopedRegionName name = new ScopedRegionName(scopeID,rinfo.RegionName);
111 m_NameCache.AddOrUpdate(name, id, CACHE_EXPIRATION_SECONDS);
112 92
113 ScopedRegionPosition pos = new ScopedRegionPosition(scopeID, rinfo.RegionHandle); 93 m_Cache.AddOrUpdate(scopeID, rinfo, expireSeconds);
114 m_PositionCache.AddOrUpdate(pos, rinfo, CACHE_EXPIRATION_SECONDS); 94 }
115 } 95
96 public void Remove(UUID scopeID, GridRegion rinfo)
97 {
98 m_Cache.Remove(scopeID, rinfo);
99 }
100
101 public void Remove(UUID scopeID, ulong regionHandle)
102 {
103 m_Cache.Remove(scopeID, regionHandle);
116 } 104 }
117 105
118 public GridRegion Get(UUID scopeID, UUID regionID, out bool inCache) 106 public GridRegion Get(UUID scopeID, UUID regionID, out bool inCache)
@@ -120,8 +108,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
120 inCache = false; 108 inCache = false;
121 109
122 GridRegion rinfo = null; 110 GridRegion rinfo = null;
123 ScopedRegionUUID id = new ScopedRegionUUID(scopeID,regionID); 111 if (m_Cache.TryGetValue(scopeID, regionID, out rinfo))
124 if (m_UUIDCache.TryGetValue(id, out rinfo))
125 { 112 {
126 inCache = true; 113 inCache = true;
127 return rinfo; 114 return rinfo;
@@ -135,8 +122,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
135 inCache = false; 122 inCache = false;
136 123
137 GridRegion rinfo = null; 124 GridRegion rinfo = null;
138 ScopedRegionPosition pos = new ScopedRegionPosition(scopeID, handle); 125 if (m_Cache.TryGetValue(scopeID, handle, out rinfo))
139 if (m_PositionCache.TryGetValue(pos, out rinfo))
140 { 126 {
141 inCache = true; 127 inCache = true;
142 return rinfo; 128 return rinfo;
@@ -145,25 +131,868 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
145 return null; 131 return null;
146 } 132 }
147 133
148
149 public GridRegion Get(UUID scopeID, string name, out bool inCache) 134 public GridRegion Get(UUID scopeID, string name, out bool inCache)
150 { 135 {
151 inCache = false; 136 inCache = false;
152 137
153 ScopedRegionName sname = new ScopedRegionName(scopeID,name); 138 GridRegion rinfo = null;
139 if (m_Cache.TryGetValue(scopeID, name, out rinfo))
140 {
141 inCache = true;
142 return rinfo;
143 }
144
145 return null;
146 }
147
148 public GridRegion Get(UUID scopeID, uint x, uint y, out bool inCache)
149 {
150 inCache = false;
151
152 GridRegion rinfo = null;
153 if (m_Cache.TryGetValue(scopeID, x, y, out rinfo))
154 {
155 inCache = true;
156 return rinfo;
157 }
158
159 return null;
160 }
161 }
162
163 // dont care about endianess
164 [StructLayout(LayoutKind.Explicit, Size = 8, Pack = 8)]
165 public class fastRegionHandle
166 {
167 [FieldOffset(0)] public ulong handle;
168 [FieldOffset(0)] public uint y;
169 [FieldOffset(4)] public uint x;
170
171 public fastRegionHandle(ulong h)
172 {
173 handle = h;
174 }
175
176 public fastRegionHandle(uint px, uint py)
177 {
178 y = py & 0xffffff00;
179 x = px & 0xffffff00;
180 }
181 // actually do care
182 public ulong toHandle()
183 {
184 if(BitConverter.IsLittleEndian)
185 return handle;
186 return (ulong) x << 32 | (ulong)y ;
187 }
188
189 public static bool operator ==(fastRegionHandle value1, fastRegionHandle value2)
190 {
191 return value1.handle == value2.handle;
192 }
193 public static bool operator !=(fastRegionHandle value1, fastRegionHandle value2)
194 {
195 return value1.handle != value2.handle;
196 }
197 public override int GetHashCode()
198 {
199 return handle.GetHashCode();
200 }
201 public override bool Equals(Object obj)
202 {
203 if(obj == null)
204 return false;
205 fastRegionHandle p = obj as fastRegionHandle;
206 return p.handle == handle;
207 }
208 }
209
210/*
211 [StructLayout(LayoutKind.Explicit, Size = 8, Pack = 8)]
212 public class regionHandle
213 {
214 [FieldOffset(0)] private ulong handle;
215 [FieldOffset(0)] public uint a;
216 [FieldOffset(4)] public uint b;
217
218 public regionHandle(ulong h)
219 {
220 handle = h;
221 }
222
223 public regionHandle(uint px, uint py)
224 {
225 if(BitConverter.IsLittleEndian)
226 {
227 a = py & 0xffffff00;
228 b = px & 0xffffff00;
229 }
230 else
231 {
232 a = px & 0xffffff00;
233 b = py & 0xffffff00;
234 }
235 }
236
237 public uint x
238 {
239 get
240 {
241 if(BitConverter.IsLittleEndian)
242 return b;
243 return a;
244 }
245 set
246 {
247 if(BitConverter.IsLittleEndian)
248 b = value & 0xffffff00;
249 else
250 a = value & 0xffffff00;
251 }
252 }
253
254 public uint y
255 {
256 get
257 {
258 if(BitConverter.IsLittleEndian)
259 return a;
260 return b;
261 }
262 set
263 {
264 if(BitConverter.IsLittleEndian)
265 a = value;
266 else
267 b = value;
268 }
269 }
270
271 public static bool operator ==(regionHandle value1, regionHandle value2)
272 {
273 return value1.handle == value2.handle;
274 }
275 public static bool operator !=(regionHandle value1, regionHandle value2)
276 {
277 return value1.handle != value2.handle;
278 }
279 public override int GetHashCode()
280 {
281 return handle.GetHashCode();
282 }
283 public override bool Equals(Object obj)
284 {
285 if(obj == null)
286 return false;
287 regionHandle p = obj as regionHandle;
288 return p.handle == handle;
289 }
290 }
291*/
292
293 public class RegionInfoForScope
294 {
295 public const ulong HANDLEMASK = 0xffffff00ffffff00ul;
296 public const ulong HANDLECOORDMASK = 0xffffff00ul;
297
298 private Dictionary<ulong, GridRegion> storage;
299 private Dictionary<ulong, DateTime> expires;
300 private Dictionary<string, ulong> byname;
301 private Dictionary<UUID, ulong> byuuid;
302 // includes handles to the inside of large regions
303 private Dictionary<ulong, ulong> innerHandles = new Dictionary<ulong, ulong>();
304
305 public RegionInfoForScope()
306 {
307 storage = new Dictionary<ulong, GridRegion>();
308 expires = new Dictionary<ulong, DateTime>();
309 byname = new Dictionary<string, ulong>();
310 byuuid = new Dictionary<UUID, ulong>();
311 }
312
313 public RegionInfoForScope(GridRegion region, DateTime expire)
314 {
315 storage = new Dictionary<ulong, GridRegion>();
316 expires = new Dictionary<ulong, DateTime>();
317 byname = new Dictionary<string, ulong>();
318 byuuid = new Dictionary<UUID, ulong>();
319
320 ulong handle = region.RegionHandle & HANDLEMASK;
321 storage[handle] = region;
322 expires[handle] = expire;
323 byname[region.RegionName] = handle;
324 byuuid[region.RegionID] = handle;
325 addToInner(region);
326 }
327
328 public void Add(GridRegion region, DateTime expire)
329 {
330 ulong handle = region.RegionHandle & HANDLEMASK;
331
332 if(storage != null && storage.ContainsKey(handle))
333 return;
334
335 if(storage == null)
336 storage = new Dictionary<ulong, GridRegion>();
337 if(expires == null)
338 expires = new Dictionary<ulong, DateTime>();
339 if(byname == null)
340 byname = new Dictionary<string, ulong>();
341 if(byuuid == null)
342 byuuid = new Dictionary<UUID, ulong>();
343
344 storage[handle] = region;
345 expires[handle] = expire;
346 byname[region.RegionName] = handle;
347 byuuid[region.RegionID] = handle;
348
349 addToInner(region);
350 }
351
352 public void AddUpdate(GridRegion region, DateTime expire)
353 {
354 if(storage == null)
355 storage = new Dictionary<ulong, GridRegion>();
356 if(expires == null)
357 expires = new Dictionary<ulong, DateTime>();
358 if(byname == null)
359 byname = new Dictionary<string, ulong>();
360 if(byuuid == null)
361 byuuid = new Dictionary<UUID, ulong>();
362
363 ulong handle = region.RegionHandle & HANDLEMASK;
154 364
155 ScopedRegionUUID id; 365 if(expires.ContainsKey(handle))
156 if (m_NameCache.TryGetValue(sname, out id))
157 { 366 {
158 GridRegion rinfo = null; 367 if(expires[handle] < expire)
159 if (m_UUIDCache.TryGetValue(id, out rinfo)) 368 expires[handle] = expire;
369 if(storage.ContainsKey(handle))
160 { 370 {
161 inCache = true; 371 GridRegion oldr = storage[handle];
162 return rinfo; 372 if (oldr.RegionSizeX != region.RegionSizeX
373 || oldr.RegionSizeY != region.RegionSizeY)
374 {
375 removeFromInner(oldr);
376 addToInner(region);
377 }
163 } 378 }
164 } 379 }
165 380 else
381 {
382 expires[handle] = expire;
383 addToInner(region);
384 }
385 storage[handle] = region;
386 byname[region.RegionName] = handle;
387 byuuid[region.RegionID] = handle;
388 }
389
390 public void Remove(GridRegion region)
391 {
392 if(region == null)
393 return;
394
395 if(byname != null)
396 byname.Remove(region.RegionName);
397 if(byuuid != null)
398 byuuid.Remove(region.RegionID);
399
400 ulong handle = region.RegionHandle & HANDLEMASK;
401 if(storage != null)
402 {
403 if(storage.ContainsKey(handle))
404 {
405 storage[handle] = null;
406 storage.Remove(handle);
407 }
408 }
409 removeFromInner(region);
410 if(expires != null)
411 {
412 expires.Remove(handle);
413 if(expires.Count == 0)
414 Clear();
415 }
416 }
417
418 public void Remove(ulong handle)
419 {
420 handle &= HANDLEMASK;
421
422 if(storage != null)
423 {
424 if(storage.ContainsKey(handle))
425 {
426 GridRegion r = storage[handle];
427 if(byname != null)
428 byname.Remove(r.RegionName);
429 if(byuuid != null)
430 byuuid.Remove(r.RegionID);
431 removeFromInner(r);
432 storage[handle] = null;
433 }
434 storage.Remove(handle);
435 }
436 if(expires != null)
437 {
438 expires.Remove(handle);
439 if(expires.Count == 0)
440 Clear();
441 }
442 }
443
444 public void Clear()
445 {
446 if(expires != null)
447 expires.Clear();
448 if(storage != null)
449 storage.Clear();
450 if(byname != null)
451 byname.Clear();
452 if(byuuid != null)
453 byuuid.Clear();
454 byname = null;
455 byuuid = null;
456 storage = null;
457 expires = null;
458 innerHandles.Clear();
459 }
460
461 public bool Contains(GridRegion region)
462 {
463 if(storage == null)
464 return false;
465 if(region == null)
466 return false;
467
468 ulong handle = region.RegionHandle & HANDLEMASK;
469 return storage.ContainsKey(handle);
470 }
471
472 public bool Contains(ulong handle)
473 {
474 if(storage == null)
475 return false;
476
477 handle &= HANDLEMASK;
478 return storage.ContainsKey(handle);
479 }
480
481 public GridRegion get(ulong handle)
482 {
483 if(storage == null)
484 return null;
485
486 handle &= HANDLEMASK;
487 if(storage.ContainsKey(handle))
488 return storage[handle];
489
490 if(!innerHandles.ContainsKey(handle))
491 return null;
492
493 ulong rhandle = innerHandles[handle];
494 if(storage.ContainsKey(rhandle))
495 return storage[rhandle];
496
166 return null; 497 return null;
167 } 498 }
499
500 public GridRegion get(string name)
501 {
502 if(byname == null || !byname.ContainsKey(name))
503 return null;
504
505 ulong handle = byname[name];
506 if(storage.ContainsKey(handle))
507 return storage[handle];
508 return null;
509 }
510
511 public GridRegion get(UUID id)
512 {
513 if(byuuid == null || !byuuid.ContainsKey(id))
514 return null;
515
516 ulong handle = byuuid[id];
517 if(storage.ContainsKey(handle))
518 return storage[handle];
519 return null;
520 }
521
522 public GridRegion get(uint x, uint y)
523 {
524 if(storage == null)
525 return null;
526
527 // look for a handle first this should find normal size regions
528 ulong handle = (ulong)x & HANDLECOORDMASK;
529 handle <<= 32;
530 handle |= ((ulong)y & HANDLECOORDMASK);
531
532 if(storage.ContainsKey(handle))
533 return storage[handle];
534
535 if(!innerHandles.ContainsKey(handle))
536 return null;
537
538 ulong rhandle = innerHandles[handle];
539 if(!storage.ContainsKey(rhandle))
540 return null;
541
542 GridRegion r = storage[rhandle];
543 if(r == null)
544 return null;
545
546 // extra check, possible redundant
547
548 int test = r.RegionLocX;
549 if(x < test)
550 return null;
551 test += r.RegionSizeX;
552 if(x >= test)
553 return null;
554 test = r.RegionLocY;
555 if (y < test)
556 return null;
557 test += r.RegionSizeY;
558 if (y < test)
559 return r;
560
561/*
562 // next do the harder work
563 foreach(KeyValuePair<ulong, GridRegion> kvp in storage)
564 {
565 GridRegion r = kvp.Value;
566 if(r == null) // ??
567 continue;
568
569 int test = r.RegionLocX;
570 if(x < test)
571 continue;
572 test += r.RegionSizeX;
573 if(x >= test)
574 continue;
575 test = r.RegionLocY;
576 if (y < test)
577 continue;
578 test += r.RegionSizeY;
579 if (y < test)
580 return r;
581 }
582*/
583 return null;
584 }
585
586 public int expire(DateTime now )
587 {
588 if(expires == null || expires.Count == 0)
589 return 0;
590
591 int expiresCount = expires.Count;
592 List<ulong> toexpire = new List<ulong>();
593
594 foreach(KeyValuePair<ulong, DateTime> kvp in expires)
595 {
596 if(kvp.Value < now)
597 toexpire.Add(kvp.Key);
598 }
599
600 int toexpireCount = toexpire.Count;
601 if(toexpireCount == 0)
602 return expiresCount;
603
604 if(toexpireCount == expiresCount)
605 {
606 Clear();
607 return 0;
608 }
609
610 if(storage != null)
611 {
612 ulong h;
613 for(int i = 0; i < toexpireCount; i++)
614 {
615 h = toexpire[i];
616 if(storage.ContainsKey(h))
617 {
618 GridRegion r = storage[h];
619 if(byname != null)
620 byname.Remove(r.RegionName);
621 if(byuuid != null)
622 byuuid.Remove(r.RegionID);
623 removeFromInner(r);
624
625 storage[h] = null;
626 storage.Remove(h);
627 }
628 if(expires != null)
629 expires.Remove(h);
630 }
631 }
632 else
633 {
634 Clear();
635 return 0;
636 }
637
638 expiresCount = expires.Count;
639 if(expiresCount == 0)
640 {
641 byname = null;
642 byuuid = null;
643 storage = null;
644 expires = null;
645 return 0;
646 }
647
648 return expiresCount;
649 }
650
651 public int Count()
652 {
653 if(byname == null)
654 return 0;
655 else
656 return byname.Count;
657 }
658
659 private void addToInner(GridRegion region)
660 {
661 int rsx = region.RegionSizeX;
662 int rsy = region.RegionSizeY;
663
664 if(rsx < 512 && rsy < 512)
665 return;
666
667 rsx >>= 8;
668 rsy >>= 8;
669
670 ulong handle = region.RegionHandle & HANDLEMASK;
671 fastRegionHandle fh = new fastRegionHandle(handle);
672 uint startY = fh.y;
673 for(int i = 0; i < rsx; i++)
674 {
675 for(int j = 0; j < rsy ; j++)
676 {
677 innerHandles[fh.toHandle()] = handle;
678 fh.y += 256;
679 }
680
681 fh.y = startY;
682 fh.x += 256;
683 }
684 }
685
686 private void removeFromInner(GridRegion region)
687 {
688 int rsx = region.RegionSizeX;
689 int rsy = region.RegionSizeY;
690
691 if(rsx < 512 && rsy < 512)
692 return;
693
694 rsx >>= 8;
695 rsy >>= 8;
696 ulong handle = region.RegionHandle & HANDLEMASK;
697 fastRegionHandle fh = new fastRegionHandle(handle);
698 uint startY = fh.y;
699 for(int i = 0; i < rsx; i++)
700 {
701 for(int j = 0; j < rsy ; j++)
702 {
703 innerHandles.Remove(fh.toHandle());
704 fh.y += 256;
705 }
706
707 fh.y = startY;
708 fh.x += 256;
709 }
710 }
711 }
712
713 public class RegionsExpiringCache
714 {
715 const double CACHE_PURGE_TIME = 60000; // milliseconds
716 const int MAX_LOCK_WAIT = 10000; // milliseconds
717
718 /// <summary>For thread safety</summary>
719 object syncRoot = new object();
720 /// <summary>For thread safety</summary>
721 object isPurging = new object();
722
723 Dictionary<UUID, RegionInfoForScope> InfobyScope = new Dictionary<UUID, RegionInfoForScope>();
724 private System.Timers.Timer timer = new System.Timers.Timer(CACHE_PURGE_TIME);
725
726 public RegionsExpiringCache()
727 {
728 timer.Elapsed += PurgeCache;
729 timer.Start();
730 }
731
732 public bool AddOrUpdate(UUID scope, GridRegion region, float expirationSeconds)
733 {
734 if(region == null)
735 return false;
736
737 if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
738 throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
739
740 try
741 {
742 DateTime expire = DateTime.UtcNow + TimeSpan.FromSeconds(expirationSeconds);
743
744 RegionInfoForScope ris = null;
745 if(!InfobyScope.TryGetValue(scope, out ris) || ris == null)
746 {
747 ris = new RegionInfoForScope(region, expire);
748 InfobyScope[scope] = ris;
749 }
750 else
751 ris.AddUpdate(region, expire);
752
753 return true;
754 }
755 finally { Monitor.Exit(syncRoot); }
756 }
757
758 public void Clear()
759 {
760 if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
761 throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
762 try
763 {
764 foreach(RegionInfoForScope ris in InfobyScope.Values)
765 ris.Clear();
766 InfobyScope.Clear();
767 }
768 finally { Monitor.Exit(syncRoot); }
769 }
770
771 public bool Contains(UUID scope, GridRegion region)
772 {
773 if(region == null)
774 return false;
775
776 if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
777 throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
778
779 try
780 {
781 RegionInfoForScope ris = null;
782 if(!InfobyScope.TryGetValue(scope, out ris) || ris == null)
783 return false;
784
785 return ris.Contains(region);
786 }
787 finally { Monitor.Exit(syncRoot); }
788 }
789
790 public bool Contains(UUID scope, ulong handle)
791 {
792 if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
793 throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
794
795 try
796 {
797 RegionInfoForScope ris = null;
798 if(!InfobyScope.TryGetValue(scope, out ris) || ris == null)
799 return false;
800
801 return ris.Contains(handle);
802 }
803 finally { Monitor.Exit(syncRoot); }
804 }
805
806 public int Count()
807 {
808 if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
809 throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
810
811 try
812 {
813 int count = 0;
814 foreach(RegionInfoForScope ris in InfobyScope.Values)
815 count += ris.Count();
816 return count;
817 }
818 finally { Monitor.Exit(syncRoot); }
819 }
820
821 public bool Remove(UUID scope, ulong handle)
822 {
823 if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
824 throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
825 try
826 {
827 RegionInfoForScope ris = null;
828 if(!InfobyScope.TryGetValue(scope, out ris) || ris == null)
829 return false;
830
831 ris.Remove(handle);
832 if(ris.Count() == 0)
833 InfobyScope.Remove(scope);
834 return true;
835 }
836 finally { Monitor.Exit(syncRoot); }
837 }
838
839 public bool Remove(UUID scope, GridRegion region)
840 {
841 if(region == null)
842 return false;
843
844 if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
845 throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
846 try
847 {
848 RegionInfoForScope ris = null;
849 if(!InfobyScope.TryGetValue(scope, out ris) || ris == null)
850 return false;
851
852 ris.Remove(region);
853 if(ris.Count() == 0)
854 InfobyScope.Remove(scope);
855 return true;
856 }
857 finally { Monitor.Exit(syncRoot); }
858 }
859
860 public bool TryGetValue(UUID scope, ulong handle, out GridRegion value)
861 {
862 if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
863 throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
864
865 value = null;
866 try
867 {
868 RegionInfoForScope ris = null;
869 if(!InfobyScope.TryGetValue(scope, out ris) || ris == null)
870 return false;
871 value = ris.get(handle);
872 }
873 finally { Monitor.Exit(syncRoot); }
874
875 return value != null;
876 }
877
878 public bool TryGetValue(UUID scope, string name, out GridRegion value)
879 {
880 if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
881 throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
882
883 value = null;
884 try
885 {
886 RegionInfoForScope ris = null;
887 if(!InfobyScope.TryGetValue(scope, out ris) || ris == null)
888 return false;
889 value = ris.get(name);
890 }
891 finally { Monitor.Exit(syncRoot); }
892
893 return value != null;
894 }
895
896 public bool TryGetValue(UUID scope, UUID id, out GridRegion value)
897 {
898 if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
899 throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
900
901 value = null;
902 try
903 {
904 RegionInfoForScope ris = null;
905 if(!InfobyScope.TryGetValue(scope, out ris) || ris == null)
906 return false;
907 value = ris.get(id);
908 }
909 finally { Monitor.Exit(syncRoot); }
910
911 return value != null;
912 }
913
914 // gets a region that contains world position (x,y)
915 // hopefull will not take ages
916 public bool TryGetValue(UUID scope, uint x, uint y, out GridRegion value)
917 {
918 if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
919 throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
920
921 value = null;
922 try
923 {
924 RegionInfoForScope ris = null;
925 if(!InfobyScope.TryGetValue(scope, out ris) || ris == null)
926 return false;
927
928 value = ris.get(x, y);
929 }
930 finally { Monitor.Exit(syncRoot); }
931
932 return value != null;
933 }
934
935 public bool Update(UUID scope, GridRegion region, double expirationSeconds)
936 {
937 if(region == null)
938 return false;
939
940 if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
941 throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
942
943 try
944 {
945 RegionInfoForScope ris = null;
946 if(!InfobyScope.TryGetValue(scope, out ris) || ris == null)
947 return false;
948
949 DateTime expire = DateTime.UtcNow + TimeSpan.FromSeconds(expirationSeconds);
950 ris.AddUpdate(region,expire);
951 return true;
952 }
953 finally { Monitor.Exit(syncRoot); }
954 }
955
956 /// <summary>
957 /// Purges expired objects from the cache. Called automatically by the purge timer.
958 /// </summary>
959 private void PurgeCache(object sender, System.Timers.ElapsedEventArgs e)
960 {
961 // Only let one thread purge at once - a buildup could cause a crash
962 // This could cause the purge to be delayed while there are lots of read/write ops
963 // happening on the cache
964 if (!Monitor.TryEnter(isPurging))
965 return;
966
967 DateTime now = DateTime.UtcNow;
968
969 try
970 {
971 // If we fail to acquire a lock on the synchronization root after MAX_LOCK_WAIT, skip this purge cycle
972 if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
973 return;
974 try
975 {
976 List<UUID> expiredscopes = new List<UUID>();
977
978 foreach (KeyValuePair<UUID, RegionInfoForScope> kvp in InfobyScope)
979 {
980 if (kvp.Value.expire(now) == 0)
981 expiredscopes.Add(kvp.Key);
982 }
983
984 if (expiredscopes.Count > 0)
985 {
986 foreach (UUID sid in expiredscopes)
987 {
988 InfobyScope[sid] = null;
989 InfobyScope.Remove(sid);
990 }
991 }
992 }
993 finally { Monitor.Exit(syncRoot); }
994 }
995 finally { Monitor.Exit(isPurging); }
996 }
168 } 997 }
169} 998}
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs
index 85073fc..ee17093 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs
@@ -52,12 +52,13 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
52 MethodBase.GetCurrentMethod().DeclaringType); 52 MethodBase.GetCurrentMethod().DeclaringType);
53 53
54 private bool m_Enabled = false; 54 private bool m_Enabled = false;
55 private string m_ThisGatekeeper = string.Empty;
55 56
56 private IGridService m_LocalGridService; 57 private IGridService m_LocalGridService;
57 private IGridService m_RemoteGridService; 58 private IGridService m_RemoteGridService;
58 59
59 private RegionInfoCache m_RegionInfoCache = new RegionInfoCache(); 60 private RegionInfoCache m_RegionInfoCache;
60 61
61 public RemoteGridServicesConnector() 62 public RemoteGridServicesConnector()
62 { 63 {
63 } 64 }
@@ -69,7 +70,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
69 70
70 #region ISharedRegionmodule 71 #region ISharedRegionmodule
71 72
72 public Type ReplaceableInterface 73 public Type ReplaceableInterface
73 { 74 {
74 get { return null; } 75 get { return null; }
75 } 76 }
@@ -87,38 +88,57 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
87 string name = moduleConfig.GetString("GridServices", ""); 88 string name = moduleConfig.GetString("GridServices", "");
88 if (name == Name) 89 if (name == Name)
89 { 90 {
90 InitialiseServices(source); 91 if(InitialiseServices(source))
91 m_Enabled = true; 92 {
92 m_log.Info("[REMOTE GRID CONNECTOR]: Remote grid enabled"); 93 m_Enabled = true;
94 m_log.Info("[REMOTE GRID CONNECTOR]: Remote grid enabled");
95 }
93 } 96 }
94 } 97 }
95 } 98 }
96 99
97 private void InitialiseServices(IConfigSource source) 100 private bool InitialiseServices(IConfigSource source)
98 { 101 {
99 IConfig gridConfig = source.Configs["GridService"]; 102 IConfig gridConfig = source.Configs["GridService"];
100 if (gridConfig == null) 103 if (gridConfig == null)
101 { 104 {
102 m_log.Error("[REMOTE GRID CONNECTOR]: GridService missing from OpenSim.ini"); 105 m_log.Error("[REMOTE GRID CONNECTOR]: GridService missing from OpenSim.ini");
103 return; 106 return false;
104 } 107 }
105 108
106 string networkConnector = gridConfig.GetString("NetworkConnector", string.Empty); 109 string networkConnector = gridConfig.GetString("NetworkConnector", string.Empty);
107 if (networkConnector == string.Empty) 110 if (networkConnector == string.Empty)
108 { 111 {
109 m_log.Error("[REMOTE GRID CONNECTOR]: Please specify a network connector under [GridService]"); 112 m_log.Error("[REMOTE GRID CONNECTOR]: Please specify a network connector under [GridService]");
110 return; 113 return false;
111 } 114 }
112 115
113 Object[] args = new Object[] { source }; 116 Object[] args = new Object[] { source };
114 m_RemoteGridService = ServerUtils.LoadPlugin<IGridService>(networkConnector, args); 117 m_RemoteGridService = ServerUtils.LoadPlugin<IGridService>(networkConnector, args);
115 118
116 m_LocalGridService = new LocalGridServicesConnector(source); 119 m_LocalGridService = new LocalGridServicesConnector(source, m_RegionInfoCache);
117 } 120 if (m_LocalGridService == null)
121 {
122 m_log.Error("[REMOTE GRID CONNECTOR]: failed to load local connector");
123 return false;
124 }
125
126 if(m_RegionInfoCache == null)
127 m_RegionInfoCache = new RegionInfoCache();
128
129 m_ThisGatekeeper = Util.GetConfigVarFromSections<string>(source, "GatekeeperURI",
130 new string[] { "Startup", "Hypergrid", "GridService" }, String.Empty);
131 // Legacy. Remove soon!
132 m_ThisGatekeeper = gridConfig.GetString("Gatekeeper", m_ThisGatekeeper);
133
134 Util.checkServiceURI(m_ThisGatekeeper, out m_ThisGatekeeper);
135
136 return true;
137 }
118 138
119 public void PostInitialise() 139 public void PostInitialise()
120 { 140 {
121 if (m_LocalGridService != null) 141 if (m_Enabled)
122 ((ISharedRegionModule)m_LocalGridService).PostInitialise(); 142 ((ISharedRegionModule)m_LocalGridService).PostInitialise();
123 } 143 }
124 144
@@ -129,15 +149,15 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
129 public void AddRegion(Scene scene) 149 public void AddRegion(Scene scene)
130 { 150 {
131 if (m_Enabled) 151 if (m_Enabled)
152 {
132 scene.RegisterModuleInterface<IGridService>(this); 153 scene.RegisterModuleInterface<IGridService>(this);
133
134 if (m_LocalGridService != null)
135 ((ISharedRegionModule)m_LocalGridService).AddRegion(scene); 154 ((ISharedRegionModule)m_LocalGridService).AddRegion(scene);
155 }
136 } 156 }
137 157
138 public void RemoveRegion(Scene scene) 158 public void RemoveRegion(Scene scene)
139 { 159 {
140 if (m_LocalGridService != null) 160 if (m_Enabled)
141 ((ISharedRegionModule)m_LocalGridService).RemoveRegion(scene); 161 ((ISharedRegionModule)m_LocalGridService).RemoveRegion(scene);
142 } 162 }
143 163
@@ -174,16 +194,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
174 194
175 public GridRegion GetRegionByUUID(UUID scopeID, UUID regionID) 195 public GridRegion GetRegionByUUID(UUID scopeID, UUID regionID)
176 { 196 {
177 bool inCache = false; 197 GridRegion rinfo = m_LocalGridService.GetRegionByUUID(scopeID, regionID);
178 GridRegion rinfo = m_RegionInfoCache.Get(scopeID,regionID,out inCache); 198 if (rinfo != null)
179 if (inCache)
180 return rinfo; 199 return rinfo;
181
182 rinfo = m_LocalGridService.GetRegionByUUID(scopeID, regionID);
183 if (rinfo == null)
184 rinfo = m_RemoteGridService.GetRegionByUUID(scopeID, regionID);
185 200
186 m_RegionInfoCache.Cache(scopeID,regionID,rinfo); 201 rinfo = m_RemoteGridService.GetRegionByUUID(scopeID, regionID);
202 m_RegionInfoCache.Cache(scopeID, rinfo);
187 return rinfo; 203 return rinfo;
188 } 204 }
189 205
@@ -193,51 +209,56 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
193 // The coordinates are world coords (meters), NOT region units. 209 // The coordinates are world coords (meters), NOT region units.
194 public GridRegion GetRegionByPosition(UUID scopeID, int x, int y) 210 public GridRegion GetRegionByPosition(UUID scopeID, int x, int y)
195 { 211 {
196 ulong regionHandle = Util.RegionWorldLocToHandle((uint)x, (uint)y); 212 GridRegion rinfo = m_LocalGridService.GetRegionByPosition(scopeID, x, y);
197 uint regionX = Util.WorldToRegionLoc((uint)x); 213 if (rinfo != null)
198 uint regionY = Util.WorldToRegionLoc((uint)y);
199
200 // Sanity check
201 if ((Util.RegionToWorldLoc(regionX) != (uint)x) || (Util.RegionToWorldLoc(regionY) != (uint)y))
202 { 214 {
203 m_log.WarnFormat("[REMOTE GRID CONNECTOR]: GetRegionByPosition. Bad position requested: not the base of the region. Requested Pos=<{0},{1}>, Should Be=<{2},{3}>", 215// m_log.DebugFormat("[REMOTE GRID CONNECTOR]: GetRegionByPosition. Found region {0} on local. Pos=<{1},{2}>, RegionHandle={3}",
204 x, y, Util.RegionToWorldLoc(regionX), Util.RegionToWorldLoc(regionY)); 216// rinfo.RegionName, rinfo.RegionCoordX, rinfo.RegionCoordY, rinfo.RegionHandle);
205 }
206
207 bool inCache = false;
208 GridRegion rinfo = m_RegionInfoCache.Get(scopeID, regionHandle, out inCache);
209 if (inCache)
210 {
211 //m_log.DebugFormat("[REMOTE GRID CONNECTOR]: GetRegionByPosition. Found region {0} in cache. Pos=<{1},{2}>, RegionHandle={3}",
212 // (rinfo == null) ? "<missing>" : rinfo.RegionName, regionX, regionY, (rinfo == null) ? regionHandle : rinfo.RegionHandle);
213 return rinfo; 217 return rinfo;
214 } 218 }
215 219
216 rinfo = m_LocalGridService.GetRegionByPosition(scopeID, x, y); 220 rinfo = m_RemoteGridService.GetRegionByPosition(scopeID, x, y);
217 if (rinfo == null)
218 rinfo = m_RemoteGridService.GetRegionByPosition(scopeID, x, y);
219 221
220 m_RegionInfoCache.Cache(rinfo); 222 if (rinfo == null)
221 223 {
222 //m_log.DebugFormat("[REMOTE GRID CONNECTOR]: GetRegionByPosition. Added region {0} to the cache. Pos=<{1},{2}>, RegionHandle={3}", 224// uint regionX = Util.WorldToRegionLoc((uint)x);
223 // (rinfo == null) ? "<missing>" : rinfo.RegionName, regionX, regionY, (rinfo == null) ? regionHandle : rinfo.RegionHandle); 225// uint regionY = Util.WorldToRegionLoc((uint)y);
226// m_log.WarnFormat("[REMOTE GRID CONNECTOR]: Requested region {0}-{1} not found", regionX, regionY);
227 }
228 else
229 {
230 m_RegionInfoCache.Cache(scopeID, rinfo);
224 231
232// m_log.DebugFormat("[REMOTE GRID CONNECTOR]: GetRegionByPosition. Added region {0} to the cache. Pos=<{1},{2}>, RegionHandle={3}",
233// rinfo.RegionName, rinfo.RegionCoordX, rinfo.RegionCoordY, rinfo.RegionHandle);
234 }
225 return rinfo; 235 return rinfo;
226 } 236 }
227 237
228 public GridRegion GetRegionByName(UUID scopeID, string regionName) 238 public GridRegion GetRegionByName(UUID scopeID, string name)
229 { 239 {
230 bool inCache = false; 240 GridRegion rinfo = m_LocalGridService.GetRegionByName(scopeID, name);
231 GridRegion rinfo = m_RegionInfoCache.Get(scopeID,regionName, out inCache); 241 if (rinfo != null)
232 if (inCache)
233 return rinfo; 242 return rinfo;
234
235 rinfo = m_LocalGridService.GetRegionByName(scopeID, regionName);
236 if (rinfo == null)
237 rinfo = m_RemoteGridService.GetRegionByName(scopeID, regionName);
238 243
239 // can't cache negative results for name lookups 244 // HG urls should not get here, strip them
240 m_RegionInfoCache.Cache(rinfo); 245 // side effect is that local regions with same name as HG may also be found
246 // this mb good or bad
247 string regionName = name;
248 if(name.Contains("."))
249 {
250 if(string.IsNullOrWhiteSpace(m_ThisGatekeeper))
251 return rinfo; // no HG
252
253 string regionURI = "";
254 if(!Util.buildHGRegionURI(name, out regionURI, out regionName) || string.IsNullOrWhiteSpace(regionName))
255 return rinfo; // invalid
256 if(m_ThisGatekeeper != regionURI)
257 return rinfo; // not local grid
258 }
259
260 rinfo = m_RemoteGridService.GetRegionByName(scopeID, regionName);
261 m_RegionInfoCache.Cache(scopeID, rinfo);
241 return rinfo; 262 return rinfo;
242 } 263 }
243 264
@@ -245,7 +266,24 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
245 { 266 {
246 List<GridRegion> rinfo = m_LocalGridService.GetRegionsByName(scopeID, name, maxNumber); 267 List<GridRegion> rinfo = m_LocalGridService.GetRegionsByName(scopeID, name, maxNumber);
247 //m_log.DebugFormat("[REMOTE GRID CONNECTOR]: Local GetRegionsByName {0} found {1} regions", name, rinfo.Count); 268 //m_log.DebugFormat("[REMOTE GRID CONNECTOR]: Local GetRegionsByName {0} found {1} regions", name, rinfo.Count);
248 List<GridRegion> grinfo = m_RemoteGridService.GetRegionsByName(scopeID, name, maxNumber); 269
270 // HG urls should not get here, strip them
271 // side effect is that local regions with same name as HG may also be found
272 // this mb good or bad
273 string regionName = name;
274 if(name.Contains("."))
275 {
276 if(string.IsNullOrWhiteSpace(m_ThisGatekeeper))
277 return rinfo; // no HG
278
279 string regionURI = "";
280 if(!Util.buildHGRegionURI(name, out regionURI, out regionName) || string.IsNullOrWhiteSpace(regionName))
281 return rinfo; // invalid
282 if(m_ThisGatekeeper != regionURI)
283 return rinfo; // not local grid
284 }
285
286 List<GridRegion> grinfo = m_RemoteGridService.GetRegionsByName(scopeID, regionName, maxNumber);
249 287
250 if (grinfo != null) 288 if (grinfo != null)
251 { 289 {
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs
index 25ae689..1378368 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs
@@ -64,7 +64,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
64 config.Configs["GridService"].Set("Region_Test_Region_3", "FallbackRegion"); 64 config.Configs["GridService"].Set("Region_Test_Region_3", "FallbackRegion");
65 config.Configs["GridService"].Set("Region_Other_Region_4", "FallbackRegion"); 65 config.Configs["GridService"].Set("Region_Other_Region_4", "FallbackRegion");
66 66
67 m_LocalConnector = new LocalGridServicesConnector(config); 67 m_LocalConnector = new LocalGridServicesConnector(config, null);
68 } 68 }
69 69
70 /// <summary> 70 /// <summary>
@@ -88,7 +88,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
88 Scene s = new Scene(new RegionInfo()); 88 Scene s = new Scene(new RegionInfo());
89 s.RegionInfo.RegionID = r1.RegionID; 89 s.RegionInfo.RegionID = r1.RegionID;
90 m_LocalConnector.AddRegion(s); 90 m_LocalConnector.AddRegion(s);
91 91
92 GridRegion r2 = new GridRegion(); 92 GridRegion r2 = new GridRegion();
93 r2.RegionName = "Test Region 2"; 93 r2.RegionName = "Test Region 2";
94 r2.RegionID = new UUID(2); 94 r2.RegionID = new UUID(2);
@@ -198,4 +198,4 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
198 Assert.That(results.Count, Is.EqualTo(0), "Retrieved linked regions collection is not the number expected"); 198 Assert.That(results.Count, Is.EqualTo(0), "Retrieved linked regions collection is not the number expected");
199 } 199 }
200 } 200 }
201} \ No newline at end of file 201}