diff --git a/OpenSim/Data/MySQL/MySQLRegionData.cs b/OpenSim/Data/MySQL/MySQLRegionData.cs index 3dc049b3fa..99d4944b52 100644 --- a/OpenSim/Data/MySQL/MySQLRegionData.cs +++ b/OpenSim/Data/MySQL/MySQLRegionData.cs @@ -204,7 +204,7 @@ namespace OpenSim.Data.MySQL foreach (RegionData r in dbret) { if (r.posX + r.sizeX > startX && r.posX <= endX - && r.posY + r.sizeX > startY && r.posY <= endY) + && r.posY + r.sizeY > startY && r.posY <= endY) ret.Add(r); } return ret; diff --git a/OpenSim/Data/PGSQL/PGSQLRegionData.cs b/OpenSim/Data/PGSQL/PGSQLRegionData.cs index 3924b7bba1..fc352c3905 100644 --- a/OpenSim/Data/PGSQL/PGSQLRegionData.cs +++ b/OpenSim/Data/PGSQL/PGSQLRegionData.cs @@ -211,7 +211,7 @@ namespace OpenSim.Data.PGSQL foreach (RegionData r in dbret) { if (r.posX + r.sizeX > startX && r.posX <= endX - && r.posY + r.sizeX > startY && r.posY <= endY) + && r.posY + r.sizeY > startY && r.posY <= endY) ret.Add(r); } return ret; diff --git a/OpenSim/Framework/Cache.cs b/OpenSim/Framework/Cache.cs index 31cab4a021..80f5ff44ee 100644 --- a/OpenSim/Framework/Cache.cs +++ b/OpenSim/Framework/Cache.cs @@ -89,14 +89,14 @@ namespace OpenSim.Framework public CacheItemBase(string index) { uuid = index; - entered = DateTime.Now; + entered = DateTime.UtcNow; lastUsed = entered; } public CacheItemBase(string index, DateTime ttl) { uuid = index; - entered = DateTime.Now; + entered = DateTime.UtcNow; lastUsed = entered; expires = ttl; } @@ -215,6 +215,8 @@ namespace OpenSim.Framework private CacheFlags m_Flags = 0; private int m_Size = 1024; private TimeSpan m_DefaultTTL = new TimeSpan(0); + private DateTime m_nextExpire; + private TimeSpan m_expiresTime = new TimeSpan(0,0,30); public ExpireDelegate OnExpire; // Comparison interfaces @@ -233,6 +235,21 @@ namespace OpenSim.Framework return(a.lastUsed.CompareTo(b.lastUsed)); } } + // same as above, reverse order + private class SortLRUrev : IComparer + { + public int Compare(CacheItemBase a, CacheItemBase b) + { + if (a == null && b == null) + return 0; + if (a == null) + return -1; + if (b == null) + return 1; + + return(b.lastUsed.CompareTo(a.lastUsed)); + } + } // Convenience constructors // @@ -241,6 +258,8 @@ namespace OpenSim.Framework m_Strategy = CacheStrategy.Balanced; m_Medium = CacheMedium.Memory; m_Flags = 0; + m_nextExpire = DateTime.UtcNow + m_expiresTime; + m_Strategy = CacheStrategy.Aggressive; } public Cache(CacheMedium medium) : @@ -295,19 +314,23 @@ namespace OpenSim.Framework { lock (m_Index) { - if (Count <= Size) - return; + int target = newSize; + if(m_Strategy == CacheStrategy.Aggressive) + target = (int)(newSize * 0.9); - m_Index.Sort(new SortLRU()); - m_Index.Reverse(); + if(Count > target) + { + m_Index.Sort(new SortLRUrev()); - m_Index.RemoveRange(newSize, Count - newSize); + m_Index.RemoveRange(newSize, Count - target); + + m_Lookup.Clear(); + + foreach (CacheItemBase item in m_Index) + m_Lookup[item.uuid] = item; + } m_Size = newSize; - m_Lookup.Clear(); - - foreach (CacheItemBase item in m_Index) - m_Lookup[item.uuid] = item; } } @@ -335,7 +358,7 @@ namespace OpenSim.Framework } item.hits++; - item.lastUsed = DateTime.Now; + item.lastUsed = DateTime.UtcNow; Expire(true); } @@ -361,30 +384,26 @@ namespace OpenSim.Framework // public virtual Object Get(string index, FetchDelegate fetch) { - Object item = Get(index); + CacheItemBase item = GetItem(index); if (item != null) - return item; + return item.Retrieve(); Object data = fetch(index); - if (data == null) - { - if ((m_Flags & CacheFlags.CacheMissing) != 0) - { - lock (m_Index) - { - CacheItemBase missing = new CacheItemBase(index); - if (!m_Index.Contains(missing)) - { - m_Index.Add(missing); - m_Lookup[index] = missing; - } - } - } + + if (data == null && (m_Flags & CacheFlags.CacheMissing) == 0) return null; + + lock (m_Index) + { + CacheItemBase missing = new CacheItemBase(index); + if (!m_Index.Contains(missing)) + { + m_Index.Add(missing); + m_Lookup[index] = missing; + } } Store(index, data); - return data; } @@ -442,9 +461,9 @@ namespace OpenSim.Framework item = GetItem(index); item.hits++; - item.lastUsed = DateTime.Now; + item.lastUsed = DateTime.UtcNow; if (m_DefaultTTL.Ticks != 0) - item.expires = DateTime.Now + m_DefaultTTL; + item.expires = DateTime.UtcNow + m_DefaultTTL; item.Store(data); } @@ -455,7 +474,7 @@ namespace OpenSim.Framework parameters); if (m_DefaultTTL.Ticks != 0) - item.expires = DateTime.Now + m_DefaultTTL; + item.expires = DateTime.UtcNow + m_DefaultTTL; m_Index.Add(item); m_Lookup[index] = item; @@ -476,10 +495,14 @@ namespace OpenSim.Framework if (getting && (m_Strategy == CacheStrategy.Aggressive)) return; + DateTime now = DateTime.UtcNow; + if(now < m_nextExpire) + return; + + m_nextExpire = now + m_expiresTime; + if (m_DefaultTTL.Ticks != 0) { - DateTime now= DateTime.Now; - foreach (CacheItemBase item in new List(m_Index)) { if (item.expires.Ticks == 0 || @@ -494,16 +517,14 @@ namespace OpenSim.Framework switch (m_Strategy) { case CacheStrategy.Aggressive: - if (Count < Size) - return; - - m_Index.Sort(new SortLRU()); - m_Index.Reverse(); - int target = (int)((float)Size * 0.9); - if (target == Count) // Cover ridiculous cache sizes + if (Count < target) // Cover ridiculous cache sizes return; + target = (int)((float)Size * 0.8); + + m_Index.Sort(new SortLRUrev()); + ExpireDelegate doExpire = OnExpire; if (doExpire != null) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 6cdf6f635d..ce7ee98d9b 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -619,11 +619,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_entityProps = new PriorityQueue(1); m_killRecord.Clear(); GroupsInView.Clear(); -// m_scene = null; can't do this unless checks are added everywhere due to workitems already in pools - //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false)); - //GC.Collect(); - //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true)); + if(m_scene.GetNumberOfClients() == 0) + GC.Collect(); } public void Kick(string message) @@ -2996,7 +2994,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP return; } - int WearableOut = 0; bool isWearable = false; isWearable = ((AssetType) req.AssetInf.Type == @@ -8563,7 +8560,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP // surrounding scene if ((ImageType)block.Type == ImageType.Baked) args.Priority *= 2.0f; - int wearableout = 0; ImageManager.EnqueueReq(args); } diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index c4abc99d3f..9413598de6 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -62,6 +62,7 @@ namespace OpenSim.Region.CoreModules.Asset MethodBase.GetCurrentMethod().DeclaringType); private bool m_Enabled; + private bool m_Running; private const string m_ModuleName = "FlotsamAssetCache"; private const string m_DefaultCacheDirectory = "./assetcache"; @@ -94,7 +95,7 @@ namespace OpenSim.Region.CoreModules.Asset private const double m_DefaultFileExpiration = 48; private TimeSpan m_MemoryExpiration = TimeSpan.FromHours(m_DefaultMemoryExpiration); private TimeSpan m_FileExpiration = TimeSpan.FromHours(m_DefaultFileExpiration); - private TimeSpan m_FileExpirationCleanupTimer = TimeSpan.FromHours(0.166); + private TimeSpan m_FileExpirationCleanupTimer = TimeSpan.FromHours(1.0); private static int m_CacheDirectoryTiers = 1; private static int m_CacheDirectoryTierLen = 3; @@ -104,7 +105,8 @@ namespace OpenSim.Region.CoreModules.Asset private IAssetService m_AssetService; private List m_Scenes = new List(); - + private object timerLock = new object(); + public FlotsamAssetCache() { m_InvalidChars.AddRange(Path.GetInvalidPathChars()); @@ -170,14 +172,6 @@ namespace OpenSim.Region.CoreModules.Asset m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Cache Directory {0}", m_CacheDirectory); - if (m_FileCacheEnabled && (m_FileExpiration > TimeSpan.Zero) && (m_FileExpirationCleanupTimer > TimeSpan.Zero)) - { - m_CacheCleanTimer = new System.Timers.Timer(m_FileExpirationCleanupTimer.TotalMilliseconds); - m_CacheCleanTimer.AutoReset = true; - m_CacheCleanTimer.Elapsed += CleanupExpiredFiles; - lock (m_CacheCleanTimer) - m_CacheCleanTimer.Start(); - } if (m_CacheDirectoryTiers < 1) { @@ -219,7 +213,6 @@ namespace OpenSim.Region.CoreModules.Asset { scene.RegisterModuleInterface(this); m_Scenes.Add(scene); - } } @@ -229,13 +222,39 @@ namespace OpenSim.Region.CoreModules.Asset { scene.UnregisterModuleInterface(this); m_Scenes.Remove(scene); + lock(timerLock) + { + if(m_Running && m_Scenes.Count <= 0) + { + m_Running = false; + m_CacheCleanTimer.Stop(); + m_CacheCleanTimer.Close(); + } + } } } public void RegionLoaded(Scene scene) { - if (m_Enabled && m_AssetService == null) - m_AssetService = scene.RequestModuleInterface(); + if (m_Enabled) + { + if(m_AssetService == null) + m_AssetService = scene.RequestModuleInterface(); + lock(timerLock) + { + if(!m_Running) + { + if (m_FileCacheEnabled && (m_FileExpiration > TimeSpan.Zero) && (m_FileExpirationCleanupTimer > TimeSpan.Zero)) + { + m_CacheCleanTimer = new System.Timers.Timer(m_FileExpirationCleanupTimer.TotalMilliseconds); + m_CacheCleanTimer.AutoReset = false; + m_CacheCleanTimer.Elapsed += CleanupExpiredFiles; + m_CacheCleanTimer.Start(); + m_Running = true; + } + } + } + } } //////////////////////////////////////////////////////////// @@ -542,6 +561,8 @@ namespace OpenSim.Region.CoreModules.Asset if (m_LogLevel >= 2) m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Checking for expired files older then {0}.", m_FileExpiration); + if(!m_Running) + return; // Purge all files last accessed prior to this point DateTime purgeLine = DateTime.Now - m_FileExpiration; @@ -554,6 +575,12 @@ namespace OpenSim.Region.CoreModules.Asset { CleanExpiredFiles(dir, purgeLine); } + + lock(timerLock) + { + if(m_Running) + m_CacheCleanTimer.Start(); + } } /// @@ -789,9 +816,15 @@ namespace OpenSim.Region.CoreModules.Asset s.ForEachSOG(delegate(SceneObjectGroup e) { + if(!m_Running && !storeUncached) + return; + gatherer.AddForInspection(e); gatherer.GatherAll(); + if(!m_Running && !storeUncached) + return; + foreach (UUID assetID in gatherer.GatheredUuids.Keys) { if (!assetsFound.ContainsKey(assetID)) @@ -801,6 +834,7 @@ namespace OpenSim.Region.CoreModules.Asset if (File.Exists(filename)) { UpdateFileLastAccessTime(filename); + assetsFound[assetID] = true; } else if (storeUncached) { @@ -820,7 +854,14 @@ namespace OpenSim.Region.CoreModules.Asset } gatherer.GatheredUuids.Clear(); + if(!m_Running && !storeUncached) + return; + + if(!storeUncached) + Thread.Sleep(50); }); + if(!m_Running && !storeUncached) + break; } return assetsFound.Count; @@ -982,7 +1023,27 @@ namespace OpenSim.Region.CoreModules.Asset WorkManager.RunInThread(delegate { + bool wasRunning= false; + lock(timerLock) + { + if(m_Running) + { + m_CacheCleanTimer.Stop(); + m_Running = false; + wasRunning = true; + Thread.Sleep(100); + } + } int assetReferenceTotal = TouchAllSceneAssets(true); + GC.Collect(); + lock(timerLock) + { + if(wasRunning) + { + m_CacheCleanTimer.Start(); + m_Running = true; + } + } con.OutputFormat("Completed check with {0} assets.", assetReferenceTotal); }, null, "TouchAllSceneAssets"); diff --git a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs index b1234fec28..d1fe3c7c2f 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs @@ -188,7 +188,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap //m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions", mapName, regionInfos.Count); MapBlockData data; - if (regionInfos.Count > 0) + if (regionInfos != null && regionInfos.Count > 0) { foreach (GridRegion info in regionInfos) { @@ -205,7 +205,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap } // final block, closing the search result - AddFinalBlock(blocks,mapNameOrig); + AddFinalBlock(blocks,mapNameOrig); // flags are agent flags sent from the viewer. // they have different values depending on different viewers, apparently diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 80bb461746..9c8d40a8a6 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -13792,6 +13792,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case ScriptBaseClass.OBJECT_GROUP_TAG: ret.Add(new LSL_String(av.Grouptitle)); break; + case ScriptBaseClass.OBJECT_TEMP_ATTACHED: + ret.Add(new LSL_Integer(0)); + break; default: // Invalid or unhandled constant. ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); @@ -13984,6 +13987,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case ScriptBaseClass.OBJECT_GROUP_TAG: ret.Add(new LSL_String(String.Empty)); break; + case ScriptBaseClass.OBJECT_TEMP_ATTACHED: + if (obj.ParentGroup.AttachmentPoint != 0 && obj.ParentGroup.FromItemID == UUID.Zero) + { + ret.Add(new LSL_Integer(1)); + } + else + { + ret.Add(new LSL_Integer(0)); + } + break; default: // Invalid or unhandled constant. ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs index 17173a2444..48afcc03e1 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs @@ -641,6 +641,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int OBJECT_PRIM_COUNT = 30; public const int OBJECT_TOTAL_INVENTORY_COUNT = 31; public const int OBJECT_GROUP_TAG = 33; + public const int OBJECT_TEMP_ATTACHED = 34; // Pathfinding types public const int OPT_OTHER = -1; diff --git a/OpenSim/Services/GridService/GridService.cs b/OpenSim/Services/GridService/GridService.cs index 66c918f9e3..31a186ab3c 100644 --- a/OpenSim/Services/GridService/GridService.cs +++ b/OpenSim/Services/GridService/GridService.cs @@ -202,10 +202,24 @@ namespace OpenSim.Services.GridService if (regionInfos.RegionID == UUID.Zero) return "Invalid RegionID - cannot be zero UUID"; - String reason = "Region overlaps another region"; - // we should not need to check for overlaps + String reason = "Region overlaps another region"; + + List rdatas = m_Database.Get( + regionInfos.RegionLocX, + regionInfos.RegionLocY, + regionInfos.RegionLocX + regionInfos.RegionSizeX - 1, + regionInfos.RegionLocY + regionInfos.RegionSizeY - 1 , + scopeID); + + RegionData region = null; + if(rdatas.Count > 1) + { + m_log.WarnFormat("{0} Register region overlaps with {1} regions", LogHeader, scopeID, rdatas.Count); + return reason; + } + else if(rdatas.Count == 1) + region = rdatas[0]; - RegionData region = m_Database.Get(regionInfos.RegionLocX, regionInfos.RegionLocY, scopeID); if ((region != null) && (region.RegionID != regionInfos.RegionID)) { // If not same ID and same coordinates, this new region has conflicts and can't be registered. @@ -341,99 +355,7 @@ namespace OpenSim.Services.GridService return String.Empty; } -/* - /// - /// Search the region map for regions conflicting with this region. - /// The region to be added is passed and we look for any existing regions that are - /// in the requested location, that are large varregions that overlap this region, or - /// are previously defined regions that would lie under this new region. - /// - /// Information on region requested to be added to the world map - /// Grid id for region - /// The reason the returned region conflicts with passed region - /// - private RegionData FindAnyConflictingRegion(GridRegion regionInfos, UUID scopeID, out string reason) - { - reason = "Reregistration"; - // First see if there is an existing region right where this region is trying to go - // (We keep this result so it can be returned if suppressing errors) - RegionData noErrorRegion = m_Database.Get(regionInfos.RegionLocX, regionInfos.RegionLocY, scopeID); - RegionData region = noErrorRegion; - if (region != null - && region.RegionID == regionInfos.RegionID - && region.sizeX == regionInfos.RegionSizeX - && region.sizeY == regionInfos.RegionSizeY) - { - // If this seems to be exactly the same region, return this as it could be - // a re-registration (permissions checked by calling routine). - m_log.DebugFormat("{0} FindAnyConflictingRegion: re-register of {1}", - LogHeader, RegionString(regionInfos)); - return region; - } - // No region exactly there or we're resizing an existing region. - // Fetch regions that could be varregions overlapping requested location. - int xmin = regionInfos.RegionLocX - (int)Constants.MaximumRegionSize + 10; - int xmax = regionInfos.RegionLocX; - int ymin = regionInfos.RegionLocY - (int)Constants.MaximumRegionSize + 10; - int ymax = regionInfos.RegionLocY; - List rdatas = m_Database.Get(xmin, ymin, xmax, ymax, scopeID); - foreach (RegionData rdata in rdatas) - { - // m_log.DebugFormat("{0} FindAnyConflictingRegion: find existing. Checking {1}", LogHeader, RegionString(rdata) ); - if ( (rdata.posX + rdata.sizeX > regionInfos.RegionLocX) - && (rdata.posY + rdata.sizeY > regionInfos.RegionLocY) ) - { - region = rdata; - m_log.WarnFormat("{0} FindAnyConflictingRegion: conflict of {1} by existing varregion {2}", - LogHeader, RegionString(regionInfos), RegionString(region)); - reason = String.Format("Region location is overlapped by existing varregion {0}", - RegionString(region)); - - if (m_SuppressVarregionOverlapCheckOnRegistration) - region = noErrorRegion; - return region; - } - } - - // There isn't a region that overlaps this potential region. - // See if this potential region overlaps an existing region. - // First, a shortcut of not looking for overlap if new region is legacy region sized - // and connot overlap anything. - if (regionInfos.RegionSizeX != Constants.RegionSize - || regionInfos.RegionSizeY != Constants.RegionSize) - { - // trim range looked for so we don't pick up neighbor regions just off the edges - xmin = regionInfos.RegionLocX; - xmax = regionInfos.RegionLocX + regionInfos.RegionSizeX - 10; - ymin = regionInfos.RegionLocY; - ymax = regionInfos.RegionLocY + regionInfos.RegionSizeY - 10; - rdatas = m_Database.Get(xmin, ymin, xmax, ymax, scopeID); - - // If the region is being resized, the found region could be ourself. - foreach (RegionData rdata in rdatas) - { - // m_log.DebugFormat("{0} FindAnyConflictingRegion: see if overlap. Checking {1}", LogHeader, RegionString(rdata) ); - if (region == null || region.RegionID != regionInfos.RegionID) - { - region = rdata; - m_log.WarnFormat("{0} FindAnyConflictingRegion: conflict of varregion {1} overlaps existing region {2}", - LogHeader, RegionString(regionInfos), RegionString(region)); - reason = String.Format("Region {0} would overlap existing region {1}", - RegionString(regionInfos), RegionString(region)); - - if (m_SuppressVarregionOverlapCheckOnRegistration) - region = noErrorRegion; - return region; - } - } - } - - // If we get here, region is either null (nothing found here) or - // is the non-conflicting region found at the location being requested. - return region; - } -*/ // String describing name and region location of passed region private String RegionString(RegionData reg) { diff --git a/bin/config-include/FlotsamCache.ini.example b/bin/config-include/FlotsamCache.ini.example index ad74fc14e9..db8d4db01a 100644 --- a/bin/config-include/FlotsamCache.ini.example +++ b/bin/config-include/FlotsamCache.ini.example @@ -36,7 +36,7 @@ ; How often {in hours} should the disk be checked for expired filed ; Specify 0 to disable expiration checking - FileCleanupTimer = 1.0 ;every hour + FileCleanupTimer = 0.0 ; disabled ; If WAIT_ON_INPROGRESS_REQUESTS has been defined then this specifies how ; long (in miliseconds) to block a request thread while trying to complete