From 7cf2e812233d767b5a3573b74792aa28d6d91988 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 29 Dec 2016 00:47:02 +0000 Subject: [PATCH 01/10] reinforce gc.collect on region load to also do pending finalizers --- OpenSim/Region/Framework/Scenes/Scene.cs | 11 +++++------ .../Scripting/RegionReadyModule/RegionReadyModule.cs | 4 ++++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index e44f11a54e..d7a4ca46aa 100755 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -1581,6 +1581,8 @@ namespace OpenSim.Region.Framework.Scenes m_heartbeatThread = null; } + GC.Collect(); + GC.WaitForPendingFinalizers(); GC.Collect(); // tell physics to finish building actor m_sceneGraph.ProcessPhysicsPreSimulation(); @@ -1856,13 +1858,9 @@ namespace OpenSim.Region.Framework.Scenes if (!LoginsEnabled && Frame == 20) { - // m_log.DebugFormat("{0} {1} {2}", LoginsDisabled, m_sceneGraph.GetActiveScriptsCount(), LoginLock); - - // In 99.9% of cases it is a bad idea to manually force garbage collection. However, - // this is a rare case where we know we have just went through a long cycle of heap - // allocations, and there is no more work to be done until someone logs in GC.Collect(); - + GC.WaitForPendingFinalizers(); + GC.Collect(); if (!LoginLock) { if (!StartDisabled) @@ -1887,6 +1885,7 @@ namespace OpenSim.Region.Framework.Scenes // LoginLock can currently only be set by a region module implementation. // If somehow this hasn't been done then the quickest way to bugfix is to see the // NullReferenceException + IRegionReadyModule rrm = RequestModuleInterface(); rrm.TriggerRegionReady(this); } diff --git a/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs b/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs index 870c0bbce9..1725eb4f0c 100644 --- a/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs @@ -214,6 +214,10 @@ namespace OpenSim.Region.OptionalModules.Scripting.RegionReady m_scene.EventManager.OnEmptyScriptCompileQueue -= OnEmptyScriptCompileQueue; m_scene.LoginLock = false; + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.Collect(); + if (!m_scene.StartDisabled) { m_scene.LoginsEnabled = true; From 1ffcc5981803bd2adb8178daa0e34c353a2ca824 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 29 Dec 2016 03:10:10 +0000 Subject: [PATCH 02/10] gc is also a unwanted cache, so use it. With this, memcache with short expires is no longer needed --- .../CoreModules/Asset/FlotsamAssetCache.cs | 83 ++++++++++++++++--- bin/config-include/FlotsamCache.ini.example | 4 +- 2 files changed, 73 insertions(+), 14 deletions(-) diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index b6dd5652c7..7bb88b9af6 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -78,6 +78,7 @@ namespace OpenSim.Region.CoreModules.Asset private static ulong m_RequestsForInprogress; private static ulong m_DiskHits; private static ulong m_MemoryHits; + private static ulong m_weakRefHits; #if WAIT_ON_INPROGRESS_REQUESTS private Dictionary m_CurrentlyWriting = new Dictionary(); @@ -92,7 +93,7 @@ namespace OpenSim.Region.CoreModules.Asset private bool m_MemoryCacheEnabled = false; // Expiration is expressed in hours. - private double m_MemoryExpiration = 0.001; + private double m_MemoryExpiration = 0.016; private const double m_DefaultFileExpiration = 48; private TimeSpan m_FileExpiration = TimeSpan.FromHours(m_DefaultFileExpiration); private TimeSpan m_FileExpirationCleanupTimer = TimeSpan.FromHours(1.0); @@ -107,6 +108,9 @@ namespace OpenSim.Region.CoreModules.Asset private List m_Scenes = new List(); private object timerLock = new object(); + private Dictionary weakAssetReferences = new Dictionary(); + private object weakAssetReferencesLock = new object(); + public FlotsamAssetCache() { m_InvalidChars.AddRange(Path.GetInvalidPathChars()); @@ -255,12 +259,23 @@ namespace OpenSim.Region.CoreModules.Asset } } } + if (m_MemoryCacheEnabled) + m_MemoryCache = new ExpiringCache(); + + lock(weakAssetReferencesLock) + weakAssetReferences = new Dictionary(); } } //////////////////////////////////////////////////////////// // IImprovedAssetCache // + private void UpdateWeakReference(string key, AssetBase asset) + { + WeakReference aref = new WeakReference(asset); + lock(weakAssetReferencesLock) + weakAssetReferences[key] = aref; + } private void UpdateMemoryCache(string key, AssetBase asset) { @@ -327,6 +342,7 @@ namespace OpenSim.Region.CoreModules.Asset if (asset != null) { //m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Caching asset with id {0}", asset.ID); + UpdateWeakReference(asset.ID, asset); if (m_MemoryCacheEnabled) UpdateMemoryCache(asset.ID, asset); @@ -354,6 +370,25 @@ namespace OpenSim.Region.CoreModules.Asset } } + private AssetBase GetFromWeakReference(string id) + { + AssetBase asset = null; + WeakReference aref; + + lock(weakAssetReferencesLock) + { + if (weakAssetReferences.TryGetValue(id, out aref)) + { + asset = aref.Target as AssetBase; + if(asset == null) + weakAssetReferences.Remove(id); + else + m_weakRefHits++; + } + } + return asset; + } + /// /// Try to get an asset from the in-memory cache. /// @@ -477,12 +512,21 @@ namespace OpenSim.Region.CoreModules.Asset m_Requests++; AssetBase asset = null; + asset = GetFromWeakReference(id); - if (m_MemoryCacheEnabled) + if (m_MemoryCacheEnabled && asset == null) + { asset = GetFromMemoryCache(id); + if(asset != null) + UpdateWeakReference(id,asset); + } if (asset == null && m_FileCacheEnabled) + { asset = GetFromFileCache(id); + if(asset != null) + UpdateWeakReference(id,asset); + } if (m_MemoryCacheEnabled && asset != null) UpdateMemoryCache(id, asset); @@ -494,6 +538,12 @@ namespace OpenSim.Region.CoreModules.Asset GenerateCacheHitReport().ForEach(l => m_log.InfoFormat("[FLOTSAM ASSET CACHE]: {0}", l)); } + if(asset == null) + { + + + } + return asset; } @@ -553,7 +603,10 @@ namespace OpenSim.Region.CoreModules.Asset } if (m_MemoryCacheEnabled) - m_MemoryCache.Clear(); + m_MemoryCache = new ExpiringCache(); + + lock(weakAssetReferencesLock) + weakAssetReferences = new Dictionary(); } private void CleanupExpiredFiles(object source, ElapsedEventArgs e) @@ -911,28 +964,34 @@ namespace OpenSim.Region.CoreModules.Asset List outputLines = new List(); double invReq = 100.0 / m_Requests; + + double weakHitRate = m_weakRefHits * invReq; + int weakEntries = weakAssetReferences.Count; double fileHitRate = m_DiskHits * invReq; + double TotalHitRate = weakHitRate + fileHitRate; + outputLines.Add( - string.Format("File Hit Rate: {0}% for {1} requests", fileHitRate.ToString("0.00"), m_Requests)); + string.Format("Total requests: {0}", m_Requests)); + outputLines.Add( + string.Format("unCollected Hit Rate: {0}% ({1} entries)", weakHitRate.ToString("0.00"),weakEntries)); + outputLines.Add( + string.Format("File Hit Rate: {0}%", fileHitRate.ToString("0.00"))); if (m_MemoryCacheEnabled) { double HitRate = m_MemoryHits * invReq; - outputLines.Add( - string.Format("Memory Hit Rate: {0}% for {1} requests", HitRate.ToString("0.00"), m_Requests)); + string.Format("Memory Hit Rate: {0}%", HitRate.ToString("0.00"))); - HitRate += fileHitRate; - - outputLines.Add( - string.Format("Total Hit Rate: {0}% for {1} requests", HitRate.ToString("0.00"), m_Requests)); + TotalHitRate += HitRate; } + outputLines.Add( + string.Format("Total Hit Rate: {0}%", TotalHitRate.ToString("0.00"))); outputLines.Add( string.Format( - "Unnecessary requests due to requests for assets that are currently downloading: {0}", - m_RequestsForInprogress)); + "Requests overlap during file writing: {0}", m_RequestsForInprogress)); return outputLines; } diff --git a/bin/config-include/FlotsamCache.ini.example b/bin/config-include/FlotsamCache.ini.example index c0d743093b..917ea4607c 100644 --- a/bin/config-include/FlotsamCache.ini.example +++ b/bin/config-include/FlotsamCache.ini.example @@ -22,7 +22,7 @@ ; Set to false for no memory cache ; assets can be requested several times in short periods ; so even a small memory cache is useful - MemoryCacheEnabled = true + MemoryCacheEnabled = false ; Set to false for no file cache FileCacheEnabled = true @@ -32,7 +32,7 @@ ; this is good if memory is not a problem. ; if memory is a problem then a few seconds may actually save same. ; see hit rates with console comand: fcache status - MemoryCacheTimeout = .001 ; 3.6s ie around 4s (1s resolution) + MemoryCacheTimeout = .016 // one minute ; How long {in hours} to keep assets cached on disk, .5 == 30 minutes ; Specify 0 if you do not want your disk cache to expire From 3a310d77c88f4ddd8e564a98ef7c46665999c3a6 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 29 Dec 2016 03:12:50 +0000 Subject: [PATCH 03/10] forgot one gc.collect wait for finalizers --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index a69b670cd7..55050d9de4 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -621,7 +621,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP GroupsInView.Clear(); if(m_scene.GetNumberOfClients() == 0) - GC.Collect(); + { + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.Collect(); + } } public void Kick(string message) From c78da183b233f80ba436f677ecbbe32a477bd676 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 29 Dec 2016 03:25:12 +0000 Subject: [PATCH 04/10] expire also from weak references --- OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index 7bb88b9af6..e7f498130a 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -580,6 +580,9 @@ namespace OpenSim.Region.CoreModules.Asset if (m_MemoryCacheEnabled) m_MemoryCache.Remove(id); + + lock(weakAssetReferencesLock) + weakAssetReferences.Remove(id); } catch (Exception e) { From feca9fd15385a5e2df27b5a3cc4ea3253be00909 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Thu, 29 Dec 2016 11:53:38 +0000 Subject: [PATCH 05/10] Add an option to update the file access time even when an asset is found in cache. When the cache is shared between multiple sims, it is often more efficient to have a single expire job run from cron. Updating file access times is vital to the functioning of such setups. --- .../Region/CoreModules/Asset/FlotsamAssetCache.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index e7f498130a..5400c91d6b 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -110,6 +110,7 @@ namespace OpenSim.Region.CoreModules.Asset private Dictionary weakAssetReferences = new Dictionary(); private object weakAssetReferencesLock = new object(); + private bool m_updateFileTimeOnCacheHit = false; public FlotsamAssetCache() { @@ -156,6 +157,8 @@ namespace OpenSim.Region.CoreModules.Asset m_MemoryCacheEnabled = assetConfig.GetBoolean("MemoryCacheEnabled", m_MemoryCacheEnabled); m_MemoryExpiration = assetConfig.GetDouble("MemoryCacheTimeout", m_MemoryExpiration); m_MemoryExpiration *= 3600.0; // config in hours to seconds + + m_updateFileTimeOnCacheHit = assetConfig.GetBoolean("UpdateFileTimeOnCacheHit", m_updateFileTimeOnCacheHit); #if WAIT_ON_INPROGRESS_REQUESTS m_WaitOnInprogressTimeout = assetConfig.GetInt("WaitOnInprogressTimeout", 3000); @@ -513,12 +516,24 @@ namespace OpenSim.Region.CoreModules.Asset AssetBase asset = null; asset = GetFromWeakReference(id); + if (asset != null && m_updateFileTimeOnCacheHit) + { + string filename = GetFileName(id); + UpdateFileLastAccessTime(filename); + } if (m_MemoryCacheEnabled && asset == null) { asset = GetFromMemoryCache(id); if(asset != null) + { UpdateWeakReference(id,asset); + if (m_updateFileTimeOnCacheHit) + { + string filename = GetFileName(id); + UpdateFileLastAccessTime(filename); + } + } } if (asset == null && m_FileCacheEnabled) From f021c64eb060046bff6e91384e1bbca0384b7d61 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Thu, 29 Dec 2016 12:34:09 +0000 Subject: [PATCH 06/10] Refactor: Rename IImprovedAssetCache to IAssetCache as the old IAssetCache is long gone. --- OpenSim/Framework/IImprovedAssetCache.cs | 4 ++-- OpenSim/Framework/WearableCacheItem.cs | 4 ++-- .../CoreModules/Agent/TextureSender/J2KDecoderModule.cs | 6 +++--- OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs | 6 +++--- OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs | 6 +++--- OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs | 8 ++++---- OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs | 6 +++--- .../Avatar/AvatarFactory/AvatarFactoryModule.cs | 4 ++-- .../CoreModules/Avatar/UserProfiles/UserProfileModule.cs | 4 ++-- .../ServiceConnectorsOut/Asset/HGAssetBroker.cs | 4 ++-- .../Asset/LocalAssetServiceConnector.cs | 4 ++-- .../Asset/RemoteAssetServiceConnector.cs | 4 ++-- .../Region/OptionalModules/Materials/MaterialsModule.cs | 4 ++-- .../Services/Connectors/Asset/AssetServicesConnector.cs | 4 ++-- .../Connectors/SimianGrid/SimianAssetServiceConnector.cs | 4 ++-- 15 files changed, 36 insertions(+), 36 deletions(-) diff --git a/OpenSim/Framework/IImprovedAssetCache.cs b/OpenSim/Framework/IImprovedAssetCache.cs index a853e9015d..855b86b15a 100644 --- a/OpenSim/Framework/IImprovedAssetCache.cs +++ b/OpenSim/Framework/IImprovedAssetCache.cs @@ -29,7 +29,7 @@ using OpenSim.Framework; namespace OpenSim.Framework { - public interface IImprovedAssetCache + public interface IAssetCache { /// /// Cache the specified asset. @@ -61,4 +61,4 @@ namespace OpenSim.Framework /// void Clear(); } -} \ No newline at end of file +} diff --git a/OpenSim/Framework/WearableCacheItem.cs b/OpenSim/Framework/WearableCacheItem.cs index af28abc74c..966a6bc290 100644 --- a/OpenSim/Framework/WearableCacheItem.cs +++ b/OpenSim/Framework/WearableCacheItem.cs @@ -50,7 +50,7 @@ namespace OpenSim.Framework return retitems; } - public static WearableCacheItem[] FromOSD(OSD pInput, IImprovedAssetCache dataCache) + public static WearableCacheItem[] FromOSD(OSD pInput, IAssetCache dataCache) { List ret = new List(); if (pInput.Type == OSDType.Array) @@ -100,7 +100,7 @@ namespace OpenSim.Framework } - public static OSD ToOSD(WearableCacheItem[] pcacheItems, IImprovedAssetCache dataCache) + public static OSD ToOSD(WearableCacheItem[] pcacheItems, IAssetCache dataCache) { OSDArray arr = new OSDArray(); foreach (WearableCacheItem item in pcacheItems) diff --git a/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs b/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs index 47dcbcd3ff..6d1f0c2ab1 100644 --- a/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs +++ b/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs @@ -57,13 +57,13 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender /// List of client methods to notify of results of decode private readonly Dictionary> m_notifyList = new Dictionary>(); /// Cache that will store decoded JPEG2000 layer boundary data - private IImprovedAssetCache m_cache; - private IImprovedAssetCache Cache + private IAssetCache m_cache; + private IAssetCache Cache { get { if (m_cache == null) - m_cache = m_scene.RequestModuleInterface(); + m_cache = m_scene.RequestModuleInterface(); return m_cache; } diff --git a/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs b/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs index ebec9d2d74..382b5f2821 100644 --- a/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs @@ -91,7 +91,7 @@ namespace OpenSim.Region.CoreModules.Asset /// /// [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "CenomeMemoryAssetCache")] - public class CenomeMemoryAssetCache : IImprovedAssetCache, ISharedRegionModule + public class CenomeMemoryAssetCache : IAssetCache, ISharedRegionModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -192,7 +192,7 @@ namespace OpenSim.Region.CoreModules.Asset expirationTime); } - #region IImprovedAssetCache Members + #region IAssetCache Members public bool Check(string id) { @@ -308,7 +308,7 @@ namespace OpenSim.Region.CoreModules.Asset public void AddRegion(Scene scene) { if (m_enabled) - scene.RegisterModuleInterface(this); + scene.RegisterModuleInterface(this); } /// diff --git a/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs b/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs index f72074851e..d78b082366 100644 --- a/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs @@ -40,7 +40,7 @@ using OpenSim.Services.Interfaces; namespace OpenSim.Region.CoreModules.Asset { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "CoreAssetCache")] - public class CoreAssetCache : ISharedRegionModule, IImprovedAssetCache + public class CoreAssetCache : ISharedRegionModule, IAssetCache { private static readonly ILog m_log = LogManager.GetLogger( @@ -98,7 +98,7 @@ namespace OpenSim.Region.CoreModules.Asset public void AddRegion(Scene scene) { if (m_Enabled) - scene.RegisterModuleInterface(this); + scene.RegisterModuleInterface(this); } public void RemoveRegion(Scene scene) @@ -110,7 +110,7 @@ namespace OpenSim.Region.CoreModules.Asset } //////////////////////////////////////////////////////////// - // IImprovedAssetCache + // IAssetCache // public bool Check(string id) { diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index 5400c91d6b..fcd42524d2 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -55,7 +55,7 @@ using OpenSim.Services.Interfaces; namespace OpenSim.Region.CoreModules.Asset { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "FlotsamAssetCache")] - public class FlotsamAssetCache : ISharedRegionModule, IImprovedAssetCache, IAssetService + public class FlotsamAssetCache : ISharedRegionModule, IAssetCache, IAssetService { private static readonly ILog m_log = LogManager.GetLogger( @@ -219,7 +219,7 @@ namespace OpenSim.Region.CoreModules.Asset { if (m_Enabled) { - scene.RegisterModuleInterface(this); + scene.RegisterModuleInterface(this); m_Scenes.Add(scene); } } @@ -228,7 +228,7 @@ namespace OpenSim.Region.CoreModules.Asset { if (m_Enabled) { - scene.UnregisterModuleInterface(this); + scene.UnregisterModuleInterface(this); m_Scenes.Remove(scene); lock(timerLock) { @@ -271,7 +271,7 @@ namespace OpenSim.Region.CoreModules.Asset } //////////////////////////////////////////////////////////// - // IImprovedAssetCache + // IAssetCache // private void UpdateWeakReference(string key, AssetBase asset) { diff --git a/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs b/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs index 5f76ac2c9e..7343f4fbb8 100644 --- a/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs @@ -41,7 +41,7 @@ using OpenSim.Services.Interfaces; namespace OpenSim.Region.CoreModules.Asset { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GlynnTuckerAssetCache")] - public class GlynnTuckerAssetCache : ISharedRegionModule, IImprovedAssetCache + public class GlynnTuckerAssetCache : ISharedRegionModule, IAssetCache { private static readonly ILog m_log = LogManager.GetLogger( @@ -100,7 +100,7 @@ namespace OpenSim.Region.CoreModules.Asset public void AddRegion(Scene scene) { if (m_Enabled) - scene.RegisterModuleInterface(this); + scene.RegisterModuleInterface(this); } public void RemoveRegion(Scene scene) @@ -112,7 +112,7 @@ namespace OpenSim.Region.CoreModules.Asset } //////////////////////////////////////////////////////////// - // IImprovedAssetCache + // IAssetCache // public bool Check(string id) diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs index 41a3f5239e..67256ee685 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs @@ -288,7 +288,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory if (bakedTextures.Count == 0) return false; - IImprovedAssetCache cache = sp.Scene.RequestModuleInterface(); + IAssetCache cache = sp.Scene.RequestModuleInterface(); if(cache == null) return true; // no baked local caching so nothing to do @@ -705,7 +705,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory return 0; int texturesRebaked = 0; -// IImprovedAssetCache cache = m_scene.RequestModuleInterface(); +// IAssetCache cache = m_scene.RequestModuleInterface(); for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++) { diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index 3f7a8ee7a9..df5265cbe8 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -69,7 +69,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles Dictionary m_classifiedCache = new Dictionary(); Dictionary m_classifiedInterest = new Dictionary(); ExpiringCache m_profilesCache = new ExpiringCache(); - IImprovedAssetCache m_assetCache; + IAssetCache m_assetCache; private JsonRpcRequestManager rpc = new JsonRpcRequestManager(); private bool m_allowUserProfileWebURLs = true; @@ -221,7 +221,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles { if(!Enabled) return; - m_assetCache = Scene.RequestModuleInterface(); + m_assetCache = Scene.RequestModuleInterface(); } /// diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs index 9eb41f94f6..31d112925f 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs @@ -48,7 +48,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); - private IImprovedAssetCache m_Cache = null; + private IAssetCache m_Cache = null; private IAssetService m_GridService; private IAssetService m_HGService; @@ -176,7 +176,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset if (m_Cache == null) { - m_Cache = scene.RequestModuleInterface(); + m_Cache = scene.RequestModuleInterface(); if (!(m_Cache is ISharedRegionModule)) m_Cache = null; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs index 5f3445068b..d5d6667504 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs @@ -44,7 +44,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private IImprovedAssetCache m_Cache = null; + private IAssetCache m_Cache = null; private IAssetService m_AssetService; @@ -128,7 +128,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset if (m_Cache == null) { - m_Cache = scene.RequestModuleInterface(); + m_Cache = scene.RequestModuleInterface(); if (!(m_Cache is ISharedRegionModule)) m_Cache = null; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/RemoteAssetServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/RemoteAssetServiceConnector.cs index e6eeacfaf6..ff04f9d66e 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/RemoteAssetServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/RemoteAssetServiceConnector.cs @@ -48,7 +48,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset MethodBase.GetCurrentMethod().DeclaringType); private bool m_Enabled = false; - private IImprovedAssetCache m_Cache; + private IAssetCache m_Cache; public Type ReplaceableInterface { @@ -111,7 +111,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset if (m_Cache == null) { - m_Cache = scene.RequestModuleInterface(); + m_Cache = scene.RequestModuleInterface(); // Since we are a shared module and scene data is not // available for every method, the cache must be shared, too diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs index 7312bc39a8..b259f52f8f 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs @@ -63,7 +63,7 @@ namespace OpenSim.Region.OptionalModules.Materials public Type ReplaceableInterface { get { return null; } } - IImprovedAssetCache m_cache; + IAssetCache m_cache; private Scene m_scene = null; private bool m_enabled = false; private int m_maxMaterialsPerTransaction = 50; @@ -207,7 +207,7 @@ namespace OpenSim.Region.OptionalModules.Materials { if (!m_enabled) return; - m_cache = scene.RequestModuleInterface(); + m_cache = scene.RequestModuleInterface(); ISimulatorFeaturesModule featuresModule = scene.RequestModuleInterface(); if (featuresModule != null) featuresModule.OnSimulatorFeaturesRequest += OnSimulatorFeaturesRequest; diff --git a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs index a6e8eb424b..b8449d7ce4 100644 --- a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs +++ b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs @@ -49,7 +49,7 @@ namespace OpenSim.Services.Connectors const int MAXSENDRETRIESLEN = 30; private string m_ServerURI = String.Empty; - private IImprovedAssetCache m_Cache = null; + private IAssetCache m_Cache = null; private int m_retryCounter; private bool m_inRetries; private List[] m_sendRetries = new List[MAXSENDRETRIESLEN]; @@ -233,7 +233,7 @@ namespace OpenSim.Services.Connectors } } - protected void SetCache(IImprovedAssetCache cache) + protected void SetCache(IAssetCache cache) { m_Cache = cache; } diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs index 9ad4a7a56f..531939f2cc 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs @@ -55,7 +55,7 @@ namespace OpenSim.Services.Connectors.SimianGrid private static string ZeroID = UUID.Zero.ToString(); private string m_serverUrl = String.Empty; - private IImprovedAssetCache m_cache; + private IAssetCache m_cache; private bool m_Enabled = false; #region ISharedRegionModule @@ -65,7 +65,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { if (m_cache == null) { - IImprovedAssetCache cache = scene.RequestModuleInterface(); + IAssetCache cache = scene.RequestModuleInterface(); if (cache is ISharedRegionModule) m_cache = cache; } From ec4c258794a9be8c5497b82173759e46e8c63cea Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Thu, 29 Dec 2016 12:36:13 +0000 Subject: [PATCH 07/10] Actually rename the file, too --- OpenSim/Framework/{IImprovedAssetCache.cs => IAssetCache.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename OpenSim/Framework/{IImprovedAssetCache.cs => IAssetCache.cs} (100%) diff --git a/OpenSim/Framework/IImprovedAssetCache.cs b/OpenSim/Framework/IAssetCache.cs similarity index 100% rename from OpenSim/Framework/IImprovedAssetCache.cs rename to OpenSim/Framework/IAssetCache.cs From 07b48fd58c343d18b8ce64179e344439070511e8 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Thu, 29 Dec 2016 15:47:46 +0000 Subject: [PATCH 08/10] Add negative caching to flotsam cache. Prevents scripts from hammering the asset server --- OpenSim/Framework/IAssetCache.cs | 6 +++ .../CoreModules/Asset/CenomeAssetCache.cs | 5 +++ .../CoreModules/Asset/CoreAssetCache.cs | 5 +++ .../CoreModules/Asset/FlotsamAssetCache.cs | 27 ++++++++++++++ .../Asset/GlynnTuckerAssetCache.cs | 5 +++ .../Asset/AssetServicesConnector.cs | 9 ++++- bin/config-include/FlotsamCache.ini.example | 37 +++++++++++++++++++ 7 files changed, 92 insertions(+), 2 deletions(-) diff --git a/OpenSim/Framework/IAssetCache.cs b/OpenSim/Framework/IAssetCache.cs index 855b86b15a..8477116403 100644 --- a/OpenSim/Framework/IAssetCache.cs +++ b/OpenSim/Framework/IAssetCache.cs @@ -38,6 +38,12 @@ namespace OpenSim.Framework void Cache(AssetBase asset); /// + /// Cache that the specified asset wasn't found. + /// + /// + /// + void CacheNegative(string id); + /// Get an asset by its id. /// /// diff --git a/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs b/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs index 382b5f2821..14b0280cd5 100644 --- a/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs @@ -221,6 +221,11 @@ namespace OpenSim.Region.CoreModules.Asset } + public void CacheNegative(string id) + { + // We don't do negative caching + } + /// /// Clear asset cache. /// diff --git a/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs b/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs index d78b082366..82bc5ccebb 100644 --- a/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs @@ -124,6 +124,11 @@ namespace OpenSim.Region.CoreModules.Asset m_Cache.Store(asset.ID, asset); } + public void CacheNegative(string id) + { + // We don't do negative caching + } + public AssetBase Get(string id) { return (AssetBase)m_Cache.Get(id); diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index fcd42524d2..84e13a0d9d 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -92,9 +92,15 @@ namespace OpenSim.Region.CoreModules.Asset private ExpiringCache m_MemoryCache; private bool m_MemoryCacheEnabled = false; + private ExpiringCache m_negativeCache; + private bool m_negativeCacheEnabled = true; + private bool m_negativeCacheSliding = false; + // Expiration is expressed in hours. private double m_MemoryExpiration = 0.016; private const double m_DefaultFileExpiration = 48; + // Negative cache is in seconds + private int m_negativeExpiration = 120; private TimeSpan m_FileExpiration = TimeSpan.FromHours(m_DefaultFileExpiration); private TimeSpan m_FileExpirationCleanupTimer = TimeSpan.FromHours(1.0); @@ -139,6 +145,7 @@ namespace OpenSim.Region.CoreModules.Asset if (name == Name) { m_MemoryCache = new ExpiringCache(); + m_negativeCache = new ExpiringCache(); m_Enabled = true; m_log.InfoFormat("[FLOTSAM ASSET CACHE]: {0} enabled", this.Name); @@ -158,6 +165,9 @@ namespace OpenSim.Region.CoreModules.Asset m_MemoryExpiration = assetConfig.GetDouble("MemoryCacheTimeout", m_MemoryExpiration); m_MemoryExpiration *= 3600.0; // config in hours to seconds + m_negativeCacheEnabled = assetConfig.GetBoolean("NegativeCacheEnabled", m_negativeCacheEnabled); + m_negativeExpiration = assetConfig.GetInt("NegativeCacheTimeout", m_negativeExpiration); + m_negativeCacheSliding = assetConfig.GetBoolean("NegativeCacheSliding", m_negativeCacheSliding); m_updateFileTimeOnCacheHit = assetConfig.GetBoolean("UpdateFileTimeOnCacheHit", m_updateFileTimeOnCacheHit); #if WAIT_ON_INPROGRESS_REQUESTS @@ -355,6 +365,17 @@ namespace OpenSim.Region.CoreModules.Asset } } + public void CacheNegative(string id) + { + if (m_negativeCacheEnabled) + { + if (m_negativeCacheSliding) + m_negativeCache.AddOrUpdate(id, null, TimeSpan.FromSeconds(m_negativeExpiration)); + else + m_negativeCache.AddOrUpdate(id, null, m_negativeExpiration); + } + } + /// /// Updates the cached file with the current time. /// @@ -514,6 +535,10 @@ namespace OpenSim.Region.CoreModules.Asset { m_Requests++; + object dummy; + if (m_negativeCache.TryGetValue(id, out dummy)) + return null; + AssetBase asset = null; asset = GetFromWeakReference(id); if (asset != null && m_updateFileTimeOnCacheHit) @@ -622,6 +647,8 @@ namespace OpenSim.Region.CoreModules.Asset if (m_MemoryCacheEnabled) m_MemoryCache = new ExpiringCache(); + if (m_negativeCacheEnabled) + m_negativeCache = new ExpiringCache(); lock(weakAssetReferencesLock) weakAssetReferences = new Dictionary(); diff --git a/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs b/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs index 7343f4fbb8..195bdaa43f 100644 --- a/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs @@ -126,6 +126,11 @@ namespace OpenSim.Region.CoreModules.Asset m_Cache.AddOrUpdate(asset.ID, asset); } + public void CacheNegative(string id) + { + // We don't do negative caching + } + public AssetBase Get(string id) { Object asset = null; diff --git a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs index b8449d7ce4..bdc3befb08 100644 --- a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs +++ b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs @@ -260,8 +260,13 @@ namespace OpenSim.Services.Connectors asset = SynchronousRestObjectRequester.MakeRequest("GET", uri, 0, m_Auth); - if (asset != null && m_Cache != null) - m_Cache.Cache(asset); + if (m_Cache != null) + { + if (asset != null) + m_Cache.Cache(asset); + else + m_Cache.CacheNegative(id); + } } return asset; } diff --git a/bin/config-include/FlotsamCache.ini.example b/bin/config-include/FlotsamCache.ini.example index 917ea4607c..2b5d37e0e0 100644 --- a/bin/config-include/FlotsamCache.ini.example +++ b/bin/config-include/FlotsamCache.ini.example @@ -24,6 +24,43 @@ ; so even a small memory cache is useful MemoryCacheEnabled = false + ; If a memory cache hit happens, or the asset is still in memory + ; due to other causes, update the timestamp on the disk file anyway. + ; Don't turn this on unless you share your asset cache between simulators + ; AND use an external process, e.g. cron job, to clean it up. + UpdateFileTimeOnCacheHit = false + + ; Enabling this will cache negative fetches. If an asset is negative-cached + ; it will not be re-requested from the asset server again for a while. + ; Generally, this is a good thing. + ; + ; Regular expiration settings (non-sliding) mean that the asset will be + ; retried after the time has expired. Sliding expiration means that + ; the time the negative cache will keep the asset is refreshed each + ; time a fetch is attempted. Use sliding expiration if you have rogue + ; scripts hammering the asset server with requests for nonexistent + ; assets. + ; + ; There are two cases where negative caching may cause issues: + ; + ; 1 - If an invalid asset is repeatedly requested by a script and that asset is + ; subsequently created, it will not be seen until fcache clear + ; is used. This is a very theoretical scenario since UUID collisions + ; are deemed to be not occuring in practice. + ; This can only become an issue with sliding expiration time. + ; + ; 2 - If the asset service is clustered, an asset may not have propagated + ; to all cluster members when it is first attempted to fetch it. + ; This may theoretically occur with networked vendor systems and + ; would lead to an asset not found message. However, after the + ; expiration time has elapsed, the asset will the be fetchable. + ; + ; The defaults below are suitable for all small to medium installations + ; including grids. + NegativeCacheEnabled = true + NegativeCacheTimeout = 120 + NegativeCacheSliding = false + ; Set to false for no file cache FileCacheEnabled = true From e0b5135010f2292f5c28232e874841b5ed92a559 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Thu, 29 Dec 2016 16:29:44 +0000 Subject: [PATCH 09/10] Add a MaxRetries option to the inventory connector. If clustered services are used, another try would go to another server and may succeed. --- .../Inventory/XInventoryServicesConnector.cs | 17 +++++++++++++++-- bin/config-include/GridCommon.ini.example | 1 + 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs b/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs index d80e660553..2ddd7a2f55 100644 --- a/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs +++ b/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs @@ -54,6 +54,8 @@ namespace OpenSim.Services.Connectors private string m_ServerURI = String.Empty; + private int m_maxRetries = 0; + /// /// Timeout for remote requests. /// @@ -100,6 +102,7 @@ namespace OpenSim.Services.Connectors m_ServerURI = serviceURI; m_requestTimeoutSecs = config.GetInt("RemoteRequestTimeout", m_requestTimeoutSecs); + m_maxRetries = config.GetInt("MaxRetries", m_maxRetries); StatsManager.RegisterStat( new Stat( @@ -700,10 +703,20 @@ namespace OpenSim.Services.Connectors RequestsMade++; - string reply - = SynchronousRestFormsRequester.MakeRequest( + string reply = String.Empty; + int retries = 0; + + do + { + reply = SynchronousRestFormsRequester.MakeRequest( "POST", m_ServerURI + "/xinventory", ServerUtils.BuildQueryString(sendData), m_requestTimeoutSecs, m_Auth); + + if (reply != String.Empty) + break; + + retries++; + } while (retries <= m_maxRetries); Dictionary replyData = ServerUtils.ParseXmlResponse( reply); diff --git a/bin/config-include/GridCommon.ini.example b/bin/config-include/GridCommon.ini.example index 0922cf5a4a..10a5b474d9 100644 --- a/bin/config-include/GridCommon.ini.example +++ b/bin/config-include/GridCommon.ini.example @@ -85,6 +85,7 @@ ; Change this to your grid-wide inventory server ; InventoryServerURI = "${Const|BaseURL}:${Const|PrivatePort}" + ;MaxRetries = 0 [GridInfo] ; From aee3f273f099c16a770ad4f3f4c9f1ee40227aef Mon Sep 17 00:00:00 2001 From: Mandarinka Tasty Date: Thu, 29 Dec 2016 23:20:33 +0100 Subject: [PATCH 10/10] Serving robots.txt from bin Idea of solution for http://opensimulator.org/mantis/view.php?id=7392 Signed-off-by: Mandarinka Tasty Signed-off-by: Melanie Thielker --- OpenSim/Region/Application/OpenSim.cs | 1 + OpenSim/Region/Application/OpenSimBase.cs | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 3cb999bee5..d9fdcde732 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -206,6 +206,7 @@ namespace OpenSim MainServer.Instance.AddStreamHandler(new OpenSim.XSimStatusHandler(this)); if (userStatsURI != String.Empty) MainServer.Instance.AddStreamHandler(new OpenSim.UXSimStatusHandler(this)); + MainServer.Instance.AddStreamHandler(new OpenSim.SimRobotsHandler()); if (managedStatsURI != String.Empty) { diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs index 52ded3d055..8499a90acd 100644 --- a/OpenSim/Region/Application/OpenSimBase.cs +++ b/OpenSim/Region/Application/OpenSimBase.cs @@ -876,6 +876,26 @@ namespace OpenSim } } + /// + /// handler to supply serving http://domainname:port/robots.txt + /// + public class SimRobotsHandler : BaseStreamHandler + { + public SimRobotsHandler() : base("GET", "/robots.txt", "SimRobots.txt", "Simulator Robots.txt") {} + + protected override byte[] ProcessRequest(string path, Stream request, + IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + string robots = "# go away\nUser-agent: *\nDisallow: /\n"; + return Util.UTF8.GetBytes(robots); + } + + public override string ContentType + { + get { return "text/plain"; } + } + } + #endregion ///