aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2015-01-16 22:44:54 +0000
committerJustin Clark-Casey (justincc)2015-01-16 22:46:48 +0000
commit8d724e90de0fb3b406f82f4e06b6f5b79c5a538c (patch)
tree069eac2d8fa46b63267d4119795a6cabf218c97f
parentminor: Suppress the log messages when user profiles data is requested for an ... (diff)
downloadopensim-SC-8d724e90de0fb3b406f82f4e06b6f5b79c5a538c.zip
opensim-SC-8d724e90de0fb3b406f82f4e06b6f5b79c5a538c.tar.gz
opensim-SC-8d724e90de0fb3b406f82f4e06b6f5b79c5a538c.tar.bz2
opensim-SC-8d724e90de0fb3b406f82f4e06b6f5b79c5a538c.tar.xz
For scripts in attachments, don't save .state files apart from the initial one as these are ignored since .state is saved in the attachment's asset.
This eliminates pointless work and exceptions when an appdomain is unloaded whilst an attachment script state is persisted. Adds test for this case. Relates to http://opensimulator.org/mantis/view.php?id=7407
-rw-r--r--OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs6
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs27
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/Tests/XEnginePersistenceTests.cs152
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XEngine.cs18
-rw-r--r--OpenSim/Tests/Common/Helpers/TaskInventoryHelpers.cs32
5 files changed, 220 insertions, 15 deletions
diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
index 1097efb..35e5f18 100644
--- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
@@ -98,6 +98,12 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
98 string State { get; set; } 98 string State { get; set; }
99 99
100 /// <summary> 100 /// <summary>
101 /// If true then the engine is responsible for persisted state. If false then some other component may
102 /// persist state (e.g. attachments persisting in assets).
103 /// </summary>
104 bool StatePersistedHere { get; }
105
106 /// <summary>
101 /// Time the script was last started 107 /// Time the script was last started
102 /// </summary> 108 /// </summary>
103 DateTime TimeStarted { get; } 109 DateTime TimeStarted { get; }
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
index 79e4774..9498aa8 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
@@ -58,6 +58,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
58 { 58 {
59 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 59 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
60 60
61 public bool StatePersistedHere { get { return m_AttachedAvatar == UUID.Zero; } }
62
61 /// <summary> 63 /// <summary>
62 /// The current work item if an event for this script is running or waiting to run, 64 /// The current work item if an event for this script is running or waiting to run,
63 /// </summary> 65 /// </summary>
@@ -76,7 +78,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
76 private string m_CurrentEvent = String.Empty; 78 private string m_CurrentEvent = String.Empty;
77 private bool m_InSelfDelete; 79 private bool m_InSelfDelete;
78 private int m_MaxScriptQueue; 80 private int m_MaxScriptQueue;
79 private bool m_SaveState = true; 81 private bool m_SaveState;
80 private int m_ControlEventsInQueue; 82 private int m_ControlEventsInQueue;
81 private int m_LastControlLevel; 83 private int m_LastControlLevel;
82 private bool m_CollisionInQueue; 84 private bool m_CollisionInQueue;
@@ -238,6 +240,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
238 m_postOnRez = postOnRez; 240 m_postOnRez = postOnRez;
239 m_AttachedAvatar = Part.ParentGroup.AttachedAvatar; 241 m_AttachedAvatar = Part.ParentGroup.AttachedAvatar;
240 m_RegionID = Part.ParentGroup.Scene.RegionInfo.RegionID; 242 m_RegionID = Part.ParentGroup.Scene.RegionInfo.RegionID;
243
244 m_SaveState = StatePersistedHere;
245
246// m_log.DebugFormat(
247// "[SCRIPT INSTANCE]: Instantiated script instance {0} (id {1}) in part {2} (id {3}) in object {4} attached avatar {5} in {6}",
248// ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, m_AttachedAvatar, Engine.World.Name);
241 } 249 }
242 250
243 /// <summary> 251 /// <summary>
@@ -339,8 +347,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
339 return false; 347 return false;
340 } 348 }
341 349
342 m_SaveState = true; 350 // For attachments, XEngine saves the state into a .state file when XEngine.SetXMLState() is called.
343
344 string savedState = Path.Combine(m_dataPath, ItemID.ToString() + ".state"); 351 string savedState = Path.Combine(m_dataPath, ItemID.ToString() + ".state");
345 352
346 if (File.Exists(savedState)) 353 if (File.Exists(savedState))
@@ -389,6 +396,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
389 m_SaveState = false; 396 m_SaveState = false;
390 m_startedFromSavedState = true; 397 m_startedFromSavedState = true;
391 } 398 }
399
400 // If this script is in an attachment then we no longer need the state file.
401 if (!StatePersistedHere)
402 RemoveState();
392 } 403 }
393// else 404// else
394// { 405// {
@@ -984,7 +995,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
984 (int)m_Script.GetStateEventFlags(State)); 995 (int)m_Script.GetStateEventFlags(State));
985 if (running) 996 if (running)
986 Start(); 997 Start();
987 m_SaveState = true; 998
999 m_SaveState = StatePersistedHere;
1000
988 PostEvent(new EventParams("state_entry", 1001 PostEvent(new EventParams("state_entry",
989 new Object[0], new DetectParams[0])); 1002 new Object[0], new DetectParams[0]));
990 } 1003 }
@@ -1010,7 +1023,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
1010 1023
1011 if (m_CurrentEvent != "state_entry") 1024 if (m_CurrentEvent != "state_entry")
1012 { 1025 {
1013 m_SaveState = true; 1026 m_SaveState = StatePersistedHere;
1014 PostEvent(new EventParams("state_entry", 1027 PostEvent(new EventParams("state_entry",
1015 new Object[0], new DetectParams[0])); 1028 new Object[0], new DetectParams[0]));
1016 throw new EventAbortException(); 1029 throw new EventAbortException();
@@ -1060,6 +1073,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
1060 return; 1073 return;
1061 } 1074 }
1062 1075
1076// m_log.DebugFormat(
1077// "[SCRIPT INSTANCE]: Saving state for script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}",
1078// ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name);
1079
1063 PluginData = AsyncCommandManager.GetSerializationData(Engine, ItemID); 1080 PluginData = AsyncCommandManager.GetSerializationData(Engine, ItemID);
1064 1081
1065 string xml = ScriptSerializer.Serialize(this); 1082 string xml = ScriptSerializer.Serialize(this);
diff --git a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEnginePersistenceTests.cs b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEnginePersistenceTests.cs
new file mode 100644
index 0000000..5b7e5f7
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEnginePersistenceTests.cs
@@ -0,0 +1,152 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Linq;
32using System.Threading;
33using Nini.Config;
34using NUnit.Framework;
35using OpenMetaverse;
36using OpenSim.Framework;
37using OpenSim.Region.CoreModules.Avatar.Attachments;
38using OpenSim.Region.CoreModules.Framework.InventoryAccess;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Region.ScriptEngine.XEngine;
41using OpenSim.Services.Interfaces;
42using OpenSim.Tests.Common;
43
44namespace OpenSim.Region.ScriptEngine.Tests
45{
46 [TestFixture]
47 public class XEnginePersistenceTests : OpenSimTestCase
48 {
49 private AutoResetEvent m_chatEvent = new AutoResetEvent(false);
50
51 private void OnChatFromWorld(object sender, OSChatMessage oscm)
52 {
53 // Console.WriteLine("Got chat [{0}]", oscm.Message);
54
55 // m_osChatMessageReceived = oscm;
56 m_chatEvent.Set();
57 }
58
59 private void AddCommonConfig(IConfigSource config, List<object> modules)
60 {
61 config.AddConfig("Modules");
62 config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule");
63
64 AttachmentsModule attMod = new AttachmentsModule();
65 attMod.DebugLevel = 1;
66 modules.Add(attMod);
67 modules.Add(new BasicInventoryAccessModule());
68 }
69
70 private void AddScriptingConfig(IConfigSource config, XEngine.XEngine xEngine, List<object> modules)
71 {
72 IConfig startupConfig = config.AddConfig("Startup");
73 startupConfig.Set("DefaultScriptEngine", "XEngine");
74
75 IConfig xEngineConfig = config.AddConfig("XEngine");
76 xEngineConfig.Set("Enabled", "true");
77 xEngineConfig.Set("StartDelay", "0");
78
79 // These tests will not run with AppDomainLoading = true, at least on mono. For unknown reasons, the call
80 // to AssemblyResolver.OnAssemblyResolve fails.
81 xEngineConfig.Set("AppDomainLoading", "false");
82
83 modules.Add(xEngine);
84 }
85
86 private Scene CreateScriptingEnabledTestScene(XEngine.XEngine xEngine)
87 {
88 IConfigSource config = new IniConfigSource();
89 List<object> modules = new List<object>();
90
91 AddCommonConfig(config, modules);
92 AddScriptingConfig(config, xEngine, modules);
93
94 Scene scene
95 = new SceneHelpers().SetupScene(
96 "attachments-test-scene", TestHelpers.ParseTail(999), 1000, 1000, config);
97 SceneHelpers.SetupSceneModules(scene, config, modules.ToArray());
98
99 scene.StartScripts();
100
101 return scene;
102 }
103
104 [Test]
105 public void TestScriptedAttachmentPersistence()
106 {
107 TestHelpers.InMethod();
108// TestHelpers.EnableLogging();
109
110 XEngine.XEngine xEngine = new XEngine.XEngine();
111 Scene scene = CreateScriptingEnabledTestScene(xEngine);
112 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
113 ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1);
114
115 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, sp.UUID, "att-name", 0x10);
116 TaskInventoryHelpers.AddScript(
117 scene,
118 so.RootPart,
119 "scriptItem",
120 "default { attach(key id) { if (id != NULL_KEY) { llSay(0, \"Hello World\"); } } }");
121
122 InventoryItemBase userItem = UserInventoryHelpers.AddInventoryItem(scene, so, 0x100, 0x1000);
123
124 // FIXME: Right now, we have to do a tricksy chat listen to make sure we know when the script is running.
125 // In the future, we need to be able to do this programatically more predicably.
126 scene.EventManager.OnChatFromWorld += OnChatFromWorld;
127
128 SceneObjectGroup rezzedSo
129 = scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, userItem.ID, (uint)AttachmentPoint.Chest);
130 TaskInventoryItem rezzedScriptItem = rezzedSo.RootPart.Inventory.GetInventoryItem("scriptItem");
131
132 // Wait for chat to signal rezzed script has been started.
133 m_chatEvent.WaitOne(60000);
134
135 // Force save
136 xEngine.DoBackup(new Object[] { 0 });
137
138// Console.WriteLine("ItemID {0}", rezzedScriptItem.ItemID);
139//
140// foreach (
141// string s in Directory.EnumerateFileSystemEntries(
142// string.Format("ScriptEngines/{0}", scene.RegionInfo.RegionID)))
143// Console.WriteLine(s);
144
145 Assert.IsFalse(
146 File.Exists(
147 string.Format("ScriptEngines/{0}/{1}.state", scene.RegionInfo.RegionID, rezzedScriptItem.ItemID)));
148
149 scene.AttachmentsModule.DetachSingleAttachmentToInv(sp, rezzedSo);
150 }
151 }
152} \ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
index f87d631..03fafed 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
@@ -718,7 +718,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
718 // 718 //
719 try 719 try
720 { 720 {
721 instance.SaveState(); 721 if (instance.StatePersistedHere)
722 instance.SaveState();
722 } 723 }
723 catch (Exception e) 724 catch (Exception e)
724 { 725 {
@@ -830,7 +831,16 @@ namespace OpenSim.Region.ScriptEngine.XEngine
830 lock (m_Scripts) 831 lock (m_Scripts)
831 { 832 {
832 foreach (IScriptInstance instance in m_Scripts.Values) 833 foreach (IScriptInstance instance in m_Scripts.Values)
833 instances.Add(instance); 834 {
835 if (instance.StatePersistedHere)
836 {
837// m_log.DebugFormat(
838// "[XEngine]: Adding script {0}.{1}, item UUID {2}, prim UUID {3} in {4} for state persistence",
839// instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, World.Name);
840
841 instances.Add(instance);
842 }
843 }
834 } 844 }
835 845
836 foreach (IScriptInstance i in instances) 846 foreach (IScriptInstance i in instances)
@@ -1457,7 +1467,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1457 } 1467 }
1458 } 1468 }
1459 1469
1460 instance.RemoveState(); 1470 if (instance.StatePersistedHere)
1471 instance.RemoveState();
1472
1461 instance.DestroyScriptInstance(); 1473 instance.DestroyScriptInstance();
1462 1474
1463 m_DomainScripts[instance.AppDomain].Remove(instance.ItemID); 1475 m_DomainScripts[instance.AppDomain].Remove(instance.ItemID);
diff --git a/OpenSim/Tests/Common/Helpers/TaskInventoryHelpers.cs b/OpenSim/Tests/Common/Helpers/TaskInventoryHelpers.cs
index bb4b55f..b4bd50b 100644
--- a/OpenSim/Tests/Common/Helpers/TaskInventoryHelpers.cs
+++ b/OpenSim/Tests/Common/Helpers/TaskInventoryHelpers.cs
@@ -117,25 +117,43 @@ namespace OpenSim.Tests.Common
117 public static TaskInventoryItem AddScript( 117 public static TaskInventoryItem AddScript(
118 Scene scene, SceneObjectPart part, string scriptName, string scriptSource) 118 Scene scene, SceneObjectPart part, string scriptName, string scriptSource)
119 { 119 {
120 return AddScript(scene, part, UUID.Random(), UUID.Random(), scriptName, scriptSource);
121 }
122
123 /// <summary>
124 /// Add a simple script to the given part.
125 /// </summary>
126 /// <remarks>
127 /// TODO: Accept input for item and asset IDs so that we have completely replicatable regression tests rather
128 /// than a random component.
129 /// </remarks>
130 /// <param name="scene"></param>
131 /// <param name="part"></param>
132 /// <param name="itemId">Item UUID for the script</param>
133 /// <param name="assetId">Asset UUID for the script</param>
134 /// <param name="scriptName">Name of the script to add</param>
135 /// <param name="scriptSource">LSL script source</param>
136 /// <returns>The item that was added</returns>
137 public static TaskInventoryItem AddScript(
138 Scene scene, SceneObjectPart part, UUID itemId, UUID assetId, string scriptName, string scriptSource)
139 {
120 AssetScriptText ast = new AssetScriptText(); 140 AssetScriptText ast = new AssetScriptText();
121 ast.Source = scriptSource; 141 ast.Source = scriptSource;
122 ast.Encode(); 142 ast.Encode();
123 143
124 UUID assetUuid = UUID.Random();
125 UUID itemUuid = UUID.Random();
126
127 AssetBase asset 144 AssetBase asset
128 = AssetHelpers.CreateAsset(assetUuid, AssetType.LSLText, ast.AssetData, UUID.Zero); 145 = AssetHelpers.CreateAsset(assetId, AssetType.LSLText, ast.AssetData, UUID.Zero);
129 scene.AssetService.Store(asset); 146 scene.AssetService.Store(asset);
130 TaskInventoryItem item 147 TaskInventoryItem item
131 = new TaskInventoryItem 148 = new TaskInventoryItem
132 { Name = scriptName, AssetID = assetUuid, ItemID = itemUuid, 149 { Name = scriptName, AssetID = assetId, ItemID = itemId,
133 Type = (int)AssetType.LSLText, InvType = (int)InventoryType.LSL }; 150 Type = (int)AssetType.LSLText, InvType = (int)InventoryType.LSL };
134 part.Inventory.AddInventoryItem(item, true); 151 part.Inventory.AddInventoryItem(item, true);
135 152
136 return item; 153 return item;
137 } 154 }
138 155
156
139 /// <summary> 157 /// <summary>
140 /// Add a scene object item to the given part. 158 /// Add a scene object item to the given part.
141 /// </summary> 159 /// </summary>