aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules
diff options
context:
space:
mode:
authorUbitUmarov2016-07-30 01:44:33 +0100
committerUbitUmarov2016-07-30 01:44:33 +0100
commit55b2d010281f989beeb0088bde95245bb1f99054 (patch)
treec00ed28b158efc4720221822abbcec0e108a1c6c /OpenSim/Region/CoreModules
parent fix llEdgeOfWorld() for var regions (someone needs to test this better (diff)
downloadopensim-SC-55b2d010281f989beeb0088bde95245bb1f99054.zip
opensim-SC-55b2d010281f989beeb0088bde95245bb1f99054.tar.gz
opensim-SC-55b2d010281f989beeb0088bde95245bb1f99054.tar.bz2
opensim-SC-55b2d010281f989beeb0088bde95245bb1f99054.tar.xz
in RegionInfoCache, replace lib omv ExpireCaches by a single dedicated one
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionInfoCache.cs506
1 files changed, 441 insertions, 65 deletions
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionInfoCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionInfoCache.cs
index be8a9a2..4dc9033 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionInfoCache.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionInfoCache.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27using System; 27using System;
28using System.Reflection; 28using System.Reflection;
29using System.Threading;
29using System.Collections.Generic; 30using System.Collections.Generic;
30using OpenSim.Framework; 31using OpenSim.Framework;
31using OpenSim.Services.Interfaces; 32using OpenSim.Services.Interfaces;
@@ -37,54 +38,17 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
37{ 38{
38 public class RegionInfoCache 39 public class RegionInfoCache
39 { 40 {
40 private const double CACHE_EXPIRATION_SECONDS = 300.0; // 5 minutes 41 private const double CACHE_EXPIRATION_SECONDS = 120; // 2 minutes opensim regions change a lot
41 42
42// private static readonly ILog m_log = 43// private static readonly ILog m_log =
43// LogManager.GetLogger( 44// LogManager.GetLogger(
44// MethodBase.GetCurrentMethod().DeclaringType); 45// MethodBase.GetCurrentMethod().DeclaringType);
45 46
46 internal struct ScopedRegionUUID 47 private RegionsExpiringCache m_Cache;
47 {
48 public UUID m_scopeID;
49 public UUID m_regionID;
50 public ScopedRegionUUID(UUID scopeID, UUID regionID)
51 {
52 m_scopeID = scopeID;
53 m_regionID = regionID;
54 }
55 }
56
57 internal struct ScopedRegionName
58 {
59 public UUID m_scopeID;
60 public string m_name;
61 public ScopedRegionName(UUID scopeID, string name)
62 {
63 m_scopeID = scopeID;
64 m_name = name;
65 }
66 }
67
68 internal struct ScopedRegionPosition
69 {
70 public UUID m_scopeID;
71 public ulong m_regionHandle;
72 public ScopedRegionPosition(UUID scopeID, ulong handle)
73 {
74 m_scopeID = scopeID;
75 m_regionHandle = handle;
76 }
77 }
78
79 private ExpiringCache<ScopedRegionUUID, GridRegion> m_UUIDCache;
80 private ExpiringCache<ScopedRegionName, ScopedRegionUUID> m_NameCache;
81 private ExpiringCache<ScopedRegionPosition, GridRegion> m_PositionCache;
82 48
83 public RegionInfoCache() 49 public RegionInfoCache()
84 { 50 {
85 m_UUIDCache = new ExpiringCache<ScopedRegionUUID, GridRegion>(); 51 m_Cache = new RegionsExpiringCache();
86 m_NameCache = new ExpiringCache<ScopedRegionName, ScopedRegionUUID>();
87 m_PositionCache = new ExpiringCache<ScopedRegionPosition, GridRegion>();
88 } 52 }
89 53
90 public void Cache(GridRegion rinfo) 54 public void Cache(GridRegion rinfo)
@@ -101,18 +65,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
101 if (rinfo == null) 65 if (rinfo == null)
102 return; 66 return;
103 67
104 ScopedRegionUUID id = new ScopedRegionUUID(scopeID,regionID); 68 m_Cache.AddOrUpdate(scopeID, rinfo, CACHE_EXPIRATION_SECONDS);
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
113 ScopedRegionPosition pos = new ScopedRegionPosition(scopeID, rinfo.RegionHandle);
114 m_PositionCache.AddOrUpdate(pos, rinfo, CACHE_EXPIRATION_SECONDS);
115 }
116 } 69 }
117 70
118 public GridRegion Get(UUID scopeID, UUID regionID, out bool inCache) 71 public GridRegion Get(UUID scopeID, UUID regionID, out bool inCache)
@@ -120,8 +73,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
120 inCache = false; 73 inCache = false;
121 74
122 GridRegion rinfo = null; 75 GridRegion rinfo = null;
123 ScopedRegionUUID id = new ScopedRegionUUID(scopeID,regionID); 76 if (m_Cache.TryGetValue(scopeID, regionID, out rinfo))
124 if (m_UUIDCache.TryGetValue(id, out rinfo))
125 { 77 {
126 inCache = true; 78 inCache = true;
127 return rinfo; 79 return rinfo;
@@ -135,8 +87,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
135 inCache = false; 87 inCache = false;
136 88
137 GridRegion rinfo = null; 89 GridRegion rinfo = null;
138 ScopedRegionPosition pos = new ScopedRegionPosition(scopeID, handle); 90 if (m_Cache.TryGetValue(scopeID, handle, out rinfo))
139 if (m_PositionCache.TryGetValue(pos, out rinfo))
140 { 91 {
141 inCache = true; 92 inCache = true;
142 return rinfo; 93 return rinfo;
@@ -145,25 +96,450 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
145 return null; 96 return null;
146 } 97 }
147 98
148
149 public GridRegion Get(UUID scopeID, string name, out bool inCache) 99 public GridRegion Get(UUID scopeID, string name, out bool inCache)
150 { 100 {
151 inCache = false; 101 inCache = false;
152 102
153 ScopedRegionName sname = new ScopedRegionName(scopeID,name); 103 GridRegion rinfo = null;
104 if (m_Cache.TryGetValue(scopeID, name, out rinfo))
105 {
106 inCache = true;
107 return rinfo;
108 }
109
110 return null;
111 }
112 }
113
114
115 // following code partialy adapted from lib OpenMetaverse
116 public class RegionKey : IComparable<RegionKey>
117 {
118 private UUID m_scopeID;
119 private UUID m_RegionID;
120 private DateTime m_expirationDate;
121
122 public RegionKey(UUID scopeID, UUID id)
123 {
124 m_scopeID = scopeID;
125 m_RegionID = id;
126 }
127
128 public UUID ScopeID
129 {
130 get { return m_scopeID; }
131 }
132 public DateTime ExpirationDate
133 {
134 get { return m_expirationDate; }
135 set { m_expirationDate = value; }
136 }
137
138 public int GetHaskCode()
139 {
140 int hash = m_scopeID.GetHashCode();
141 hash += hash * 23 + m_RegionID.GetHashCode();
142 return hash;
143 }
144
145 public int CompareTo(RegionKey other)
146 {
147 return GetHashCode().CompareTo(other.GetHashCode());
148 }
149 }
150
151 public class RegionInfoByScope
152 {
153 private Dictionary<string, RegionKey> byname;
154 private Dictionary<ulong, RegionKey> byhandle;
155
156 public RegionInfoByScope()
157 {
158 byname = new Dictionary<string, RegionKey>();
159 byhandle = new Dictionary<ulong, RegionKey>();
160 }
161
162 public RegionInfoByScope(GridRegion region, RegionKey key)
163 {
164 byname = new Dictionary<string, RegionKey>();
165 byhandle = new Dictionary<ulong, RegionKey>();
166
167 byname[region.RegionName] = key;
168 byhandle[region.RegionHandle] = key;
169 }
154 170
155 ScopedRegionUUID id; 171 public void AddRegion(GridRegion region, RegionKey key)
156 if (m_NameCache.TryGetValue(sname, out id)) 172 {
173 if(byname == null)
174 byname = new Dictionary<string, RegionKey>();
175 if(byhandle == null)
176 byhandle = new Dictionary<ulong, RegionKey>();
177
178 byname[region.RegionName] = key;
179 byhandle[region.RegionHandle] = key;
180 }
181
182 public void RemoveRegion(GridRegion region)
183 {
184 if(byname != null)
185 byname.Remove(region.RegionName);
186 if(byhandle != null)
187 byhandle.Remove(region.RegionHandle);
188 }
189
190 public void Clear()
191 {
192 if(byname != null)
193 byname.Clear();
194 if(byhandle != null)
195 byhandle.Clear();
196 byname = null;
197 byhandle = null;
198 }
199
200 public RegionKey get(string name)
201 {
202 if(byname == null || !byname.ContainsKey(name))
203 return null;
204 return byname[name];
205 }
206
207 public RegionKey get(ulong handle)
208 {
209 if(byhandle == null || !byhandle.ContainsKey(handle))
210 return null;
211 return byhandle[handle];
212 }
213
214 public int Count()
215 {
216 if(byname == null)
217 return 0;
218 else
219 return byname.Count;
220 }
221 }
222
223 public sealed class RegionsExpiringCache
224 {
225 const double CACHE_PURGE_HZ = 60;
226 const int MAX_LOCK_WAIT = 5000; // milliseconds
227
228 /// <summary>For thread safety</summary>
229 object syncRoot = new object();
230 /// <summary>For thread safety</summary>
231 object isPurging = new object();
232
233 Dictionary<RegionKey, GridRegion> timedStorage = new Dictionary<RegionKey, GridRegion>();
234 Dictionary<UUID, RegionInfoByScope> InfobyScope = new Dictionary<UUID, RegionInfoByScope>();
235 private System.Timers.Timer timer = new System.Timers.Timer(TimeSpan.FromSeconds(CACHE_PURGE_HZ).TotalMilliseconds);
236
237 public RegionsExpiringCache()
238 {
239 timer.Elapsed += PurgeCache;
240 timer.Start();
241 }
242
243 public bool Add(UUID scope, GridRegion region, double expirationSeconds)
244 {
245 if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
246 throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
247
248 RegionKey key = new RegionKey(scope , region.RegionID);
249
250 try
157 { 251 {
158 GridRegion rinfo = null; 252 if (timedStorage.ContainsKey(key))
159 if (m_UUIDCache.TryGetValue(id, out rinfo)) 253 return false;
254
255 key.ExpirationDate = DateTime.UtcNow + TimeSpan.FromSeconds(expirationSeconds);
256 timedStorage.Add(key, region);
257
258 RegionInfoByScope ris = null;
259 if(!InfobyScope.TryGetValue(scope, out ris) || ris == null)
160 { 260 {
161 inCache = true; 261 ris = new RegionInfoByScope(region, key);
162 return rinfo; 262 InfobyScope[scope] = ris;
163 } 263 }
264 else
265 ris.AddRegion(region, key);
266
267 return true;
164 } 268 }
269 finally { Monitor.Exit(syncRoot);}
270 }
271
272 public bool AddOrUpdate(UUID scope, GridRegion region, double expirationSeconds)
273 {
274 if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
275 throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
165 276
166 return null; 277 try
278 {
279 RegionKey key = new RegionKey(scope, region.RegionID);
280 key.ExpirationDate = DateTime.UtcNow + TimeSpan.FromSeconds(expirationSeconds);
281
282 if (timedStorage.ContainsKey(key))
283 {
284 timedStorage.Remove(key);
285 timedStorage.Add(key, region);
286
287 if(!InfobyScope.ContainsKey(scope))
288 {
289 RegionInfoByScope ris = new RegionInfoByScope(region, key);
290 InfobyScope[scope] = ris;
291 }
292 return false;
293 }
294 else
295 {
296 timedStorage.Add(key, region);
297 RegionInfoByScope ris = null;
298 if(!InfobyScope.TryGetValue(scope, out ris) || ris == null)
299 {
300 ris = new RegionInfoByScope(region,key);
301 InfobyScope[scope] = ris;
302 }
303 else
304 ris.AddRegion(region,key);
305 return true;
306 }
307 }
308 finally { Monitor.Exit(syncRoot); }
309 }
310
311 public void Clear()
312 {
313 if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
314 throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
315 try
316 {
317 timedStorage.Clear();
318 InfobyScope.Clear();
319 }
320 finally { Monitor.Exit(syncRoot); }
321 }
322
323 public bool Contains(UUID scope, GridRegion region)
324 {
325 RegionKey key = new RegionKey(scope, region.RegionID);
326 return Contains(key);
327 }
328
329 public bool Contains(RegionKey key)
330 {
331 if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
332 throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
333 try
334 {
335 return timedStorage.ContainsKey(key);
336 }
337 finally { Monitor.Exit(syncRoot); }
338 }
339
340 public int Count
341 {
342 get
343 {
344 return timedStorage.Count;
345 }
346 }
347
348 public bool Remove(UUID scope, GridRegion region)
349 {
350 RegionKey key = new RegionKey(scope, region.RegionID);
351
352 if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
353 throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
354 try
355 {
356 if (timedStorage.ContainsKey(key))
357 {
358 RegionInfoByScope ris = null;
359 if(InfobyScope.TryGetValue(scope, out ris) && ris != null)
360 {
361 GridRegion r = timedStorage[key];
362 if(r != null)
363 ris.RemoveRegion(r);
364 if(ris.Count() == 0)
365 InfobyScope.Remove(scope);
366 }
367 timedStorage.Remove(key);
368 return true;
369 }
370 else
371 return false;
372 }
373 finally { Monitor.Exit(syncRoot); }
374 }
375
376 public bool TryGetValue(RegionKey key, out GridRegion value)
377 {
378 if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
379 throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
380 try
381 {
382 if (timedStorage.ContainsKey(key))
383 {
384 value = timedStorage[key];
385 return true;
386 }
387 }
388 finally { Monitor.Exit(syncRoot); }
389
390 value = null;
391 return false;
392 }
393
394 public bool TryGetValue(UUID scope, UUID id, out GridRegion value)
395 {
396 if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
397 throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
398 try
399 {
400 RegionKey rk = new RegionKey(scope, id);
401 if(timedStorage.ContainsKey(rk))
402 {
403 value = timedStorage[rk];
404 return true;
405 }
406 }
407 finally { Monitor.Exit(syncRoot); }
408
409 value = null;
410 return false;
411 }
412
413 public bool TryGetValue(UUID scope, string name, out GridRegion value)
414 {
415 if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
416 throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
417 try
418 {
419 value = null;
420 RegionInfoByScope ris = null;
421 if(!InfobyScope.TryGetValue(scope, out ris) || ris == null)
422 return false;
423
424 RegionKey key = ris.get(name);
425 if(key == null)
426 return false;
427
428 if(timedStorage.ContainsKey(key))
429 {
430 value = timedStorage[key];
431 return true;
432 }
433 }
434 finally { Monitor.Exit(syncRoot); }
435
436 return false;
437 }
438
439 public bool TryGetValue(UUID scope, ulong handle, out GridRegion value)
440 {
441 if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
442 throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
443 try
444 {
445 value = null;
446 RegionInfoByScope ris = null;
447 if(!InfobyScope.TryGetValue(scope, out ris) || ris == null)
448 return false;
449
450 RegionKey key = ris.get(handle);
451 if(key == null)
452 return false;
453
454 if(timedStorage.ContainsKey(key))
455 {
456 value = timedStorage[key];
457 return true;
458 }
459 }
460 finally { Monitor.Exit(syncRoot); }
461
462 value = null;
463 return false;
464 }
465
466 public bool Update(UUID scope, GridRegion region, double expirationSeconds)
467 {
468 if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
469 throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
470
471 RegionKey key = new RegionKey(scope, region.RegionID);
472 try
473 {
474 if (!timedStorage.ContainsKey(key))
475 return false;
476
477 timedStorage.Remove(key);
478 key.ExpirationDate = DateTime.UtcNow + TimeSpan.FromSeconds(expirationSeconds);
479 timedStorage.Add(key, region);
480 return true;
481 }
482 finally { Monitor.Exit(syncRoot); }
483 }
484
485 /// <summary>
486 /// Purges expired objects from the cache. Called automatically by the purge timer.
487 /// </summary>
488 private void PurgeCache(object sender, System.Timers.ElapsedEventArgs e)
489 {
490 // Only let one thread purge at once - a buildup could cause a crash
491 // This could cause the purge to be delayed while there are lots of read/write ops
492 // happening on the cache
493 if (!Monitor.TryEnter(isPurging))
494 return;
495
496 DateTime signalTime = DateTime.UtcNow;
497
498 try
499 {
500 // If we fail to acquire a lock on the synchronization root after MAX_LOCK_WAIT, skip this purge cycle
501 if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
502 return;
503 try
504 {
505 OpenMetaverse.Lazy<List<object>> expiredItems = new OpenMetaverse.Lazy<List<object>>();
506
507 foreach (RegionKey timedKey in timedStorage.Keys)
508 {
509 if (timedKey.ExpirationDate < signalTime)
510 {
511 // Mark the object for purge
512 expiredItems.Value.Add(timedKey);
513 }
514 else
515 {
516 break;
517 }
518 }
519
520
521 RegionInfoByScope ris;
522 if (expiredItems.IsValueCreated)
523 {
524 foreach (RegionKey key in expiredItems.Value)
525 {
526 ris = null;
527 if(InfobyScope.TryGetValue(key.ScopeID, out ris) && ris != null)
528 {
529 GridRegion r = timedStorage[key];
530 if(r != null)
531 ris.RemoveRegion(r);
532
533 if(ris.Count() == 0)
534 InfobyScope.Remove(key.ScopeID);
535 }
536 timedStorage.Remove(key);
537 }
538 }
539 }
540 finally { Monitor.Exit(syncRoot); }
541 }
542 finally { Monitor.Exit(isPurging); }
167 } 543 }
168 } 544 }
169} 545}