Merge branch 'master' into careminster-presence-refactor

This commit is contained in:
root
2011-07-05 04:01:59 +01:00
26 changed files with 766 additions and 315 deletions

View File

@@ -86,6 +86,8 @@ namespace Flotsam.RegionModules.AssetCache
private List<string> m_CurrentlyWriting = new List<string>();
#endif
private bool m_FileCacheEnabled = true;
private ExpiringCache<string, AssetBase> m_MemoryCache;
private bool m_MemoryCacheEnabled = false;
@@ -146,6 +148,7 @@ namespace Flotsam.RegionModules.AssetCache
}
else
{
m_FileCacheEnabled = assetConfig.GetBoolean("FileCacheEnabled", m_FileCacheEnabled);
m_CacheDirectory = assetConfig.GetString("CacheDirectory", m_DefaultCacheDirectory);
m_MemoryCacheEnabled = assetConfig.GetBoolean("MemoryCacheEnabled", m_MemoryCacheEnabled);
@@ -173,7 +176,7 @@ namespace Flotsam.RegionModules.AssetCache
m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Cache Directory {0}", m_CacheDirectory);
if ((m_FileExpiration > TimeSpan.Zero) && (m_FileExpirationCleanupTimer > TimeSpan.Zero))
if (m_FileCacheEnabled && (m_FileExpiration > TimeSpan.Zero) && (m_FileExpirationCleanupTimer > TimeSpan.Zero))
{
m_CacheCleanTimer = new System.Timers.Timer(m_FileExpirationCleanupTimer.TotalMilliseconds);
m_CacheCleanTimer.AutoReset = true;
@@ -226,7 +229,6 @@ namespace Flotsam.RegionModules.AssetCache
if (m_AssetService == null)
{
m_AssetService = scene.RequestModuleInterface<IAssetService>();
}
}
}
@@ -250,18 +252,15 @@ namespace Flotsam.RegionModules.AssetCache
private void UpdateMemoryCache(string key, AssetBase asset)
{
if (m_MemoryCacheEnabled)
m_MemoryCache.AddOrUpdate(key, asset, m_MemoryExpiration);
m_MemoryCache.AddOrUpdate(key, asset, m_MemoryExpiration);
}
public void Cache(AssetBase asset)
private void UpdateFileCache(string key, AssetBase asset)
{
// TODO: Spawn this off to some seperate thread to do the actual writing
if (asset != null)
{
UpdateMemoryCache(asset.ID, asset);
string filename = GetFileName(asset.ID);
string filename = GetFileName(key);
try
{
@@ -278,8 +277,8 @@ namespace Flotsam.RegionModules.AssetCache
catch
{
}
} else {
} else {
// Once we start writing, make sure we flag that we're writing
// that object to the cache so that we don't try to write the
// same file multiple times.
@@ -319,78 +318,118 @@ namespace Flotsam.RegionModules.AssetCache
}
}
public void Cache(AssetBase asset)
{
// TODO: Spawn this off to some seperate thread to do the actual writing
if (asset != null)
{
//m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Caching asset with id {0}", asset.ID);
if (m_MemoryCacheEnabled)
UpdateMemoryCache(asset.ID, asset);
if (m_FileCacheEnabled)
UpdateFileCache(asset.ID, asset);
}
}
/// <summary>
/// Try to get an asset from the in-memory cache.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
private AssetBase GetFromMemoryCache(string id)
{
AssetBase asset = null;
if (m_MemoryCache.TryGetValue(id, out asset))
m_MemoryHits++;
return asset;
}
/// <summary>
/// Try to get an asset from the file cache.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
private AssetBase GetFromFileCache(string id)
{
AssetBase asset = null;
string filename = GetFileName(id);
if (File.Exists(filename))
{
FileStream stream = null;
try
{
stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
BinaryFormatter bformatter = new BinaryFormatter();
asset = (AssetBase)bformatter.Deserialize(stream);
UpdateMemoryCache(id, asset);
m_DiskHits++;
}
catch (System.Runtime.Serialization.SerializationException e)
{
LogException(e);
// If there was a problem deserializing the asset, the asset may
// either be corrupted OR was serialized under an old format
// {different version of AssetBase} -- we should attempt to
// delete it and re-cache
File.Delete(filename);
}
catch (Exception e)
{
LogException(e);
}
finally
{
if (stream != null)
stream.Close();
}
}
#if WAIT_ON_INPROGRESS_REQUESTS
// Check if we're already downloading this asset. If so, try to wait for it to
// download.
if (m_WaitOnInprogressTimeout > 0)
{
m_RequestsForInprogress++;
ManualResetEvent waitEvent;
if (m_CurrentlyWriting.TryGetValue(filename, out waitEvent))
{
waitEvent.WaitOne(m_WaitOnInprogressTimeout);
return Get(id);
}
}
#else
// Track how often we have the problem that an asset is requested while
// it is still being downloaded by a previous request.
if (m_CurrentlyWriting.Contains(filename))
{
m_RequestsForInprogress++;
}
#endif
return asset;
}
public AssetBase Get(string id)
{
m_Requests++;
AssetBase asset = null;
if (m_MemoryCacheEnabled && m_MemoryCache.TryGetValue(id, out asset))
{
m_MemoryHits++;
}
else
{
string filename = GetFileName(id);
if (File.Exists(filename))
{
FileStream stream = null;
try
{
stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
BinaryFormatter bformatter = new BinaryFormatter();
asset = (AssetBase)bformatter.Deserialize(stream);
UpdateMemoryCache(id, asset);
m_DiskHits++;
}
catch (System.Runtime.Serialization.SerializationException e)
{
LogException(e);
// If there was a problem deserializing the asset, the asset may
// either be corrupted OR was serialized under an old format
// {different version of AssetBase} -- we should attempt to
// delete it and re-cache
File.Delete(filename);
}
catch (Exception e)
{
LogException(e);
}
finally
{
if (stream != null)
stream.Close();
}
}
#if WAIT_ON_INPROGRESS_REQUESTS
// Check if we're already downloading this asset. If so, try to wait for it to
// download.
if (m_WaitOnInprogressTimeout > 0)
{
m_RequestsForInprogress++;
ManualResetEvent waitEvent;
if (m_CurrentlyWriting.TryGetValue(filename, out waitEvent))
{
waitEvent.WaitOne(m_WaitOnInprogressTimeout);
return Get(id);
}
}
#else
// Track how often we have the problem that an asset is requested while
// it is still being downloaded by a previous request.
if (m_CurrentlyWriting.Contains(filename))
{
m_RequestsForInprogress++;
}
#endif
}
if (m_MemoryCacheEnabled)
asset = GetFromMemoryCache(id);
else if (m_FileCacheEnabled)
asset = GetFromFileCache(id);
if (((m_LogLevel >= 1)) && (m_HitRateDisplay != 0) && (m_Requests % m_HitRateDisplay == 0))
{
@@ -424,10 +463,13 @@ namespace Flotsam.RegionModules.AssetCache
try
{
string filename = GetFileName(id);
if (File.Exists(filename))
if (m_FileCacheEnabled)
{
File.Delete(filename);
string filename = GetFileName(id);
if (File.Exists(filename))
{
File.Delete(filename);
}
}
if (m_MemoryCacheEnabled)
@@ -442,11 +484,14 @@ namespace Flotsam.RegionModules.AssetCache
public void Clear()
{
if (m_LogLevel >= 2)
m_log.Debug("[FLOTSAM ASSET CACHE]: Clearing Cache.");
m_log.Debug("[FLOTSAM ASSET CACHE]: Clearing caches.");
foreach (string dir in Directory.GetDirectories(m_CacheDirectory))
if (m_FileCacheEnabled)
{
Directory.Delete(dir);
foreach (string dir in Directory.GetDirectories(m_CacheDirectory))
{
Directory.Delete(dir);
}
}
if (m_MemoryCacheEnabled)
@@ -481,9 +526,9 @@ namespace Flotsam.RegionModules.AssetCache
/// removes empty tier directories.
/// </summary>
/// <param name="dir"></param>
/// <param name="purgeLine"></param>
private void CleanExpiredFiles(string dir, DateTime purgeLine)
{
foreach (string file in Directory.GetFiles(dir))
{
if (File.GetLastAccessTime(file) < purgeLine)
@@ -721,18 +766,28 @@ namespace Flotsam.RegionModules.AssetCache
switch (cmd)
{
case "status":
m_log.InfoFormat("[FLOTSAM ASSET CACHE] Memory Cache : {0} assets", m_MemoryCache.Count);
if (m_MemoryCacheEnabled)
m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Memory Cache : {0} assets", m_MemoryCache.Count);
else
m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Memory cache disabled");
int fileCount = GetFileCacheCount(m_CacheDirectory);
m_log.InfoFormat("[FLOTSAM ASSET CACHE] File Cache : {0} assets", fileCount);
foreach (string s in Directory.GetFiles(m_CacheDirectory, "*.fac"))
if (m_FileCacheEnabled)
{
m_log.Info("[FLOTSAM ASSET CACHE] Deep Scans were performed on the following regions:");
string RegionID = s.Remove(0,s.IndexOf("_")).Replace(".fac","");
DateTime RegionDeepScanTMStamp = File.GetLastWriteTime(s);
m_log.InfoFormat("[FLOTSAM ASSET CACHE] Region: {0}, {1}", RegionID, RegionDeepScanTMStamp.ToString("MM/dd/yyyy hh:mm:ss"));
int fileCount = GetFileCacheCount(m_CacheDirectory);
m_log.InfoFormat("[FLOTSAM ASSET CACHE]: File Cache : {0} assets", fileCount);
foreach (string s in Directory.GetFiles(m_CacheDirectory, "*.fac"))
{
m_log.Info("[FLOTSAM ASSET CACHE]: Deep Scans were performed on the following regions:");
string RegionID = s.Remove(0,s.IndexOf("_")).Replace(".fac","");
DateTime RegionDeepScanTMStamp = File.GetLastWriteTime(s);
m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Region: {0}, {1}", RegionID, RegionDeepScanTMStamp.ToString("MM/dd/yyyy hh:mm:ss"));
}
}
else
{
m_log.InfoFormat("[FLOTSAM ASSET CACHE]: File cache disabled");
}
break;
@@ -740,7 +795,7 @@ namespace Flotsam.RegionModules.AssetCache
case "clear":
if (cmdparams.Length < 2)
{
m_log.Warn("[FLOTSAM ASSET CACHE] Usage is fcache clear [file] [memory]");
m_log.Warn("[FLOTSAM ASSET CACHE]: Usage is fcache clear [file] [memory]");
break;
}
@@ -761,36 +816,48 @@ namespace Flotsam.RegionModules.AssetCache
if (clearMemory)
{
m_MemoryCache.Clear();
m_log.Info("[FLOTSAM ASSET CACHE] Memory cache cleared.");
if (m_MemoryCacheEnabled)
{
m_MemoryCache.Clear();
m_log.Info("[FLOTSAM ASSET CACHE]: Memory cache cleared.");
}
else
{
m_log.Info("[FLOTSAM ASSET CACHE]: Memory cache not enabled.");
}
}
if (clearFile)
{
ClearFileCache();
m_log.Info("[FLOTSAM ASSET CACHE] File cache cleared.");
if (m_FileCacheEnabled)
{
ClearFileCache();
m_log.Info("[FLOTSAM ASSET CACHE]: File cache cleared.");
}
else
{
m_log.Info("[FLOTSAM ASSET CACHE]: File cache not enabled.");
}
}
break;
case "assets":
m_log.Info("[FLOTSAM ASSET CACHE] Caching all assets, in all scenes.");
m_log.Info("[FLOTSAM ASSET CACHE]: Caching all assets, in all scenes.");
Util.FireAndForget(delegate {
int assetsCached = CacheScenes();
m_log.InfoFormat("[FLOTSAM ASSET CACHE] Completed Scene Caching, {0} assets found.", assetsCached);
m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Completed Scene Caching, {0} assets found.", assetsCached);
});
break;
case "expire":
if (cmdparams.Length < 3)
{
m_log.InfoFormat("[FLOTSAM ASSET CACHE] Invalid parameters for Expire, please specify a valid date & time", cmd);
m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Invalid parameters for Expire, please specify a valid date & time", cmd);
break;
}
@@ -808,26 +875,28 @@ namespace Flotsam.RegionModules.AssetCache
if (!DateTime.TryParse(s_expirationDate, out expirationDate))
{
m_log.InfoFormat("[FLOTSAM ASSET CACHE] {0} is not a valid date & time", cmd);
m_log.InfoFormat("[FLOTSAM ASSET CACHE]: {0} is not a valid date & time", cmd);
break;
}
CleanExpiredFiles(m_CacheDirectory, expirationDate);
if (m_FileCacheEnabled)
CleanExpiredFiles(m_CacheDirectory, expirationDate);
else
m_log.InfoFormat("[FLOTSAM ASSET CACHE]: File cache not active, not clearing.");
break;
default:
m_log.InfoFormat("[FLOTSAM ASSET CACHE] Unknown command {0}", cmd);
m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Unknown command {0}", cmd);
break;
}
}
else if (cmdparams.Length == 1)
{
m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache status - Display cache status");
m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache clearmem - Remove all assets cached in memory");
m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache clearfile - Remove all assets cached on disk");
m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache cachescenes - Attempt a deep cache of all assets in all scenes");
m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache <datetime> - Purge assets older then the specified date & time");
m_log.InfoFormat("[FLOTSAM ASSET CACHE]: fcache status - Display cache status");
m_log.InfoFormat("[FLOTSAM ASSET CACHE]: fcache clearmem - Remove all assets cached in memory");
m_log.InfoFormat("[FLOTSAM ASSET CACHE]: fcache clearfile - Remove all assets cached on disk");
m_log.InfoFormat("[FLOTSAM ASSET CACHE]: fcache cachescenes - Attempt a deep cache of all assets in all scenes");
m_log.InfoFormat("[FLOTSAM ASSET CACHE]: fcache <datetime> - Purge assets older then the specified date & time");
}
}

View File

@@ -0,0 +1,127 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Threading;
using log4net.Config;
using Nini.Config;
using NUnit.Framework;
using OpenMetaverse;
using OpenMetaverse.Assets;
using Flotsam.RegionModules.AssetCache;
using OpenSim.Framework;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.Framework.Scenes.Serialization;
using OpenSim.Tests.Common;
using OpenSim.Tests.Common.Mock;
namespace OpenSim.Region.CoreModules.Asset.Tests
{
/// <summary>
/// At the moment we're only test the in-memory part of the FlotsamAssetCache. This is a considerable weakness.
/// </summary>
[TestFixture]
public class FlotsamAssetCacheTests
{
protected TestScene m_scene;
protected FlotsamAssetCache m_cache;
[SetUp]
public void SetUp()
{
IConfigSource config = new IniConfigSource();
config.AddConfig("Modules");
config.Configs["Modules"].Set("AssetCaching", "FlotsamAssetCache");
config.AddConfig("AssetCache");
config.Configs["AssetCache"].Set("FileCacheEnabled", "false");
config.Configs["AssetCache"].Set("MemoryCacheEnabled", "true");
m_cache = new FlotsamAssetCache();
m_scene = SceneSetupHelpers.SetupScene();
SceneSetupHelpers.SetupSceneModules(m_scene, config, m_cache);
}
[Test]
public void TestCacheAsset()
{
TestHelper.InMethod();
// log4net.Config.XmlConfigurator.Configure();
AssetBase asset = AssetHelpers.CreateAsset();
asset.ID = TestHelper.ParseTail(0x1).ToString();
// Check we don't get anything before the asset is put in the cache
AssetBase retrievedAsset = m_cache.Get(asset.ID.ToString());
Assert.That(retrievedAsset, Is.Null);
m_cache.Store(asset);
// Check that asset is now in cache
retrievedAsset = m_cache.Get(asset.ID.ToString());
Assert.That(retrievedAsset, Is.Not.Null);
Assert.That(retrievedAsset.ID, Is.EqualTo(asset.ID));
}
[Test]
public void TestExpireAsset()
{
TestHelper.InMethod();
// log4net.Config.XmlConfigurator.Configure();
AssetBase asset = AssetHelpers.CreateAsset();
asset.ID = TestHelper.ParseTail(0x2).ToString();
m_cache.Store(asset);
m_cache.Expire(asset.ID);
AssetBase retrievedAsset = m_cache.Get(asset.ID.ToString());
Assert.That(retrievedAsset, Is.Null);
}
[Test]
public void TestClearCache()
{
TestHelper.InMethod();
// log4net.Config.XmlConfigurator.Configure();
AssetBase asset = AssetHelpers.CreateAsset();
asset.ID = TestHelper.ParseTail(0x2).ToString();
m_cache.Store(asset);
m_cache.Clear();
AssetBase retrievedAsset = m_cache.Get(asset.ID.ToString());
Assert.That(retrievedAsset, Is.Null);
}
}
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using OpenMetaverse;
using OpenSim.Region.Framework.Scenes;
namespace OpenSim.Region.CoreModules.Avatar.NPC
{
public interface INPCModule
{
UUID CreateNPC(string firstname, string lastname, Vector3 position, Scene scene, UUID cloneAppearanceFrom);
void Autopilot(UUID agentID, Scene scene, Vector3 pos);
void Say(UUID agentID, Scene scene, string text);
void DeleteNPC(UUID agentID, Scene scene);
}
}

View File

@@ -449,7 +449,7 @@ namespace OpenSim.Region.CoreModules.World.Land
public bool IsBannedFromLand(UUID avatar)
{
if (m_scene.Permissions.IsAdministrator(avatar))
if (m_scene.Permissions.CanEditParcelProperties(avatar, this, 0))
return false;
if (m_scene.RegionInfo.EstateSettings.IsEstateManager(avatar))
@@ -463,7 +463,7 @@ namespace OpenSim.Region.CoreModules.World.Land
if (e.AgentID == avatar && e.Flags == AccessList.Ban)
return true;
return false;
}) != -1 && LandData.OwnerID != avatar)
}) != -1)
{
return true;
}
@@ -473,7 +473,7 @@ namespace OpenSim.Region.CoreModules.World.Land
public bool IsRestrictedFromLand(UUID avatar)
{
if (m_scene.Permissions.IsAdministrator(avatar))
if (m_scene.Permissions.CanEditParcelProperties(avatar, this, 0))
return false;
if (m_scene.RegionInfo.EstateSettings.IsEstateManager(avatar))
@@ -487,7 +487,7 @@ namespace OpenSim.Region.CoreModules.World.Land
if (e.AgentID == avatar && e.Flags == AccessList.Access)
return true;
return false;
}) == -1 && LandData.OwnerID != avatar)
}) == -1)
{
if (!HasGroupAccess(avatar))
{

View File

@@ -134,7 +134,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions
return;
m_allowGridGods = myConfig.GetBoolean("allow_grid_gods", false);
m_bypassPermissions = !myConfig.GetBoolean("serverside_object_permissions", false);
m_bypassPermissions = !myConfig.GetBoolean("serverside_object_permissions", true);
m_propagatePermissions = myConfig.GetBoolean("propagate_permissions", true);
m_RegionOwnerIsGod = myConfig.GetBoolean("region_owner_is_god", true);
m_RegionManagerIsGod = myConfig.GetBoolean("region_manager_is_god", false);