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