aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/Asset
diff options
context:
space:
mode:
authoronefang2019-05-19 21:24:15 +1000
committeronefang2019-05-19 21:24:15 +1000
commit5e4d6cab00cb29cd088ab7b62ab13aff103b64cb (patch)
treea9fbc62df9eb2d1d9ba2698d8552eae71eca20d8 /OpenSim/Region/CoreModules/Asset
parentAdd a build script. (diff)
downloadopensim-SC_OLD-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.zip
opensim-SC_OLD-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.tar.gz
opensim-SC_OLD-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.tar.bz2
opensim-SC_OLD-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.tar.xz
Dump OpenSim 0.9.0.1 into it's own branch.
Diffstat (limited to 'OpenSim/Region/CoreModules/Asset')
-rw-r--r--OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs38
-rw-r--r--OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs23
-rw-r--r--OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs371
-rw-r--r--OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs24
-rw-r--r--OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs2
5 files changed, 347 insertions, 111 deletions
diff --git a/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs b/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs
index ebec9d2..403236c 100644
--- a/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs
+++ b/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs
@@ -41,16 +41,16 @@ namespace OpenSim.Region.CoreModules.Asset
41 /// </summary> 41 /// </summary>
42 /// <remarks> 42 /// <remarks>
43 /// <para> 43 /// <para>
44 /// Cache is enabled by setting "AssetCaching" configuration to value "CenomeMemoryAssetCache". 44 /// Cache is enabled by setting "AssetCaching" configuration to value "CenomeMemoryAssetCache".
45 /// When cache is successfully enable log should have message 45 /// When cache is successfully enable log should have message
46 /// "[ASSET CACHE]: Cenome asset cache enabled (MaxSize = XXX bytes, MaxCount = XXX, ExpirationTime = XXX)". 46 /// "[ASSET CACHE]: Cenome asset cache enabled (MaxSize = XXX bytes, MaxCount = XXX, ExpirationTime = XXX)".
47 /// </para> 47 /// </para>
48 /// <para> 48 /// <para>
49 /// Cache's size is limited by two parameters: 49 /// Cache's size is limited by two parameters:
50 /// maximal allowed size in bytes and maximal allowed asset count. When new asset 50 /// maximal allowed size in bytes and maximal allowed asset count. When new asset
51 /// is added to cache that have achieved either size or count limitation, cache 51 /// is added to cache that have achieved either size or count limitation, cache
52 /// will automatically remove less recently used assets from cache. Additionally 52 /// will automatically remove less recently used assets from cache. Additionally
53 /// asset's lifetime is controlled by expiration time. 53 /// asset's lifetime is controlled by expiration time.
54 /// </para> 54 /// </para>
55 /// <para> 55 /// <para>
56 /// <list type="table"> 56 /// <list type="table">
@@ -91,10 +91,10 @@ namespace OpenSim.Region.CoreModules.Asset
91 /// </code> 91 /// </code>
92 /// </example> 92 /// </example>
93 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "CenomeMemoryAssetCache")] 93 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "CenomeMemoryAssetCache")]
94 public class CenomeMemoryAssetCache : IImprovedAssetCache, ISharedRegionModule 94 public class CenomeMemoryAssetCache : IAssetCache, ISharedRegionModule
95 { 95 {
96 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 96 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
97 97
98 /// <summary> 98 /// <summary>
99 /// Cache's default maximal asset count. 99 /// Cache's default maximal asset count.
100 /// </summary> 100 /// </summary>
@@ -119,7 +119,7 @@ namespace OpenSim.Region.CoreModules.Asset
119 /// Asset's default expiration time in the cache. 119 /// Asset's default expiration time in the cache.
120 /// </summary> 120 /// </summary>
121 public static readonly TimeSpan DefaultExpirationTime = TimeSpan.FromMinutes(30.0); 121 public static readonly TimeSpan DefaultExpirationTime = TimeSpan.FromMinutes(30.0);
122 122
123 /// <summary> 123 /// <summary>
124 /// Cache object. 124 /// Cache object.
125 /// </summary> 125 /// </summary>
@@ -192,7 +192,7 @@ namespace OpenSim.Region.CoreModules.Asset
192 expirationTime); 192 expirationTime);
193 } 193 }
194 194
195 #region IImprovedAssetCache Members 195 #region IAssetCache Members
196 196
197 public bool Check(string id) 197 public bool Check(string id)
198 { 198 {
@@ -213,7 +213,7 @@ namespace OpenSim.Region.CoreModules.Asset
213 if (asset != null) 213 if (asset != null)
214 { 214 {
215// m_log.DebugFormat("[CENOME ASSET CACHE]: Caching asset {0}", asset.ID); 215// m_log.DebugFormat("[CENOME ASSET CACHE]: Caching asset {0}", asset.ID);
216 216
217 long size = asset.Data != null ? asset.Data.Length : 1; 217 long size = asset.Data != null ? asset.Data.Length : 1;
218 m_cache.Set(asset.ID, asset, size); 218 m_cache.Set(asset.ID, asset, size);
219 m_cachedCount++; 219 m_cachedCount++;
@@ -221,6 +221,11 @@ namespace OpenSim.Region.CoreModules.Asset
221 221
222 } 222 }
223 223
224 public void CacheNegative(string id)
225 {
226 // We don't do negative caching
227 }
228
224 /// <summary> 229 /// <summary>
225 /// Clear asset cache. 230 /// Clear asset cache.
226 /// </summary> 231 /// </summary>
@@ -241,7 +246,7 @@ namespace OpenSim.Region.CoreModules.Asset
241 } 246 }
242 247
243 /// <summary> 248 /// <summary>
244 /// Get asset stored 249 /// Get asset stored
245 /// </summary> 250 /// </summary>
246 /// <param name="id"> 251 /// <param name="id">
247 /// The asset's id. 252 /// The asset's id.
@@ -255,10 +260,9 @@ namespace OpenSim.Region.CoreModules.Asset
255 /// Cache doesn't guarantee in any situation that asset is stored to it. 260 /// Cache doesn't guarantee in any situation that asset is stored to it.
256 /// </para> 261 /// </para>
257 /// </remarks> 262 /// </remarks>
258 public AssetBase Get(string id) 263 public bool Get(string id, out AssetBase assetBase)
259 { 264 {
260 m_getCount++; 265 m_getCount++;
261 AssetBase assetBase;
262 if (m_cache.TryGetValue(id, out assetBase)) 266 if (m_cache.TryGetValue(id, out assetBase))
263 m_hitCount++; 267 m_hitCount++;
264 268
@@ -278,8 +282,8 @@ namespace OpenSim.Region.CoreModules.Asset
278 282
279// if (null == assetBase) 283// if (null == assetBase)
280// m_log.DebugFormat("[CENOME ASSET CACHE]: Asset {0} not in cache", id); 284// m_log.DebugFormat("[CENOME ASSET CACHE]: Asset {0} not in cache", id);
281 285
282 return assetBase; 286 return true;
283 } 287 }
284 288
285 #endregion 289 #endregion
@@ -294,7 +298,7 @@ namespace OpenSim.Region.CoreModules.Asset
294 get { return "CenomeMemoryAssetCache"; } 298 get { return "CenomeMemoryAssetCache"; }
295 } 299 }
296 300
297 public Type ReplaceableInterface 301 public Type ReplaceableInterface
298 { 302 {
299 get { return null; } 303 get { return null; }
300 } 304 }
@@ -308,7 +312,7 @@ namespace OpenSim.Region.CoreModules.Asset
308 public void AddRegion(Scene scene) 312 public void AddRegion(Scene scene)
309 { 313 {
310 if (m_enabled) 314 if (m_enabled)
311 scene.RegisterModuleInterface<IImprovedAssetCache>(this); 315 scene.RegisterModuleInterface<IAssetCache>(this);
312 } 316 }
313 317
314 /// <summary> 318 /// <summary>
@@ -344,7 +348,7 @@ namespace OpenSim.Region.CoreModules.Asset
344 348
345 if (name != Name) 349 if (name != Name)
346 return; 350 return;
347 351
348 long maxSize = DefaultMaxSize; 352 long maxSize = DefaultMaxSize;
349 int maxCount = DefaultMaxCount; 353 int maxCount = DefaultMaxCount;
350 TimeSpan expirationTime = DefaultExpirationTime; 354 TimeSpan expirationTime = DefaultExpirationTime;
diff --git a/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs b/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs
index f720748..10c0e85 100644
--- a/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs
+++ b/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs
@@ -40,7 +40,7 @@ using OpenSim.Services.Interfaces;
40namespace OpenSim.Region.CoreModules.Asset 40namespace OpenSim.Region.CoreModules.Asset
41{ 41{
42 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "CoreAssetCache")] 42 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "CoreAssetCache")]
43 public class CoreAssetCache : ISharedRegionModule, IImprovedAssetCache 43 public class CoreAssetCache : ISharedRegionModule, IAssetCache
44 { 44 {
45 private static readonly ILog m_log = 45 private static readonly ILog m_log =
46 LogManager.GetLogger( 46 LogManager.GetLogger(
@@ -54,7 +54,7 @@ namespace OpenSim.Region.CoreModules.Asset
54 get { return "CoreAssetCache"; } 54 get { return "CoreAssetCache"; }
55 } 55 }
56 56
57 public Type ReplaceableInterface 57 public Type ReplaceableInterface
58 { 58 {
59 get { return null; } 59 get { return null; }
60 } 60 }
@@ -98,7 +98,7 @@ namespace OpenSim.Region.CoreModules.Asset
98 public void AddRegion(Scene scene) 98 public void AddRegion(Scene scene)
99 { 99 {
100 if (m_Enabled) 100 if (m_Enabled)
101 scene.RegisterModuleInterface<IImprovedAssetCache>(this); 101 scene.RegisterModuleInterface<IAssetCache>(this);
102 } 102 }
103 103
104 public void RemoveRegion(Scene scene) 104 public void RemoveRegion(Scene scene)
@@ -110,12 +110,15 @@ namespace OpenSim.Region.CoreModules.Asset
110 } 110 }
111 111
112 //////////////////////////////////////////////////////////// 112 ////////////////////////////////////////////////////////////
113 // IImprovedAssetCache 113 // IAssetCache
114 // 114 //
115 public bool Check(string id) 115 public bool Check(string id)
116 { 116 {
117 // XXX This is probably not an efficient implementation. 117 // XXX This is probably not an efficient implementation.
118 return Get(id) != null; 118 AssetBase asset;
119 if (!Get(id, out asset))
120 return false;
121 return asset != null;
119 } 122 }
120 123
121 public void Cache(AssetBase asset) 124 public void Cache(AssetBase asset)
@@ -124,9 +127,15 @@ namespace OpenSim.Region.CoreModules.Asset
124 m_Cache.Store(asset.ID, asset); 127 m_Cache.Store(asset.ID, asset);
125 } 128 }
126 129
127 public AssetBase Get(string id) 130 public void CacheNegative(string id)
128 { 131 {
129 return (AssetBase)m_Cache.Get(id); 132 // We don't do negative caching
133 }
134
135 public bool Get(string id, out AssetBase asset)
136 {
137 asset = (AssetBase)m_Cache.Get(id);
138 return true;
130 } 139 }
131 140
132 public void Expire(string id) 141 public void Expire(string id)
diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
index 17646fb..c1bf544 100644
--- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
+++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
@@ -25,7 +25,7 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28// Uncomment to make asset Get requests for existing 28// Uncomment to make asset Get requests for existing
29// #define WAIT_ON_INPROGRESS_REQUESTS 29// #define WAIT_ON_INPROGRESS_REQUESTS
30 30
31using System; 31using System;
@@ -55,16 +55,18 @@ using OpenSim.Services.Interfaces;
55namespace OpenSim.Region.CoreModules.Asset 55namespace OpenSim.Region.CoreModules.Asset
56{ 56{
57 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "FlotsamAssetCache")] 57 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "FlotsamAssetCache")]
58 public class FlotsamAssetCache : ISharedRegionModule, IImprovedAssetCache, IAssetService 58 public class FlotsamAssetCache : ISharedRegionModule, IAssetCache, IAssetService
59 { 59 {
60 private static readonly ILog m_log = 60 private static readonly ILog m_log =
61 LogManager.GetLogger( 61 LogManager.GetLogger(
62 MethodBase.GetCurrentMethod().DeclaringType); 62 MethodBase.GetCurrentMethod().DeclaringType);
63 63
64 private bool m_Enabled; 64 private bool m_Enabled;
65 private bool m_timerRunning;
66 private bool m_cleanupRunning;
65 67
66 private const string m_ModuleName = "FlotsamAssetCache"; 68 private const string m_ModuleName = "FlotsamAssetCache";
67 private const string m_DefaultCacheDirectory = "../caches/assetcache"; 69 private const string m_DefaultCacheDirectory = "./assetcache";
68 private string m_CacheDirectory = m_DefaultCacheDirectory; 70 private string m_CacheDirectory = m_DefaultCacheDirectory;
69 71
70 private readonly List<char> m_InvalidChars = new List<char>(); 72 private readonly List<char> m_InvalidChars = new List<char>();
@@ -76,6 +78,7 @@ namespace OpenSim.Region.CoreModules.Asset
76 private static ulong m_RequestsForInprogress; 78 private static ulong m_RequestsForInprogress;
77 private static ulong m_DiskHits; 79 private static ulong m_DiskHits;
78 private static ulong m_MemoryHits; 80 private static ulong m_MemoryHits;
81 private static ulong m_weakRefHits;
79 82
80#if WAIT_ON_INPROGRESS_REQUESTS 83#if WAIT_ON_INPROGRESS_REQUESTS
81 private Dictionary<string, ManualResetEvent> m_CurrentlyWriting = new Dictionary<string, ManualResetEvent>(); 84 private Dictionary<string, ManualResetEvent> m_CurrentlyWriting = new Dictionary<string, ManualResetEvent>();
@@ -89,12 +92,17 @@ namespace OpenSim.Region.CoreModules.Asset
89 private ExpiringCache<string, AssetBase> m_MemoryCache; 92 private ExpiringCache<string, AssetBase> m_MemoryCache;
90 private bool m_MemoryCacheEnabled = false; 93 private bool m_MemoryCacheEnabled = false;
91 94
95 private ExpiringCache<string, object> m_negativeCache;
96 private bool m_negativeCacheEnabled = true;
97 private bool m_negativeCacheSliding = false;
98
92 // Expiration is expressed in hours. 99 // Expiration is expressed in hours.
93 private const double m_DefaultMemoryExpiration = 2; 100 private double m_MemoryExpiration = 0.016;
94 private const double m_DefaultFileExpiration = 48; 101 private const double m_DefaultFileExpiration = 48;
95 private TimeSpan m_MemoryExpiration = TimeSpan.FromHours(m_DefaultMemoryExpiration); 102 // Negative cache is in seconds
103 private int m_negativeExpiration = 120;
96 private TimeSpan m_FileExpiration = TimeSpan.FromHours(m_DefaultFileExpiration); 104 private TimeSpan m_FileExpiration = TimeSpan.FromHours(m_DefaultFileExpiration);
97 private TimeSpan m_FileExpirationCleanupTimer = TimeSpan.FromHours(0.166); 105 private TimeSpan m_FileExpirationCleanupTimer = TimeSpan.FromHours(1.0);
98 106
99 private static int m_CacheDirectoryTiers = 1; 107 private static int m_CacheDirectoryTiers = 1;
100 private static int m_CacheDirectoryTierLen = 3; 108 private static int m_CacheDirectoryTierLen = 3;
@@ -104,6 +112,11 @@ namespace OpenSim.Region.CoreModules.Asset
104 112
105 private IAssetService m_AssetService; 113 private IAssetService m_AssetService;
106 private List<Scene> m_Scenes = new List<Scene>(); 114 private List<Scene> m_Scenes = new List<Scene>();
115 private object timerLock = new object();
116
117 private Dictionary<string,WeakReference> weakAssetReferences = new Dictionary<string, WeakReference>();
118 private object weakAssetReferencesLock = new object();
119 private bool m_updateFileTimeOnCacheHit = false;
107 120
108 public FlotsamAssetCache() 121 public FlotsamAssetCache()
109 { 122 {
@@ -111,7 +124,7 @@ namespace OpenSim.Region.CoreModules.Asset
111 m_InvalidChars.AddRange(Path.GetInvalidFileNameChars()); 124 m_InvalidChars.AddRange(Path.GetInvalidFileNameChars());
112 } 125 }
113 126
114 public Type ReplaceableInterface 127 public Type ReplaceableInterface
115 { 128 {
116 get { return null; } 129 get { return null; }
117 } 130 }
@@ -124,7 +137,7 @@ namespace OpenSim.Region.CoreModules.Asset
124 public void Initialise(IConfigSource source) 137 public void Initialise(IConfigSource source)
125 { 138 {
126 IConfig moduleConfig = source.Configs["Modules"]; 139 IConfig moduleConfig = source.Configs["Modules"];
127 140
128 if (moduleConfig != null) 141 if (moduleConfig != null)
129 { 142 {
130 string name = moduleConfig.GetString("AssetCaching", String.Empty); 143 string name = moduleConfig.GetString("AssetCaching", String.Empty);
@@ -132,6 +145,7 @@ namespace OpenSim.Region.CoreModules.Asset
132 if (name == Name) 145 if (name == Name)
133 { 146 {
134 m_MemoryCache = new ExpiringCache<string, AssetBase>(); 147 m_MemoryCache = new ExpiringCache<string, AssetBase>();
148 m_negativeCache = new ExpiringCache<string, object>();
135 m_Enabled = true; 149 m_Enabled = true;
136 150
137 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: {0} enabled", this.Name); 151 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: {0} enabled", this.Name);
@@ -148,12 +162,18 @@ namespace OpenSim.Region.CoreModules.Asset
148 m_CacheDirectory = assetConfig.GetString("CacheDirectory", m_DefaultCacheDirectory); 162 m_CacheDirectory = assetConfig.GetString("CacheDirectory", m_DefaultCacheDirectory);
149 163
150 m_MemoryCacheEnabled = assetConfig.GetBoolean("MemoryCacheEnabled", m_MemoryCacheEnabled); 164 m_MemoryCacheEnabled = assetConfig.GetBoolean("MemoryCacheEnabled", m_MemoryCacheEnabled);
151 m_MemoryExpiration = TimeSpan.FromHours(assetConfig.GetDouble("MemoryCacheTimeout", m_DefaultMemoryExpiration)); 165 m_MemoryExpiration = assetConfig.GetDouble("MemoryCacheTimeout", m_MemoryExpiration);
152 166 m_MemoryExpiration *= 3600.0; // config in hours to seconds
167
168 m_negativeCacheEnabled = assetConfig.GetBoolean("NegativeCacheEnabled", m_negativeCacheEnabled);
169 m_negativeExpiration = assetConfig.GetInt("NegativeCacheTimeout", m_negativeExpiration);
170 m_negativeCacheSliding = assetConfig.GetBoolean("NegativeCacheSliding", m_negativeCacheSliding);
171 m_updateFileTimeOnCacheHit = assetConfig.GetBoolean("UpdateFileTimeOnCacheHit", m_updateFileTimeOnCacheHit);
172
153 #if WAIT_ON_INPROGRESS_REQUESTS 173 #if WAIT_ON_INPROGRESS_REQUESTS
154 m_WaitOnInprogressTimeout = assetConfig.GetInt("WaitOnInprogressTimeout", 3000); 174 m_WaitOnInprogressTimeout = assetConfig.GetInt("WaitOnInprogressTimeout", 3000);
155 #endif 175 #endif
156 176
157 m_LogLevel = assetConfig.GetInt("LogLevel", m_LogLevel); 177 m_LogLevel = assetConfig.GetInt("LogLevel", m_LogLevel);
158 m_HitRateDisplay = (ulong)assetConfig.GetLong("HitRateDisplay", (long)m_HitRateDisplay); 178 m_HitRateDisplay = (ulong)assetConfig.GetLong("HitRateDisplay", (long)m_HitRateDisplay);
159 179
@@ -170,14 +190,6 @@ namespace OpenSim.Region.CoreModules.Asset
170 190
171 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Cache Directory {0}", m_CacheDirectory); 191 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Cache Directory {0}", m_CacheDirectory);
172 192
173 if (m_FileCacheEnabled && (m_FileExpiration > TimeSpan.Zero) && (m_FileExpirationCleanupTimer > TimeSpan.Zero))
174 {
175 m_CacheCleanTimer = new System.Timers.Timer(m_FileExpirationCleanupTimer.TotalMilliseconds);
176 m_CacheCleanTimer.AutoReset = true;
177 m_CacheCleanTimer.Elapsed += CleanupExpiredFiles;
178 lock (m_CacheCleanTimer)
179 m_CacheCleanTimer.Start();
180 }
181 193
182 if (m_CacheDirectoryTiers < 1) 194 if (m_CacheDirectoryTiers < 1)
183 { 195 {
@@ -217,9 +229,8 @@ namespace OpenSim.Region.CoreModules.Asset
217 { 229 {
218 if (m_Enabled) 230 if (m_Enabled)
219 { 231 {
220 scene.RegisterModuleInterface<IImprovedAssetCache>(this); 232 scene.RegisterModuleInterface<IAssetCache>(this);
221 m_Scenes.Add(scene); 233 m_Scenes.Add(scene);
222
223 } 234 }
224 } 235 }
225 236
@@ -227,23 +238,61 @@ namespace OpenSim.Region.CoreModules.Asset
227 { 238 {
228 if (m_Enabled) 239 if (m_Enabled)
229 { 240 {
230 scene.UnregisterModuleInterface<IImprovedAssetCache>(this); 241 scene.UnregisterModuleInterface<IAssetCache>(this);
231 m_Scenes.Remove(scene); 242 m_Scenes.Remove(scene);
243 lock(timerLock)
244 {
245 if(m_timerRunning && m_Scenes.Count <= 0)
246 {
247 m_timerRunning = false;
248 m_CacheCleanTimer.Stop();
249 m_CacheCleanTimer.Close();
250 }
251 }
232 } 252 }
233 } 253 }
234 254
235 public void RegionLoaded(Scene scene) 255 public void RegionLoaded(Scene scene)
236 { 256 {
237 if (m_Enabled && m_AssetService == null) 257 if (m_Enabled)
238 m_AssetService = scene.RequestModuleInterface<IAssetService>(); 258 {
259 if(m_AssetService == null)
260 m_AssetService = scene.RequestModuleInterface<IAssetService>();
261 lock(timerLock)
262 {
263 if(!m_timerRunning)
264 {
265 if (m_FileCacheEnabled && (m_FileExpiration > TimeSpan.Zero) && (m_FileExpirationCleanupTimer > TimeSpan.Zero))
266 {
267 m_CacheCleanTimer = new System.Timers.Timer(m_FileExpirationCleanupTimer.TotalMilliseconds);
268 m_CacheCleanTimer.AutoReset = false;
269 m_CacheCleanTimer.Elapsed += CleanupExpiredFiles;
270 m_CacheCleanTimer.Start();
271 m_timerRunning = true;
272 }
273 }
274 }
275 if (m_MemoryCacheEnabled)
276 m_MemoryCache = new ExpiringCache<string, AssetBase>();
277
278 lock(weakAssetReferencesLock)
279 weakAssetReferences = new Dictionary<string, WeakReference>();
280 }
239 } 281 }
240 282
241 //////////////////////////////////////////////////////////// 283 ////////////////////////////////////////////////////////////
242 // IImprovedAssetCache 284 // IAssetCache
243 // 285 //
286 private void UpdateWeakReference(string key, AssetBase asset)
287 {
288 WeakReference aref = new WeakReference(asset);
289 lock(weakAssetReferencesLock)
290 weakAssetReferences[key] = aref;
291 }
244 292
245 private void UpdateMemoryCache(string key, AssetBase asset) 293 private void UpdateMemoryCache(string key, AssetBase asset)
246 { 294 {
295 // NOTE DO NOT USE SLIDEEXPIRE option on current libomv
247 m_MemoryCache.AddOrUpdate(key, asset, m_MemoryExpiration); 296 m_MemoryCache.AddOrUpdate(key, asset, m_MemoryExpiration);
248 } 297 }
249 298
@@ -257,11 +306,11 @@ namespace OpenSim.Region.CoreModules.Asset
257 if (File.Exists(filename)) 306 if (File.Exists(filename))
258 { 307 {
259 UpdateFileLastAccessTime(filename); 308 UpdateFileLastAccessTime(filename);
260 } 309 }
261 else 310 else
262 { 311 {
263 // Once we start writing, make sure we flag that we're writing 312 // Once we start writing, make sure we flag that we're writing
264 // that object to the cache so that we don't try to write the 313 // that object to the cache so that we don't try to write the
265 // same file multiple times. 314 // same file multiple times.
266 lock (m_CurrentlyWriting) 315 lock (m_CurrentlyWriting)
267 { 316 {
@@ -306,6 +355,7 @@ namespace OpenSim.Region.CoreModules.Asset
306 if (asset != null) 355 if (asset != null)
307 { 356 {
308 //m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Caching asset with id {0}", asset.ID); 357 //m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Caching asset with id {0}", asset.ID);
358 UpdateWeakReference(asset.ID, asset);
309 359
310 if (m_MemoryCacheEnabled) 360 if (m_MemoryCacheEnabled)
311 UpdateMemoryCache(asset.ID, asset); 361 UpdateMemoryCache(asset.ID, asset);
@@ -315,6 +365,17 @@ namespace OpenSim.Region.CoreModules.Asset
315 } 365 }
316 } 366 }
317 367
368 public void CacheNegative(string id)
369 {
370 if (m_negativeCacheEnabled)
371 {
372 if (m_negativeCacheSliding)
373 m_negativeCache.AddOrUpdate(id, null, TimeSpan.FromSeconds(m_negativeExpiration));
374 else
375 m_negativeCache.AddOrUpdate(id, null, m_negativeExpiration);
376 }
377 }
378
318 /// <summary> 379 /// <summary>
319 /// Updates the cached file with the current time. 380 /// Updates the cached file with the current time.
320 /// </summary> 381 /// </summary>
@@ -333,6 +394,25 @@ namespace OpenSim.Region.CoreModules.Asset
333 } 394 }
334 } 395 }
335 396
397 private AssetBase GetFromWeakReference(string id)
398 {
399 AssetBase asset = null;
400 WeakReference aref;
401
402 lock(weakAssetReferencesLock)
403 {
404 if (weakAssetReferences.TryGetValue(id, out aref))
405 {
406 asset = aref.Target as AssetBase;
407 if(asset == null)
408 weakAssetReferences.Remove(id);
409 else
410 m_weakRefHits++;
411 }
412 }
413 return asset;
414 }
415
336 /// <summary> 416 /// <summary>
337 /// Try to get an asset from the in-memory cache. 417 /// Try to get an asset from the in-memory cache.
338 /// </summary> 418 /// </summary>
@@ -359,7 +439,7 @@ namespace OpenSim.Region.CoreModules.Asset
359 /// <param name="id"></param> 439 /// <param name="id"></param>
360 /// <returns>An asset retrieved from the file cache. null if there was a problem retrieving an asset.</returns> 440 /// <returns>An asset retrieved from the file cache. null if there was a problem retrieving an asset.</returns>
361 private AssetBase GetFromFileCache(string id) 441 private AssetBase GetFromFileCache(string id)
362 { 442 {
363 string filename = GetFileName(id); 443 string filename = GetFileName(id);
364 444
365#if WAIT_ON_INPROGRESS_REQUESTS 445#if WAIT_ON_INPROGRESS_REQUESTS
@@ -394,6 +474,8 @@ namespace OpenSim.Region.CoreModules.Asset
394 { 474 {
395 using (FileStream stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read)) 475 using (FileStream stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
396 { 476 {
477 if (stream.Length == 0) // Empty file will trigger exception below
478 return null;
397 BinaryFormatter bformatter = new BinaryFormatter(); 479 BinaryFormatter bformatter = new BinaryFormatter();
398 480
399 asset = (AssetBase)bformatter.Deserialize(stream); 481 asset = (AssetBase)bformatter.Deserialize(stream);
@@ -451,23 +533,57 @@ namespace OpenSim.Region.CoreModules.Asset
451 return found; 533 return found;
452 } 534 }
453 535
536 // For IAssetService
454 public AssetBase Get(string id) 537 public AssetBase Get(string id)
455 { 538 {
539 AssetBase asset;
540 Get(id, out asset);
541 return asset;
542 }
543
544 public bool Get(string id, out AssetBase asset)
545 {
546 asset = null;
547
456 m_Requests++; 548 m_Requests++;
457 549
458 AssetBase asset = null; 550 object dummy;
551 if (m_negativeCache.TryGetValue(id, out dummy))
552 {
553 return false;
554 }
459 555
460 if (m_MemoryCacheEnabled) 556 asset = GetFromWeakReference(id);
557 if (asset != null && m_updateFileTimeOnCacheHit)
558 {
559 string filename = GetFileName(id);
560 UpdateFileLastAccessTime(filename);
561 }
562
563 if (m_MemoryCacheEnabled && asset == null)
564 {
461 asset = GetFromMemoryCache(id); 565 asset = GetFromMemoryCache(id);
566 if(asset != null)
567 {
568 UpdateWeakReference(id,asset);
569 if (m_updateFileTimeOnCacheHit)
570 {
571 string filename = GetFileName(id);
572 UpdateFileLastAccessTime(filename);
573 }
574 }
575 }
462 576
463 if (asset == null && m_FileCacheEnabled) 577 if (asset == null && m_FileCacheEnabled)
464 { 578 {
465 asset = GetFromFileCache(id); 579 asset = GetFromFileCache(id);
466 580 if(asset != null)
467 if (m_MemoryCacheEnabled && asset != null) 581 UpdateWeakReference(id,asset);
468 UpdateMemoryCache(id, asset);
469 } 582 }
470 583
584 if (m_MemoryCacheEnabled && asset != null)
585 UpdateMemoryCache(id, asset);
586
471 if (((m_LogLevel >= 1)) && (m_HitRateDisplay != 0) && (m_Requests % m_HitRateDisplay == 0)) 587 if (((m_LogLevel >= 1)) && (m_HitRateDisplay != 0) && (m_Requests % m_HitRateDisplay == 0))
472 { 588 {
473 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Cache Get :: {0} :: {1}", id, asset == null ? "Miss" : "Hit"); 589 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Cache Get :: {0} :: {1}", id, asset == null ? "Miss" : "Hit");
@@ -475,7 +591,7 @@ namespace OpenSim.Region.CoreModules.Asset
475 GenerateCacheHitReport().ForEach(l => m_log.InfoFormat("[FLOTSAM ASSET CACHE]: {0}", l)); 591 GenerateCacheHitReport().ForEach(l => m_log.InfoFormat("[FLOTSAM ASSET CACHE]: {0}", l));
476 } 592 }
477 593
478 return asset; 594 return true;
479 } 595 }
480 596
481 public bool Check(string id) 597 public bool Check(string id)
@@ -490,7 +606,9 @@ namespace OpenSim.Region.CoreModules.Asset
490 606
491 public AssetBase GetCached(string id) 607 public AssetBase GetCached(string id)
492 { 608 {
493 return Get(id); 609 AssetBase asset;
610 Get(id, out asset);
611 return asset;
494 } 612 }
495 613
496 public void Expire(string id) 614 public void Expire(string id)
@@ -511,6 +629,9 @@ namespace OpenSim.Region.CoreModules.Asset
511 629
512 if (m_MemoryCacheEnabled) 630 if (m_MemoryCacheEnabled)
513 m_MemoryCache.Remove(id); 631 m_MemoryCache.Remove(id);
632
633 lock(weakAssetReferencesLock)
634 weakAssetReferences.Remove(id);
514 } 635 }
515 catch (Exception e) 636 catch (Exception e)
516 { 637 {
@@ -525,7 +646,7 @@ namespace OpenSim.Region.CoreModules.Asset
525 if (m_LogLevel >= 2) 646 if (m_LogLevel >= 2)
526 m_log.Debug("[FLOTSAM ASSET CACHE]: Clearing caches."); 647 m_log.Debug("[FLOTSAM ASSET CACHE]: Clearing caches.");
527 648
528 if (m_FileCacheEnabled) 649 if (m_FileCacheEnabled && Directory.Exists(m_CacheDirectory))
529 { 650 {
530 foreach (string dir in Directory.GetDirectories(m_CacheDirectory)) 651 foreach (string dir in Directory.GetDirectories(m_CacheDirectory))
531 { 652 {
@@ -534,7 +655,12 @@ namespace OpenSim.Region.CoreModules.Asset
534 } 655 }
535 656
536 if (m_MemoryCacheEnabled) 657 if (m_MemoryCacheEnabled)
537 m_MemoryCache.Clear(); 658 m_MemoryCache = new ExpiringCache<string, AssetBase>();
659 if (m_negativeCacheEnabled)
660 m_negativeCache = new ExpiringCache<string, object>();
661
662 lock(weakAssetReferencesLock)
663 weakAssetReferences = new Dictionary<string, WeakReference>();
538 } 664 }
539 665
540 private void CleanupExpiredFiles(object source, ElapsedEventArgs e) 666 private void CleanupExpiredFiles(object source, ElapsedEventArgs e)
@@ -542,6 +668,12 @@ namespace OpenSim.Region.CoreModules.Asset
542 if (m_LogLevel >= 2) 668 if (m_LogLevel >= 2)
543 m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Checking for expired files older then {0}.", m_FileExpiration); 669 m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Checking for expired files older then {0}.", m_FileExpiration);
544 670
671 lock(timerLock)
672 {
673 if(!m_timerRunning || m_cleanupRunning)
674 return;
675 m_cleanupRunning = true;
676 }
545 // Purge all files last accessed prior to this point 677 // Purge all files last accessed prior to this point
546 DateTime purgeLine = DateTime.Now - m_FileExpiration; 678 DateTime purgeLine = DateTime.Now - m_FileExpiration;
547 679
@@ -549,27 +681,34 @@ namespace OpenSim.Region.CoreModules.Asset
549 // before cleaning up expired files we must scan the objects in the scene to make sure that we retain 681 // before cleaning up expired files we must scan the objects in the scene to make sure that we retain
550 // such local assets if they have not been recently accessed. 682 // such local assets if they have not been recently accessed.
551 TouchAllSceneAssets(false); 683 TouchAllSceneAssets(false);
684 if(Directory.Exists(m_CacheDirectory))
685 {
686 foreach (string dir in Directory.GetDirectories(m_CacheDirectory))
687 CleanExpiredFiles(dir, purgeLine);
688 }
552 689
553 foreach (string dir in Directory.GetDirectories(m_CacheDirectory)) 690 lock(timerLock)
554 { 691 {
555 CleanExpiredFiles(dir, purgeLine); 692 if(m_timerRunning)
693 m_CacheCleanTimer.Start();
694 m_cleanupRunning = false;
556 } 695 }
557 } 696 }
558 697
559 /// <summary> 698 /// <summary>
560 /// Recurses through specified directory checking for asset files last 699 /// Recurses through specified directory checking for asset files last
561 /// accessed prior to the specified purge line and deletes them. Also 700 /// accessed prior to the specified purge line and deletes them. Also
562 /// removes empty tier directories. 701 /// removes empty tier directories.
563 /// </summary> 702 /// </summary>
564 /// <param name="dir"></param> 703 /// <param name="dir"></param>
565 /// <param name="purgeLine"></param> 704 /// <param name="purgeLine"></param>
566 private void CleanExpiredFiles(string dir, DateTime purgeLine) 705 private void CleanExpiredFiles(string dir, DateTime purgeLine)
567 { 706 {
568 // Yet another "directory we are trying to remove doesn't exist, so don't complain" idiocy fix.
569 if (!Directory.Exists(dir))
570 return;
571 try 707 try
572 { 708 {
709 if(!Directory.Exists(dir))
710 return;
711
573 foreach (string file in Directory.GetFiles(dir)) 712 foreach (string file in Directory.GetFiles(dir))
574 { 713 {
575 if (File.GetLastAccessTime(file) < purgeLine) 714 if (File.GetLastAccessTime(file) < purgeLine)
@@ -593,14 +732,19 @@ namespace OpenSim.Region.CoreModules.Asset
593 else if (dirSize >= m_CacheWarnAt) 732 else if (dirSize >= m_CacheWarnAt)
594 { 733 {
595 m_log.WarnFormat( 734 m_log.WarnFormat(
596 "[FLOTSAM ASSET CACHE]: Cache folder exceeded CacheWarnAt limit {0} {1}. Suggest increasing tiers, tier length, or reducing cache expiration", 735 "[FLOTSAM ASSET CACHE]: Cache folder exceeded CacheWarnAt limit {0} {1}. Suggest increasing tiers, tier length, or reducing cache expiration",
597 dir, dirSize); 736 dir, dirSize);
598 } 737 }
599 } 738 }
739 catch (DirectoryNotFoundException)
740 {
741 // If we get here, another node on the same box has
742 // already removed the directory. Continue with next.
743 }
600 catch (Exception e) 744 catch (Exception e)
601 { 745 {
602//// TODO - I'm almost sure this is another case of failing to delete something that doesn't actually exist. 746 m_log.Warn(
603//// m_log.Warn(string.Format("[FLOTSAM ASSET CACHE]: Could not complete clean of expired files in {0}", dir)); 747 string.Format("[FLOTSAM ASSET CACHE]: Could not complete clean of expired files in {0}, exception ", dir), e);
604 } 748 }
605 } 749 }
606 750
@@ -628,7 +772,7 @@ namespace OpenSim.Region.CoreModules.Asset
628 } 772 }
629 773
630 /// <summary> 774 /// <summary>
631 /// Writes a file to the file cache, creating any nessesary 775 /// Writes a file to the file cache, creating any nessesary
632 /// tier directories along the way 776 /// tier directories along the way
633 /// </summary> 777 /// </summary>
634 /// <param name="filename"></param> 778 /// <param name="filename"></param>
@@ -640,7 +784,7 @@ namespace OpenSim.Region.CoreModules.Asset
640 // Make sure the target cache directory exists 784 // Make sure the target cache directory exists
641 string directory = Path.GetDirectoryName(filename); 785 string directory = Path.GetDirectoryName(filename);
642 786
643 // Write file first to a temp name, so that it doesn't look 787 // Write file first to a temp name, so that it doesn't look
644 // like it's already cached while it's still writing. 788 // like it's already cached while it's still writing.
645 string tempname = Path.Combine(directory, Path.GetRandomFileName()); 789 string tempname = Path.Combine(directory, Path.GetRandomFileName());
646 790
@@ -652,7 +796,7 @@ namespace OpenSim.Region.CoreModules.Asset
652 { 796 {
653 Directory.CreateDirectory(directory); 797 Directory.CreateDirectory(directory);
654 } 798 }
655 799
656 stream = File.Open(tempname, FileMode.Create); 800 stream = File.Open(tempname, FileMode.Create);
657 BinaryFormatter bformatter = new BinaryFormatter(); 801 BinaryFormatter bformatter = new BinaryFormatter();
658 bformatter.Serialize(stream, asset); 802 bformatter.Serialize(stream, asset);
@@ -665,6 +809,9 @@ namespace OpenSim.Region.CoreModules.Asset
665 809
666 return; 810 return;
667 } 811 }
812 catch (UnauthorizedAccessException)
813 {
814 }
668 finally 815 finally
669 { 816 {
670 if (stream != null) 817 if (stream != null)
@@ -686,7 +833,7 @@ namespace OpenSim.Region.CoreModules.Asset
686 // This situation occurs fairly rarely anyway. We assume in this that moves are atomic on the 833 // This situation occurs fairly rarely anyway. We assume in this that moves are atomic on the
687 // filesystem. 834 // filesystem.
688 File.Move(tempname, filename); 835 File.Move(tempname, filename);
689 836
690 if (m_LogLevel >= 2) 837 if (m_LogLevel >= 2)
691 m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Cache Stored :: {0}", asset.ID); 838 m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Cache Stored :: {0}", asset.ID);
692 } 839 }
@@ -725,6 +872,9 @@ namespace OpenSim.Region.CoreModules.Asset
725 /// <returns></returns> 872 /// <returns></returns>
726 private int GetFileCacheCount(string dir) 873 private int GetFileCacheCount(string dir)
727 { 874 {
875 if(!Directory.Exists(dir))
876 return 0;
877
728 int count = Directory.GetFiles(dir).Length; 878 int count = Directory.GetFiles(dir).Length;
729 879
730 foreach (string subdir in Directory.GetDirectories(dir)) 880 foreach (string subdir in Directory.GetDirectories(dir))
@@ -743,7 +893,7 @@ namespace OpenSim.Region.CoreModules.Asset
743 { 893 {
744 string RegionCacheStatusFile = Path.Combine(m_CacheDirectory, "RegionStatus_" + regionID.ToString() + ".fac"); 894 string RegionCacheStatusFile = Path.Combine(m_CacheDirectory, "RegionStatus_" + regionID.ToString() + ".fac");
745 895
746 try 896 try
747 { 897 {
748 if (File.Exists(RegionCacheStatusFile)) 898 if (File.Exists(RegionCacheStatusFile))
749 { 899 {
@@ -752,7 +902,7 @@ namespace OpenSim.Region.CoreModules.Asset
752 else 902 else
753 { 903 {
754 File.WriteAllText( 904 File.WriteAllText(
755 RegionCacheStatusFile, 905 RegionCacheStatusFile,
756 "Please do not delete this file unless you are manually clearing your Flotsam Asset Cache."); 906 "Please do not delete this file unless you are manually clearing your Flotsam Asset Cache.");
757 } 907 }
758 } 908 }
@@ -760,14 +910,14 @@ namespace OpenSim.Region.CoreModules.Asset
760 { 910 {
761 m_log.Warn( 911 m_log.Warn(
762 string.Format( 912 string.Format(
763 "[FLOTSAM ASSET CACHE]: Could not stamp region status file for region {0}. Exception ", 913 "[FLOTSAM ASSET CACHE]: Could not stamp region status file for region {0}. Exception ",
764 regionID), 914 regionID),
765 e); 915 e);
766 } 916 }
767 } 917 }
768 918
769 /// <summary> 919 /// <summary>
770 /// Iterates through all Scenes, doing a deep scan through assets 920 /// Iterates through all Scenes, doing a deep scan through assets
771 /// to update the access time of all assets present in the scene or referenced by assets 921 /// to update the access time of all assets present in the scene or referenced by assets
772 /// in the scene. 922 /// in the scene.
773 /// </summary> 923 /// </summary>
@@ -786,10 +936,16 @@ namespace OpenSim.Region.CoreModules.Asset
786 StampRegionStatusFile(s.RegionInfo.RegionID); 936 StampRegionStatusFile(s.RegionInfo.RegionID);
787 937
788 s.ForEachSOG(delegate(SceneObjectGroup e) 938 s.ForEachSOG(delegate(SceneObjectGroup e)
789 { 939 {
940 if(!m_timerRunning && !storeUncached)
941 return;
942
790 gatherer.AddForInspection(e); 943 gatherer.AddForInspection(e);
791 gatherer.GatherAll(); 944 gatherer.GatherAll();
792 945
946 if(!m_timerRunning && !storeUncached)
947 return;
948
793 foreach (UUID assetID in gatherer.GatheredUuids.Keys) 949 foreach (UUID assetID in gatherer.GatheredUuids.Keys)
794 { 950 {
795 if (!assetsFound.ContainsKey(assetID)) 951 if (!assetsFound.ContainsKey(assetID))
@@ -799,6 +955,7 @@ namespace OpenSim.Region.CoreModules.Asset
799 if (File.Exists(filename)) 955 if (File.Exists(filename))
800 { 956 {
801 UpdateFileLastAccessTime(filename); 957 UpdateFileLastAccessTime(filename);
958 assetsFound[assetID] = true;
802 } 959 }
803 else if (storeUncached) 960 else if (storeUncached)
804 { 961 {
@@ -818,7 +975,14 @@ namespace OpenSim.Region.CoreModules.Asset
818 } 975 }
819 976
820 gatherer.GatheredUuids.Clear(); 977 gatherer.GatheredUuids.Clear();
978 if(!m_timerRunning && !storeUncached)
979 return;
980
981 if(!storeUncached)
982 Thread.Sleep(50);
821 }); 983 });
984 if(!m_timerRunning && !storeUncached)
985 break;
822 } 986 }
823 987
824 return assetsFound.Count; 988 return assetsFound.Count;
@@ -829,6 +993,9 @@ namespace OpenSim.Region.CoreModules.Asset
829 /// </summary> 993 /// </summary>
830 private void ClearFileCache() 994 private void ClearFileCache()
831 { 995 {
996 if(!Directory.Exists(m_CacheDirectory))
997 return;
998
832 foreach (string dir in Directory.GetDirectories(m_CacheDirectory)) 999 foreach (string dir in Directory.GetDirectories(m_CacheDirectory))
833 { 1000 {
834 try 1001 try
@@ -862,22 +1029,35 @@ namespace OpenSim.Region.CoreModules.Asset
862 { 1029 {
863 List<string> outputLines = new List<string>(); 1030 List<string> outputLines = new List<string>();
864 1031
865 double fileHitRate = (double)m_DiskHits / m_Requests * 100.0; 1032 double invReq = 100.0 / m_Requests;
1033
1034 double weakHitRate = m_weakRefHits * invReq;
1035 int weakEntries = weakAssetReferences.Count;
1036
1037 double fileHitRate = m_DiskHits * invReq;
1038 double TotalHitRate = weakHitRate + fileHitRate;
1039
1040 outputLines.Add(
1041 string.Format("Total requests: {0}", m_Requests));
866 outputLines.Add( 1042 outputLines.Add(
867 string.Format("File Hit Rate: {0}% for {1} requests", fileHitRate.ToString("0.00"), m_Requests)); 1043 string.Format("unCollected Hit Rate: {0}% ({1} entries)", weakHitRate.ToString("0.00"),weakEntries));
1044 outputLines.Add(
1045 string.Format("File Hit Rate: {0}%", fileHitRate.ToString("0.00")));
868 1046
869 if (m_MemoryCacheEnabled) 1047 if (m_MemoryCacheEnabled)
870 { 1048 {
871 double memHitRate = (double)m_MemoryHits / m_Requests * 100.0; 1049 double HitRate = m_MemoryHits * invReq;
872
873 outputLines.Add( 1050 outputLines.Add(
874 string.Format("Memory Hit Rate: {0}% for {1} requests", memHitRate.ToString("0.00"), m_Requests)); 1051 string.Format("Memory Hit Rate: {0}%", HitRate.ToString("0.00")));
1052
1053 TotalHitRate += HitRate;
875 } 1054 }
1055 outputLines.Add(
1056 string.Format("Total Hit Rate: {0}%", TotalHitRate.ToString("0.00")));
876 1057
877 outputLines.Add( 1058 outputLines.Add(
878 string.Format( 1059 string.Format(
879 "Unnecessary requests due to requests for assets that are currently downloading: {0}", 1060 "Requests overlap during file writing: {0}", m_RequestsForInprogress));
880 m_RequestsForInprogress));
881 1061
882 return outputLines; 1062 return outputLines;
883 } 1063 }
@@ -914,9 +1094,9 @@ namespace OpenSim.Region.CoreModules.Asset
914 if (m_FileCacheEnabled) 1094 if (m_FileCacheEnabled)
915 { 1095 {
916 con.Output("Deep scans have previously been performed on the following regions:"); 1096 con.Output("Deep scans have previously been performed on the following regions:");
917 1097
918 foreach (string s in Directory.GetFiles(m_CacheDirectory, "*.fac")) 1098 foreach (string s in Directory.GetFiles(m_CacheDirectory, "*.fac"))
919 { 1099 {
920 string RegionID = s.Remove(0,s.IndexOf("_")).Replace(".fac",""); 1100 string RegionID = s.Remove(0,s.IndexOf("_")).Replace(".fac","");
921 DateTime RegionDeepScanTMStamp = File.GetLastWriteTime(s); 1101 DateTime RegionDeepScanTMStamp = File.GetLastWriteTime(s);
922 con.OutputFormat("Region: {0}, {1}", RegionID, RegionDeepScanTMStamp.ToString("MM/dd/yyyy hh:mm:ss")); 1102 con.OutputFormat("Region: {0}, {1}", RegionID, RegionDeepScanTMStamp.ToString("MM/dd/yyyy hh:mm:ss"));
@@ -959,7 +1139,7 @@ namespace OpenSim.Region.CoreModules.Asset
959 con.Output("Memory cache not enabled."); 1139 con.Output("Memory cache not enabled.");
960 } 1140 }
961 } 1141 }
962 1142
963 if (clearFile) 1143 if (clearFile)
964 { 1144 {
965 if (m_FileCacheEnabled) 1145 if (m_FileCacheEnabled)
@@ -976,13 +1156,44 @@ namespace OpenSim.Region.CoreModules.Asset
976 break; 1156 break;
977 1157
978 case "assets": 1158 case "assets":
979 con.Output("Ensuring assets are cached for all scenes."); 1159 lock(timerLock)
1160 {
1161 if(m_cleanupRunning)
1162 {
1163 con.OutputFormat("FloatSam assets check already running");
1164 return;
1165 }
1166 m_cleanupRunning = true;
1167 }
980 1168
981 WorkManager.RunInThread(delegate 1169 con.Output("FloatSam Ensuring assets are cached for all scenes.");
1170
1171 WorkManager.RunInThreadPool(delegate
982 { 1172 {
1173 bool wasRunning= false;
1174 lock(timerLock)
1175 {
1176 if(m_timerRunning)
1177 {
1178 m_CacheCleanTimer.Stop();
1179 m_timerRunning = false;
1180 wasRunning = true;
1181 Thread.Sleep(100);
1182 }
1183 }
983 int assetReferenceTotal = TouchAllSceneAssets(true); 1184 int assetReferenceTotal = TouchAllSceneAssets(true);
1185 GC.Collect();
1186 lock(timerLock)
1187 {
1188 if(wasRunning)
1189 {
1190 m_CacheCleanTimer.Start();
1191 m_timerRunning = true;
1192 }
1193 m_cleanupRunning = false;
1194 }
984 con.OutputFormat("Completed check with {0} assets.", assetReferenceTotal); 1195 con.OutputFormat("Completed check with {0} assets.", assetReferenceTotal);
985 }, null, "TouchAllSceneAssets"); 1196 }, null, "TouchAllSceneAssets", false);
986 1197
987 break; 1198 break;
988 1199
@@ -1037,19 +1248,23 @@ namespace OpenSim.Region.CoreModules.Asset
1037 1248
1038 public AssetMetadata GetMetadata(string id) 1249 public AssetMetadata GetMetadata(string id)
1039 { 1250 {
1040 AssetBase asset = Get(id); 1251 AssetBase asset;
1252 Get(id, out asset);
1041 return asset.Metadata; 1253 return asset.Metadata;
1042 } 1254 }
1043 1255
1044 public byte[] GetData(string id) 1256 public byte[] GetData(string id)
1045 { 1257 {
1046 AssetBase asset = Get(id); 1258 AssetBase asset;
1259 Get(id, out asset);
1047 return asset.Data; 1260 return asset.Data;
1048 } 1261 }
1049 1262
1050 public bool Get(string id, object sender, AssetRetrieved handler) 1263 public bool Get(string id, object sender, AssetRetrieved handler)
1051 { 1264 {
1052 AssetBase asset = Get(id); 1265 AssetBase asset;
1266 if (!Get(id, out asset))
1267 return false;
1053 handler(id, sender, asset); 1268 handler(id, sender, asset);
1054 return true; 1269 return true;
1055 } 1270 }
@@ -1057,12 +1272,12 @@ namespace OpenSim.Region.CoreModules.Asset
1057 public bool[] AssetsExist(string[] ids) 1272 public bool[] AssetsExist(string[] ids)
1058 { 1273 {
1059 bool[] exist = new bool[ids.Length]; 1274 bool[] exist = new bool[ids.Length];
1060 1275
1061 for (int i = 0; i < ids.Length; i++) 1276 for (int i = 0; i < ids.Length; i++)
1062 { 1277 {
1063 exist[i] = Check(ids[i]); 1278 exist[i] = Check(ids[i]);
1064 } 1279 }
1065 1280
1066 return exist; 1281 return exist;
1067 } 1282 }
1068 1283
@@ -1080,7 +1295,9 @@ namespace OpenSim.Region.CoreModules.Asset
1080 1295
1081 public bool UpdateContent(string id, byte[] data) 1296 public bool UpdateContent(string id, byte[] data)
1082 { 1297 {
1083 AssetBase asset = Get(id); 1298 AssetBase asset;
1299 if (!Get(id, out asset))
1300 return false;
1084 asset.Data = data; 1301 asset.Data = data;
1085 Cache(asset); 1302 Cache(asset);
1086 return true; 1303 return true;
diff --git a/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs b/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs
index 5f76ac2..abe9b23 100644
--- a/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs
+++ b/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs
@@ -41,7 +41,7 @@ using OpenSim.Services.Interfaces;
41namespace OpenSim.Region.CoreModules.Asset 41namespace OpenSim.Region.CoreModules.Asset
42{ 42{
43 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GlynnTuckerAssetCache")] 43 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GlynnTuckerAssetCache")]
44 public class GlynnTuckerAssetCache : ISharedRegionModule, IImprovedAssetCache 44 public class GlynnTuckerAssetCache : ISharedRegionModule, IAssetCache
45 { 45 {
46 private static readonly ILog m_log = 46 private static readonly ILog m_log =
47 LogManager.GetLogger( 47 LogManager.GetLogger(
@@ -55,7 +55,7 @@ namespace OpenSim.Region.CoreModules.Asset
55 // Instrumentation 55 // Instrumentation
56 private uint m_DebugRate; 56 private uint m_DebugRate;
57 57
58 public Type ReplaceableInterface 58 public Type ReplaceableInterface
59 { 59 {
60 get { return null; } 60 get { return null; }
61 } 61 }
@@ -100,7 +100,7 @@ namespace OpenSim.Region.CoreModules.Asset
100 public void AddRegion(Scene scene) 100 public void AddRegion(Scene scene)
101 { 101 {
102 if (m_Enabled) 102 if (m_Enabled)
103 scene.RegisterModuleInterface<IImprovedAssetCache>(this); 103 scene.RegisterModuleInterface<IAssetCache>(this);
104 } 104 }
105 105
106 public void RemoveRegion(Scene scene) 106 public void RemoveRegion(Scene scene)
@@ -112,7 +112,7 @@ namespace OpenSim.Region.CoreModules.Asset
112 } 112 }
113 113
114 //////////////////////////////////////////////////////////// 114 ////////////////////////////////////////////////////////////
115 // IImprovedAssetCache 115 // IAssetCache
116 // 116 //
117 117
118 public bool Check(string id) 118 public bool Check(string id)
@@ -126,14 +126,20 @@ namespace OpenSim.Region.CoreModules.Asset
126 m_Cache.AddOrUpdate(asset.ID, asset); 126 m_Cache.AddOrUpdate(asset.ID, asset);
127 } 127 }
128 128
129 public AssetBase Get(string id) 129 public void CacheNegative(string id)
130 { 130 {
131 Object asset = null; 131 // We don't do negative caching
132 m_Cache.TryGet(id, out asset); 132 }
133
134 public bool Get(string id, out AssetBase asset)
135 {
136 Object a = null;
137 m_Cache.TryGet(id, out a);
133 138
134 Debug(asset); 139 Debug(a);
135 140
136 return (AssetBase)asset; 141 asset = (AssetBase)a;
142 return true;
137 } 143 }
138 144
139 public void Expire(string id) 145 public void Expire(string id)
diff --git a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs
index 73e4431..dbb7941 100644
--- a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs
+++ b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs
@@ -112,7 +112,7 @@ namespace OpenSim.Region.CoreModules.Asset.Tests
112 { 112 {
113 TestHelpers.InMethod(); 113 TestHelpers.InMethod();
114// log4net.Config.XmlConfigurator.Configure(); 114// log4net.Config.XmlConfigurator.Configure();
115 115
116 AssetBase asset = AssetHelpers.CreateNotecardAsset(); 116 AssetBase asset = AssetHelpers.CreateNotecardAsset();
117 asset.ID = TestHelpers.ParseTail(0x2).ToString(); 117 asset.ID = TestHelpers.ParseTail(0x2).ToString();
118 118