Merge branch 'master' into httptests

httptests
UbitUmarov 2016-07-30 01:53:25 +01:00
commit 18bcacdded
2 changed files with 485 additions and 112 deletions

View File

@ -26,6 +26,7 @@
*/
using System;
using System.Reflection;
using System.Threading;
using System.Collections.Generic;
using OpenSim.Framework;
using OpenSim.Services.Interfaces;
@ -37,54 +38,17 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
{
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 =
// LogManager.GetLogger(
// MethodBase.GetCurrentMethod().DeclaringType);
internal struct ScopedRegionUUID
{
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;
private RegionsExpiringCache m_Cache;
public RegionInfoCache()
{
m_UUIDCache = new ExpiringCache<ScopedRegionUUID, GridRegion>();
m_NameCache = new ExpiringCache<ScopedRegionName, ScopedRegionUUID>();
m_PositionCache = new ExpiringCache<ScopedRegionPosition, GridRegion>();
m_Cache = new RegionsExpiringCache();
}
public void Cache(GridRegion rinfo)
@ -101,18 +65,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
if (rinfo == null)
return;
ScopedRegionUUID id = new ScopedRegionUUID(scopeID,regionID);
// 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);
}
m_Cache.AddOrUpdate(scopeID, rinfo, CACHE_EXPIRATION_SECONDS);
}
public GridRegion Get(UUID scopeID, UUID regionID, out bool inCache)
@ -120,8 +73,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
inCache = false;
GridRegion rinfo = null;
ScopedRegionUUID id = new ScopedRegionUUID(scopeID,regionID);
if (m_UUIDCache.TryGetValue(id, out rinfo))
if (m_Cache.TryGetValue(scopeID, regionID, out rinfo))
{
inCache = true;
return rinfo;
@ -135,8 +87,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
inCache = false;
GridRegion rinfo = null;
ScopedRegionPosition pos = new ScopedRegionPosition(scopeID, handle);
if (m_PositionCache.TryGetValue(pos, out rinfo))
if (m_Cache.TryGetValue(scopeID, handle, out rinfo))
{
inCache = true;
return rinfo;
@ -145,25 +96,450 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
return null;
}
public GridRegion Get(UUID scopeID, string name, out bool inCache)
{
inCache = false;
ScopedRegionName sname = new ScopedRegionName(scopeID,name);
ScopedRegionUUID id;
if (m_NameCache.TryGetValue(sname, out id))
GridRegion rinfo = null;
if (m_Cache.TryGetValue(scopeID, name, out rinfo))
{
GridRegion rinfo = null;
if (m_UUIDCache.TryGetValue(id, out rinfo))
{
inCache = true;
return rinfo;
}
inCache = true;
return rinfo;
}
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); }
}
}
}

View File

@ -6394,64 +6394,61 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
{
m_host.AddScriptLPS(1);
// edge will be used to pass the Region Coordinates offset
// we want to check for a neighboring sim
LSL_Vector edge = new LSL_Vector(0, 0, 0);
if(dir.x == 0.0 && dir.y == 0.0)
return 1; // SL wiki
float rsx = World.RegionInfo.RegionSizeX;
float rsy = World.RegionInfo.RegionSizeY;
// can understand what sl does if position is not in region, so do something :)
float px = (float)Util.Clamp(pos.x, 0.5, rsx - 0.5);
float py = (float)Util.Clamp(pos.y, 0.5, rsy - 0.5);
float ex, ey;
if (dir.x == 0)
{
if (dir.y == 0)
{
// Direction vector is 0,0 so return
// false since we're staying in the sim
return 0;
}
else
{
// Y is the only valid direction
edge.y = dir.y / Math.Abs(dir.y) * (World.RegionInfo.RegionSizeY / Constants.RegionSize);
}
ex = px;
ey = dir.y > 0.0 ? rsy + 1.0f : -1.0f;
}
else if(dir.y == 0.0f)
{
ex = dir.x > 0 ? rsx + 1.0f : -1.0f;
ey = py;
}
else
{
LSL_Float mag;
if (dir.x > 0)
{
mag = (World.RegionInfo.RegionSizeX - pos.x) / dir.x;
}
float dx = (float) dir.x;
float dy = (float) dir.y;
float t1 = dx * dx + dy * dy;
dx /= t1;
dy /= t1;
if(dx > 0)
t1 = (rsx + 1f - px)/dx;
else
{
mag = (pos.x/dir.x);
}
t1 = -(px + 1f)/dx;
mag = Math.Abs(mag);
edge.y = pos.y + (dir.y * mag);
if (edge.y > World.RegionInfo.RegionSizeY || edge.y < 0)
{
// Y goes out of bounds first
edge.y = dir.y / Math.Abs(dir.y) * (World.RegionInfo.RegionSizeY / Constants.RegionSize);
}
float t2;
if(dy > 0)
t2 = (rsy + 1f - py)/dy;
else
{
// X goes out of bounds first or its a corner exit
edge.y = 0;
edge.x = dir.x / Math.Abs(dir.x) * (World.RegionInfo.RegionSizeY / Constants.RegionSize);
}
t2 = -(py + 1f)/dy;
if(t1 > t2)
t1 = t2;
ex = px + t1 * dx;
ey = py + t1 * dy;
}
List<GridRegion> neighbors = World.GridService.GetNeighbours(World.RegionInfo.ScopeID, World.RegionInfo.RegionID);
uint neighborX = World.RegionInfo.RegionLocX + (uint)edge.x;
uint neighborY = World.RegionInfo.RegionLocY + (uint)edge.y;
foreach (GridRegion sri in neighbors)
{
if (sri.RegionCoordX == neighborX && sri.RegionCoordY == neighborY)
return 0;
}
ex += World.RegionInfo.WorldLocX;
ey += World.RegionInfo.WorldLocY;
if(World.GridService.GetRegionByPosition(World.RegionInfo.ScopeID, (int)ex, (int)ey) != null)
return 0;
return 1;
}