From 07b48fd58c343d18b8ce64179e344439070511e8 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Thu, 29 Dec 2016 15:47:46 +0000 Subject: [PATCH] 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