in RegionInfoCache, replace lib omv ExpireCaches by a single dedicated one
parent
3d58198c55
commit
55b2d01028
|
@ -26,6 +26,7 @@
|
||||||
*/
|
*/
|
||||||
using System;
|
using System;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Threading;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
using OpenSim.Services.Interfaces;
|
using OpenSim.Services.Interfaces;
|
||||||
|
@ -37,54 +38,17 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
|
||||||
{
|
{
|
||||||
public class RegionInfoCache
|
public class RegionInfoCache
|
||||||
{
|
{
|
||||||
private const double CACHE_EXPIRATION_SECONDS = 300.0; // 5 minutes
|
private const double CACHE_EXPIRATION_SECONDS = 120; // 2 minutes opensim regions change a lot
|
||||||
|
|
||||||
// private static readonly ILog m_log =
|
// private static readonly ILog m_log =
|
||||||
// LogManager.GetLogger(
|
// LogManager.GetLogger(
|
||||||
// MethodBase.GetCurrentMethod().DeclaringType);
|
// MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
internal struct ScopedRegionUUID
|
private RegionsExpiringCache m_Cache;
|
||||||
{
|
|
||||||
public UUID m_scopeID;
|
|
||||||
public UUID m_regionID;
|
|
||||||
public ScopedRegionUUID(UUID scopeID, UUID regionID)
|
|
||||||
{
|
|
||||||
m_scopeID = scopeID;
|
|
||||||
m_regionID = regionID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal struct ScopedRegionName
|
|
||||||
{
|
|
||||||
public UUID m_scopeID;
|
|
||||||
public string m_name;
|
|
||||||
public ScopedRegionName(UUID scopeID, string name)
|
|
||||||
{
|
|
||||||
m_scopeID = scopeID;
|
|
||||||
m_name = name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal struct ScopedRegionPosition
|
|
||||||
{
|
|
||||||
public UUID m_scopeID;
|
|
||||||
public ulong m_regionHandle;
|
|
||||||
public ScopedRegionPosition(UUID scopeID, ulong handle)
|
|
||||||
{
|
|
||||||
m_scopeID = scopeID;
|
|
||||||
m_regionHandle = handle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ExpiringCache<ScopedRegionUUID, GridRegion> m_UUIDCache;
|
|
||||||
private ExpiringCache<ScopedRegionName, ScopedRegionUUID> m_NameCache;
|
|
||||||
private ExpiringCache<ScopedRegionPosition, GridRegion> m_PositionCache;
|
|
||||||
|
|
||||||
public RegionInfoCache()
|
public RegionInfoCache()
|
||||||
{
|
{
|
||||||
m_UUIDCache = new ExpiringCache<ScopedRegionUUID, GridRegion>();
|
m_Cache = new RegionsExpiringCache();
|
||||||
m_NameCache = new ExpiringCache<ScopedRegionName, ScopedRegionUUID>();
|
|
||||||
m_PositionCache = new ExpiringCache<ScopedRegionPosition, GridRegion>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Cache(GridRegion rinfo)
|
public void Cache(GridRegion rinfo)
|
||||||
|
@ -101,18 +65,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
|
||||||
if (rinfo == null)
|
if (rinfo == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ScopedRegionUUID id = new ScopedRegionUUID(scopeID,regionID);
|
m_Cache.AddOrUpdate(scopeID, rinfo, CACHE_EXPIRATION_SECONDS);
|
||||||
|
|
||||||
// Cache even null accounts
|
|
||||||
m_UUIDCache.AddOrUpdate(id, rinfo, CACHE_EXPIRATION_SECONDS);
|
|
||||||
if (rinfo != null)
|
|
||||||
{
|
|
||||||
ScopedRegionName name = new ScopedRegionName(scopeID,rinfo.RegionName);
|
|
||||||
m_NameCache.AddOrUpdate(name, id, CACHE_EXPIRATION_SECONDS);
|
|
||||||
|
|
||||||
ScopedRegionPosition pos = new ScopedRegionPosition(scopeID, rinfo.RegionHandle);
|
|
||||||
m_PositionCache.AddOrUpdate(pos, rinfo, CACHE_EXPIRATION_SECONDS);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public GridRegion Get(UUID scopeID, UUID regionID, out bool inCache)
|
public GridRegion Get(UUID scopeID, UUID regionID, out bool inCache)
|
||||||
|
@ -120,8 +73,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
|
||||||
inCache = false;
|
inCache = false;
|
||||||
|
|
||||||
GridRegion rinfo = null;
|
GridRegion rinfo = null;
|
||||||
ScopedRegionUUID id = new ScopedRegionUUID(scopeID,regionID);
|
if (m_Cache.TryGetValue(scopeID, regionID, out rinfo))
|
||||||
if (m_UUIDCache.TryGetValue(id, out rinfo))
|
|
||||||
{
|
{
|
||||||
inCache = true;
|
inCache = true;
|
||||||
return rinfo;
|
return rinfo;
|
||||||
|
@ -135,8 +87,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
|
||||||
inCache = false;
|
inCache = false;
|
||||||
|
|
||||||
GridRegion rinfo = null;
|
GridRegion rinfo = null;
|
||||||
ScopedRegionPosition pos = new ScopedRegionPosition(scopeID, handle);
|
if (m_Cache.TryGetValue(scopeID, handle, out rinfo))
|
||||||
if (m_PositionCache.TryGetValue(pos, out rinfo))
|
|
||||||
{
|
{
|
||||||
inCache = true;
|
inCache = true;
|
||||||
return rinfo;
|
return rinfo;
|
||||||
|
@ -145,25 +96,450 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public GridRegion Get(UUID scopeID, string name, out bool inCache)
|
public GridRegion Get(UUID scopeID, string name, out bool inCache)
|
||||||
{
|
{
|
||||||
inCache = false;
|
inCache = false;
|
||||||
|
|
||||||
ScopedRegionName sname = new ScopedRegionName(scopeID,name);
|
GridRegion rinfo = null;
|
||||||
|
if (m_Cache.TryGetValue(scopeID, name, out rinfo))
|
||||||
ScopedRegionUUID id;
|
|
||||||
if (m_NameCache.TryGetValue(sname, out id))
|
|
||||||
{
|
{
|
||||||
GridRegion rinfo = null;
|
inCache = true;
|
||||||
if (m_UUIDCache.TryGetValue(id, out rinfo))
|
return rinfo;
|
||||||
{
|
|
||||||
inCache = true;
|
|
||||||
return rinfo;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// following code partialy adapted from lib OpenMetaverse
|
||||||
|
public class RegionKey : IComparable<RegionKey>
|
||||||
|
{
|
||||||
|
private UUID m_scopeID;
|
||||||
|
private UUID m_RegionID;
|
||||||
|
private DateTime m_expirationDate;
|
||||||
|
|
||||||
|
public RegionKey(UUID scopeID, UUID id)
|
||||||
|
{
|
||||||
|
m_scopeID = scopeID;
|
||||||
|
m_RegionID = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID ScopeID
|
||||||
|
{
|
||||||
|
get { return m_scopeID; }
|
||||||
|
}
|
||||||
|
public DateTime ExpirationDate
|
||||||
|
{
|
||||||
|
get { return m_expirationDate; }
|
||||||
|
set { m_expirationDate = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetHaskCode()
|
||||||
|
{
|
||||||
|
int hash = m_scopeID.GetHashCode();
|
||||||
|
hash += hash * 23 + m_RegionID.GetHashCode();
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CompareTo(RegionKey other)
|
||||||
|
{
|
||||||
|
return GetHashCode().CompareTo(other.GetHashCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RegionInfoByScope
|
||||||
|
{
|
||||||
|
private Dictionary<string, RegionKey> byname;
|
||||||
|
private Dictionary<ulong, RegionKey> byhandle;
|
||||||
|
|
||||||
|
public RegionInfoByScope()
|
||||||
|
{
|
||||||
|
byname = new Dictionary<string, RegionKey>();
|
||||||
|
byhandle = new Dictionary<ulong, RegionKey>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegionInfoByScope(GridRegion region, RegionKey key)
|
||||||
|
{
|
||||||
|
byname = new Dictionary<string, RegionKey>();
|
||||||
|
byhandle = new Dictionary<ulong, RegionKey>();
|
||||||
|
|
||||||
|
byname[region.RegionName] = key;
|
||||||
|
byhandle[region.RegionHandle] = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddRegion(GridRegion region, RegionKey key)
|
||||||
|
{
|
||||||
|
if(byname == null)
|
||||||
|
byname = new Dictionary<string, RegionKey>();
|
||||||
|
if(byhandle == null)
|
||||||
|
byhandle = new Dictionary<ulong, RegionKey>();
|
||||||
|
|
||||||
|
byname[region.RegionName] = key;
|
||||||
|
byhandle[region.RegionHandle] = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveRegion(GridRegion region)
|
||||||
|
{
|
||||||
|
if(byname != null)
|
||||||
|
byname.Remove(region.RegionName);
|
||||||
|
if(byhandle != null)
|
||||||
|
byhandle.Remove(region.RegionHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
if(byname != null)
|
||||||
|
byname.Clear();
|
||||||
|
if(byhandle != null)
|
||||||
|
byhandle.Clear();
|
||||||
|
byname = null;
|
||||||
|
byhandle = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegionKey get(string name)
|
||||||
|
{
|
||||||
|
if(byname == null || !byname.ContainsKey(name))
|
||||||
|
return null;
|
||||||
|
return byname[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegionKey get(ulong handle)
|
||||||
|
{
|
||||||
|
if(byhandle == null || !byhandle.ContainsKey(handle))
|
||||||
|
return null;
|
||||||
|
return byhandle[handle];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count()
|
||||||
|
{
|
||||||
|
if(byname == null)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return byname.Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class RegionsExpiringCache
|
||||||
|
{
|
||||||
|
const double CACHE_PURGE_HZ = 60;
|
||||||
|
const int MAX_LOCK_WAIT = 5000; // milliseconds
|
||||||
|
|
||||||
|
/// <summary>For thread safety</summary>
|
||||||
|
object syncRoot = new object();
|
||||||
|
/// <summary>For thread safety</summary>
|
||||||
|
object isPurging = new object();
|
||||||
|
|
||||||
|
Dictionary<RegionKey, GridRegion> timedStorage = new Dictionary<RegionKey, GridRegion>();
|
||||||
|
Dictionary<UUID, RegionInfoByScope> InfobyScope = new Dictionary<UUID, RegionInfoByScope>();
|
||||||
|
private System.Timers.Timer timer = new System.Timers.Timer(TimeSpan.FromSeconds(CACHE_PURGE_HZ).TotalMilliseconds);
|
||||||
|
|
||||||
|
public RegionsExpiringCache()
|
||||||
|
{
|
||||||
|
timer.Elapsed += PurgeCache;
|
||||||
|
timer.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Add(UUID scope, GridRegion region, double expirationSeconds)
|
||||||
|
{
|
||||||
|
if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
|
||||||
|
throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
|
||||||
|
|
||||||
|
RegionKey key = new RegionKey(scope , region.RegionID);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (timedStorage.ContainsKey(key))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
key.ExpirationDate = DateTime.UtcNow + TimeSpan.FromSeconds(expirationSeconds);
|
||||||
|
timedStorage.Add(key, region);
|
||||||
|
|
||||||
|
RegionInfoByScope ris = null;
|
||||||
|
if(!InfobyScope.TryGetValue(scope, out ris) || ris == null)
|
||||||
|
{
|
||||||
|
ris = new RegionInfoByScope(region, key);
|
||||||
|
InfobyScope[scope] = ris;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ris.AddRegion(region, key);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
finally { Monitor.Exit(syncRoot);}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool AddOrUpdate(UUID scope, GridRegion region, double expirationSeconds)
|
||||||
|
{
|
||||||
|
if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
|
||||||
|
throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
RegionKey key = new RegionKey(scope, region.RegionID);
|
||||||
|
key.ExpirationDate = DateTime.UtcNow + TimeSpan.FromSeconds(expirationSeconds);
|
||||||
|
|
||||||
|
if (timedStorage.ContainsKey(key))
|
||||||
|
{
|
||||||
|
timedStorage.Remove(key);
|
||||||
|
timedStorage.Add(key, region);
|
||||||
|
|
||||||
|
if(!InfobyScope.ContainsKey(scope))
|
||||||
|
{
|
||||||
|
RegionInfoByScope ris = new RegionInfoByScope(region, key);
|
||||||
|
InfobyScope[scope] = ris;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
timedStorage.Add(key, region);
|
||||||
|
RegionInfoByScope ris = null;
|
||||||
|
if(!InfobyScope.TryGetValue(scope, out ris) || ris == null)
|
||||||
|
{
|
||||||
|
ris = new RegionInfoByScope(region,key);
|
||||||
|
InfobyScope[scope] = ris;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ris.AddRegion(region,key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally { Monitor.Exit(syncRoot); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
|
||||||
|
throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
timedStorage.Clear();
|
||||||
|
InfobyScope.Clear();
|
||||||
|
}
|
||||||
|
finally { Monitor.Exit(syncRoot); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(UUID scope, GridRegion region)
|
||||||
|
{
|
||||||
|
RegionKey key = new RegionKey(scope, region.RegionID);
|
||||||
|
return Contains(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(RegionKey key)
|
||||||
|
{
|
||||||
|
if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
|
||||||
|
throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return timedStorage.ContainsKey(key);
|
||||||
|
}
|
||||||
|
finally { Monitor.Exit(syncRoot); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return timedStorage.Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(UUID scope, GridRegion region)
|
||||||
|
{
|
||||||
|
RegionKey key = new RegionKey(scope, region.RegionID);
|
||||||
|
|
||||||
|
if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
|
||||||
|
throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (timedStorage.ContainsKey(key))
|
||||||
|
{
|
||||||
|
RegionInfoByScope ris = null;
|
||||||
|
if(InfobyScope.TryGetValue(scope, out ris) && ris != null)
|
||||||
|
{
|
||||||
|
GridRegion r = timedStorage[key];
|
||||||
|
if(r != null)
|
||||||
|
ris.RemoveRegion(r);
|
||||||
|
if(ris.Count() == 0)
|
||||||
|
InfobyScope.Remove(scope);
|
||||||
|
}
|
||||||
|
timedStorage.Remove(key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
finally { Monitor.Exit(syncRoot); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetValue(RegionKey key, out GridRegion value)
|
||||||
|
{
|
||||||
|
if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
|
||||||
|
throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (timedStorage.ContainsKey(key))
|
||||||
|
{
|
||||||
|
value = timedStorage[key];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally { Monitor.Exit(syncRoot); }
|
||||||
|
|
||||||
|
value = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetValue(UUID scope, UUID id, out GridRegion value)
|
||||||
|
{
|
||||||
|
if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
|
||||||
|
throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
RegionKey rk = new RegionKey(scope, id);
|
||||||
|
if(timedStorage.ContainsKey(rk))
|
||||||
|
{
|
||||||
|
value = timedStorage[rk];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally { Monitor.Exit(syncRoot); }
|
||||||
|
|
||||||
|
value = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetValue(UUID scope, string name, out GridRegion value)
|
||||||
|
{
|
||||||
|
if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
|
||||||
|
throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
value = null;
|
||||||
|
RegionInfoByScope ris = null;
|
||||||
|
if(!InfobyScope.TryGetValue(scope, out ris) || ris == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
RegionKey key = ris.get(name);
|
||||||
|
if(key == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(timedStorage.ContainsKey(key))
|
||||||
|
{
|
||||||
|
value = timedStorage[key];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally { Monitor.Exit(syncRoot); }
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetValue(UUID scope, ulong handle, out GridRegion value)
|
||||||
|
{
|
||||||
|
if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
|
||||||
|
throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
value = null;
|
||||||
|
RegionInfoByScope ris = null;
|
||||||
|
if(!InfobyScope.TryGetValue(scope, out ris) || ris == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
RegionKey key = ris.get(handle);
|
||||||
|
if(key == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(timedStorage.ContainsKey(key))
|
||||||
|
{
|
||||||
|
value = timedStorage[key];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally { Monitor.Exit(syncRoot); }
|
||||||
|
|
||||||
|
value = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Update(UUID scope, GridRegion region, double expirationSeconds)
|
||||||
|
{
|
||||||
|
if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
|
||||||
|
throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms");
|
||||||
|
|
||||||
|
RegionKey key = new RegionKey(scope, region.RegionID);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!timedStorage.ContainsKey(key))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
timedStorage.Remove(key);
|
||||||
|
key.ExpirationDate = DateTime.UtcNow + TimeSpan.FromSeconds(expirationSeconds);
|
||||||
|
timedStorage.Add(key, region);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
finally { Monitor.Exit(syncRoot); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Purges expired objects from the cache. Called automatically by the purge timer.
|
||||||
|
/// </summary>
|
||||||
|
private void PurgeCache(object sender, System.Timers.ElapsedEventArgs e)
|
||||||
|
{
|
||||||
|
// Only let one thread purge at once - a buildup could cause a crash
|
||||||
|
// This could cause the purge to be delayed while there are lots of read/write ops
|
||||||
|
// happening on the cache
|
||||||
|
if (!Monitor.TryEnter(isPurging))
|
||||||
|
return;
|
||||||
|
|
||||||
|
DateTime signalTime = DateTime.UtcNow;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// If we fail to acquire a lock on the synchronization root after MAX_LOCK_WAIT, skip this purge cycle
|
||||||
|
if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT))
|
||||||
|
return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
OpenMetaverse.Lazy<List<object>> expiredItems = new OpenMetaverse.Lazy<List<object>>();
|
||||||
|
|
||||||
|
foreach (RegionKey timedKey in timedStorage.Keys)
|
||||||
|
{
|
||||||
|
if (timedKey.ExpirationDate < signalTime)
|
||||||
|
{
|
||||||
|
// Mark the object for purge
|
||||||
|
expiredItems.Value.Add(timedKey);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RegionInfoByScope ris;
|
||||||
|
if (expiredItems.IsValueCreated)
|
||||||
|
{
|
||||||
|
foreach (RegionKey key in expiredItems.Value)
|
||||||
|
{
|
||||||
|
ris = null;
|
||||||
|
if(InfobyScope.TryGetValue(key.ScopeID, out ris) && ris != null)
|
||||||
|
{
|
||||||
|
GridRegion r = timedStorage[key];
|
||||||
|
if(r != null)
|
||||||
|
ris.RemoveRegion(r);
|
||||||
|
|
||||||
|
if(ris.Count() == 0)
|
||||||
|
InfobyScope.Remove(key.ScopeID);
|
||||||
|
}
|
||||||
|
timedStorage.Remove(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally { Monitor.Exit(syncRoot); }
|
||||||
|
}
|
||||||
|
finally { Monitor.Exit(isPurging); }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue