Merge branch 'master' of ssh://opensimulator.org/var/git/opensim

mb-throttle-test
Diva Canto 2014-12-25 08:01:50 -08:00
commit 27c34b69bf
28 changed files with 764 additions and 429 deletions

View File

@ -90,7 +90,7 @@ namespace OpenSim.Framework.Communications
private byte[] _readbuf;
/// <summary>
/// MemoryStream representing the resultiong resource
/// MemoryStream representing the resulting resource
/// </summary>
private Stream _resource;
@ -352,42 +352,46 @@ namespace OpenSim.Framework.Communications
m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} REST {1} to {2}", reqnum, _request.Method, _request.RequestUri);
// IAsyncResult responseAsyncResult = _request.BeginGetResponse(new AsyncCallback(ResponseIsReadyDelegate), _request);
try
{
_response = (HttpWebResponse) _request.GetResponse();
using (_response = (HttpWebResponse) _request.GetResponse())
{
using (Stream src = _response.GetResponseStream())
{
int length = src.Read(_readbuf, 0, BufferSize);
while (length > 0)
{
_resource.Write(_readbuf, 0, length);
length = src.Read(_readbuf, 0, BufferSize);
}
// TODO! Implement timeout, without killing the server
// this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted
//ThreadPool.RegisterWaitForSingleObject(responseAsyncResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true);
// _allDone.WaitOne();
}
}
}
catch (WebException e)
{
HttpWebResponse errorResponse = e.Response as HttpWebResponse;
if (null != errorResponse && HttpStatusCode.NotFound == errorResponse.StatusCode)
using (HttpWebResponse errorResponse = e.Response as HttpWebResponse)
{
// This is often benign. E.g., requesting a missing asset will return 404.
m_log.DebugFormat("[REST CLIENT] Resource not found (404): {0}", _request.Address.ToString());
}
else
{
m_log.Error(string.Format("[REST CLIENT] Error fetching resource from server: {0} ", _request.Address.ToString()), e);
if (null != errorResponse && HttpStatusCode.NotFound == errorResponse.StatusCode)
{
// This is often benign. E.g., requesting a missing asset will return 404.
m_log.DebugFormat("[REST CLIENT] Resource not found (404): {0}", _request.Address.ToString());
}
else
{
m_log.Error(string.Format("[REST CLIENT] Error fetching resource from server: {0} ", _request.Address.ToString()), e);
}
}
return null;
}
Stream src = _response.GetResponseStream();
int length = src.Read(_readbuf, 0, BufferSize);
while (length > 0)
{
_resource.Write(_readbuf, 0, length);
length = src.Read(_readbuf, 0, BufferSize);
}
// TODO! Implement timeout, without killing the server
// this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted
//ThreadPool.RegisterWaitForSingleObject(responseAsyncResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true);
// _allDone.WaitOne();
if (_response != null)
_response.Close();
if (_asyncException != null)
throw _asyncException;
@ -515,4 +519,4 @@ namespace OpenSim.Framework.Communications
#endregion Async Invocation
}
}
}

View File

@ -32,6 +32,8 @@ namespace OpenSim.Framework
{
public interface ISceneObject
{
string Name { get; }
UUID UUID { get; }
/// <summary>

View File

@ -256,20 +256,7 @@ namespace OpenSim.Region.CoreModules.Asset
// If the file is already cached, don't cache it, just touch it so access time is updated
if (File.Exists(filename))
{
// We don't really want to know about sharing
// violations here. If the file is locked, then
// the other thread has updated the time for us.
try
{
lock (m_CurrentlyWriting)
{
if (!m_CurrentlyWriting.Contains(filename))
File.SetLastAccessTime(filename, DateTime.Now);
}
}
catch
{
}
UpdateFileLastAccessTime(filename);
}
else
{
@ -328,6 +315,24 @@ namespace OpenSim.Region.CoreModules.Asset
}
}
/// <summary>
/// Updates the cached file with the current time.
/// </summary>
/// <param name="filename">Filename.</param>
/// <returns><c>true</c>, if the update was successful, false otherwise.</returns>
private bool UpdateFileLastAccessTime(string filename)
{
try
{
File.SetLastAccessTime(filename, DateTime.Now);
return true;
}
catch
{
return false;
}
}
/// <summary>
/// Try to get an asset from the in-memory cache.
/// </summary>
@ -771,8 +776,8 @@ namespace OpenSim.Region.CoreModules.Asset
{
UuidGatherer gatherer = new UuidGatherer(m_AssetService);
HashSet<UUID> uniqueUuids = new HashSet<UUID>();
Dictionary<UUID, sbyte> assets = new Dictionary<UUID, sbyte>();
Dictionary<UUID, sbyte> assetIdsToCheck = new Dictionary<UUID, sbyte>();
Dictionary<UUID, bool> assetsFound = new Dictionary<UUID, bool>();
foreach (Scene s in m_Scenes)
{
@ -780,34 +785,40 @@ namespace OpenSim.Region.CoreModules.Asset
s.ForEachSOG(delegate(SceneObjectGroup e)
{
gatherer.GatherAssetUuids(e, assets);
gatherer.GatherAssetUuids(e, assetIdsToCheck);
foreach (UUID assetID in assets.Keys)
foreach (UUID assetID in assetIdsToCheck.Keys)
{
uniqueUuids.Add(assetID);
string filename = GetFileName(assetID.ToString());
if (File.Exists(filename))
if (!assetsFound.ContainsKey(assetID))
{
File.SetLastAccessTime(filename, DateTime.Now);
string filename = GetFileName(assetID.ToString());
if (File.Exists(filename))
{
UpdateFileLastAccessTime(filename);
}
else if (storeUncached)
{
AssetBase cachedAsset = m_AssetService.Get(assetID.ToString());
if (cachedAsset == null && assetIdsToCheck[assetID] != (sbyte)AssetType.Unknown)
assetsFound[assetID] = false;
else
assetsFound[assetID] = true;
}
}
else if (storeUncached)
else if (!assetsFound[assetID])
{
AssetBase cachedAsset = m_AssetService.Get(assetID.ToString());
if (cachedAsset == null && assets[assetID] != (sbyte)AssetType.Unknown)
m_log.DebugFormat(
m_log.DebugFormat(
"[FLOTSAM ASSET CACHE]: Could not find asset {0}, type {1} referenced by object {2} at {3} in scene {4} when pre-caching all scene assets",
assetID, assets[assetID], e.Name, e.AbsolutePosition, s.Name);
assetID, assetIdsToCheck[assetID], e.Name, e.AbsolutePosition, s.Name);
}
}
assets.Clear();
assetIdsToCheck.Clear();
});
}
return uniqueUuids.Count;
return assetsFound.Count;
}
/// <summary>

View File

@ -255,6 +255,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
public void CopyAttachments(AgentData ad, IScenePresence sp)
{
// m_log.DebugFormat("[ATTACHMENTS MODULE]: Copying attachment data into {0} in {1}", sp.Name, m_scene.Name);
if (ad.AttachmentObjects != null && ad.AttachmentObjects.Count > 0)
{
lock (sp.AttachmentsSyncLock)
@ -265,6 +267,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
{
((SceneObjectGroup)so).LocalId = 0;
((SceneObjectGroup)so).RootPart.ClearUpdateSchedule();
// m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: Copying script state with {0} bytes for object {1} for {2} in {3}",
// ad.AttachmentObjectStates[i].Length, so.Name, sp.Name, m_scene.Name);
so.SetState(ad.AttachmentObjectStates[i++], m_scene);
m_scene.IncomingCreateObject(Vector3.Zero, so);
}
@ -334,11 +341,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
if (!Enabled)
return;
if (DebugLevel > 0)
m_log.DebugFormat("[ATTACHMENTS MODULE]: Saving changed attachments for {0}", sp.Name);
List<SceneObjectGroup> attachments = sp.GetAttachments();
if (DebugLevel > 0)
m_log.DebugFormat(
"[ATTACHMENTS MODULE]: Saving for {0} attachments for {1} in {2}",
attachments.Count, sp.Name, m_scene.Name);
if (attachments.Count <= 0)
return;
@ -352,6 +361,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
// This must be done outside the sp.AttachmentSyncLock so that there is no risk of a deadlock from
// scripts performing attachment operations at the same time. Getting object states stops the scripts.
scriptStates[so] = PrepareScriptInstanceForSave(so, false);
// m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: For object {0} for {1} in {2} got saved state {3}",
// so.Name, sp.Name, m_scene.Name, scriptStates[so]);
}
lock (sp.AttachmentsSyncLock)
@ -819,8 +832,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
{
if (DebugLevel > 0)
m_log.DebugFormat(
"[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}",
so.Name, sp.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos);
"[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} at pt {2} pos {3} {4} in {5}",
so.Name, sp.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos, m_scene.Name);
// Remove from database and parcel prim count
m_scene.DeleteFromStorage(so.UUID);

View File

@ -103,48 +103,51 @@ namespace OpenSim.Region.CoreModules.Avatar.BakedTextures
return null;
int size = 0;
RestClient rc = new RestClient(m_URL);
List<WearableCacheItem> ret = new List<WearableCacheItem>();
rc.AddResourcePath("bakes");
rc.AddResourcePath(id.ToString());
rc.RequestMethod = "GET";
try
using (RestClient rc = new RestClient(m_URL))
{
Stream s = rc.Request(m_Auth);
XmlTextReader sr = new XmlTextReader(s);
List<WearableCacheItem> ret = new List<WearableCacheItem>();
rc.AddResourcePath("bakes");
rc.AddResourcePath(id.ToString());
sr.ReadStartElement("BakedAppearance");
while (sr.LocalName == "BakedTexture")
rc.RequestMethod = "GET";
try
{
string sTextureIndex = sr.GetAttribute("TextureIndex");
int lTextureIndex = Convert.ToInt32(sTextureIndex);
string sCacheId = sr.GetAttribute("CacheId");
UUID lCacheId = UUID.Zero;
if (!(UUID.TryParse(sCacheId, out lCacheId)))
Stream s = rc.Request(m_Auth);
using (XmlTextReader sr = new XmlTextReader(s))
{
// ?? Nothing here
sr.ReadStartElement("BakedAppearance");
while (sr.LocalName == "BakedTexture")
{
string sTextureIndex = sr.GetAttribute("TextureIndex");
int lTextureIndex = Convert.ToInt32(sTextureIndex);
string sCacheId = sr.GetAttribute("CacheId");
UUID lCacheId = UUID.Zero;
if (!(UUID.TryParse(sCacheId, out lCacheId)))
{
// ?? Nothing here
}
++size;
sr.ReadStartElement("BakedTexture");
AssetBase a = (AssetBase)m_serializer.Deserialize(sr);
ret.Add(new WearableCacheItem() { CacheId = lCacheId, TextureIndex = (uint)lTextureIndex, TextureAsset = a, TextureID = a.FullID });
sr.ReadEndElement();
}
m_log.DebugFormat("[XBakes]: read {0} textures for user {1}", ret.Count, id);
}
++size;
sr.ReadStartElement("BakedTexture");
AssetBase a = (AssetBase)m_serializer.Deserialize(sr);
ret.Add(new WearableCacheItem() { CacheId = lCacheId, TextureIndex = (uint)lTextureIndex, TextureAsset = a, TextureID = a.FullID });
sr.ReadEndElement();
return ret.ToArray();
}
catch (XmlException)
{
return null;
}
m_log.DebugFormat("[XBakes]: read {0} textures for user {1}", ret.Count, id);
sr.Close();
s.Close();
return ret.ToArray();
}
catch (XmlException)
{
return null;
}
}
@ -153,27 +156,32 @@ namespace OpenSim.Region.CoreModules.Avatar.BakedTextures
if (m_URL == String.Empty)
return;
MemoryStream bakeStream = new MemoryStream();
XmlTextWriter bakeWriter = new XmlTextWriter(bakeStream, null);
MemoryStream reqStream;
bakeWriter.WriteStartElement(String.Empty, "BakedAppearance", String.Empty);
for (int i = 0; i < data.Length; i++)
using (MemoryStream bakeStream = new MemoryStream())
using (XmlTextWriter bakeWriter = new XmlTextWriter(bakeStream, null))
{
if (data[i] != null)
bakeWriter.WriteStartElement(String.Empty, "BakedAppearance", String.Empty);
for (int i = 0; i < data.Length; i++)
{
bakeWriter.WriteStartElement(String.Empty, "BakedTexture", String.Empty);
bakeWriter.WriteAttributeString(String.Empty, "TextureIndex", String.Empty, data[i].TextureIndex.ToString());
bakeWriter.WriteAttributeString(String.Empty, "CacheId", String.Empty, data[i].CacheId.ToString());
if (data[i].TextureAsset != null)
m_serializer.Serialize(bakeWriter, data[i].TextureAsset);
if (data[i] != null)
{
bakeWriter.WriteStartElement(String.Empty, "BakedTexture", String.Empty);
bakeWriter.WriteAttributeString(String.Empty, "TextureIndex", String.Empty, data[i].TextureIndex.ToString());
bakeWriter.WriteAttributeString(String.Empty, "CacheId", String.Empty, data[i].CacheId.ToString());
if (data[i].TextureAsset != null)
m_serializer.Serialize(bakeWriter, data[i].TextureAsset);
bakeWriter.WriteEndElement();
bakeWriter.WriteEndElement();
}
}
}
bakeWriter.WriteEndElement();
bakeWriter.Flush();
bakeWriter.WriteEndElement();
bakeWriter.Flush();
reqStream = new MemoryStream(bakeStream.ToArray());
}
RestClient rc = new RestClient(m_URL);
rc.AddResourcePath("bakes");
@ -181,7 +189,6 @@ namespace OpenSim.Region.CoreModules.Avatar.BakedTextures
rc.RequestMethod = "POST";
MemoryStream reqStream = new MemoryStream(bakeStream.ToArray());
Util.FireAndForget(
delegate
{
@ -191,4 +198,4 @@ namespace OpenSim.Region.CoreModules.Avatar.BakedTextures
);
}
}
}
}

View File

@ -604,8 +604,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// "[HG ENTITY TRANSFER MODULE]: Incoming attachment {0} for HG user {1} with asset service {2}",
// so.Name, so.AttachedAvatar, url);
IteratingHGUuidGatherer uuidGatherer = new IteratingHGUuidGatherer(Scene.AssetService, url);
uuidGatherer.RecordAssetUuids(so);
IDictionary<UUID, sbyte> ids = new Dictionary<UUID, sbyte>();
IteratingHGUuidGatherer uuidGatherer
= new IteratingHGUuidGatherer(Scene.AssetService, url, ids);
uuidGatherer.AddForInspection(so);
while (!uuidGatherer.Complete)
{
@ -632,8 +634,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
}
}
IDictionary<UUID, sbyte> ids = uuidGatherer.GetGatheredUuids();
// m_log.DebugFormat(
// "[HG ENTITY TRANSFER]: Fetching {0} assets for attachment {1} for HG user {2} with asset service {3}",
// ids.Count, so.Name, so.OwnerID, url);

View File

@ -680,6 +680,21 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
"Show the bindings between user UUIDs and user names",
String.Empty,
HandleShowUsers);
MainConsole.Instance.Commands.AddCommand("Users", true,
"reset user cache",
"reset user cache",
"reset user cache to allow changed settings to be applied",
String.Empty,
HandleResetUserCache);
}
private void HandleResetUserCache(string module, string[] cmd)
{
lock(m_UserCache)
{
m_UserCache.Clear();
}
}
private void HandleShowUser(string module, string[] cmd)

View File

@ -595,6 +595,9 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap
/// <returns>true if the url matches an entry on the whitelist, false otherwise</returns>
protected bool CheckUrlAgainstWhitelist(string rawUrl, string[] whitelist)
{
if (whitelist == null)
return false;
Uri url = new Uri(rawUrl);
foreach (string origWlUrl in whitelist)

View File

@ -122,6 +122,17 @@ namespace OpenSim.Region.Framework.Interfaces
/// <summary>
/// Check if the caller has permission to manipulate the given NPC.
/// </summary>
/// <remarks>
/// A caller has permission if
/// * An NPC exists with the given npcID.
/// * The caller UUID given is UUID.Zero.
/// * The avatar is unowned (owner is UUID.Zero).
/// * The avatar is owned and the owner and callerID match.
/// * The avatar is owned and the callerID matches its agentID.
/// </remarks>
/// <param name="av"></param>
/// <param name="callerID"></param>
/// <returns>true if they do, false if they don't.</returns>
/// <param name="npcID"></param>
/// <param name="callerID"></param>
/// <returns>

View File

@ -823,7 +823,6 @@ namespace OpenSim.Region.Framework.Scenes
m_sceneGridService = sceneGridService;
m_SimulationDataService = simDataService;
m_EstateDataService = estateDataService;
m_regionHandle = RegionInfo.RegionHandle;
m_asyncSceneObjectDeleter = new AsyncSceneObjectGroupDeleter(this);
m_asyncSceneObjectDeleter.Enabled = true;
@ -2042,11 +2041,11 @@ namespace OpenSim.Region.Framework.Scenes
GridRegion region = new GridRegion(RegionInfo);
string error = GridService.RegisterRegion(RegionInfo.ScopeID, region);
m_log.DebugFormat("{0} RegisterRegionWithGrid. name={1},id={2},loc=<{3},{4}>,size=<{5},{6}>",
LogHeader, m_regionName,
RegionInfo.RegionID,
RegionInfo.RegionLocX, RegionInfo.RegionLocY,
RegionInfo.RegionSizeX, RegionInfo.RegionSizeY);
// m_log.DebugFormat("[SCENE]: RegisterRegionWithGrid. name={0},id={1},loc=<{2},{3}>,size=<{4},{5}>",
// m_regionName,
// RegionInfo.RegionID,
// RegionInfo.RegionLocX, RegionInfo.RegionLocY,
// RegionInfo.RegionSizeX, RegionInfo.RegionSizeY);
if (error != String.Empty)
throw new Exception(error);

View File

@ -145,10 +145,6 @@ namespace OpenSim.Region.Framework.Scenes
get { return 1.0f; }
}
protected ulong m_regionHandle;
protected string m_regionName;
protected RegionInfo m_regInfo;
public ITerrainChannel Heightmap;
/// <value>

View File

@ -1228,45 +1228,27 @@ namespace OpenSim.Region.Framework.Scenes
m_scene.SwapRootAgentCount(false);
// The initial login scene presence is already root when it gets here
// and it has already rezzed the attachments and started their scripts.
// We do the following only for non-login agents, because their scripts
// haven't started yet.
if (PresenceType == PresenceType.Npc || IsRealLogin(m_teleportFlags))
if (Scene.AttachmentsModule != null)
{
// Viewers which have a current outfit folder will actually rez their own attachments. However,
// viewers without (e.g. v1 viewers) will not, so we still need to make this call.
if (Scene.AttachmentsModule != null)
// The initial login scene presence is already root when it gets here
// and it has already rezzed the attachments and started their scripts.
// We do the following only for non-login agents, because their scripts
// haven't started yet.
if (PresenceType == PresenceType.Npc || IsRealLogin(m_teleportFlags))
{
// Viewers which have a current outfit folder will actually rez their own attachments. However,
// viewers without (e.g. v1 viewers) will not, so we still need to make this call.
WorkManager.RunJob(
"RezAttachments",
o => Scene.AttachmentsModule.RezAttachments(this),
null,
string.Format("Rez attachments for {0} in {1}", Name, Scene.Name));
}
}
else
{
// We need to restart scripts here so that they receive the correct changed events (CHANGED_TELEPORT
// and CHANGED_REGION) when the attachments have been rezzed in the new region. This cannot currently
// be done in AttachmentsModule.CopyAttachments(AgentData ad, IScenePresence sp) itself since we are
// not transporting the required data.
//
// We must take a copy of the attachments list here (rather than locking) to avoid a deadlock where a script in one of
// the attachments may start processing an event (which locks ScriptInstance.m_Script) that then calls a method here
// which needs to lock m_attachments. ResumeScripts() needs to take a ScriptInstance.m_Script lock to try to unset the Suspend status.
//
// FIXME: In theory, this deadlock should not arise since scripts should not be processing events until ResumeScripts().
// But XEngine starts all scripts unsuspended. Starting them suspended will not currently work because script rezzing
// is placed in an asynchronous queue in XEngine and so the ResumeScripts() call will almost certainly execute before the
// script is rezzed. This means the ResumeScripts() does absolutely nothing when using XEngine.
List<SceneObjectGroup> attachments = GetAttachments();
if (attachments.Count > 0)
else
{
WorkManager.RunJob(
"StartAttachmentScripts",
o => RestartAttachmentScripts(attachments),
"StartAttachmentScripts",
o => RestartAttachmentScripts(),
null,
string.Format("Start attachment scripts for {0} in {1}", Name, Scene.Name),
true);
@ -1292,10 +1274,25 @@ namespace OpenSim.Region.Framework.Scenes
return true;
}
private void RestartAttachmentScripts(List<SceneObjectGroup> attachments)
private void RestartAttachmentScripts()
{
// We need to restart scripts here so that they receive the correct changed events (CHANGED_TELEPORT
// and CHANGED_REGION) when the attachments have been rezzed in the new region. This cannot currently
// be done in AttachmentsModule.CopyAttachments(AgentData ad, IScenePresence sp) itself since we are
// not transporting the required data.
//
// We must take a copy of the attachments list here (rather than locking) to avoid a deadlock where a script in one of
// the attachments may start processing an event (which locks ScriptInstance.m_Script) that then calls a method here
// which needs to lock m_attachments. ResumeScripts() needs to take a ScriptInstance.m_Script lock to try to unset the Suspend status.
//
// FIXME: In theory, this deadlock should not arise since scripts should not be processing events until ResumeScripts().
// But XEngine starts all scripts unsuspended. Starting them suspended will not currently work because script rezzing
// is placed in an asynchronous queue in XEngine and so the ResumeScripts() call will almost certainly execute before the
// script is rezzed. This means the ResumeScripts() does absolutely nothing when using XEngine.
List<SceneObjectGroup> attachments = GetAttachments();
m_log.DebugFormat(
"[SCENE PRESENCE]: Restarting scripts in attachments for {0} in {1}", Name, Scene.Name);
"[SCENE PRESENCE]: Restarting scripts in {0} attachments for {1} in {2}", attachments.Count, Name, Scene.Name);
// Resume scripts
foreach (SceneObjectGroup sog in attachments)

View File

@ -648,6 +648,15 @@ namespace OpenSim.Region.Framework.Scenes
}
}
/// <summary>
/// Gather uuids for a given entity.
/// </summary>
/// <remarks>
/// This does a deep inspection of the entity to retrieve all the assets it uses (whether as textures, as scripts
/// contained in inventory, as scripts contained in objects contained in another object's inventory, etc. Assets
/// are only retrieved when they are necessary to carry out the inspection (i.e. a serialized object needs to be
/// retrieved to work out which assets it references).
/// </remarks>
public class IteratingUuidGatherer
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@ -678,21 +687,31 @@ namespace OpenSim.Region.Framework.Scenes
protected Queue<UUID> m_assetUuidsToInspect;
public IteratingUuidGatherer(IAssetService assetService)
/// <summary>
/// Initializes a new instance of the <see cref="OpenSim.Region.Framework.Scenes.UuidGatherer"/> class.
/// </summary>
/// <param name="assetService">
/// Asset service.
/// </param>
/// <param name="collector">
/// Gathered UUIDs will be collected in this dictinaory.
/// It can be pre-populated if you want to stop the gatherer from analyzing assets that have already been fetched and inspected.
/// </param>
public IteratingUuidGatherer(IAssetService assetService, IDictionary<UUID, sbyte> collector)
{
m_assetService = assetService;
m_gatheredAssetUuids = new Dictionary<UUID, sbyte>();
m_gatheredAssetUuids = collector;
// FIXME: Not efficient for searching, can improve.
m_assetUuidsToInspect = new Queue<UUID>();
}
public IDictionary<UUID, sbyte> GetGatheredUuids()
{
return new Dictionary<UUID, sbyte>(m_gatheredAssetUuids);
}
public bool AddAssetUuidToInspect(UUID uuid)
/// <summary>
/// Adds the asset uuid for inspection during the gathering process.
/// </summary>
/// <returns><c>true</c>, if for inspection was added, <c>false</c> otherwise.</returns>
/// <param name="uuid">UUID.</param>
public bool AddForInspection(UUID uuid)
{
if (m_assetUuidsToInspect.Contains(uuid))
return false;
@ -701,6 +720,107 @@ namespace OpenSim.Region.Framework.Scenes
return true;
}
/// <summary>
/// Gather all the asset uuids associated with a given object.
/// </summary>
/// <remarks>
/// This includes both those directly associated with
/// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained
/// within this object).
/// </remarks>
/// <param name="sceneObject">The scene object for which to gather assets</param>
public void AddForInspection(SceneObjectGroup sceneObject)
{
// m_log.DebugFormat(
// "[ASSET GATHERER]: Getting assets for object {0}, {1}", sceneObject.Name, sceneObject.UUID);
SceneObjectPart[] parts = sceneObject.Parts;
for (int i = 0; i < parts.Length; i++)
{
SceneObjectPart part = parts[i];
// m_log.DebugFormat(
// "[ARCHIVER]: Getting part {0}, {1} for object {2}", part.Name, part.UUID, sceneObject.UUID);
try
{
Primitive.TextureEntry textureEntry = part.Shape.Textures;
if (textureEntry != null)
{
// Get the prim's default texture. This will be used for faces which don't have their own texture
if (textureEntry.DefaultTexture != null)
RecordTextureEntryAssetUuids(textureEntry.DefaultTexture);
if (textureEntry.FaceTextures != null)
{
// Loop through the rest of the texture faces (a non-null face means the face is different from DefaultTexture)
foreach (Primitive.TextureEntryFace texture in textureEntry.FaceTextures)
{
if (texture != null)
RecordTextureEntryAssetUuids(texture);
}
}
}
// If the prim is a sculpt then preserve this information too
if (part.Shape.SculptTexture != UUID.Zero)
m_gatheredAssetUuids[part.Shape.SculptTexture] = (sbyte)AssetType.Texture;
if (part.Shape.ProjectionTextureUUID != UUID.Zero)
m_gatheredAssetUuids[part.Shape.ProjectionTextureUUID] = (sbyte)AssetType.Texture;
if (part.CollisionSound != UUID.Zero)
m_gatheredAssetUuids[part.CollisionSound] = (sbyte)AssetType.Sound;
if (part.ParticleSystem.Length > 0)
{
try
{
Primitive.ParticleSystem ps = new Primitive.ParticleSystem(part.ParticleSystem, 0);
if (ps.Texture != UUID.Zero)
m_gatheredAssetUuids[ps.Texture] = (sbyte)AssetType.Texture;
}
catch (Exception)
{
m_log.WarnFormat(
"[UUID GATHERER]: Could not check particle system for part {0} {1} in object {2} {3} since it is corrupt. Continuing.",
part.Name, part.UUID, sceneObject.Name, sceneObject.UUID);
}
}
TaskInventoryDictionary taskDictionary = (TaskInventoryDictionary)part.TaskInventory.Clone();
// Now analyze this prim's inventory items to preserve all the uuids that they reference
foreach (TaskInventoryItem tii in taskDictionary.Values)
{
// m_log.DebugFormat(
// "[ARCHIVER]: Analysing item {0} asset type {1} in {2} {3}",
// tii.Name, tii.Type, part.Name, part.UUID);
if (!m_gatheredAssetUuids.ContainsKey(tii.AssetID))
AddForInspection(tii.AssetID, (sbyte)tii.Type);
}
// FIXME: We need to make gathering modular but we cannot yet, since gatherers are not guaranteed
// to be called with scene objects that are in a scene (e.g. in the case of hg asset mapping and
// inventory transfer. There needs to be a way for a module to register a method without assuming a
// Scene.EventManager is present.
// part.ParentGroup.Scene.EventManager.TriggerGatherUuids(part, assetUuids);
// still needed to retrieve textures used as materials for any parts containing legacy materials stored in DynAttrs
RecordMaterialsUuids(part);
}
catch (Exception e)
{
m_log.ErrorFormat("[UUID GATHERER]: Failed to get part - {0}", e);
m_log.DebugFormat(
"[UUID GATHERER]: Texture entry length for prim was {0} (min is 46)",
part.Shape.TextureEntry.Length);
}
}
}
/// <summary>
/// Gathers the next set of assets returned by the next uuid to get from the asset service.
@ -790,7 +910,7 @@ namespace OpenSim.Region.Framework.Scenes
}
}
private void RecordAssetUuids(UUID assetUuid, sbyte assetType)
private void AddForInspection(UUID assetUuid, sbyte assetType)
{
// Here, we want to collect uuids which require further asset fetches but mark the others as gathered
try
@ -799,27 +919,27 @@ namespace OpenSim.Region.Framework.Scenes
if ((sbyte)AssetType.Bodypart == assetType || (sbyte)AssetType.Clothing == assetType)
{
AddAssetUuidToInspect(assetUuid);
AddForInspection(assetUuid);
}
else if ((sbyte)AssetType.Gesture == assetType)
{
AddAssetUuidToInspect(assetUuid);
AddForInspection(assetUuid);
}
else if ((sbyte)AssetType.Notecard == assetType)
{
AddAssetUuidToInspect(assetUuid);
AddForInspection(assetUuid);
}
else if ((sbyte)AssetType.LSLText == assetType)
{
AddAssetUuidToInspect(assetUuid);
AddForInspection(assetUuid);
}
else if ((sbyte)OpenSimAssetType.Material == assetType)
{
AddAssetUuidToInspect(assetUuid);
AddForInspection(assetUuid);
}
else if ((sbyte)AssetType.Object == assetType)
{
AddAssetUuidToInspect(assetUuid);
AddForInspection(assetUuid);
}
}
catch (Exception)
@ -831,107 +951,6 @@ namespace OpenSim.Region.Framework.Scenes
}
}
/// <summary>
/// Gather all the asset uuids associated with a given object.
/// </summary>
/// <remarks>
/// This includes both those directly associated with
/// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained
/// within this object).
/// </remarks>
/// <param name="sceneObject">The scene object for which to gather assets</param>
public void RecordAssetUuids(SceneObjectGroup sceneObject)
{
// m_log.DebugFormat(
// "[ASSET GATHERER]: Getting assets for object {0}, {1}", sceneObject.Name, sceneObject.UUID);
SceneObjectPart[] parts = sceneObject.Parts;
for (int i = 0; i < parts.Length; i++)
{
SceneObjectPart part = parts[i];
// m_log.DebugFormat(
// "[ARCHIVER]: Getting part {0}, {1} for object {2}", part.Name, part.UUID, sceneObject.UUID);
try
{
Primitive.TextureEntry textureEntry = part.Shape.Textures;
if (textureEntry != null)
{
// Get the prim's default texture. This will be used for faces which don't have their own texture
if (textureEntry.DefaultTexture != null)
RecordTextureEntryAssetUuids(textureEntry.DefaultTexture);
if (textureEntry.FaceTextures != null)
{
// Loop through the rest of the texture faces (a non-null face means the face is different from DefaultTexture)
foreach (Primitive.TextureEntryFace texture in textureEntry.FaceTextures)
{
if (texture != null)
RecordTextureEntryAssetUuids(texture);
}
}
}
// If the prim is a sculpt then preserve this information too
if (part.Shape.SculptTexture != UUID.Zero)
m_gatheredAssetUuids[part.Shape.SculptTexture] = (sbyte)AssetType.Texture;
if (part.Shape.ProjectionTextureUUID != UUID.Zero)
m_gatheredAssetUuids[part.Shape.ProjectionTextureUUID] = (sbyte)AssetType.Texture;
if (part.CollisionSound != UUID.Zero)
m_gatheredAssetUuids[part.CollisionSound] = (sbyte)AssetType.Sound;
if (part.ParticleSystem.Length > 0)
{
try
{
Primitive.ParticleSystem ps = new Primitive.ParticleSystem(part.ParticleSystem, 0);
if (ps.Texture != UUID.Zero)
m_gatheredAssetUuids[ps.Texture] = (sbyte)AssetType.Texture;
}
catch (Exception)
{
m_log.WarnFormat(
"[UUID GATHERER]: Could not check particle system for part {0} {1} in object {2} {3} since it is corrupt. Continuing.",
part.Name, part.UUID, sceneObject.Name, sceneObject.UUID);
}
}
TaskInventoryDictionary taskDictionary = (TaskInventoryDictionary)part.TaskInventory.Clone();
// Now analyze this prim's inventory items to preserve all the uuids that they reference
foreach (TaskInventoryItem tii in taskDictionary.Values)
{
// m_log.DebugFormat(
// "[ARCHIVER]: Analysing item {0} asset type {1} in {2} {3}",
// tii.Name, tii.Type, part.Name, part.UUID);
if (!m_gatheredAssetUuids.ContainsKey(tii.AssetID))
RecordAssetUuids(tii.AssetID, (sbyte)tii.Type);
}
// FIXME: We need to make gathering modular but we cannot yet, since gatherers are not guaranteed
// to be called with scene objects that are in a scene (e.g. in the case of hg asset mapping and
// inventory transfer. There needs to be a way for a module to register a method without assuming a
// Scene.EventManager is present.
// part.ParentGroup.Scene.EventManager.TriggerGatherUuids(part, assetUuids);
// still needed to retrieve textures used as materials for any parts containing legacy materials stored in DynAttrs
RecordMaterialsUuids(part);
}
catch (Exception e)
{
m_log.ErrorFormat("[UUID GATHERER]: Failed to get part - {0}", e);
m_log.DebugFormat(
"[UUID GATHERER]: Texture entry length for prim was {0} (min is 46)",
part.Shape.TextureEntry.Length);
}
}
}
/// <summary>
/// Collect all the asset uuids found in one face of a Texture Entry.
/// </summary>
@ -940,7 +959,7 @@ namespace OpenSim.Region.Framework.Scenes
m_gatheredAssetUuids[texture.TextureID] = (sbyte)AssetType.Texture;
if (texture.MaterialID != UUID.Zero)
AddAssetUuidToInspect(texture.MaterialID);
AddForInspection(texture.MaterialID);
}
/// <summary>
@ -948,7 +967,7 @@ namespace OpenSim.Region.Framework.Scenes
/// stored in legacy format in part.DynAttrs
/// </summary>
/// <param name="part"></param>
public void RecordMaterialsUuids(SceneObjectPart part)
private void RecordMaterialsUuids(SceneObjectPart part)
{
// scan thru the dynAttrs map of this part for any textures used as materials
OSD osdMaterials = null;
@ -1039,7 +1058,7 @@ namespace OpenSim.Region.Framework.Scenes
UUID uuid = new UUID(uuidMatch.Value);
// m_log.DebugFormat("[ARCHIVER]: Recording {0} in text", uuid);
AddAssetUuidToInspect(uuid);
AddForInspection(uuid);
}
}
@ -1074,14 +1093,14 @@ namespace OpenSim.Region.Framework.Scenes
if (CoalescedSceneObjectsSerializer.TryFromXml(xml, out coa))
{
foreach (SceneObjectGroup sog in coa.Objects)
RecordAssetUuids(sog);
AddForInspection(sog);
}
else
{
SceneObjectGroup sog = SceneObjectSerializer.FromOriginalXmlFormat(xml);
if (null != sog)
RecordAssetUuids(sog);
AddForInspection(sog);
}
}
@ -1147,8 +1166,8 @@ namespace OpenSim.Region.Framework.Scenes
protected string m_assetServerURL;
public IteratingHGUuidGatherer(IAssetService assetService, string assetServerURL)
: base(assetService)
public IteratingHGUuidGatherer(IAssetService assetService, string assetServerURL, IDictionary<UUID, sbyte> collector)
: base(assetService, collector)
{
m_assetServerURL = assetServerURL;
if (!m_assetServerURL.EndsWith("/") && !m_assetServerURL.EndsWith("="))

View File

@ -441,13 +441,20 @@ namespace OpenSim.Region.OptionalModules.World.NPC
/// <summary>
/// Check if the caller has permission to manipulate the given NPC.
/// </summary>
/// <remarks>
/// A caller has permission if
/// * The caller UUID given is UUID.Zero.
/// * The avatar is unowned (owner is UUID.Zero).
/// * The avatar is owned and the owner and callerID match.
/// * The avatar is owned and the callerID matches its agentID.
/// </remarks>
/// <param name="av"></param>
/// <param name="callerID"></param>
/// <returns>true if they do, false if they don't.</returns>
private bool CheckPermissions(NPCAvatar av, UUID callerID)
{
return callerID == UUID.Zero || av.OwnerID == UUID.Zero ||
av.OwnerID == callerID;
av.OwnerID == callerID || av.AgentId == callerID;
}
}
}

View File

@ -222,7 +222,7 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
void SetVars(Dictionary<string, object> vars);
DetectParams GetDetectParams(int idx);
UUID GetDetectID(int idx);
void SaveState(string assembly);
void SaveState();
void DestroyScriptInstance();
IScriptApi GetApi(string name);

View File

@ -663,9 +663,8 @@ namespace SecondLife
try
{
FileStream fs = File.Open(assembly, FileMode.Open, FileAccess.Read);
fs.Read(data, 0, data.Length);
fs.Close();
using (FileStream fs = File.Open(assembly, FileMode.Open, FileAccess.Read))
fs.Read(data, 0, data.Length);
}
catch (Exception)
{
@ -680,9 +679,8 @@ namespace SecondLife
Byte[] buf = Encoding.ASCII.GetBytes(filetext);
FileStream sfs = File.Create(assembly + ".text");
sfs.Write(buf, 0, buf.Length);
sfs.Close();
using (FileStream sfs = File.Create(assembly + ".text"))
sfs.Write(buf, 0, buf.Length);
return assembly;
}
@ -775,7 +773,6 @@ namespace SecondLife
return message;
}
private static void WriteMapFile(string filename, Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap)
{
string mapstring = String.Empty;
@ -787,40 +784,42 @@ namespace SecondLife
}
Byte[] mapbytes = Encoding.ASCII.GetBytes(mapstring);
FileStream mfs = File.Create(filename);
mfs.Write(mapbytes, 0, mapbytes.Length);
mfs.Close();
}
using (FileStream mfs = File.Create(filename))
mfs.Write(mapbytes, 0, mapbytes.Length);
}
private static Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> ReadMapFile(string filename)
{
Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap;
try
{
StreamReader r = File.OpenText(filename);
linemap = new Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>();
string line;
while ((line = r.ReadLine()) != null)
using (StreamReader r = File.OpenText(filename))
{
String[] parts = line.Split(new Char[] { ',' });
int kk = System.Convert.ToInt32(parts[0]);
int kv = System.Convert.ToInt32(parts[1]);
int vk = System.Convert.ToInt32(parts[2]);
int vv = System.Convert.ToInt32(parts[3]);
linemap = new Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>();
KeyValuePair<int, int> k = new KeyValuePair<int, int>(kk, kv);
KeyValuePair<int, int> v = new KeyValuePair<int, int>(vk, vv);
string line;
while ((line = r.ReadLine()) != null)
{
String[] parts = line.Split(new Char[] { ',' });
int kk = System.Convert.ToInt32(parts[0]);
int kv = System.Convert.ToInt32(parts[1]);
int vk = System.Convert.ToInt32(parts[2]);
int vv = System.Convert.ToInt32(parts[3]);
linemap[k] = v;
KeyValuePair<int, int> k = new KeyValuePair<int, int>(kk, kv);
KeyValuePair<int, int> v = new KeyValuePair<int, int>(vk, vv);
linemap[k] = v;
}
}
}
catch
{
linemap = new Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>();
}
return linemap;
}
}
}
}

View File

@ -71,7 +71,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
private bool m_TimerQueued;
private DateTime m_EventStart;
private bool m_InEvent;
private string m_Assembly;
private string m_assemblyPath;
private string m_dataPath;
private string m_CurrentEvent = String.Empty;
private bool m_InSelfDelete;
private int m_MaxScriptQueue;
@ -244,12 +245,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
/// </summary>
/// <param name='dom'></param>
/// <param name='assembly'></param>
/// <param name='dataPath'>
/// Path for all script associated data (state, etc.). In a multi-region set up
/// with all scripts loading into the same AppDomain this may not be the same place as the DLL itself.
/// </param>
/// <param name='stateSource'></param>
/// <returns>false if load failed, true if suceeded</returns>
public bool Load(AppDomain dom, Assembly scriptAssembly, StateSource stateSource)
public bool Load(AppDomain dom, Assembly scriptAssembly, string dataPath, StateSource stateSource)
{
//m_Assembly = scriptAssembly.CodeBase;
m_Assembly = scriptAssembly.Location;
m_assemblyPath = scriptAssembly.Location;
m_dataPath = dataPath;
m_stateSource = stateSource;
try
@ -270,14 +275,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
constructorParams = null;
}
// m_log.DebugFormat(
// "[SCRIP
// scriptType.FullName, m_Assembly, Engine.World.Name);
if (dom != System.AppDomain.CurrentDomain)
m_Script
= (IScript)dom.CreateInstanceAndUnwrap(
Path.GetFileNameWithoutExtension(m_Assembly),
Path.GetFileNameWithoutExtension(m_assemblyPath),
scriptType.FullName,
false,
BindingFlags.Default,
@ -305,7 +306,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
{
m_log.ErrorFormat(
"[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Error loading assembly {6}. Exception {7}{8}",
ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, m_Assembly, e.Message, e.StackTrace);
ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, scriptAssembly.Location, e.Message, e.StackTrace);
return false;
}
@ -340,10 +341,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
m_SaveState = true;
string savedState = Path.Combine(Path.GetDirectoryName(m_Assembly), ItemID.ToString() + ".state");
string savedState = Path.Combine(m_dataPath, ItemID.ToString() + ".state");
if (File.Exists(savedState))
{
// m_log.DebugFormat(
// "[SCRIPT INSTANCE]: Found state for script {0} for {1} ({2}) at {3} in {4}",
// ItemID, savedState, Part.Name, Part.ParentGroup.Name, Part.ParentGroup.Scene.Name);
string xml = String.Empty;
try
@ -385,12 +390,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
m_startedFromSavedState = true;
}
}
else
{
m_log.WarnFormat(
"[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Unable to load script state file {6}. Memory limit exceeded.",
ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState);
}
// else
// {
// m_log.WarnFormat(
// "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Unable to load script state file {6}. Memory limit exceeded.",
// ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState);
// }
}
catch (Exception e)
{
@ -401,11 +406,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
}
// else
// {
// ScenePresence presence = Engine.World.GetScenePresence(part.OwnerID);
// if (presence != null && (!postOnRez))
// presence.ControllingClient.SendAgentAlertMessage("Compile successful", false);
// m_log.DebugFormat(
// "[SCRIPT INSTANCE]: Did not find state for script {0} for {1} ({2}) at {3} in {4}",
// ItemID, savedState, Part.Name, Part.ParentGroup.Name, Part.ParentGroup.Scene.Name);
// }
return true;
@ -498,8 +501,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
public void RemoveState()
{
string savedState = Path.Combine(Path.GetDirectoryName(m_Assembly),
ItemID.ToString() + ".state");
string savedState = Path.Combine(m_dataPath, ItemID.ToString() + ".state");
// m_log.DebugFormat(
// "[SCRIPT INSTANCE]: Deleting state {0} for script {1} (id {2}) in part {3} (id {4}) in object {5} in {6}.",
// savedState, ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name);
try
{
@ -822,8 +828,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
if (Engine.World.PipeEventsForScript(LocalID) ||
data.EventName == "control") // Don't freeze avies!
{
// m_log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}",
// PrimName, ScriptName, data.EventName, State);
// m_log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}",
// PrimName, ScriptName, data.EventName, State);
try
{
@ -849,7 +855,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
// This will be the very first event we deliver
// (state_entry) in default state
//
SaveState(m_Assembly);
SaveState();
m_SaveState = false;
}
@ -1043,7 +1049,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
return m_DetectParams[idx].Key;
}
public void SaveState(string assembly)
public void SaveState()
{
// If we're currently in an event, just tell it to save upon return
//
@ -1065,10 +1071,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
{
try
{
FileStream fs = File.Create(Path.Combine(Path.GetDirectoryName(assembly), ItemID.ToString() + ".state"));
Byte[] buf = Util.UTF8NoBomEncoding.GetBytes(xml);
fs.Write(buf, 0, buf.Length);
fs.Close();
using (FileStream fs = File.Create(Path.Combine(m_dataPath, ItemID.ToString() + ".state")))
{
Byte[] buf = Util.UTF8NoBomEncoding.GetBytes(xml);
fs.Write(buf, 0, buf.Length);
}
}
catch(Exception)
{
@ -1148,7 +1155,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
public string GetAssemblyName()
{
return m_Assembly;
return m_assemblyPath;
}
public string GetXMLState()

View File

@ -40,10 +40,10 @@ using OpenSim.Tests.Common;
namespace OpenSim.Region.ScriptEngine.XEngine.Tests
{
/// <summary>
/// XEngine tests.
/// Basic XEngine tests.
/// </summary>
[TestFixture]
public class XEngineTest : OpenSimTestCase
public class XEngineBasicTests : OpenSimTestCase
{
private TestScene m_scene;
private XEngine m_xEngine;

View File

@ -0,0 +1,195 @@
/*
* 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.Threading;
using Nini.Config;
using NUnit.Framework;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Region.CoreModules.Framework.EntityTransfer;
using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.ScriptEngine.Shared;
using OpenSim.Tests.Common;
namespace OpenSim.Region.ScriptEngine.XEngine.Tests
{
/// <summary>
/// XEngine tests connected with crossing scripts between regions.
/// </summary>
[TestFixture]
public class XEngineCrossingTests : OpenSimTestCase
{
[TestFixtureSetUp]
public void FixtureInit()
{
// Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
}
[TestFixtureTearDown]
public void TearDown()
{
// We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
// threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
// tests really shouldn't).
Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
}
/// <summary>
/// Test script state preservation when a script crosses between regions on the same simulator.
/// </summary>
[Test]
public void TestScriptCrossOnSameSimulator()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
UUID userId = TestHelpers.ParseTail(0x1);
int sceneObjectIdTail = 0x2;
EntityTransferModule etmA = new EntityTransferModule();
EntityTransferModule etmB = new EntityTransferModule();
LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule();
XEngine xEngineA = new XEngine();
XEngine xEngineB = new XEngine();
xEngineA.DebugLevel = 1;
xEngineB.DebugLevel = 1;
IConfigSource configSource = new IniConfigSource();
IConfig startupConfig = configSource.AddConfig("Startup");
startupConfig.Set("DefaultScriptEngine", "XEngine");
IConfig xEngineConfig = configSource.AddConfig("XEngine");
xEngineConfig.Set("Enabled", "true");
xEngineConfig.Set("StartDelay", "0");
// These tests will not run with AppDomainLoading = true, at least on mono. For unknown reasons, the call
// to AssemblyResolver.OnAssemblyResolve fails.
xEngineConfig.Set("AppDomainLoading", "false");
IConfig modulesConfig = configSource.AddConfig("Modules");
modulesConfig.Set("EntityTransferModule", etmA.Name);
modulesConfig.Set("SimulationServices", lscm.Name);
SceneHelpers sh = new SceneHelpers();
TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000, configSource);
TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999, configSource);
SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, configSource, lscm);
SceneHelpers.SetupSceneModules(sceneA, configSource, etmA, xEngineA);
SceneHelpers.SetupSceneModules(sceneB, configSource, etmB, xEngineB);
sceneA.StartScripts();
sceneB.StartScripts();
SceneObjectGroup soSceneA = SceneHelpers.AddSceneObject(sceneA, 1, userId, "so1-", sceneObjectIdTail);
soSceneA.AbsolutePosition = new Vector3(128, 10, 20);
// CREATE SCRIPT TODO
InventoryItemBase scriptItemSceneA = new InventoryItemBase();
// itemTemplate.ID = itemId;
scriptItemSceneA.Name = "script1";
scriptItemSceneA.Folder = soSceneA.UUID;
scriptItemSceneA.InvType = (int)InventoryType.LSL;
AutoResetEvent chatEvent = new AutoResetEvent(false);
OSChatMessage messageReceived = null;
sceneA.EventManager.OnChatFromWorld += (s, m) => { messageReceived = m; chatEvent.Set(); };
sceneA.RezNewScript(userId, scriptItemSceneA,
@"integer c = 0;
default
{
state_entry()
{
llSay(0, ""Script running"");
}
changed(integer change)
{
llSay(0, ""Changed"");
}
touch_start(integer n)
{
c = c + 1;
llSay(0, (string)c);
}
}");
chatEvent.WaitOne(60000);
Assert.That(messageReceived, Is.Not.Null, "No chat message received.");
Assert.That(messageReceived.Message, Is.EqualTo("Script running"));
{
// XXX: Should not be doing this so directly. Should call some variant of EventManager.touch() instead.
DetectParams[] det = new DetectParams[1];
det[0] = new DetectParams();
det[0].Key = userId;
det[0].Populate(sceneA);
EventParams ep = new EventParams("touch_start", new Object[] { new LSL_Types.LSLInteger(1) }, det);
xEngineA.PostObjectEvent(soSceneA.LocalId, ep);
chatEvent.WaitOne(60000);
Assert.That(messageReceived.Message, Is.EqualTo("1"));
}
sceneB.EventManager.OnChatFromWorld += (s, m) => { messageReceived = m; chatEvent.Set(); };
// Cross with a negative value
soSceneA.AbsolutePosition = new Vector3(128, -10, 20);
chatEvent.WaitOne(60000);
Assert.That(messageReceived.Message, Is.EqualTo("Changed"));
// TEST sending event to moved prim and output
{
SceneObjectGroup soSceneB = sceneB.GetSceneObjectGroup(soSceneA.Name);
TaskInventoryItem scriptItemSceneB = soSceneB.RootPart.Inventory.GetInventoryItem(scriptItemSceneA.Name);
// XXX: Should not be doing this so directly. Should call some variant of EventManager.touch() instead.
DetectParams[] det = new DetectParams[1];
det[0] = new DetectParams();
det[0].Key = userId;
det[0].Populate(sceneB);
EventParams ep = new EventParams("touch_start", new Object[] { new LSL_Types.LSLInteger(1) }, det);
xEngineB.PostObjectEvent(soSceneB.LocalId, ep);
chatEvent.WaitOne(60000);
Assert.That(messageReceived.Message, Is.EqualTo("2"));
}
}
}
}

View File

@ -70,7 +70,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
/// <remarks>
/// If DebugLevel >= 1, then we log every time that a script is started.
/// </remarks>
// public int DebugLevel { get; set; }
public int DebugLevel { get; set; }
private SmartThreadPool m_ThreadPool;
private int m_MaxScriptQueue;
@ -101,7 +101,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine
private bool m_InitialStartup = true;
private int m_ScriptFailCount; // Number of script fails since compile queue was last empty
private string m_ScriptErrorMessage;
private Dictionary<string, string> m_uniqueScripts = new Dictionary<string, string>();
private bool m_AppDomainLoading;
private Dictionary<UUID,ArrayList> m_ScriptErrors =
new Dictionary<UUID,ArrayList>();
@ -403,12 +402,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine
+ "Level >= 2, log event invocations.\n",
HandleDebugScriptLogCommand);
// MainConsole.Instance.Commands.AddCommand(
// "Debug", false, "debug xengine", "debug xengine [<level>]",
// "Turn on detailed xengine debugging.",
// "If level <= 0, then no extra logging is done.\n"
// + "If level >= 1, then we log every time that a script is started.",
// HandleDebugLevelCommand);
MainConsole.Instance.Commands.AddCommand(
"Debug", false, "debug xengine log", "debug xengine log [<level>]",
"Turn on detailed xengine debugging.",
"If level <= 0, then no extra logging is done.\n"
+ "If level >= 1, then we log every time that a script is started.",
HandleDebugLevelCommand);
}
private void HandleDebugScriptLogCommand(string module, string[] args)
@ -451,26 +450,26 @@ namespace OpenSim.Region.ScriptEngine.XEngine
/// </summary>
/// <param name="module"></param>
/// <param name="args"></param>
// private void HandleDebugLevelCommand(string module, string[] args)
// {
// if (args.Length == 3)
// {
// int newDebug;
// if (int.TryParse(args[2], out newDebug))
// {
// DebugLevel = newDebug;
// MainConsole.Instance.OutputFormat("Debug level set to {0}", newDebug);
// }
// }
// else if (args.Length == 2)
// {
// MainConsole.Instance.OutputFormat("Current debug level is {0}", DebugLevel);
// }
// else
// {
// MainConsole.Instance.Output("Usage: debug xengine 0..1");
// }
// }
private void HandleDebugLevelCommand(string module, string[] args)
{
if (args.Length <= 4)
{
int newDebug;
if (ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, args[3], out newDebug))
{
DebugLevel = newDebug;
MainConsole.Instance.OutputFormat("Debug level set to {0} in XEngine for region {1}", newDebug, m_Scene.Name);
}
}
else if (args.Length == 3)
{
MainConsole.Instance.OutputFormat("Current debug level is {0}", DebugLevel);
}
else
{
MainConsole.Instance.Output("Usage: debug xengine log <level>");
}
}
/// <summary>
/// Parse the raw item id into a script instance from the command params if it's present.
@ -570,7 +569,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine
}
sb.AppendFormat("Scripts loaded : {0}\n", scriptsLoaded);
sb.AppendFormat("Unique scripts : {0}\n", m_uniqueScripts.Count);
sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count);
sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads);
sb.AppendFormat("Min threads : {0}\n", m_ThreadPool.MinThreads);
@ -716,22 +714,17 @@ namespace OpenSim.Region.ScriptEngine.XEngine
{
// Force a final state save
//
if (m_Assemblies.ContainsKey(instance.AssetID))
try
{
string assembly = m_Assemblies[instance.AssetID];
try
{
instance.SaveState(assembly);
}
catch (Exception e)
{
m_log.Error(
string.Format(
"[XEngine]: Failed final state save for script {0}.{1}, item UUID {2}, prim UUID {3} in {4}. Exception ",
instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, World.Name)
, e);
}
instance.SaveState();
}
catch (Exception e)
{
m_log.Error(
string.Format(
"[XEngine]: Failed final state save for script {0}.{1}, item UUID {2}, prim UUID {3} in {4}. Exception ",
instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, World.Name)
, e);
}
// Clear the event queue and abort the instance thread
@ -840,18 +833,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine
foreach (IScriptInstance i in instances)
{
string assembly = String.Empty;
lock (m_Scripts)
{
if (!m_Assemblies.ContainsKey(i.AssetID))
continue;
assembly = m_Assemblies[i.AssetID];
}
try
{
i.SaveState(assembly);
i.SaveState();
}
catch (Exception e)
{
@ -1001,12 +985,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine
if (engine != ScriptEngineName)
return;
// If we've seen this exact script text before, use that reference instead
if (m_uniqueScripts.ContainsKey(script))
script = m_uniqueScripts[script];
else
m_uniqueScripts[script] = script;
Object[] parms = new Object[]{localID, itemID, script, startParam, postOnRez, (StateSource)stateSource};
if (stateSource == (int)StateSource.ScriptedRez)
@ -1020,11 +998,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine
}
else
{
m_CompileQueue.Enqueue(parms);
lock (m_CompileDict)
{
m_CompileDict[itemID] = 0;
}
// This must occur after the m_CompileDict so that an existing compile thread cannot hit the check
// in DoOnRezScript() before m_CompileDict has been updated.
m_CompileQueue.Enqueue(parms);
// m_log.DebugFormat("[XEngine]: Added script {0} to compile queue", itemID);
@ -1100,7 +1079,15 @@ namespace OpenSim.Region.ScriptEngine.XEngine
// due to a race condition
//
lock (m_CompileQueue)
{
m_CurrentCompile = null;
// This is to avoid a situation where the m_CompileQueue while loop above could complete but
// OnRezScript() place a new script on the queue and check m_CurrentCompile = null before we hit
// this section.
if (m_CompileQueue.Count > 0)
m_CurrentCompile = m_ThreadPool.QueueWorkItem(DoOnRezScriptQueue, null);
}
}
return null;
@ -1148,10 +1135,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine
return false;
}
m_log.DebugFormat(
"[XEngine]: Loading script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5}",
part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID,
part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName);
if (DebugLevel > 0)
m_log.DebugFormat(
"[XEngine]: Loading script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5}",
part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID,
part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName);
UUID assetID = item.AssetID;
@ -1170,7 +1158,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine
lock (m_AddingAssemblies)
{
m_Compiler.PerformScriptCompile(script, assetID.ToString(), item.OwnerID, out assemblyPath, out linemap);
// m_log.DebugFormat(
// "[XENGINE]: Found assembly path {0} onrez {1} in {2}",
// assemblyPath, item.ItemID, World.Name);
if (!m_AddingAssemblies.ContainsKey(assemblyPath)) {
m_AddingAssemblies[assemblyPath] = 1;
} else {
@ -1348,14 +1340,24 @@ namespace OpenSim.Region.ScriptEngine.XEngine
// simulator session if the script halt strategy has been changed. Instead, we'll continue with
// the existing DLL and the new one will be used in the next simulator session.
if (recompile)
{
m_log.DebugFormat(
"[XEngine]: Recompiling script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5} to switch it to {6} termination. Will be active on next restart.",
part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID,
part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.Name,
m_coopTermination ? "co-op" : "abort");
m_Compiler.PerformScriptCompile(script, assetID.ToString(), item.OwnerID, true, out assemblyPath, out linemap);
}
instance = new ScriptInstance(this, part,
item,
startParam, postOnRez,
m_MaxScriptQueue);
if (!instance.Load(m_AppDomains[appDomain], scriptAssembly, stateSource))
if (!instance.Load(
m_AppDomains[appDomain], scriptAssembly,
Path.Combine(ScriptEnginePath, World.RegionInfo.RegionID.ToString()), stateSource))
return false;
// if (DebugLevel >= 1)
@ -1586,7 +1588,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
IScriptInstance instance = (ScriptInstance) parms;
//m_log.DebugFormat("[XEngine]: Processing event for {0}", instance);
// m_log.DebugFormat("[XEngine]: Processing event for {0}", instance);
return instance.EventProcessor();
}
@ -2155,7 +2157,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
catch (IOException ex)
{
// if there already exists a file at that location, it may be locked.
m_log.ErrorFormat("[XEngine]: Linemap file {0} already exists! {1}", mappath, ex.Message);
m_log.Error(
string.Format("[XEngine]: Linemap file {0} could not be written. Exception ", mappath), ex);
}
}
}
@ -2181,6 +2184,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine
m_log.ErrorFormat("[XEngine]: Error whilst writing state file {0}, {1}", statepath, ex.Message);
}
// m_log.DebugFormat(
// "[XEngine]: Wrote state for script item with ID {0} at {1} in {2}", itemID, statepath, m_Scene.Name);
return true;
}

View File

@ -107,11 +107,9 @@ namespace OpenSim.Server.Handlers.BakedTextures
File.Delete(diskFile);
byte[] data = utf8encoding.GetBytes(sdata);
FileStream fs = File.Create(diskFile);
fs.Write(data, 0, data.Length);
fs.Close();
using (FileStream fs = File.Create(diskFile))
fs.Write(data, 0, data.Length);
}
private void HandleDeleteBakes(string module, string[] args)

View File

@ -317,8 +317,10 @@ namespace OpenSim.Services.GridService
m_log.DebugFormat("[GRID SERVICE]: Database exception: {0}", e);
}
m_log.DebugFormat("[GRID SERVICE]: Region {0} ({1}) registered successfully at {2}-{3} with flags {4}",
regionInfos.RegionName, regionInfos.RegionID, regionInfos.RegionCoordX, regionInfos.RegionCoordY,
m_log.DebugFormat
("[GRID SERVICE]: Region {0} ({1}, {2}x{3}) registered at {4},{5} with flags {6}",
regionInfos.RegionName, regionInfos.RegionID, regionInfos.RegionSizeX, regionInfos.RegionSizeY,
regionInfos.RegionCoordX, regionInfos.RegionCoordY,
(OpenSim.Framework.RegionFlags)flags);
return String.Empty;

View File

@ -98,7 +98,12 @@ namespace OpenSim.Services.UserAccountService
MainConsole.Instance.Commands.AddCommand("Users", false,
"reset user password",
"reset user password [<first> [<last> [<password>]]]",
"Reset a user password", HandleResetUserPassword);
"Reset a user password", HandleResetUserPassword);
MainConsole.Instance.Commands.AddCommand("Users", false,
"reset user email",
"reset user email [<first> [<last> [<email>]]]",
"Reset a user email address", HandleResetUserEmail);
MainConsole.Instance.Commands.AddCommand("Users", false,
"set user level",
@ -420,6 +425,43 @@ namespace OpenSim.Services.UserAccountService
MainConsole.Instance.OutputFormat("Password reset for user {0} {1}", firstName, lastName);
}
protected void HandleResetUserEmail(string module, string[] cmdparams)
{
string firstName;
string lastName;
string newEmail;
if (cmdparams.Length < 4)
firstName = MainConsole.Instance.CmdPrompt("First name");
else firstName = cmdparams[3];
if (cmdparams.Length < 5)
lastName = MainConsole.Instance.CmdPrompt("Last name");
else lastName = cmdparams[4];
if (cmdparams.Length < 6)
newEmail = MainConsole.Instance.PasswdPrompt("New Email");
else newEmail = cmdparams[5];
UserAccount account = GetUserAccount(UUID.Zero, firstName, lastName);
if (account == null)
{
MainConsole.Instance.OutputFormat("No such user as {0} {1}", firstName, lastName);
return;
}
bool success = false;
account.Email = newEmail;
success = StoreUserAccount(account);
if (!success)
MainConsole.Instance.OutputFormat("Unable to set Email for account {0} {1}.", firstName, lastName);
else
MainConsole.Instance.OutputFormat("User Email set for user {0} {1} to {2}", firstName, lastName, account.Email);
}
protected void HandleSetUserLevel(string module, string[] cmdparams)
{
string firstName;

Binary file not shown.

View File

@ -57,11 +57,6 @@
<appender-ref ref="LogFileAppender" />
</root>
<!-- Independently control logging level for XEngine -->
<logger name="OpenSim.Region.ScriptEngine.XEngine">
<level value="INFO"/>
</logger>
<!-- Independently control logging level for per region module loading -->
<logger name="OpenSim.ApplicationPlugins.RegionModulesController.RegionModulesControllerPlugin">
<level value="INFO"/>

View File

@ -208,6 +208,10 @@
[InventoryService]
LocalServiceModule = "OpenSim.Services.InventoryService.dll:XInventoryService"
; Will calls to purge folders (empty trash) and immediately delete/update items or folders (not move to trash first) succeed?
; If this is set to false then some other arrangement must be made to perform these operations if necessary.
AllowDelete = true
; * This is the new style grid service.
; * "Realm" is the table that is used for user lookup.

View File

@ -179,6 +179,10 @@
[InventoryService]
LocalServiceModule = "OpenSim.Services.InventoryService.dll:XInventoryService"
; Will calls to purge folders (empty trash) and immediately delete/update items or folders (not move to trash first) succeed?
; If this is set to false then some other arrangement must be made to perform these operations if necessary.
AllowDelete = true
; * This is the new style grid service.
; * "Realm" is the table that is used for user lookup.

View File

@ -2926,7 +2926,6 @@
<Reference name="Nini" path="../../../bin/"/>
<Reference name="OpenSim.Data.MySQL"/>
<Reference name="OpenSim.Data.MSSQL"/>
<Reference name="OpenSim.Data.SQLite"/>
<Reference name="MySql.Data" path="../../../bin/"/>