From 83d1680057419229b0708bde59b12159006195cd Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 11 Jul 2013 16:43:43 -0700 Subject: [PATCH 1/6] Added a few more thingies to the asset client test to poke the threadpool. --- OpenSim/Tests/Clients/Assets/AssetsClient.cs | 21 ++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/OpenSim/Tests/Clients/Assets/AssetsClient.cs b/OpenSim/Tests/Clients/Assets/AssetsClient.cs index dd168a195b..26d740b771 100644 --- a/OpenSim/Tests/Clients/Assets/AssetsClient.cs +++ b/OpenSim/Tests/Clients/Assets/AssetsClient.cs @@ -82,7 +82,16 @@ namespace OpenSim.Tests.Clients.AssetsClient m_log.InfoFormat("[ASSET CLIENT]: [{0}] requested asset {1}", i, uuid); } - Thread.Sleep(20 * 1000); + for (int i = 0; i < 500; i++) + { + var x = i; + ThreadPool.QueueUserWorkItem(delegate + { + Dummy(x); + }); + } + + Thread.Sleep(30 * 1000); m_log.InfoFormat("[ASSET CLIENT]: Received responses {0}", m_NReceived); } @@ -92,8 +101,16 @@ namespace OpenSim.Tests.Clients.AssetsClient m_MaxThreadID = Thread.CurrentThread.ManagedThreadId; int max1, max2; ThreadPool.GetAvailableThreads(out max1, out max2); - m_log.InfoFormat("[ASSET CLIENT]: Received asset {0} ({1}) ({2}-{3})", id, m_MaxThreadID, max1, max2); + m_log.InfoFormat("[ASSET CLIENT]: Received asset {0} ({1}) ({2}-{3}) {4}", id, m_MaxThreadID, max1, max2, DateTime.Now.ToString("hh:mm:ss")); m_NReceived++; } + + private static void Dummy(int i) + { + int max1, max2; + ThreadPool.GetAvailableThreads(out max1, out max2); + m_log.InfoFormat("[ASSET CLIENT]: ({0}) Hello! {1} - {2} {3}", i, max1, max2, DateTime.Now.ToString("hh:mm:ss")); + Thread.Sleep(2000); + } } } From 65239b059fc8a92eee1d27655a6f85826c99306b Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 11 Jul 2013 20:55:32 -0700 Subject: [PATCH 2/6] Enhance NullEstateData to remember stored estate values and return them next time asked. This keeps any estate settings from being reset when the estate dialog is opened in a region with null estate storage. --- OpenSim/Data/Null/NullEstateData.cs | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/OpenSim/Data/Null/NullEstateData.cs b/OpenSim/Data/Null/NullEstateData.cs index d64136de8d..1df397d943 100755 --- a/OpenSim/Data/Null/NullEstateData.cs +++ b/OpenSim/Data/Null/NullEstateData.cs @@ -42,6 +42,22 @@ namespace OpenSim.Data.Null // private string m_connectionString; + private Dictionary m_knownEstates = new Dictionary(); + private EstateSettings m_estate = null; + + private EstateSettings GetEstate() + { + if (m_estate == null) + { + // This fools the initialization caller into thinking an estate was fetched (a check in OpenSimBase). + // The estate info is pretty empty so don't try banning anyone. + m_estate = new EstateSettings(); + m_estate.EstateID = 1; + m_estate.OnSave += StoreEstateSettings; + } + return m_estate; + } + protected virtual Assembly Assembly { get { return GetType().Assembly; } @@ -68,21 +84,18 @@ namespace OpenSim.Data.Null public EstateSettings LoadEstateSettings(UUID regionID, bool create) { - // This fools the initialization caller into thinking an estate was fetched (a check in OpenSimBase). - // The estate info is pretty empty so don't try banning anyone. - EstateSettings oneEstate = new EstateSettings(); - oneEstate.EstateID = 1; - return oneEstate; + return GetEstate(); } public void StoreEstateSettings(EstateSettings es) { + m_estate = es; return; } public EstateSettings LoadEstateSettings(int estateID) { - return new EstateSettings(); + return GetEstate(); } public EstateSettings CreateNewEstate() @@ -93,13 +106,14 @@ namespace OpenSim.Data.Null public List LoadEstateSettingsAll() { List allEstateSettings = new List(); - allEstateSettings.Add(new EstateSettings()); + allEstateSettings.Add(GetEstate()); return allEstateSettings; } public List GetEstatesAll() { List result = new List(); + result.Add((int)GetEstate().EstateID); return result; } From 29f6ae199efd705052422b2fe9dd0e815447b0a8 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 12 Jul 2013 12:53:58 -0700 Subject: [PATCH 3/6] Changed UploadBakedTextureModule so that it uses the same pattern as the others, in preparation for experiments to direct baked texture uploads to a robust instance. No functional or configuration changes -- should work exactly as before. --- .../Linden/Caps/UploadBakedTextureModule.cs | 35 ++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs index 3b0ccd75ec..79a935d76d 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs @@ -63,9 +63,16 @@ namespace OpenSim.Region.ClientStack.Linden private Scene m_scene; private bool m_persistBakedTextures; + private string m_URL; public void Initialise(IConfigSource source) { + IConfig config = source.Configs["ClientStack.LindenCaps"]; + if (config == null) + return; + + m_URL = config.GetString("Cap_UploadBakedTexture", string.Empty); + IConfig appearanceConfig = source.Configs["Appearance"]; if (appearanceConfig != null) m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); @@ -100,15 +107,27 @@ namespace OpenSim.Region.ClientStack.Linden public void RegisterCaps(UUID agentID, Caps caps) { - caps.RegisterHandler( - "UploadBakedTexture", - new RestStreamHandler( - "POST", - "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath, - new UploadBakedTextureHandler( - caps, m_scene.AssetService, m_persistBakedTextures).UploadBakedTexture, + UUID capID = UUID.Random(); + + //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); + if (m_URL == "localhost") + { + caps.RegisterHandler( "UploadBakedTexture", - agentID.ToString())); + new RestStreamHandler( + "POST", + "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath, + new UploadBakedTextureHandler( + caps, m_scene.AssetService, m_persistBakedTextures).UploadBakedTexture, + "UploadBakedTexture", + agentID.ToString())); + + } + else + { + caps.RegisterHandler("UploadBakedTexture", m_URL); + } + } } } \ No newline at end of file From fa02f28dbfef9b9dc3621f5bbd6b026c827459a5 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 12 Jul 2013 14:04:14 -0700 Subject: [PATCH 4/6] Add ToOSDMap() overrides to the Stat subclass CounterStat. Add a GetStatsAsOSDMap method to StatsManager which allows the filtered fetching of stats for eventual returning over the internets. --- .../Framework/Monitoring/Stats/CounterStat.cs | 21 ++++++ OpenSim/Framework/Monitoring/Stats/Stat.cs | 1 + OpenSim/Framework/Monitoring/StatsManager.cs | 66 +++++++++++++++++++ 3 files changed, 88 insertions(+) diff --git a/OpenSim/Framework/Monitoring/Stats/CounterStat.cs b/OpenSim/Framework/Monitoring/Stats/CounterStat.cs index caea30dd5d..04442c35b1 100755 --- a/OpenSim/Framework/Monitoring/Stats/CounterStat.cs +++ b/OpenSim/Framework/Monitoring/Stats/CounterStat.cs @@ -224,5 +224,26 @@ public class CounterStat : Stat } } } + + // CounterStat is a basic stat plus histograms + public override OSDMap ToOSDMap() + { + // Get the foundational instance + OSDMap map = base.ToOSDMap(); + + map["StatType"] = "CounterStat"; + + // If there are any histograms, add a new field that is an array of histograms as OSDMaps + if (m_histograms.Count > 0) + { + OSDArray histos = new OSDArray(); + foreach (EventHistogram histo in m_histograms.Values) + { + histos.Add(histo.GetHistogramAsOSDMap()); + } + map.Add("Histograms", histos); + } + return map; + } } } diff --git a/OpenSim/Framework/Monitoring/Stats/Stat.cs b/OpenSim/Framework/Monitoring/Stats/Stat.cs index c57ee0c3e8..9629b6e654 100644 --- a/OpenSim/Framework/Monitoring/Stats/Stat.cs +++ b/OpenSim/Framework/Monitoring/Stats/Stat.cs @@ -242,6 +242,7 @@ namespace OpenSim.Framework.Monitoring ret.Add("Description", OSD.FromString(Description)); ret.Add("UnitName", OSD.FromString(UnitName)); ret.Add("Value", OSD.FromReal(Value)); + ret.Add("StatType", "Stat"); // used by overloading classes to denote type of stat return ret; } diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs index 12d3a75d50..a5b54c9bf9 100644 --- a/OpenSim/Framework/Monitoring/StatsManager.cs +++ b/OpenSim/Framework/Monitoring/StatsManager.cs @@ -30,6 +30,8 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using OpenMetaverse.StructuredData; + namespace OpenSim.Framework.Monitoring { /// @@ -168,6 +170,70 @@ namespace OpenSim.Framework.Monitoring } } + // Creates an OSDMap of the format: + // { categoryName: { + // containerName: { + // statName: { + // "Name": name, + // "ShortName": shortName, + // ... + // }, + // statName: { + // "Name": name, + // "ShortName": shortName, + // ... + // }, + // ... + // }, + // containerName: { + // ... + // }, + // ... + // }, + // categoryName: { + // ... + // }, + // ... + // } + // The passed in parameters will filter the categories, containers and stats returned. If any of the + // parameters are either EmptyOrNull or the AllSubCommand value, all of that type will be returned. + // Case matters. + public static OSDMap GetStatsAsOSDMap(string pCategoryName, string pContainerName, string pStatName) + { + OSDMap map = new OSDMap(); + + foreach (string catName in RegisteredStats.Keys) + { + // Do this category if null spec, "all" subcommand or category name matches passed parameter. + // Skip category if none of the above. + if (!(String.IsNullOrEmpty(pCategoryName) || pCategoryName == AllSubCommand || pCategoryName == catName)) + continue; + + OSDMap contMap = new OSDMap(); + foreach (string contName in RegisteredStats[catName].Keys) + { + if (!(string.IsNullOrEmpty(pContainerName) || pContainerName == AllSubCommand || pContainerName == contName)) + continue; + + OSDMap statMap = new OSDMap(); + + SortedDictionary theStats = RegisteredStats[catName][contName]; + foreach (string statName in theStats.Keys) + { + if (!(String.IsNullOrEmpty(pStatName) || pStatName == AllSubCommand || pStatName == statName)) + continue; + + statMap.Add(statName, theStats[statName].ToOSDMap()); + } + + contMap.Add(contName, statMap); + } + map.Add(catName, contMap); + } + + return map; + } + // /// // /// Start collecting statistics related to assets. // /// Should only be called once. From 3d118fb580ea0a5e9d9b23f5f876fca80cd17d0e Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 12 Jul 2013 18:53:27 +0100 Subject: [PATCH 5/6] In co-op termination, extend EventWaitHandle to give this an indefinite lifetime in order to avoid a later RemotingException if scripts are being loaded into their own domains. This is necessary because XEngineScriptBase now retains a reference to an EventWaitHandle when co-op termination is active. Aims to address http://opensimulator.org/mantis/view.php?id=6634 --- .../Shared/Instance/ScriptInstance.cs | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index 887a31765a..229180fe87 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -241,7 +241,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance if (Engine.Config.GetString("ScriptStopStrategy", "abort") == "co-op") { m_coopTermination = true; - m_coopSleepHandle = new AutoResetEvent(false); + m_coopSleepHandle = new XEngineEventWaitHandle(false, EventResetMode.AutoReset); } } @@ -1201,4 +1201,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance Suspended = false; } } -} + + /// + /// Xengine event wait handle. + /// + /// + /// This class exists becase XEngineScriptBase gets a reference to this wait handle. We need to make sure that + /// when scripts are running in different AppDomains the lease does not expire. + /// FIXME: Like LSL_Api, etc., this effectively leaks memory since the GC will never collect it. To avoid this, + /// proper remoting sponsorship needs to be implemented across the board. + /// + public class XEngineEventWaitHandle : EventWaitHandle + { + public XEngineEventWaitHandle(bool initialState, EventResetMode mode) : base(initialState, mode) {} + + public override Object InitializeLifetimeService() + { + return null; + } + } +} \ No newline at end of file From d06c85ea77f76f4d915081ed6b314d66d6d38fbf Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 13 Jul 2013 00:29:07 +0100 Subject: [PATCH 6/6] Reinsert PhysicsActor variable back into SOP.SubscribeForCollisionEvents() in order to avoid a race condition. A separate PhysicsActor variable is used in case some other thread removes the PhysicsActor whilst this code is executing. If this is now impossible please revert - just adding this now whilst I remember. Also makes method comment into proper method doc. --- .../Framework/Scenes/SceneObjectPart.cs | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 830fe31319..eb3af42a13 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -4272,10 +4272,14 @@ namespace OpenSim.Region.Framework.Scenes // m_log.DebugFormat("[SCENE OBJECT PART]: Updated PrimFlags on {0} {1} to {2}", Name, LocalId, Flags); } - // Subscribe for physics collision events if needed for scripts and sounds + /// + /// Subscribe for physics collision events if needed for scripts and sounds + /// public void SubscribeForCollisionEvents() { - if (PhysActor != null) + PhysicsActor pa = PhysActor; + + if (pa != null) { if ( ((AggregateScriptEvents & scriptEvents.collision) != 0) || @@ -4293,20 +4297,20 @@ namespace OpenSim.Region.Framework.Scenes (CollisionSound != UUID.Zero) ) { - if (!PhysActor.SubscribedEvents()) + if (!pa.SubscribedEvents()) { // If not already subscribed for event, set up for a collision event. - PhysActor.OnCollisionUpdate += PhysicsCollision; - PhysActor.SubscribeEvents(1000); + pa.OnCollisionUpdate += PhysicsCollision; + pa.SubscribeEvents(1000); } } else { // There is no need to be subscribed to collisions so, if subscribed, remove subscription - if (PhysActor.SubscribedEvents()) + if (pa.SubscribedEvents()) { - PhysActor.OnCollisionUpdate -= PhysicsCollision; - PhysActor.UnSubscribeEvents(); + pa.OnCollisionUpdate -= PhysicsCollision; + pa.UnSubscribeEvents(); } } }