From 5c18ebf42470038720dffcf676bf3f9dd174d443 Mon Sep 17 00:00:00 2001 From: dahlia Date: Wed, 29 Jun 2011 17:36:41 -0700 Subject: [PATCH 01/18] Allow physics proxy generation for meshes using new asset format. Fix an invalid cast exception while decoding new mesh asset format. --- OpenSim/Region/Physics/Meshing/Meshmerizer.cs | 21 +++++++++++++++---- OpenSim/Region/Physics/OdePlugin/OdePlugin.cs | 5 ++++- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index 99b2d8477a..a5fe45b216 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs @@ -291,7 +291,14 @@ namespace OpenSim.Region.Physics.Meshing { try { - meshOsd = (OSDMap)OSDParser.DeserializeLLSDBinary(data); + OSD osd = OSDParser.DeserializeLLSDBinary(data); + if (osd is OSDMap) + meshOsd = (OSDMap)osd; + else + { + m_log.Warn("[Mesh}: unable to cast mesh asset to OSDMap"); + return null; + } } catch (Exception e) { @@ -302,11 +309,17 @@ namespace OpenSim.Region.Physics.Meshing if (meshOsd is OSDMap) { + OSDMap physicsParms = null; OSDMap map = (OSDMap)meshOsd; - OSDMap physicsParms = (OSDMap)map["physics_shape"]; // old asset format - - if (physicsParms.Count == 0) + if (map.ContainsKey("physics_shape")) + physicsParms = (OSDMap)map["physics_shape"]; // old asset format + else if (map.ContainsKey("physics_mesh")) physicsParms = (OSDMap)map["physics_mesh"]; // new asset format + if (physicsParms == null) + { + m_log.Warn("[Mesh]: no recognized physics mesh found in mesh asset"); + return null; + } int physOffset = physicsParms["offset"].AsInteger() + (int)start; int physSize = physicsParms["size"].AsInteger(); diff --git a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs index a0101af2bb..8d9f5f14d6 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs @@ -2502,7 +2502,7 @@ namespace OpenSim.Region.Physics.OdePlugin } // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since ODE can use an internal representation for the prim - if (!forceSimplePrimMeshing) + if (!forceSimplePrimMeshing && !pbs.SculptEntry) { if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 @@ -2592,6 +2592,9 @@ namespace OpenSim.Region.Physics.OdePlugin } } + if (pbs.SculptEntry && meshSculptedPrim) + iPropertiesNotSupportedDefault++; + if (iPropertiesNotSupportedDefault == 0) { From 03feb50a72a44f988f9d4d551f3c5656bbe1fe10 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 30 Jun 2011 20:26:17 +0100 Subject: [PATCH 02/18] minor: adjust some indentation and spacing in OpenSim.ini.example for consistency --- bin/OpenSim.ini.example | 44 +++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 98bb355d7a..df4e60b25e 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -292,28 +292,31 @@ ;; building's lights to possibly not be rendered. ; DisableFacelights = "false" + [ClientStack.LindenCaps] - ;; For the long list of capabilities, see OpenSimDefaults.ini - ;; Here are the few ones you may want to change. Possible values - ;; are: - ;; "" -- empty, capability disabled - ;; "localhost" -- capability enabled and served by the simulator - ;; "" -- capability enabled and served by some other server - ;; - ; These are enabled by default to localhost. Change if you see fit. - Cap_GetTexture = "localhost" - Cap_GetMesh = "localhost" - ; This is disabled by default. Change if you see fit. Note that - ; serving this cap from the simulators may lead to poor performace. - Cap_WebFetchInventoryDescendents = "" + ;; For the long list of capabilities, see OpenSimDefaults.ini + ;; Here are the few ones you may want to change. Possible values + ;; are: + ;; "" -- empty, capability disabled + ;; "localhost" -- capability enabled and served by the simulator + ;; "" -- capability enabled and served by some other server + ;; + ; These are enabled by default to localhost. Change if you see fit. + Cap_GetTexture = "localhost" + Cap_GetMesh = "localhost" + ; This is disabled by default. Change if you see fit. Note that + ; serving this cap from the simulators may lead to poor performace. + Cap_WebFetchInventoryDescendents = "" + [SimulatorFeatures] - ; Experimental new information sent in SimulatorFeatures cap for Kokua viewers - ; meant to override the MapImage and search server url given at login, and varying - ; on a sim-basis. - ; Viewers that don't understand it, will ignore it - ;MapImageServerURI = "http://127.0.0.1:9000/ - ;SearchServerURI = "http://127.0.0.1:9000/ + ; Experimental new information sent in SimulatorFeatures cap for Kokua viewers + ; meant to override the MapImage and search server url given at login, and varying + ; on a sim-basis. + ; Viewers that don't understand it, will ignore it + ;MapImageServerURI = "http://127.0.0.1:9000/ + ;SearchServerURI = "http://127.0.0.1:9000/ + [Chat] ;# {whisper_distance} {} {Distance at which a whisper is heard, in meters?} {} 10 @@ -650,6 +653,7 @@ ;; If using a remote connector, specify the server URL ; FreeswitchServiceURL = http://my.grid.server:8004/fsapi + [Groups] ;# {Enabled} {} {Enable groups?} {true false} false ;; Enables the groups module @@ -707,11 +711,13 @@ ;; Enable media on a prim facilities ; Enabled = true; + [PrimLimitsModule] ;# {EnforcePrimLimits} {} {Enforce parcel prim limits} {true false} false ;; Enable parcel prim limits. Off by default to emulate pre-existing behavior. ; EnforcePrimLimits = false + [Architecture] ;# {Include-Architecture} {} {Choose one of the following architectures} {config-include/Standalone.ini config-include/StandaloneHypergrid.ini config-include/Grid.ini config-include/GridHypergrid.ini config-include/SimianGrid.ini config-include/HyperSimianGrid.ini} config-include/Standalone.ini ;; Uncomment one of the following includes as required. For instance, to create a standalone OpenSim, From a9b7487fcb657bf50d69a522fb9dfb37d547f347 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 30 Jun 2011 22:36:22 +0100 Subject: [PATCH 03/18] improve and tidy up some config file comments --- bin/OpenSim.ini.example | 11 +++++------ bin/OpenSimDefaults.ini | 23 +++++++++++++++-------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index df4e60b25e..a4f243d486 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -78,20 +78,19 @@ ; DrawPrimOnMapTile = true ;# {NonPhysicalPrimMax} {} {Maximum size of nonphysical prims?} {} 256 - ;; Maximum size for non-physical prims + ;; Maximum size for non-physical prims. Affects resizing of existing prims. This can be overriden in the region config file (as NonphysicalPrimMax!). ; NonPhysicalPrimMax = 256 ;# {PhysicalPrimMax} {} {Maximum size of physical prims?} {} 10 - ;; Maximum size where a prim can be physical + ;; Maximum size where a prim can be physical. Affects resizing of existing prims. This can be overriden in the region config file. ; PhysicalPrimMax = 10 - ;; Prevent the creation, import and rez of prims that exceed the - ;; maximum size. + ;; If a viewer attempts to rez a prim larger than the non-physical or physical prim max, clamp the dimensions to the appropriate maximum + ;; This can be overriden in the region config file. ; ClampPrimSize = false ;# {AllowScriptCrossing} {} {Allow scripts to cross into this region} {true false} false - ;; Allow scripts to cross region boundaries. These are recompiled on the - ;; new region. + ;; Allow scripts to keep running when they cross region boundaries, rather than being restarted. Script code is recompiled on the destination region and the state reloaded. ; AllowScriptCrossing = false ;# {TrustBinaries} {AllowScriptCrossing:true} {Accept compiled binary script code? (DANGEROUS!)} {true false} false diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 57db852bfd..400d3dfac1 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -14,10 +14,13 @@ ; Place to create a PID file ; PIDFile = "/tmp/my.pid" + ; Console commands run at startup startup_console_commands_file = "startup_commands.txt" + + ; Console commands run on shutdown shutdown_console_commands_file = "shutdown_commands.txt" - ; To run a script every few minutes, set the script filename here + ; Console commands run every 20 minutes ; timer_Script = "filename" ; ## @@ -70,12 +73,17 @@ ; Use terrain texture for maptiles if true, use shaded green if false TextureOnMapTile = false - ; Maximum total size, and maximum size where a prim can be physical + ; Maximum size of non physical prims. Affects resizing of existing prims. This can be overriden in the region config file (as NonphysicalPrimMax!). NonPhysicalPrimMax = 256 - PhysicalPrimMax = 10 ; (I think this was moved to the Regions.ini!) + + ; Maximum size of physical prims. Affects resizing of existing prims. This can be overriden in the region config file. + PhysicalPrimMax = 10 + + ; If a viewer attempts to rez a prim larger than the non-physical or physical prim max, clamp the dimensions to the appropriate maximum + ; This can be overriden in the region config file. ClampPrimSize = false - ; Allow scripts to cross region boundaries. These are recompiled on the new region. + ; Allow scripts to keep running when they cross region boundaries, rather than being restarted. Script code is recompiled on the destination region and the state reloaded. AllowScriptCrossing = false ; Allow compiled script binary code to cross region boundaries. @@ -94,7 +102,7 @@ ; neighbors on each side for a total of 49 regions in view. Warning, unless ; all the regions have the same drawdistance, you will end up with strange ; effects because the agents that get closed may be inconsistent. - ; DefaultDrawDistance = 255.0 + DefaultDrawDistance = 255.0 ; If you have only one region in an instance, or to avoid the many bugs ; that you can trigger in modules by restarting a region, set this to @@ -102,7 +110,7 @@ ; This is meant to be used on systems where some external system like ; Monit will restart any instance that exits, thereby making the shutdown ; into a restart. - ;InworldRestartShutsDown = false + InworldRestartShutsDown = false ; ## ; ## PRIM STORAGE @@ -227,7 +235,6 @@ ; If enabled, enableFlySlow will change the primary fly state to ; FLYSLOW, and the "always run" state will be the regular fly. - enableflyslow = false ; PreJump is an additional animation state, but it probably @@ -236,7 +243,6 @@ ; This is commented so it will come on automatically once it's ; supported. - ; enableprejump = true ; Simulator Stats URI @@ -265,6 +271,7 @@ DelayBeforeAppearanceSave = 5 DelayBeforeAppearanceSend = 2 + [SMTP] enabled=false From 9f72fbcb7533bd960c38082cbd6956cd01fa6919 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 1 Jul 2011 21:25:40 +0100 Subject: [PATCH 04/18] Add an async inventory details sender to respond to FetchInventory packets. If a user with a very large inventory right-clicks on their "My Inventory" folder, viewer 1 code will send a massive number of Fetchinventory requests. Even though each is handled asynchronously via a pool thread, the sheer frequency of requests overwhelms the pool and freezes inbound packet handling. This change makes the first Fetchinventory thread also handle subsequent requests, freeing up the other threads. Further efficiencies could be made by handling all the items in a particular FetchInventory request together, rather than separately. --- OpenSim/Framework/IClientAPI.cs | 2 +- .../Framework/Scenes/AsyncInventorySender.cs | 156 ++++++++++++++++++ .../Framework/Scenes/Scene.Inventory.cs | 5 + .../Framework/Scenes/Scene.PacketHandlers.cs | 25 --- OpenSim/Region/Framework/Scenes/Scene.cs | 5 +- 5 files changed, 165 insertions(+), 28 deletions(-) create mode 100644 OpenSim/Region/Framework/Scenes/AsyncInventorySender.cs diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index 659d42ff91..f6e29771d8 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -737,7 +737,7 @@ namespace OpenSim.Framework bool IsActive { get; set; } /// - /// Determines whether the client is logging out or not. + /// Determines whether the client is or has been removed from a given scene /// bool IsLoggingOut { get; set; } diff --git a/OpenSim/Region/Framework/Scenes/AsyncInventorySender.cs b/OpenSim/Region/Framework/Scenes/AsyncInventorySender.cs new file mode 100644 index 0000000000..06cd14b553 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/AsyncInventorySender.cs @@ -0,0 +1,156 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; +using log4net; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; + +namespace OpenSim.Region.Framework.Scenes +{ + class FetchHolder + { + public IClientAPI Client { get; private set; } + public UUID ItemID { get; private set; } + + public FetchHolder(IClientAPI client, UUID itemID) + { + Client = client; + ItemID = itemID; + } + } + + /// + /// Send FetchInventoryReply information to clients asynchronously on a single thread rather than asynchronously via + /// multiple threads. + /// + /// + /// If the main root inventory is right-clicked on a version 1 viewer for a user with a large inventory, a very + /// very large number of FetchInventory requests are sent to the simulator. Each is handled on a separate thread + /// by the IClientAPI, but the sheer number of requests overwhelms the number of threads available and ends up + /// freezing the inbound packet handling. + /// + /// This class makes the first FetchInventory packet thread process the queue. If new requests come + /// in while it is processing, then the subsequent threads just add the requests and leave it to the original + /// thread to process them. + /// + /// This might slow down outbound packets but these are limited by the IClientAPI outbound queues + /// anyway. + /// + /// It might be possible to ignore FetchInventory requests altogether, particularly as they are redundant wrt to + /// FetchInventoryDescendents requests, but this would require more investigation. + /// + public class AsyncInventorySender + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + protected Scene m_scene; + + /// + /// Queues fetch requests + /// + Queue m_fetchHolder = new Queue(); + + /// + /// Signal whether a queue is currently being processed or not. + /// + protected volatile bool m_processing; + + public AsyncInventorySender(Scene scene) + { + m_processing = false; + m_scene = scene; + } + + /// + /// Handle a fetch inventory request from the client + /// + /// + /// + /// + public void HandleFetchInventory(IClientAPI remoteClient, UUID itemID, UUID ownerID) + { + lock (m_fetchHolder) + { +// m_log.DebugFormat( +// "[ASYNC INVENTORY SENDER]: Putting request from {0} for {1} on queue", remoteClient.Name, itemID); + + m_fetchHolder.Enqueue(new FetchHolder(remoteClient, itemID)); + } + + if (!m_processing) + { + m_processing = true; + ProcessQueue(); + } + } + + /// + /// Process the queue of fetches + /// + protected void ProcessQueue() + { + FetchHolder fh = null; + + while (true) + { + lock (m_fetchHolder) + { +// m_log.DebugFormat("[ASYNC INVENTORY SENDER]: {0} items left to process", m_fetchHolder.Count); + + if (m_fetchHolder.Count == 0) + { + m_processing = false; + return; + } + else + { + fh = m_fetchHolder.Dequeue(); + } + } + + if (fh.Client.IsLoggingOut) + continue; + +// m_log.DebugFormat( +// "[ASYNC INVENTORY SENDER]: Handling request from {0} for {1} on queue", fh.Client.Name, fh.ItemID); + + InventoryItemBase item = new InventoryItemBase(fh.ItemID, fh.Client.AgentId); + item = m_scene.InventoryService.GetItem(item); + + if (item != null) + fh.Client.SendInventoryItemDetails(item.Owner, item); + + // TODO: Possibly log any failure + } + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 13085e3838..30421d4224 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -51,6 +51,11 @@ namespace OpenSim.Region.Framework.Scenes /// protected AsyncSceneObjectGroupDeleter m_asyncSceneObjectDeleter; + /// + /// Allows inventory details to be sent to clients asynchronously + /// + protected AsyncInventorySender m_asyncInventorySender; + /// /// Start all the scripts in the scene which should be started. /// diff --git a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs index e2d7208ff7..44472b2cb7 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs @@ -461,31 +461,6 @@ namespace OpenSim.Region.Framework.Scenes } ); } - - - /// - /// Handle a fetch inventory request from the client - /// - /// - /// - /// - public void HandleFetchInventory(IClientAPI remoteClient, UUID itemID, UUID ownerID) - { - if (LibraryService != null && LibraryService.LibraryRootFolder != null && ownerID == LibraryService.LibraryRootFolder.Owner) - { - //m_log.Debug("request info for library item"); - return; - } - - InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); - item = InventoryService.GetItem(item); - - if (item != null) - { - remoteClient.SendInventoryItemDetails(ownerID, item); - } - // else shouldn't we send an alert message? - } /// /// Tell the client about the various child items and folders contained in the requested folder. diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index ad41e88db5..eeb881fe12 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -583,6 +583,8 @@ namespace OpenSim.Region.Framework.Scenes m_asyncSceneObjectDeleter = new AsyncSceneObjectGroupDeleter(this); m_asyncSceneObjectDeleter.Enabled = true; + m_asyncInventorySender = new AsyncInventorySender(this); + #region Region Settings // Load region settings @@ -2760,14 +2762,13 @@ namespace OpenSim.Region.Framework.Scenes public virtual void SubscribeToClientInventoryEvents(IClientAPI client) { - client.OnLinkInventoryItem += HandleLinkInventoryItem; client.OnCreateNewInventoryFolder += HandleCreateInventoryFolder; client.OnUpdateInventoryFolder += HandleUpdateInventoryFolder; client.OnMoveInventoryFolder += HandleMoveInventoryFolder; // 2; //!! client.OnFetchInventoryDescendents += HandleFetchInventoryDescendents; client.OnPurgeInventoryDescendents += HandlePurgeInventoryDescendents; // 2; //!! - client.OnFetchInventory += HandleFetchInventory; + client.OnFetchInventory += m_asyncInventorySender.HandleFetchInventory; client.OnUpdateInventoryItem += UpdateInventoryItemAsset; client.OnCopyInventoryItem += CopyInventoryItem; client.OnMoveInventoryItem += MoveInventoryItem; From e41093635aa9861e9115c8331b0cf27c0507fef3 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 1 Jul 2011 21:37:03 +0100 Subject: [PATCH 05/18] fix build break I just introduced --- OpenSim/Region/Framework/Scenes/Scene.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index eeb881fe12..ec6044bf44 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -2887,13 +2887,12 @@ namespace OpenSim.Region.Framework.Scenes public virtual void UnSubscribeToClientInventoryEvents(IClientAPI client) { - client.OnCreateNewInventoryFolder -= HandleCreateInventoryFolder; client.OnUpdateInventoryFolder -= HandleUpdateInventoryFolder; client.OnMoveInventoryFolder -= HandleMoveInventoryFolder; // 2; //!! client.OnFetchInventoryDescendents -= HandleFetchInventoryDescendents; client.OnPurgeInventoryDescendents -= HandlePurgeInventoryDescendents; // 2; //!! - client.OnFetchInventory -= HandleFetchInventory; + client.OnFetchInventory -= m_asyncInventorySender.HandleFetchInventory; client.OnUpdateInventoryItem -= UpdateInventoryItemAsset; client.OnCopyInventoryItem -= CopyInventoryItem; client.OnMoveInventoryItem -= MoveInventoryItem; From 759e855566a08d965059ca08d4f4510d335f1c7d Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 1 Jul 2011 21:47:30 +0100 Subject: [PATCH 06/18] refactor: rename gitCommitFileName to manualVersionFileName since bin/.version doesn't necessary have to be a git hash --- OpenSim/Framework/Servers/BaseOpenSimServer.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs index 21e1e09b70..98a92ddfed 100644 --- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs +++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs @@ -460,21 +460,20 @@ namespace OpenSim.Framework.Servers // elsewhere as well string svnRevisionFileName = "svn_revision"; string svnFileName = ".svn/entries"; - string gitCommitFileName = ".version"; + string manualVersionFileName = ".version"; string inputLine; int strcmp; - if (File.Exists(gitCommitFileName)) + if (File.Exists(manualVersionFileName)) { - StreamReader CommitFile = File.OpenText(gitCommitFileName); + StreamReader CommitFile = File.OpenText(manualVersionFileName); buildVersion = CommitFile.ReadLine(); CommitFile.Close(); m_version += buildVersion ?? ""; } - - // Remove the else logic when subversion mirror is no longer used else { + // Remove the else logic when subversion mirror is no longer used if (File.Exists(svnRevisionFileName)) { StreamReader RevisionFile = File.OpenText(svnRevisionFileName); From e765759f504b86a643fd8843e41b0283422f7980 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 1 Jul 2011 22:48:00 +0100 Subject: [PATCH 07/18] If OpenSim has been built from a git tree, then include version information automatically by dereferencing .git/HEAD A blank bin/.version file will stop this being displayed. --- .../Framework/Servers/BaseOpenSimServer.cs | 43 +++++++++++++++++-- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs index 98a92ddfed..d4c3d0848f 100644 --- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs +++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs @@ -31,6 +31,7 @@ using System.Diagnostics; using System.IO; using System.Reflection; using System.Text; +using System.Text.RegularExpressions; using System.Threading; using System.Timers; using log4net; @@ -124,7 +125,6 @@ namespace OpenSim.Framework.Servers m_logFileAppender = appender; } } - } /// @@ -458,6 +458,9 @@ namespace OpenSim.Framework.Servers // This allows to make the revision available in simulators not running from the source tree. // FIXME: Making an assumption about the directory we're currently in - we do this all over the place // elsewhere as well + string gitDir = "../.git/"; + string gitRefPointerPath = gitDir + "HEAD"; + string svnRevisionFileName = "svn_revision"; string svnFileName = ".svn/entries"; string manualVersionFileName = ".version"; @@ -466,13 +469,45 @@ namespace OpenSim.Framework.Servers if (File.Exists(manualVersionFileName)) { - StreamReader CommitFile = File.OpenText(manualVersionFileName); - buildVersion = CommitFile.ReadLine(); - CommitFile.Close(); + using (StreamReader CommitFile = File.OpenText(manualVersionFileName)) + buildVersion = CommitFile.ReadLine(); + m_version += buildVersion ?? ""; } + else if (File.Exists(gitRefPointerPath)) + { +// m_log.DebugFormat("[OPENSIM]: Found {0}", gitRefPointerPath); + + string rawPointer = ""; + + using (StreamReader pointerFile = File.OpenText(gitRefPointerPath)) + rawPointer = pointerFile.ReadLine(); + +// m_log.DebugFormat("[OPENSIM]: rawPointer [{0}]", rawPointer); + + Match m = Regex.Match(rawPointer, "^ref: (.+)$"); + + if (m.Success) + { +// m_log.DebugFormat("[OPENSIM]: Matched [{0}]", m.Groups[1].Value); + + string gitRef = m.Groups[1].Value; + string gitRefPath = gitDir + gitRef; + if (File.Exists(gitRefPath)) + { +// m_log.DebugFormat("[OPENSIM]: Found gitRefPath [{0}]", gitRefPath); + + using (StreamReader refFile = File.OpenText(gitRefPath)) + { + string gitHash = refFile.ReadLine(); + m_version += gitHash.Substring(0, 7); + } + } + } + } else { + m_log.DebugFormat("[OPENSIM]: Looking for SVN"); // Remove the else logic when subversion mirror is no longer used if (File.Exists(svnRevisionFileName)) { From fba961c63f2168eb560eec84b66203b1a875b952 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 1 Jul 2011 23:06:46 +0100 Subject: [PATCH 08/18] Make default serverside_object_permissions = true since this better matches user expectations. It also matches the default setting in the OpenSim.ini.example file --- OpenSim/Framework/Servers/BaseOpenSimServer.cs | 11 ----------- OpenSim/Region/Application/ConfigurationLoader.cs | 2 +- .../World/Permissions/PermissionsModule.cs | 2 +- OpenSim/Tools/Configger/ConfigurationLoader.cs | 2 +- bin/OpenSim.ini.example | 2 +- 5 files changed, 4 insertions(+), 15 deletions(-) diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs index d4c3d0848f..688be3f7f1 100644 --- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs +++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs @@ -443,15 +443,6 @@ namespace OpenSim.Framework.Servers { string buildVersion = string.Empty; - // Add commit hash and date information if available - // The commit hash and date are stored in a file bin/.version - // This file can automatically created by a post - // commit script in the opensim git master repository or - // by issuing the follwoing command from the top level - // directory of the opensim repository - // git log -n 1 --pretty="format:%h: %ci" >bin/.version - // For the full git commit hash use %H instead of %h - // // The subversion information is deprecated and will be removed at a later date // Add subversion revision information if available // Try file "svn_revision" in the current directory first, then the .svn info. @@ -507,7 +498,6 @@ namespace OpenSim.Framework.Servers } else { - m_log.DebugFormat("[OPENSIM]: Looking for SVN"); // Remove the else logic when subversion mirror is no longer used if (File.Exists(svnRevisionFileName)) { @@ -515,7 +505,6 @@ namespace OpenSim.Framework.Servers buildVersion = RevisionFile.ReadLine(); buildVersion.Trim(); RevisionFile.Close(); - } if (string.IsNullOrEmpty(buildVersion) && File.Exists(svnFileName)) diff --git a/OpenSim/Region/Application/ConfigurationLoader.cs b/OpenSim/Region/Application/ConfigurationLoader.cs index 2d81ea8432..d19852b1ee 100644 --- a/OpenSim/Region/Application/ConfigurationLoader.cs +++ b/OpenSim/Region/Application/ConfigurationLoader.cs @@ -328,7 +328,7 @@ namespace OpenSim config.Set("meshing", "Meshmerizer"); config.Set("physical_prim", true); config.Set("see_into_this_sim_from_neighbor", true); - config.Set("serverside_object_permissions", false); + config.Set("serverside_object_permissions", true); config.Set("storage_plugin", "OpenSim.Data.SQLite.dll"); config.Set("storage_connection_string", "URI=file:OpenSim.db,version=3"); config.Set("storage_prim_inventories", true); diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs index d7324c6c55..a40517cf3e 100644 --- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs +++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs @@ -134,7 +134,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions return; m_allowGridGods = myConfig.GetBoolean("allow_grid_gods", false); - m_bypassPermissions = !myConfig.GetBoolean("serverside_object_permissions", false); + m_bypassPermissions = !myConfig.GetBoolean("serverside_object_permissions", true); m_propagatePermissions = myConfig.GetBoolean("propagate_permissions", true); m_RegionOwnerIsGod = myConfig.GetBoolean("region_owner_is_god", true); m_RegionManagerIsGod = myConfig.GetBoolean("region_manager_is_god", false); diff --git a/OpenSim/Tools/Configger/ConfigurationLoader.cs b/OpenSim/Tools/Configger/ConfigurationLoader.cs index 8e71b42bca..39146527b8 100644 --- a/OpenSim/Tools/Configger/ConfigurationLoader.cs +++ b/OpenSim/Tools/Configger/ConfigurationLoader.cs @@ -239,7 +239,7 @@ namespace OpenSim.Tools.Configger config.Set("meshing", "Meshmerizer"); config.Set("physical_prim", true); config.Set("see_into_this_sim_from_neighbor", true); - config.Set("serverside_object_permissions", false); + config.Set("serverside_object_permissions", true); config.Set("storage_plugin", "OpenSim.Data.SQLite.dll"); config.Set("storage_connection_string", "URI=file:OpenSim.db,version=3"); config.Set("storage_prim_inventories", true); diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index a4f243d486..60d37fbcec 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -172,7 +172,7 @@ ;; permission checks (allowing anybody to copy ;; any item, etc. This may not yet be implemented uniformally. ;; If set to true, then all permissions checks are carried out - ; serverside_object_permissions = false + ; serverside_object_permissions = true ;; This allows users with a UserLevel of 200 or more to assume god ;; powers in the regions in this simulator. From ed12e38480a28d5863b5777e9bbeb94ce84d3ef1 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 2 Jul 2011 00:18:15 +0100 Subject: [PATCH 09/18] refactor: simplify existing npc code by creating them directly rather than indirectly via a timer no obvious reason for doing this asynchonously, especially as the caller was sleeping in order to pick up the response anyway! --- .../OptionalModules/World/NPC/NPCModule.cs | 141 +++++------------- 1 file changed, 38 insertions(+), 103 deletions(-) diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs index 48d236fc58..c1ddeee3b2 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs @@ -47,31 +47,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC // private const bool m_enabled = false; - private Mutex m_createMutex; - private Timer m_timer; - private Dictionary m_avatars = new Dictionary(); private Dictionary m_appearanceCache = new Dictionary(); - // Timer vars. - private bool p_inUse = false; - private readonly object p_lock = new object(); - // Private Temporary Variables. - private string p_firstname; - private string p_lastname; - private Vector3 p_position; - private Scene p_scene; - private UUID p_cloneAppearanceFrom; - private UUID p_returnUuid; - public void Initialise(Scene scene, IConfigSource source) { - m_createMutex = new Mutex(false); - - m_timer = new Timer(500); - m_timer.Elapsed += m_timer_Elapsed; - m_timer.Start(); - scene.RegisterModuleInterface(this); } @@ -92,33 +72,51 @@ namespace OpenSim.Region.OptionalModules.World.NPC public UUID CreateNPC(string firstname, string lastname,Vector3 position, Scene scene, UUID cloneAppearanceFrom) { + NPCAvatar npcAvatar = new NPCAvatar(firstname, lastname, position, scene); + npcAvatar.CircuitCode = (uint)Util.RandomClass.Next(0, int.MaxValue); + m_log.DebugFormat( - "[NPC MODULE]: Queueing request to create NPC {0} {1} at {2} in {3} cloning appearance of {4}", - firstname, lastname, position, scene.RegionInfo.RegionName, cloneAppearanceFrom); + "[NPC MODULE]: Creating NPC {0} {1} {2} at {3} in {4}", + firstname, lastname, npcAvatar.AgentId, position, scene.RegionInfo.RegionName); - // Block. - m_createMutex.WaitOne(); + AgentCircuitData acd = new AgentCircuitData(); + acd.AgentID = npcAvatar.AgentId; + acd.firstname = firstname; + acd.lastname = lastname; + acd.ServiceURLs = new Dictionary(); - // Copy Temp Variables for Timer to pick up. - lock (p_lock) + AvatarAppearance originalAppearance = GetAppearance(cloneAppearanceFrom, scene); + AvatarAppearance npcAppearance = new AvatarAppearance(originalAppearance, true); + acd.Appearance = npcAppearance; + + scene.AuthenticateHandler.AddNewCircuit(npcAvatar.CircuitCode, acd); + scene.AddNewClient(npcAvatar); + + ScenePresence sp; + if (scene.TryGetScenePresence(npcAvatar.AgentId, out sp)) { - p_firstname = firstname; - p_lastname = lastname; - p_position = position; - p_scene = scene; - p_cloneAppearanceFrom = cloneAppearanceFrom; - p_inUse = true; - p_returnUuid = UUID.Zero; + m_log.DebugFormat( + "[NPC MODULE]: Successfully retrieved scene presence for NPC {0} {1}", sp.Name, sp.UUID); + + // Shouldn't call this - temporary. + sp.CompleteMovement(npcAvatar); + +// sp.SendAppearanceToAllOtherAgents(); +// +// // Send animations back to the avatar as well +// sp.Animator.SendAnimPack(); + } + else + { + m_log.WarnFormat("[NPC MODULE]: Could not find scene presence for NPC {0} {1}", sp.Name, sp.UUID); } - while (p_returnUuid == UUID.Zero) - { - Thread.Sleep(250); - } + lock (m_avatars) + m_avatars.Add(npcAvatar.AgentId, npcAvatar); - m_createMutex.ReleaseMutex(); + m_log.DebugFormat("[NPC MODULE]: Created NPC with id {0}", npcAvatar.AgentId); - return p_returnUuid; + return npcAvatar.AgentId; } public void Autopilot(UUID agentID, Scene scene, Vector3 pos) @@ -157,69 +155,6 @@ namespace OpenSim.Region.OptionalModules.World.NPC } } - void m_timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) - { - try - { - lock (p_lock) - { - if (p_inUse) - { - p_inUse = false; - - NPCAvatar npcAvatar = new NPCAvatar(p_firstname, p_lastname, p_position, p_scene); - npcAvatar.CircuitCode = (uint) Util.RandomClass.Next(0, int.MaxValue); - - m_log.DebugFormat( - "[NPC MODULE]: Creating NPC {0} {1} {2} at {3} in {4}", - p_firstname, p_lastname, npcAvatar.AgentId, p_position, p_scene.RegionInfo.RegionName); - - AgentCircuitData acd = new AgentCircuitData(); - acd.AgentID = npcAvatar.AgentId; - acd.firstname = p_firstname; - acd.lastname = p_lastname; - acd.ServiceURLs = new Dictionary(); - - AvatarAppearance originalAppearance = GetAppearance(p_cloneAppearanceFrom, p_scene); - AvatarAppearance npcAppearance = new AvatarAppearance(originalAppearance, true); - acd.Appearance = npcAppearance; - - p_scene.AuthenticateHandler.AddNewCircuit(npcAvatar.CircuitCode, acd); - p_scene.AddNewClient(npcAvatar); - - ScenePresence sp; - if (p_scene.TryGetScenePresence(npcAvatar.AgentId, out sp)) - { - m_log.DebugFormat( - "[NPC MODULE]: Successfully retrieved scene presence for NPC {0} {1}", sp.Name, sp.UUID); - - // Shouldn't call this - temporary. - sp.CompleteMovement(npcAvatar); - - // sp.SendAppearanceToAllOtherAgents(); - // - // // Send animations back to the avatar as well - // sp.Animator.SendAnimPack(); - } - else - { - m_log.WarnFormat("[NPC MODULE]: Could not find scene presence for NPC {0} {1}", sp.Name, sp.UUID); - } - - m_avatars.Add(npcAvatar.AgentId, npcAvatar); - - p_returnUuid = npcAvatar.AgentId; - - m_log.DebugFormat("[NPC MODULE]: Created NPC with id {0}", p_returnUuid); - } - } - } - catch (Exception ex) - { - m_log.ErrorFormat("[NPC MODULE]: NPC creation failed with exception {0} {1}", ex.Message, ex.StackTrace); - } - } - public void PostInitialise() { } @@ -238,4 +173,4 @@ namespace OpenSim.Region.OptionalModules.World.NPC get { return true; } } } -} +} \ No newline at end of file From 513d63455ed7cf1a7a859e9e8abaeff7e7c7ad4f Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 2 Jul 2011 01:01:40 +0100 Subject: [PATCH 10/18] Create a very basic initial test which just creates an 'npc' and tests that the scene presence exists --- .../Interfaces}/INPCModule.cs | 2 +- .../OptionalModules/World/NPC/NPCModule.cs | 3 +- .../World/NPC/Tests/NPCModuleTests.cs | 71 +++++++++++++++++++ .../Shared/Api/Implementation/OSSL_Api.cs | 1 - prebuild.xml | 2 + 5 files changed, 75 insertions(+), 4 deletions(-) rename OpenSim/Region/{CoreModules/Avatar/NPC => Framework/Interfaces}/INPCModule.cs (97%) create mode 100644 OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs diff --git a/OpenSim/Region/CoreModules/Avatar/NPC/INPCModule.cs b/OpenSim/Region/Framework/Interfaces/INPCModule.cs similarity index 97% rename from OpenSim/Region/CoreModules/Avatar/NPC/INPCModule.cs rename to OpenSim/Region/Framework/Interfaces/INPCModule.cs index cd2fe4fc85..21a755f29a 100644 --- a/OpenSim/Region/CoreModules/Avatar/NPC/INPCModule.cs +++ b/OpenSim/Region/Framework/Interfaces/INPCModule.cs @@ -28,7 +28,7 @@ using OpenMetaverse; using OpenSim.Region.Framework.Scenes; -namespace OpenSim.Region.CoreModules.Avatar.NPC +namespace OpenSim.Region.Framework.Interfaces { public interface INPCModule { diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs index c1ddeee3b2..3cdd06d52c 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs @@ -34,7 +34,6 @@ using Nini.Config; using OpenMetaverse; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; -using OpenSim.Region.CoreModules.Avatar.NPC; using OpenSim.Framework; using Timer=System.Timers.Timer; using OpenSim.Services.Interfaces; @@ -70,7 +69,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC return new AvatarAppearance(); } - public UUID CreateNPC(string firstname, string lastname,Vector3 position, Scene scene, UUID cloneAppearanceFrom) + public UUID CreateNPC(string firstname, string lastname, Vector3 position, Scene scene, UUID cloneAppearanceFrom) { NPCAvatar npcAvatar = new NPCAvatar(firstname, lastname, position, scene); npcAvatar.CircuitCode = (uint)Util.RandomClass.Next(0, int.MaxValue); diff --git a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs new file mode 100644 index 0000000000..899e721767 --- /dev/null +++ b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs @@ -0,0 +1,71 @@ +/* + * 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.Reflection; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Communications; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Avatar; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.AvatarService; +using OpenSim.Tests.Common; +using OpenSim.Tests.Common.Mock; + +namespace OpenSim.Region.OptionalModules.World.NPC.Tests +{ + [TestFixture] + public class NPCModuleTests + { + [Test] + public void TestCreate() + { + TestHelper.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + IConfigSource config = new IniConfigSource(); + + config.AddConfig("Modules"); + config.Configs["Modules"].Set("AvatarServices", "LocalAvatarServicesConnector"); + config.AddConfig("AvatarService"); + config.Configs["AvatarService"].Set("LocalServiceModule", "OpenSim.Services.AvatarService.dll:AvatarService"); + config.Configs["AvatarService"].Set("StorageProvider", "OpenSim.Data.Null.dll"); + + TestScene scene = SceneSetupHelpers.SetupScene(); + SceneSetupHelpers.SetupSceneModules(scene, config, new NPCModule(), new LocalAvatarServicesConnector()); + + INPCModule npcModule = scene.RequestModuleInterface(); + UUID npcId = npcModule.CreateNPC("John", "Smith", new Vector3(128, 128, 30), scene, UUID.Zero); + + ScenePresence npc = scene.GetScenePresence(npcId); + Assert.That(npc, Is.Not.Null); + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 963727ded8..1bc4534750 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -38,7 +38,6 @@ using OpenSim; using OpenSim.Framework; using OpenSim.Framework.Console; -using OpenSim.Region.CoreModules.Avatar.NPC; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.ScriptEngine.Shared; diff --git a/prebuild.xml b/prebuild.xml index ed79b40c39..aebd1d66f8 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -2997,6 +2997,7 @@ + @@ -3020,6 +3021,7 @@ + From bb4cb165127164cbc9d907aac27c4fb3eb69d443 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 2 Jul 2011 01:05:03 +0100 Subject: [PATCH 11/18] Add profile, merge, noassets and skip-assets options for loading/saving oars via RemoteAdmin This is http://opensimulator.org/mantis/view.php?id=5453 Thanks Michelle Argus! --- .../RemoteController/RemoteAdminPlugin.cs | 41 ++++++++++++++++++- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs index 5a011cecb3..93a6915947 100644 --- a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs +++ b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs @@ -2201,6 +2201,10 @@ namespace OpenSim.ApplicationPlugins.RemoteController /// UUID of the region /// region_name /// region name + /// merge + /// true if oar should be merged + /// skip-assets + /// true if assets should be skiped /// /// /// region_uuid takes precedence over @@ -2259,10 +2263,22 @@ namespace OpenSim.ApplicationPlugins.RemoteController throw new Exception(String.Format("failed to switch to region {0}", region_name)); } else throw new Exception("neither region_name nor region_uuid given"); + + bool mergeOar = false; + bool skipAssets = false; + + if ((string)requestData["merge"] == "true") + { + mergeOar = true; + } + if ((string)requestData["skip-assets"] == "true") + { + skipAssets = true; + } IRegionArchiverModule archiver = scene.RequestModuleInterface(); if (archiver != null) - archiver.DearchiveRegion(filename); + archiver.DearchiveRegion(filename, mergeOar, skipAssets, Guid.Empty); else throw new Exception("Archiver module not present for scene"); @@ -2302,6 +2318,10 @@ namespace OpenSim.ApplicationPlugins.RemoteController /// UUID of the region /// region_name /// region name + /// profile + /// profile url + /// noassets + /// true if no assets should be saved /// /// /// region_uuid takes precedence over @@ -2359,12 +2379,29 @@ namespace OpenSim.ApplicationPlugins.RemoteController } else throw new Exception("neither region_name nor region_uuid given"); + Dictionary options = new Dictionary(); + + //if (requestData.Contains("version")) + //{ + // options["version"] = (string)requestData["version"]; + //} + + if (requestData.Contains("profile")) + { + options["profile"] = (string)requestData["profile"]; + } + + if (requestData["noassets"] == "true") + { + options["noassets"] = (string)requestData["noassets"] ; + } + IRegionArchiverModule archiver = scene.RequestModuleInterface(); if (archiver != null) { scene.EventManager.OnOarFileSaved += RemoteAdminOarSaveCompleted; - archiver.ArchiveRegion(filename, new Dictionary()); + archiver.ArchiveRegion(filename, options); lock (m_saveOarLock) Monitor.Wait(m_saveOarLock,5000); scene.EventManager.OnOarFileSaved -= RemoteAdminOarSaveCompleted; } From b8e7258051abab3e1310dd8b08cb1d2e09fa21e3 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 2 Jul 2011 01:14:29 +0100 Subject: [PATCH 12/18] If a user has the rights to edit a parcel's properties, then also allow them always to enter that parcel. This is patch http://opensimulator.org/mantis/view.php?id=5567 Thanks Snoopy! --- OpenSim/Region/CoreModules/World/Land/LandObject.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs index 560b862625..8c40171943 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs @@ -418,7 +418,7 @@ namespace OpenSim.Region.CoreModules.World.Land public bool IsBannedFromLand(UUID avatar) { - if (m_scene.Permissions.IsAdministrator(avatar)) + if (m_scene.Permissions.CanEditParcelProperties(avatar, this, 0)) return false; if ((LandData.Flags & (uint) ParcelFlags.UseBanList) > 0) @@ -429,7 +429,7 @@ namespace OpenSim.Region.CoreModules.World.Land if (e.AgentID == avatar && e.Flags == AccessList.Ban) return true; return false; - }) != -1 && LandData.OwnerID != avatar) + }) != -1) { return true; } @@ -439,7 +439,7 @@ namespace OpenSim.Region.CoreModules.World.Land public bool IsRestrictedFromLand(UUID avatar) { - if (m_scene.Permissions.IsAdministrator(avatar)) + if (m_scene.Permissions.CanEditParcelProperties(avatar, this, 0)) return false; if ((LandData.Flags & (uint) ParcelFlags.UseAccessList) > 0) @@ -450,7 +450,7 @@ namespace OpenSim.Region.CoreModules.World.Land if (e.AgentID == avatar && e.Flags == AccessList.Access) return true; return false; - }) == -1 && LandData.OwnerID != avatar) + }) == -1) { return true; } From 46f5893d559f87982e510d02a37856951eb1e088 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 4 Jul 2011 21:35:15 +0100 Subject: [PATCH 13/18] Add basic flotsam asset cache test for retrieved cached asset. Disabled temporarily since file system caching disrupts subsequent test runs --- OpenSim/Framework/AssetBase.cs | 1 + .../CoreModules/Asset/FlotsamAssetCache.cs | 2 + .../Asset/Tests/FlotsamAssetCacheTests.cs | 82 +++++++++++++++++++ OpenSim/Tests/Common/Helpers/AssetHelpers.cs | 9 ++ OpenSim/Tests/Common/TestHelper.cs | 11 +++ prebuild.xml | 1 + 6 files changed, 106 insertions(+) create mode 100644 OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs diff --git a/OpenSim/Framework/AssetBase.cs b/OpenSim/Framework/AssetBase.cs index 5f68cdaabf..e8c85c9f0c 100644 --- a/OpenSim/Framework/AssetBase.cs +++ b/OpenSim/Framework/AssetBase.cs @@ -273,6 +273,7 @@ namespace OpenSim.Framework return m_id; } + set { UUID uuid = UUID.Zero; diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index 48ee277ae9..a8f5c99ae7 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -259,6 +259,8 @@ namespace Flotsam.RegionModules.AssetCache // TODO: Spawn this off to some seperate thread to do the actual writing if (asset != null) { + m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Caching asset with id {0}", asset.ID); + UpdateMemoryCache(asset.ID, asset); string filename = GetFileName(asset.ID); diff --git a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs new file mode 100644 index 0000000000..3498969828 --- /dev/null +++ b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs @@ -0,0 +1,82 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Threading; +using log4net.Config; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Assets; +using Flotsam.RegionModules.AssetCache; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Scenes.Serialization; +using OpenSim.Tests.Common; +using OpenSim.Tests.Common.Mock; + +namespace OpenSim.Region.CoreModules.Asset.Tests +{ + [TestFixture] + public class FlotsamAssetCacheTests + { +// [Test] + public void TestCacheAsset() + { + TestHelper.InMethod(); + log4net.Config.XmlConfigurator.Configure(); + + IConfigSource config = new IniConfigSource(); + + config.AddConfig("Modules"); + config.Configs["Modules"].Set("AssetCaching", "FlotsamAssetCache"); + config.AddConfig("AssetCache"); + config.Configs["AssetCache"].Set("MemoryCacheEnabled", "true"); + + FlotsamAssetCache cache = new FlotsamAssetCache(); + TestScene scene = SceneSetupHelpers.SetupScene(); + SceneSetupHelpers.SetupSceneModules(scene, config, cache); + + AssetBase asset = AssetHelpers.CreateAsset(); + asset.ID = TestHelper.ParseTail(0x1).ToString(); + + // Check we don't get anything before the asset is put in the cache + AssetBase retrievedAsset = cache.Get(asset.ID.ToString()); + Assert.That(retrievedAsset, Is.Null); + + cache.Store(asset); + + // Check that asset is now in cache + retrievedAsset = cache.Get(asset.ID.ToString()); + Assert.That(retrievedAsset, Is.Not.Null); + Assert.That(retrievedAsset.ID, Is.EqualTo(asset.ID)); + } + } +} \ No newline at end of file diff --git a/OpenSim/Tests/Common/Helpers/AssetHelpers.cs b/OpenSim/Tests/Common/Helpers/AssetHelpers.cs index aa55bcdc69..9b68331038 100644 --- a/OpenSim/Tests/Common/Helpers/AssetHelpers.cs +++ b/OpenSim/Tests/Common/Helpers/AssetHelpers.cs @@ -36,6 +36,15 @@ namespace OpenSim.Tests.Common { public class AssetHelpers { + /// + /// Create a notecard asset with a random uuids and dummy text. + /// + /// + public static AssetBase CreateAsset() + { + return CreateAsset(UUID.Random(), AssetType.Notecard, "hello", UUID.Random()); + } + /// /// Create a notecard asset with a random uuid and dummy text. /// diff --git a/OpenSim/Tests/Common/TestHelper.cs b/OpenSim/Tests/Common/TestHelper.cs index 1722e59864..86bd10766b 100644 --- a/OpenSim/Tests/Common/TestHelper.cs +++ b/OpenSim/Tests/Common/TestHelper.cs @@ -28,6 +28,7 @@ using System; using System.Diagnostics; using NUnit.Framework; +using OpenMetaverse; namespace OpenSim.Tests.Common { @@ -56,5 +57,15 @@ namespace OpenSim.Tests.Common Console.WriteLine(); Console.WriteLine("===> In Test Method : {0} <===", stackTrace.GetFrame(1).GetMethod().Name); } + + /// + /// Parse tail section into full UUID. + /// + /// + /// + public static UUID ParseTail(int tail) + { + return new UUID(string.Format("00000000-0000-0000-0000-{0:X12}", tail)); + } } } diff --git a/prebuild.xml b/prebuild.xml index aebd1d66f8..8536a4898a 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -2953,6 +2953,7 @@ + From 5dc785bbf2a0197b560e94b2aa8858ad33d58504 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 4 Jul 2011 22:30:18 +0100 Subject: [PATCH 14/18] refactor: Split file cache manipulation code into separate methods, as has already been done for the memory cache --- .../CoreModules/Asset/FlotsamAssetCache.cs | 241 ++++++++++-------- 1 file changed, 135 insertions(+), 106 deletions(-) diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index a8f5c99ae7..a72cf83485 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -226,7 +226,6 @@ namespace Flotsam.RegionModules.AssetCache if (m_AssetService == null) { m_AssetService = scene.RequestModuleInterface(); - } } } @@ -250,8 +249,57 @@ namespace Flotsam.RegionModules.AssetCache private void UpdateMemoryCache(string key, AssetBase asset) { - if (m_MemoryCacheEnabled) - m_MemoryCache.AddOrUpdate(key, asset, m_MemoryExpiration); + m_MemoryCache.AddOrUpdate(key, asset, m_MemoryExpiration); + } + + private void UpdateFileCache(string key, AssetBase asset) + { + string filename = GetFileName(asset.ID); + + try + { + // If the file is already cached, don't cache it, just touch it so access time is updated + if (File.Exists(filename)) + { + File.SetLastAccessTime(filename, DateTime.Now); + } + else + { + // Once we start writing, make sure we flag that we're writing + // that object to the cache so that we don't try to write the + // same file multiple times. + lock (m_CurrentlyWriting) + { +#if WAIT_ON_INPROGRESS_REQUESTS + if (m_CurrentlyWriting.ContainsKey(filename)) + { + return; + } + else + { + m_CurrentlyWriting.Add(filename, new ManualResetEvent(false)); + } + +#else + if (m_CurrentlyWriting.Contains(filename)) + { + return; + } + else + { + m_CurrentlyWriting.Add(filename); + } +#endif + } + + Util.FireAndForget( + delegate { WriteFileCache(filename, asset); }); + } + } + catch (Exception e) + { + LogException(e); + } } public void Cache(AssetBase asset) @@ -259,57 +307,100 @@ namespace Flotsam.RegionModules.AssetCache // TODO: Spawn this off to some seperate thread to do the actual writing if (asset != null) { - m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Caching asset with id {0}", asset.ID); + //m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Caching asset with id {0}", asset.ID); - UpdateMemoryCache(asset.ID, asset); + if (m_MemoryCacheEnabled) + UpdateMemoryCache(asset.ID, asset); - string filename = GetFileName(asset.ID); + UpdateFileCache(asset.ID, asset); + } + } + /// + /// Try to get an asset from the in-memory cache. + /// + /// + /// + private AssetBase GetFromMemoryCache(string id) + { + AssetBase asset = null; + + if (m_MemoryCache.TryGetValue(id, out asset)) + m_MemoryHits++; + + return asset; + } + + /// + /// Try to get an asset from the file cache. + /// + /// + /// + private AssetBase GetFromFileCache(string id) + { + AssetBase asset = null; + + string filename = GetFileName(id); + if (File.Exists(filename)) + { + FileStream stream = null; try { - // If the file is already cached, don't cache it, just touch it so access time is updated - if (File.Exists(filename)) - { - File.SetLastAccessTime(filename, DateTime.Now); - } else { - - // Once we start writing, make sure we flag that we're writing - // that object to the cache so that we don't try to write the - // same file multiple times. - lock (m_CurrentlyWriting) - { -#if WAIT_ON_INPROGRESS_REQUESTS - if (m_CurrentlyWriting.ContainsKey(filename)) - { - return; - } - else - { - m_CurrentlyWriting.Add(filename, new ManualResetEvent(false)); - } + stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read); + BinaryFormatter bformatter = new BinaryFormatter(); -#else - if (m_CurrentlyWriting.Contains(filename)) - { - return; - } - else - { - m_CurrentlyWriting.Add(filename); - } -#endif + asset = (AssetBase)bformatter.Deserialize(stream); - } + UpdateMemoryCache(id, asset); - Util.FireAndForget( - delegate { WriteFileCache(filename, asset); }); - } + m_DiskHits++; + } + catch (System.Runtime.Serialization.SerializationException e) + { + LogException(e); + + // If there was a problem deserializing the asset, the asset may + // either be corrupted OR was serialized under an old format + // {different version of AssetBase} -- we should attempt to + // delete it and re-cache + File.Delete(filename); } catch (Exception e) { LogException(e); } + finally + { + if (stream != null) + stream.Close(); + } } + + +#if WAIT_ON_INPROGRESS_REQUESTS + // Check if we're already downloading this asset. If so, try to wait for it to + // download. + if (m_WaitOnInprogressTimeout > 0) + { + m_RequestsForInprogress++; + + ManualResetEvent waitEvent; + if (m_CurrentlyWriting.TryGetValue(filename, out waitEvent)) + { + waitEvent.WaitOne(m_WaitOnInprogressTimeout); + return Get(id); + } + } +#else + // Track how often we have the problem that an asset is requested while + // it is still being downloaded by a previous request. + if (m_CurrentlyWriting.Contains(filename)) + { + m_RequestsForInprogress++; + } +#endif + + return asset; } public AssetBase Get(string id) @@ -318,72 +409,10 @@ namespace Flotsam.RegionModules.AssetCache AssetBase asset = null; - if (m_MemoryCacheEnabled && m_MemoryCache.TryGetValue(id, out asset)) - { - m_MemoryHits++; - } + if (m_MemoryCacheEnabled) + asset = GetFromMemoryCache(id); else - { - string filename = GetFileName(id); - if (File.Exists(filename)) - { - FileStream stream = null; - try - { - stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read); - BinaryFormatter bformatter = new BinaryFormatter(); - - asset = (AssetBase)bformatter.Deserialize(stream); - - UpdateMemoryCache(id, asset); - - m_DiskHits++; - } - catch (System.Runtime.Serialization.SerializationException e) - { - LogException(e); - - // If there was a problem deserializing the asset, the asset may - // either be corrupted OR was serialized under an old format - // {different version of AssetBase} -- we should attempt to - // delete it and re-cache - File.Delete(filename); - } - catch (Exception e) - { - LogException(e); - } - finally - { - if (stream != null) - stream.Close(); - } - } - - -#if WAIT_ON_INPROGRESS_REQUESTS - // Check if we're already downloading this asset. If so, try to wait for it to - // download. - if (m_WaitOnInprogressTimeout > 0) - { - m_RequestsForInprogress++; - - ManualResetEvent waitEvent; - if (m_CurrentlyWriting.TryGetValue(filename, out waitEvent)) - { - waitEvent.WaitOne(m_WaitOnInprogressTimeout); - return Get(id); - } - } -#else - // Track how often we have the problem that an asset is requested while - // it is still being downloaded by a previous request. - if (m_CurrentlyWriting.Contains(filename)) - { - m_RequestsForInprogress++; - } -#endif - } + asset = GetFromFileCache(id); if (((m_LogLevel >= 1)) && (m_HitRateDisplay != 0) && (m_Requests % m_HitRateDisplay == 0)) { @@ -474,9 +503,9 @@ namespace Flotsam.RegionModules.AssetCache /// removes empty tier directories. /// /// + /// private void CleanExpiredFiles(string dir, DateTime purgeLine) { - foreach (string file in Directory.GetFiles(dir)) { if (File.GetLastAccessTime(file) < purgeLine) From bebc51a6e041d2bcd8fef110ea5b178ac614c59d Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 4 Jul 2011 22:51:47 +0100 Subject: [PATCH 15/18] Make it possible to disable the file part of the flotsam asset cache This matches the ability to disable the memory part This is controlled through the FileCacheEnabled parameter in FlotsamCache.ini Default is true, so existing installations are not affected. Improved fcache command feedback when various caches are disabled. Re-enabled test for flotsam cache with file caching disabled. --- .../CoreModules/Asset/FlotsamAssetCache.cs | 110 ++++++++++++------ .../Asset/Tests/FlotsamAssetCacheTests.cs | 3 +- bin/config-include/FlotsamCache.ini.example | 5 +- 3 files changed, 78 insertions(+), 40 deletions(-) diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index a72cf83485..2b3f7f5b85 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -86,6 +86,8 @@ namespace Flotsam.RegionModules.AssetCache private List m_CurrentlyWriting = new List(); #endif + private bool m_FileCacheEnabled = true; + private ExpiringCache m_MemoryCache; private bool m_MemoryCacheEnabled = false; @@ -146,6 +148,7 @@ namespace Flotsam.RegionModules.AssetCache } else { + m_FileCacheEnabled = assetConfig.GetBoolean("FileCacheEnabled", m_FileCacheEnabled); m_CacheDirectory = assetConfig.GetString("CacheDirectory", m_DefaultCacheDirectory); m_MemoryCacheEnabled = assetConfig.GetBoolean("MemoryCacheEnabled", m_MemoryCacheEnabled); @@ -173,7 +176,7 @@ namespace Flotsam.RegionModules.AssetCache m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Cache Directory {0}", m_CacheDirectory); - if ((m_FileExpiration > TimeSpan.Zero) && (m_FileExpirationCleanupTimer > TimeSpan.Zero)) + if (m_FileCacheEnabled && (m_FileExpiration > TimeSpan.Zero) && (m_FileExpirationCleanupTimer > TimeSpan.Zero)) { m_CacheCleanTimer = new System.Timers.Timer(m_FileExpirationCleanupTimer.TotalMilliseconds); m_CacheCleanTimer.AutoReset = true; @@ -312,7 +315,8 @@ namespace Flotsam.RegionModules.AssetCache if (m_MemoryCacheEnabled) UpdateMemoryCache(asset.ID, asset); - UpdateFileCache(asset.ID, asset); + if (m_FileCacheEnabled) + UpdateFileCache(asset.ID, asset); } } @@ -411,7 +415,7 @@ namespace Flotsam.RegionModules.AssetCache if (m_MemoryCacheEnabled) asset = GetFromMemoryCache(id); - else + else if (m_FileCacheEnabled) asset = GetFromFileCache(id); if (((m_LogLevel >= 1)) && (m_HitRateDisplay != 0) && (m_Requests % m_HitRateDisplay == 0)) @@ -446,10 +450,13 @@ namespace Flotsam.RegionModules.AssetCache try { - string filename = GetFileName(id); - if (File.Exists(filename)) + if (m_FileCacheEnabled) { - File.Delete(filename); + string filename = GetFileName(id); + if (File.Exists(filename)) + { + File.Delete(filename); + } } if (m_MemoryCacheEnabled) @@ -464,11 +471,14 @@ namespace Flotsam.RegionModules.AssetCache public void Clear() { if (m_LogLevel >= 2) - m_log.Debug("[FLOTSAM ASSET CACHE]: Clearing Cache."); + m_log.Debug("[FLOTSAM ASSET CACHE]: Clearing caches."); - foreach (string dir in Directory.GetDirectories(m_CacheDirectory)) + if (m_FileCacheEnabled) { - Directory.Delete(dir); + foreach (string dir in Directory.GetDirectories(m_CacheDirectory)) + { + Directory.Delete(dir); + } } if (m_MemoryCacheEnabled) @@ -743,18 +753,28 @@ namespace Flotsam.RegionModules.AssetCache switch (cmd) { case "status": - m_log.InfoFormat("[FLOTSAM ASSET CACHE] Memory Cache : {0} assets", m_MemoryCache.Count); + if (m_MemoryCacheEnabled) + m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Memory Cache : {0} assets", m_MemoryCache.Count); + else + m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Memory cache disabled"); - int fileCount = GetFileCacheCount(m_CacheDirectory); - m_log.InfoFormat("[FLOTSAM ASSET CACHE] File Cache : {0} assets", fileCount); - - foreach (string s in Directory.GetFiles(m_CacheDirectory, "*.fac")) + if (m_FileCacheEnabled) { - m_log.Info("[FLOTSAM ASSET CACHE] Deep Scans were performed on the following regions:"); - - string RegionID = s.Remove(0,s.IndexOf("_")).Replace(".fac",""); - DateTime RegionDeepScanTMStamp = File.GetLastWriteTime(s); - m_log.InfoFormat("[FLOTSAM ASSET CACHE] Region: {0}, {1}", RegionID, RegionDeepScanTMStamp.ToString("MM/dd/yyyy hh:mm:ss")); + int fileCount = GetFileCacheCount(m_CacheDirectory); + m_log.InfoFormat("[FLOTSAM ASSET CACHE]: File Cache : {0} assets", fileCount); + + foreach (string s in Directory.GetFiles(m_CacheDirectory, "*.fac")) + { + m_log.Info("[FLOTSAM ASSET CACHE]: Deep Scans were performed on the following regions:"); + + string RegionID = s.Remove(0,s.IndexOf("_")).Replace(".fac",""); + DateTime RegionDeepScanTMStamp = File.GetLastWriteTime(s); + m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Region: {0}, {1}", RegionID, RegionDeepScanTMStamp.ToString("MM/dd/yyyy hh:mm:ss")); + } + } + else + { + m_log.InfoFormat("[FLOTSAM ASSET CACHE]: File cache disabled"); } break; @@ -762,7 +782,7 @@ namespace Flotsam.RegionModules.AssetCache case "clear": if (cmdparams.Length < 2) { - m_log.Warn("[FLOTSAM ASSET CACHE] Usage is fcache clear [file] [memory]"); + m_log.Warn("[FLOTSAM ASSET CACHE]: Usage is fcache clear [file] [memory]"); break; } @@ -783,36 +803,48 @@ namespace Flotsam.RegionModules.AssetCache if (clearMemory) { - m_MemoryCache.Clear(); - m_log.Info("[FLOTSAM ASSET CACHE] Memory cache cleared."); + if (m_MemoryCacheEnabled) + { + m_MemoryCache.Clear(); + m_log.Info("[FLOTSAM ASSET CACHE]: Memory cache cleared."); + } + else + { + m_log.Info("[FLOTSAM ASSET CACHE]: Memory cache not enabled."); + } } if (clearFile) { - ClearFileCache(); - m_log.Info("[FLOTSAM ASSET CACHE] File cache cleared."); + if (m_FileCacheEnabled) + { + ClearFileCache(); + m_log.Info("[FLOTSAM ASSET CACHE]: File cache cleared."); + } + else + { + m_log.Info("[FLOTSAM ASSET CACHE]: File cache not enabled."); + } } break; case "assets": - m_log.Info("[FLOTSAM ASSET CACHE] Caching all assets, in all scenes."); + m_log.Info("[FLOTSAM ASSET CACHE]: Caching all assets, in all scenes."); Util.FireAndForget(delegate { int assetsCached = CacheScenes(); - m_log.InfoFormat("[FLOTSAM ASSET CACHE] Completed Scene Caching, {0} assets found.", assetsCached); + m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Completed Scene Caching, {0} assets found.", assetsCached); }); break; case "expire": - - if (cmdparams.Length < 3) { - m_log.InfoFormat("[FLOTSAM ASSET CACHE] Invalid parameters for Expire, please specify a valid date & time", cmd); + m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Invalid parameters for Expire, please specify a valid date & time", cmd); break; } @@ -830,26 +862,28 @@ namespace Flotsam.RegionModules.AssetCache if (!DateTime.TryParse(s_expirationDate, out expirationDate)) { - m_log.InfoFormat("[FLOTSAM ASSET CACHE] {0} is not a valid date & time", cmd); + m_log.InfoFormat("[FLOTSAM ASSET CACHE]: {0} is not a valid date & time", cmd); break; } - CleanExpiredFiles(m_CacheDirectory, expirationDate); + if (m_FileCacheEnabled) + CleanExpiredFiles(m_CacheDirectory, expirationDate); + else + m_log.InfoFormat("[FLOTSAM ASSET CACHE]: File cache not active, not clearing."); break; default: - m_log.InfoFormat("[FLOTSAM ASSET CACHE] Unknown command {0}", cmd); + m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Unknown command {0}", cmd); break; } } else if (cmdparams.Length == 1) { - m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache status - Display cache status"); - m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache clearmem - Remove all assets cached in memory"); - m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache clearfile - Remove all assets cached on disk"); - m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache cachescenes - Attempt a deep cache of all assets in all scenes"); - m_log.InfoFormat("[FLOTSAM ASSET CACHE] flotsamcache - Purge assets older then the specified date & time"); - + m_log.InfoFormat("[FLOTSAM ASSET CACHE]: fcache status - Display cache status"); + m_log.InfoFormat("[FLOTSAM ASSET CACHE]: fcache clearmem - Remove all assets cached in memory"); + m_log.InfoFormat("[FLOTSAM ASSET CACHE]: fcache clearfile - Remove all assets cached on disk"); + m_log.InfoFormat("[FLOTSAM ASSET CACHE]: fcache cachescenes - Attempt a deep cache of all assets in all scenes"); + m_log.InfoFormat("[FLOTSAM ASSET CACHE]: fcache - Purge assets older then the specified date & time"); } } diff --git a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs index 3498969828..a4aeeda197 100644 --- a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs +++ b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs @@ -47,7 +47,7 @@ namespace OpenSim.Region.CoreModules.Asset.Tests [TestFixture] public class FlotsamAssetCacheTests { -// [Test] + [Test] public void TestCacheAsset() { TestHelper.InMethod(); @@ -58,6 +58,7 @@ namespace OpenSim.Region.CoreModules.Asset.Tests config.AddConfig("Modules"); config.Configs["Modules"].Set("AssetCaching", "FlotsamAssetCache"); config.AddConfig("AssetCache"); + config.Configs["AssetCache"].Set("FileCacheEnabled", "false"); config.Configs["AssetCache"].Set("MemoryCacheEnabled", "true"); FlotsamAssetCache cache = new FlotsamAssetCache(); diff --git a/bin/config-include/FlotsamCache.ini.example b/bin/config-include/FlotsamCache.ini.example index ad38ad15b5..cd39f8c740 100644 --- a/bin/config-include/FlotsamCache.ini.example +++ b/bin/config-include/FlotsamCache.ini.example @@ -19,9 +19,12 @@ ; 0 to disable HitRateDisplay = 100 - ; Set to false for disk cache only. + ; Set to false for no memory cache MemoryCacheEnabled = false + ; Set to false for no file cache + FileCacheEnabled = true + ; How long {in hours} to keep assets cached in memory, .5 == 30 minutes ; Optimization: for VPS or limited memory system installs set Timeout to .016 (1 minute) ; increases performance without large memory impact From f58de55c843843775886a6227acbecd249a59e96 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 4 Jul 2011 22:59:36 +0100 Subject: [PATCH 16/18] refactor: Move test setup code into setup method --- .../Asset/Tests/FlotsamAssetCacheTests.cs | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs index a4aeeda197..36cffd08ad 100644 --- a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs +++ b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs @@ -47,35 +47,42 @@ namespace OpenSim.Region.CoreModules.Asset.Tests [TestFixture] public class FlotsamAssetCacheTests { - [Test] - public void TestCacheAsset() - { - TestHelper.InMethod(); - log4net.Config.XmlConfigurator.Configure(); + protected TestScene m_scene; + protected FlotsamAssetCache m_cache; + [SetUp] + public void SetUp() + { IConfigSource config = new IniConfigSource(); - - config.AddConfig("Modules"); + + config.AddConfig("Modules"); config.Configs["Modules"].Set("AssetCaching", "FlotsamAssetCache"); config.AddConfig("AssetCache"); config.Configs["AssetCache"].Set("FileCacheEnabled", "false"); config.Configs["AssetCache"].Set("MemoryCacheEnabled", "true"); - FlotsamAssetCache cache = new FlotsamAssetCache(); - TestScene scene = SceneSetupHelpers.SetupScene(); - SceneSetupHelpers.SetupSceneModules(scene, config, cache); + m_cache = new FlotsamAssetCache(); + m_scene = SceneSetupHelpers.SetupScene(); + SceneSetupHelpers.SetupSceneModules(m_scene, config, m_cache); + } + + [Test] + public void TestCacheAsset() + { + TestHelper.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); AssetBase asset = AssetHelpers.CreateAsset(); asset.ID = TestHelper.ParseTail(0x1).ToString(); // Check we don't get anything before the asset is put in the cache - AssetBase retrievedAsset = cache.Get(asset.ID.ToString()); + AssetBase retrievedAsset = m_cache.Get(asset.ID.ToString()); Assert.That(retrievedAsset, Is.Null); - cache.Store(asset); + m_cache.Store(asset); // Check that asset is now in cache - retrievedAsset = cache.Get(asset.ID.ToString()); + retrievedAsset = m_cache.Get(asset.ID.ToString()); Assert.That(retrievedAsset, Is.Not.Null); Assert.That(retrievedAsset.ID, Is.EqualTo(asset.ID)); } From cb02fc44f5f80fce8fe9e1b87bcfa09df7960a13 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 4 Jul 2011 23:03:05 +0100 Subject: [PATCH 17/18] add TestExpireAsset() --- .../Asset/Tests/FlotsamAssetCacheTests.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs index 36cffd08ad..bbe40d1fd4 100644 --- a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs +++ b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs @@ -44,6 +44,9 @@ using OpenSim.Tests.Common.Mock; namespace OpenSim.Region.CoreModules.Asset.Tests { + /// + /// At the moment we're only test the in-memory part of the FlotsamAssetCache. This is a considerable weakness. + /// [TestFixture] public class FlotsamAssetCacheTests { @@ -86,5 +89,22 @@ namespace OpenSim.Region.CoreModules.Asset.Tests Assert.That(retrievedAsset, Is.Not.Null); Assert.That(retrievedAsset.ID, Is.EqualTo(asset.ID)); } + + [Test] + public void TestExpireAsset() + { + TestHelper.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + AssetBase asset = AssetHelpers.CreateAsset(); + asset.ID = TestHelper.ParseTail(0x2).ToString(); + + m_cache.Store(asset); + + m_cache.Expire(asset.ID); + + AssetBase retrievedAsset = m_cache.Get(asset.ID.ToString()); + Assert.That(retrievedAsset, Is.Null); + } } } \ No newline at end of file From af8773d6d076f5d74133857a5074bd9e9504dd64 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 4 Jul 2011 23:05:31 +0100 Subject: [PATCH 18/18] Add TestClearCache() --- .../Asset/Tests/FlotsamAssetCacheTests.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs index bbe40d1fd4..63b0c311f1 100644 --- a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs +++ b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs @@ -106,5 +106,22 @@ namespace OpenSim.Region.CoreModules.Asset.Tests AssetBase retrievedAsset = m_cache.Get(asset.ID.ToString()); Assert.That(retrievedAsset, Is.Null); } + + [Test] + public void TestClearCache() + { + TestHelper.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + AssetBase asset = AssetHelpers.CreateAsset(); + asset.ID = TestHelper.ParseTail(0x2).ToString(); + + m_cache.Store(asset); + + m_cache.Clear(); + + AssetBase retrievedAsset = m_cache.Get(asset.ID.ToString()); + Assert.That(retrievedAsset, Is.Null); + } } } \ No newline at end of file