diff options
Diffstat (limited to 'OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs')
-rw-r--r-- | OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs | 267 |
1 files changed, 168 insertions, 99 deletions
diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index 9ef5bc9..d85d727 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs | |||
@@ -86,6 +86,8 @@ namespace Flotsam.RegionModules.AssetCache | |||
86 | private List<string> m_CurrentlyWriting = new List<string>(); | 86 | private List<string> m_CurrentlyWriting = new List<string>(); |
87 | #endif | 87 | #endif |
88 | 88 | ||
89 | private bool m_FileCacheEnabled = true; | ||
90 | |||
89 | private ExpiringCache<string, AssetBase> m_MemoryCache; | 91 | private ExpiringCache<string, AssetBase> m_MemoryCache; |
90 | private bool m_MemoryCacheEnabled = false; | 92 | private bool m_MemoryCacheEnabled = false; |
91 | 93 | ||
@@ -146,6 +148,7 @@ namespace Flotsam.RegionModules.AssetCache | |||
146 | } | 148 | } |
147 | else | 149 | else |
148 | { | 150 | { |
151 | m_FileCacheEnabled = assetConfig.GetBoolean("FileCacheEnabled", m_FileCacheEnabled); | ||
149 | m_CacheDirectory = assetConfig.GetString("CacheDirectory", m_DefaultCacheDirectory); | 152 | m_CacheDirectory = assetConfig.GetString("CacheDirectory", m_DefaultCacheDirectory); |
150 | 153 | ||
151 | m_MemoryCacheEnabled = assetConfig.GetBoolean("MemoryCacheEnabled", m_MemoryCacheEnabled); | 154 | m_MemoryCacheEnabled = assetConfig.GetBoolean("MemoryCacheEnabled", m_MemoryCacheEnabled); |
@@ -173,7 +176,7 @@ namespace Flotsam.RegionModules.AssetCache | |||
173 | 176 | ||
174 | m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Cache Directory {0}", m_CacheDirectory); | 177 | m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Cache Directory {0}", m_CacheDirectory); |
175 | 178 | ||
176 | if ((m_FileExpiration > TimeSpan.Zero) && (m_FileExpirationCleanupTimer > TimeSpan.Zero)) | 179 | if (m_FileCacheEnabled && (m_FileExpiration > TimeSpan.Zero) && (m_FileExpirationCleanupTimer > TimeSpan.Zero)) |
177 | { | 180 | { |
178 | m_CacheCleanTimer = new System.Timers.Timer(m_FileExpirationCleanupTimer.TotalMilliseconds); | 181 | m_CacheCleanTimer = new System.Timers.Timer(m_FileExpirationCleanupTimer.TotalMilliseconds); |
179 | m_CacheCleanTimer.AutoReset = true; | 182 | m_CacheCleanTimer.AutoReset = true; |
@@ -226,7 +229,6 @@ namespace Flotsam.RegionModules.AssetCache | |||
226 | if (m_AssetService == null) | 229 | if (m_AssetService == null) |
227 | { | 230 | { |
228 | m_AssetService = scene.RequestModuleInterface<IAssetService>(); | 231 | m_AssetService = scene.RequestModuleInterface<IAssetService>(); |
229 | |||
230 | } | 232 | } |
231 | } | 233 | } |
232 | } | 234 | } |
@@ -250,18 +252,15 @@ namespace Flotsam.RegionModules.AssetCache | |||
250 | 252 | ||
251 | private void UpdateMemoryCache(string key, AssetBase asset) | 253 | private void UpdateMemoryCache(string key, AssetBase asset) |
252 | { | 254 | { |
253 | if (m_MemoryCacheEnabled) | 255 | m_MemoryCache.AddOrUpdate(key, asset, m_MemoryExpiration); |
254 | m_MemoryCache.AddOrUpdate(key, asset, m_MemoryExpiration); | ||
255 | } | 256 | } |
256 | 257 | ||
257 | public void Cache(AssetBase asset) | 258 | private void UpdateFileCache(string key, AssetBase asset) |
258 | { | 259 | { |
259 | // TODO: Spawn this off to some seperate thread to do the actual writing | 260 | // TODO: Spawn this off to some seperate thread to do the actual writing |
260 | if (asset != null) | 261 | if (asset != null) |
261 | { | 262 | { |
262 | UpdateMemoryCache(asset.ID, asset); | 263 | string filename = GetFileName(key); |
263 | |||
264 | string filename = GetFileName(asset.ID); | ||
265 | 264 | ||
266 | try | 265 | try |
267 | { | 266 | { |
@@ -278,8 +277,8 @@ namespace Flotsam.RegionModules.AssetCache | |||
278 | catch | 277 | catch |
279 | { | 278 | { |
280 | } | 279 | } |
281 | } else { | 280 | } else { |
282 | 281 | ||
283 | // Once we start writing, make sure we flag that we're writing | 282 | // Once we start writing, make sure we flag that we're writing |
284 | // that object to the cache so that we don't try to write the | 283 | // that object to the cache so that we don't try to write the |
285 | // same file multiple times. | 284 | // same file multiple times. |
@@ -319,78 +318,118 @@ namespace Flotsam.RegionModules.AssetCache | |||
319 | } | 318 | } |
320 | } | 319 | } |
321 | 320 | ||
322 | public AssetBase Get(string id) | 321 | public void Cache(AssetBase asset) |
323 | { | 322 | { |
324 | m_Requests++; | 323 | // TODO: Spawn this off to some seperate thread to do the actual writing |
324 | if (asset != null) | ||
325 | { | ||
326 | //m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Caching asset with id {0}", asset.ID); | ||
327 | |||
328 | if (m_MemoryCacheEnabled) | ||
329 | UpdateMemoryCache(asset.ID, asset); | ||
330 | |||
331 | if (m_FileCacheEnabled) | ||
332 | UpdateFileCache(asset.ID, asset); | ||
333 | } | ||
334 | } | ||
325 | 335 | ||
336 | /// <summary> | ||
337 | /// Try to get an asset from the in-memory cache. | ||
338 | /// </summary> | ||
339 | /// <param name="id"></param> | ||
340 | /// <returns></returns> | ||
341 | private AssetBase GetFromMemoryCache(string id) | ||
342 | { | ||
326 | AssetBase asset = null; | 343 | AssetBase asset = null; |
327 | 344 | ||
328 | if (m_MemoryCacheEnabled && m_MemoryCache.TryGetValue(id, out asset)) | 345 | if (m_MemoryCache.TryGetValue(id, out asset)) |
329 | { | ||
330 | m_MemoryHits++; | 346 | m_MemoryHits++; |
331 | } | 347 | |
332 | else | 348 | return asset; |
349 | } | ||
350 | |||
351 | /// <summary> | ||
352 | /// Try to get an asset from the file cache. | ||
353 | /// </summary> | ||
354 | /// <param name="id"></param> | ||
355 | /// <returns></returns> | ||
356 | private AssetBase GetFromFileCache(string id) | ||
357 | { | ||
358 | AssetBase asset = null; | ||
359 | |||
360 | string filename = GetFileName(id); | ||
361 | if (File.Exists(filename)) | ||
333 | { | 362 | { |
334 | string filename = GetFileName(id); | 363 | FileStream stream = null; |
335 | if (File.Exists(filename)) | 364 | try |
336 | { | 365 | { |
337 | FileStream stream = null; | 366 | stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read); |
338 | try | 367 | BinaryFormatter bformatter = new BinaryFormatter(); |
339 | { | ||
340 | stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read); | ||
341 | BinaryFormatter bformatter = new BinaryFormatter(); | ||
342 | 368 | ||
343 | asset = (AssetBase)bformatter.Deserialize(stream); | 369 | asset = (AssetBase)bformatter.Deserialize(stream); |
344 | 370 | ||
345 | UpdateMemoryCache(id, asset); | 371 | UpdateMemoryCache(id, asset); |
346 | 372 | ||
347 | m_DiskHits++; | 373 | m_DiskHits++; |
348 | } | 374 | } |
349 | catch (System.Runtime.Serialization.SerializationException e) | 375 | catch (System.Runtime.Serialization.SerializationException e) |
350 | { | 376 | { |
351 | LogException(e); | 377 | LogException(e); |
352 | 378 | ||
353 | // If there was a problem deserializing the asset, the asset may | 379 | // If there was a problem deserializing the asset, the asset may |
354 | // either be corrupted OR was serialized under an old format | 380 | // either be corrupted OR was serialized under an old format |
355 | // {different version of AssetBase} -- we should attempt to | 381 | // {different version of AssetBase} -- we should attempt to |
356 | // delete it and re-cache | 382 | // delete it and re-cache |
357 | File.Delete(filename); | 383 | File.Delete(filename); |
358 | } | 384 | } |
359 | catch (Exception e) | 385 | catch (Exception e) |
360 | { | 386 | { |
361 | LogException(e); | 387 | LogException(e); |
362 | } | ||
363 | finally | ||
364 | { | ||
365 | if (stream != null) | ||
366 | stream.Close(); | ||
367 | } | ||
368 | } | 388 | } |
389 | finally | ||
390 | { | ||
391 | if (stream != null) | ||
392 | stream.Close(); | ||
393 | } | ||
394 | } | ||
369 | 395 | ||
370 | 396 | ||
371 | #if WAIT_ON_INPROGRESS_REQUESTS | 397 | #if WAIT_ON_INPROGRESS_REQUESTS |
372 | // Check if we're already downloading this asset. If so, try to wait for it to | 398 | // Check if we're already downloading this asset. If so, try to wait for it to |
373 | // download. | 399 | // download. |
374 | if (m_WaitOnInprogressTimeout > 0) | 400 | if (m_WaitOnInprogressTimeout > 0) |
375 | { | 401 | { |
376 | m_RequestsForInprogress++; | 402 | m_RequestsForInprogress++; |
377 | 403 | ||
378 | ManualResetEvent waitEvent; | 404 | ManualResetEvent waitEvent; |
379 | if (m_CurrentlyWriting.TryGetValue(filename, out waitEvent)) | 405 | if (m_CurrentlyWriting.TryGetValue(filename, out waitEvent)) |
380 | { | ||
381 | waitEvent.WaitOne(m_WaitOnInprogressTimeout); | ||
382 | return Get(id); | ||
383 | } | ||
384 | } | ||
385 | #else | ||
386 | // Track how often we have the problem that an asset is requested while | ||
387 | // it is still being downloaded by a previous request. | ||
388 | if (m_CurrentlyWriting.Contains(filename)) | ||
389 | { | 406 | { |
390 | m_RequestsForInprogress++; | 407 | waitEvent.WaitOne(m_WaitOnInprogressTimeout); |
408 | return Get(id); | ||
391 | } | 409 | } |
392 | #endif | ||
393 | } | 410 | } |
411 | #else | ||
412 | // Track how often we have the problem that an asset is requested while | ||
413 | // it is still being downloaded by a previous request. | ||
414 | if (m_CurrentlyWriting.Contains(filename)) | ||
415 | { | ||
416 | m_RequestsForInprogress++; | ||
417 | } | ||
418 | #endif | ||
419 | |||
420 | return asset; | ||
421 | } | ||
422 | |||
423 | public AssetBase Get(string id) | ||
424 | { | ||
425 | m_Requests++; | ||
426 | |||
427 | AssetBase asset = null; | ||
428 | |||
429 | if (m_MemoryCacheEnabled) | ||
430 | asset = GetFromMemoryCache(id); | ||
431 | else if (m_FileCacheEnabled) | ||
432 | asset = GetFromFileCache(id); | ||
394 | 433 | ||
395 | if (((m_LogLevel >= 1)) && (m_HitRateDisplay != 0) && (m_Requests % m_HitRateDisplay == 0)) | 434 | if (((m_LogLevel >= 1)) && (m_HitRateDisplay != 0) && (m_Requests % m_HitRateDisplay == 0)) |
396 | { | 435 | { |
@@ -424,10 +463,13 @@ namespace Flotsam.RegionModules.AssetCache | |||
424 | 463 | ||
425 | try | 464 | try |
426 | { | 465 | { |
427 | string filename = GetFileName(id); | 466 | if (m_FileCacheEnabled) |
428 | if (File.Exists(filename)) | ||
429 | { | 467 | { |
430 | File.Delete(filename); | 468 | string filename = GetFileName(id); |
469 | if (File.Exists(filename)) | ||
470 | { | ||
471 | File.Delete(filename); | ||
472 | } | ||
431 | } | 473 | } |
432 | 474 | ||
433 | if (m_MemoryCacheEnabled) | 475 | if (m_MemoryCacheEnabled) |
@@ -442,11 +484,14 @@ namespace Flotsam.RegionModules.AssetCache | |||
442 | public void Clear() | 484 | public void Clear() |
443 | { | 485 | { |
444 | if (m_LogLevel >= 2) | 486 | if (m_LogLevel >= 2) |
445 | m_log.Debug("[FLOTSAM ASSET CACHE]: Clearing Cache."); | 487 | m_log.Debug("[FLOTSAM ASSET CACHE]: Clearing caches."); |
446 | 488 | ||
447 | foreach (string dir in Directory.GetDirectories(m_CacheDirectory)) | 489 | if (m_FileCacheEnabled) |
448 | { | 490 | { |
449 | Directory.Delete(dir); | 491 | foreach (string dir in Directory.GetDirectories(m_CacheDirectory)) |
492 | { | ||
493 | Directory.Delete(dir); | ||
494 | } | ||
450 | } | 495 | } |
451 | 496 | ||
452 | if (m_MemoryCacheEnabled) | 497 | if (m_MemoryCacheEnabled) |
@@ -481,9 +526,9 @@ namespace Flotsam.RegionModules.AssetCache | |||
481 | /// removes empty tier directories. | 526 | /// removes empty tier directories. |
482 | /// </summary> | 527 | /// </summary> |
483 | /// <param name="dir"></param> | 528 | /// <param name="dir"></param> |
529 | /// <param name="purgeLine"></param> | ||
484 | private void CleanExpiredFiles(string dir, DateTime purgeLine) | 530 | private void CleanExpiredFiles(string dir, DateTime purgeLine) |
485 | { | 531 | { |
486 | |||
487 | foreach (string file in Directory.GetFiles(dir)) | 532 | foreach (string file in Directory.GetFiles(dir)) |
488 | { | 533 | { |
489 | if (File.GetLastAccessTime(file) < purgeLine) | 534 | if (File.GetLastAccessTime(file) < purgeLine) |
@@ -721,18 +766,28 @@ namespace Flotsam.RegionModules.AssetCache | |||
721 | switch (cmd) | 766 | switch (cmd) |
722 | { | 767 | { |
723 | case "status": | 768 | case "status": |
724 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] Memory Cache : {0} assets", m_MemoryCache.Count); | 769 | if (m_MemoryCacheEnabled) |
725 | 770 | m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Memory Cache : {0} assets", m_MemoryCache.Count); | |
726 | int fileCount = GetFileCacheCount(m_CacheDirectory); | 771 | else |
727 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] File Cache : {0} assets", fileCount); | 772 | m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Memory cache disabled"); |
728 | 773 | ||
729 | foreach (string s in Directory.GetFiles(m_CacheDirectory, "*.fac")) | 774 | if (m_FileCacheEnabled) |
730 | { | 775 | { |
731 | m_log.Info("[FLOTSAM ASSET CACHE] Deep Scans were performed on the following regions:"); | 776 | int fileCount = GetFileCacheCount(m_CacheDirectory); |
732 | 777 | m_log.InfoFormat("[FLOTSAM ASSET CACHE]: File Cache : {0} assets", fileCount); | |
733 | string RegionID = s.Remove(0,s.IndexOf("_")).Replace(".fac",""); | 778 | |
734 | DateTime RegionDeepScanTMStamp = File.GetLastWriteTime(s); | 779 | foreach (string s in Directory.GetFiles(m_CacheDirectory, "*.fac")) |
735 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] Region: {0}, {1}", RegionID, RegionDeepScanTMStamp.ToString("MM/dd/yyyy hh:mm:ss")); | 780 | { |
781 | m_log.Info("[FLOTSAM ASSET CACHE]: Deep Scans were performed on the following regions:"); | ||
782 | |||
783 | string RegionID = s.Remove(0,s.IndexOf("_")).Replace(".fac",""); | ||
784 | DateTime RegionDeepScanTMStamp = File.GetLastWriteTime(s); | ||
785 | m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Region: {0}, {1}", RegionID, RegionDeepScanTMStamp.ToString("MM/dd/yyyy hh:mm:ss")); | ||
786 | } | ||
787 | } | ||
788 | else | ||
789 | { | ||
790 | m_log.InfoFormat("[FLOTSAM ASSET CACHE]: File cache disabled"); | ||
736 | } | 791 | } |
737 | 792 | ||
738 | break; | 793 | break; |
@@ -740,7 +795,7 @@ namespace Flotsam.RegionModules.AssetCache | |||
740 | case "clear": | 795 | case "clear": |
741 | if (cmdparams.Length < 2) | 796 | if (cmdparams.Length < 2) |
742 | { | 797 | { |
743 | m_log.Warn("[FLOTSAM ASSET CACHE] Usage is fcache clear [file] [memory]"); | 798 | m_log.Warn("[FLOTSAM ASSET CACHE]: Usage is fcache clear [file] [memory]"); |
744 | break; | 799 | break; |
745 | } | 800 | } |
746 | 801 | ||
@@ -761,36 +816,48 @@ namespace Flotsam.RegionModules.AssetCache | |||
761 | 816 | ||
762 | if (clearMemory) | 817 | if (clearMemory) |
763 | { | 818 | { |
764 | m_MemoryCache.Clear(); | 819 | if (m_MemoryCacheEnabled) |
765 | m_log.Info("[FLOTSAM ASSET CACHE] Memory cache cleared."); | 820 | { |
821 | m_MemoryCache.Clear(); | ||
822 | m_log.Info("[FLOTSAM ASSET CACHE]: Memory cache cleared."); | ||
823 | } | ||
824 | else | ||
825 | { | ||
826 | m_log.Info("[FLOTSAM ASSET CACHE]: Memory cache not enabled."); | ||
827 | } | ||
766 | } | 828 | } |
767 | 829 | ||
768 | if (clearFile) | 830 | if (clearFile) |
769 | { | 831 | { |
770 | ClearFileCache(); | 832 | if (m_FileCacheEnabled) |
771 | m_log.Info("[FLOTSAM ASSET CACHE] File cache cleared."); | 833 | { |
834 | ClearFileCache(); | ||
835 | m_log.Info("[FLOTSAM ASSET CACHE]: File cache cleared."); | ||
836 | } | ||
837 | else | ||
838 | { | ||
839 | m_log.Info("[FLOTSAM ASSET CACHE]: File cache not enabled."); | ||
840 | } | ||
772 | } | 841 | } |
773 | 842 | ||
774 | break; | 843 | break; |
775 | 844 | ||
776 | 845 | ||
777 | case "assets": | 846 | case "assets": |
778 | m_log.Info("[FLOTSAM ASSET CACHE] Caching all assets, in all scenes."); | 847 | m_log.Info("[FLOTSAM ASSET CACHE]: Caching all assets, in all scenes."); |
779 | 848 | ||
780 | Util.FireAndForget(delegate { | 849 | Util.FireAndForget(delegate { |
781 | int assetsCached = CacheScenes(); | 850 | int assetsCached = CacheScenes(); |
782 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] Completed Scene Caching, {0} assets found.", assetsCached); | 851 | m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Completed Scene Caching, {0} assets found.", assetsCached); |
783 | 852 | ||
784 | }); | 853 | }); |
785 | 854 | ||
786 | break; | 855 | break; |
787 | 856 | ||
788 | case "expire": | 857 | case "expire": |
789 | |||
790 | |||
791 | if (cmdparams.Length < 3) | 858 | if (cmdparams.Length < 3) |
792 | { | 859 | { |
793 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] Invalid parameters for Expire, please specify a valid date & time", cmd); | 860 | m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Invalid parameters for Expire, please specify a valid date & time", cmd); |
794 | break; | 861 | break; |
795 | } | 862 | } |
796 | 863 | ||
@@ -808,26 +875,28 @@ namespace Flotsam.RegionModules.AssetCache | |||
808 | 875 | ||
809 | if (!DateTime.TryParse(s_expirationDate, out expirationDate)) | 876 | if (!DateTime.TryParse(s_expirationDate, out expirationDate)) |
810 | { | 877 | { |
811 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] {0} is not a valid date & time", cmd); | 878 | m_log.InfoFormat("[FLOTSAM ASSET CACHE]: {0} is not a valid date & time", cmd); |
812 | break; | 879 | break; |
813 | } | 880 | } |
814 | 881 | ||
815 | CleanExpiredFiles(m_CacheDirectory, expirationDate); | 882 | if (m_FileCacheEnabled) |
883 | CleanExpiredFiles(m_CacheDirectory, expirationDate); | ||
884 | else | ||
885 | m_log.InfoFormat("[FLOTSAM ASSET CACHE]: File cache not active, not clearing."); | ||
816 | 886 | ||
817 | break; | 887 | break; |
818 | default: | 888 | default: |
819 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] Unknown command {0}", cmd); | 889 | m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Unknown command {0}", cmd); |
820 | break; | 890 | break; |
821 | } | 891 | } |
822 | } | 892 | } |
823 | else if (cmdparams.Length == 1) | 893 | else if (cmdparams.Length == 1) |
824 | { | 894 | { |
825 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache status - Display cache status"); | 895 | m_log.InfoFormat("[FLOTSAM ASSET CACHE]: fcache status - Display cache status"); |
826 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache clearmem - Remove all assets cached in memory"); | 896 | m_log.InfoFormat("[FLOTSAM ASSET CACHE]: fcache clearmem - Remove all assets cached in memory"); |
827 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache clearfile - Remove all assets cached on disk"); | 897 | m_log.InfoFormat("[FLOTSAM ASSET CACHE]: fcache clearfile - Remove all assets cached on disk"); |
828 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache cachescenes - Attempt a deep cache of all assets in all scenes"); | 898 | m_log.InfoFormat("[FLOTSAM ASSET CACHE]: fcache cachescenes - Attempt a deep cache of all assets in all scenes"); |
829 | m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache <datetime> - Purge assets older then the specified date & time"); | 899 | m_log.InfoFormat("[FLOTSAM ASSET CACHE]: fcache <datetime> - Purge assets older then the specified date & time"); |
830 | |||
831 | } | 900 | } |
832 | } | 901 | } |
833 | 902 | ||