From 528f23beab703e60ec522117a2a442e733565727 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 8 Feb 2013 01:02:25 +0000 Subject: [PATCH 01/10] Extend TestJsonReadNotecard() for reads to non-root locations and fake stores. Assertions for loading to non-root paths are currently commented out because this doesn't seem to be working. Will be raising mantis to resolve. --- .../Tests/JsonStoreScriptModuleTests.cs | 42 +++++++++++++++---- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs index 6658e1e48e..7e0f03c2d2 100644 --- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs @@ -321,7 +321,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests } /// - /// Test for reading and writing json to a notecard + /// Test for reading json from a notecard /// /// /// TODO: Really needs to test correct receipt of the link_message event. Could do this by directly fetching @@ -338,20 +338,44 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, TestHelpers.ParseTail(0x1)); m_scene.AddSceneObject(so); - UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello':'World' }"); + UUID creatingStoreId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello':'World' }"); // Write notecard - InvokeOpOnHost("JsonWriteNotecard", so.UUID, storeId, "/", notecardName); + InvokeOpOnHost("JsonWriteNotecard", so.UUID, creatingStoreId, "/", notecardName); - // Read notecard - UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{ }"); - UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "/", notecardName); - Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero)); + { + // Read notecard + UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{ }"); + UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "/", notecardName); + Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero)); - string value = (string)InvokeOp("JsonGetValue", storeId, "Hello"); - Assert.That(value, Is.EqualTo("World")); + string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello"); + Assert.That(value, Is.EqualTo("World")); + } + { + // Read notecard to non-root path + UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{ }"); + UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "make/it/so", notecardName); + Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero)); + // These don't behave as I expect yet - reading to a path still seems to place the notecard contents at the root. +// string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello"); +// Assert.That(value, Is.EqualTo("")); +// +// value = (string)InvokeOp("JsonGetValue", receivingStoreId, "make/it/so/Hello"); +// Assert.That(value, Is.EqualTo("World")); + } + + { + // Try read notecard to fake store. + UUID fakeStoreId = TestHelpers.ParseTail(0x500); + UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, fakeStoreId, "/", notecardName); + Assert.That(fakeStoreId, Is.Not.EqualTo(UUID.Zero)); + + string value = (string)InvokeOp("JsonGetValue", fakeStoreId, "Hello"); + Assert.That(value, Is.EqualTo("")); + } } public object DummyTestMethod(object o1, object o2, object o3, object o4, object o5) { return null; } From ebb63b55aab98da6d44e82fc0ecfd5d22f245172 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 7 Feb 2013 11:53:49 -0800 Subject: [PATCH 02/10] BulletSim: add user setting of friction, density and restitution. --- .../Physics/BulletSPlugin/BSCharacter.cs | 5 +- .../Physics/BulletSPlugin/BSPhysObject.cs | 17 +++- .../Region/Physics/BulletSPlugin/BSPrim.cs | 99 +++++++++++++++---- 3 files changed, 94 insertions(+), 27 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 192bcb5f3a..d694a6a5e7 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -749,9 +749,10 @@ public sealed class BSCharacter : BSPhysObject _buoyancy = value; DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); // Buoyancy is faked by changing the gravity applied to the object - float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); + float grav = BSParam.Gravity * (1f - _buoyancy); + Gravity = new OMV.Vector3(0f, 0f, grav); if (PhysBody.HasPhysicalBody) - PhysicsScene.PE.SetGravity(PhysBody, new OMV.Vector3(0f, 0f, grav)); + PhysicsScene.PE.SetGravity(PhysBody, Gravity); } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index ec25aa927e..0b35f3a31f 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -78,6 +78,10 @@ public abstract class BSPhysObject : PhysicsActor Name = name; // PhysicsActor also has the name of the object. Someday consolidate. TypeName = typeName; + // Initialize variables kept in base. + GravityModifier = 1.0f; + Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity); + // We don't have any physical representation yet. PhysBody = new BulletBody(localID); PhysShape = new BulletShape(); @@ -88,8 +92,8 @@ public abstract class BSPhysObject : PhysicsActor LastAssetBuildFailed = false; - // Default material type - Material = MaterialAttributes.Material.Wood; + // Default material type. Also sets Friction, Restitution and Density. + SetMaterial((int)MaterialAttributes.Material.Wood); CollisionCollection = new CollisionEventUpdate(); CollisionsLastTick = CollisionCollection; @@ -122,6 +126,8 @@ public abstract class BSPhysObject : PhysicsActor // 'inWorld' true if the object has already been added to the dynamic world. public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld); + // The gravity being applied to the object. A function of default grav, GravityModifier and Buoyancy. + public virtual OMV.Vector3 Gravity { get; set; } // The last value calculated for the prim's inertia public OMV.Vector3 Inertia { get; set; } @@ -164,15 +170,16 @@ public abstract class BSPhysObject : PhysicsActor public override void SetMaterial(int material) { Material = (MaterialAttributes.Material)material; + MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false); + Friction = matAttrib.friction; + Restitution = matAttrib.restitution; + Density = matAttrib.density; } // Stop all physical motion. public abstract void ZeroMotion(bool inTaintTime); public abstract void ZeroAngularMotion(bool inTaintTime); - // Step the vehicle simulation for this object. A NOOP if the vehicle was not configured. - public virtual void StepVehicle(float timeStep) { } - // Update the physical location and motion of the object. Called with data from Bullet. public abstract void UpdateProperties(EntityProperties entprop); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 54bf063add..a86932a10b 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -55,7 +55,6 @@ public sealed class BSPrim : BSPhysObject private OMV.Vector3 _position; private float _mass; // the mass of this object - private float _density; private OMV.Vector3 _force; private OMV.Vector3 _velocity; private OMV.Vector3 _torque; @@ -64,8 +63,6 @@ public sealed class BSPrim : BSPhysObject private int _physicsActorType; private bool _isPhysical; private bool _flying; - private float _friction; - private float _restitution; private bool _setAlwaysRun; private bool _throttleUpdates; private bool _floatOnWater; @@ -101,12 +98,6 @@ public sealed class BSPrim : BSPhysObject _isPhysical = pisPhysical; _isVolumeDetect = false; - // Someday set default attributes based on the material but, for now, we don't know the prim material yet. - // MaterialAttributes primMat = BSMaterials.GetAttributes(Material, pisPhysical); - _density = PhysicsScene.Params.defaultDensity; - _friction = PhysicsScene.Params.defaultFriction; - _restitution = PhysicsScene.Params.defaultRestitution; - VehicleController = new BSDynamics(PhysicsScene, this); // add vehicleness _mass = CalculateMass(); @@ -457,11 +448,6 @@ public sealed class BSPrim : BSPhysObject { AddObjectToPhysicalWorld(); } - - // Must set gravity after it has been added to the world because, for unknown reasons, - // adding the object resets the object's gravity to world gravity - PhysicsScene.PE.SetGravity(PhysBody, grav); - } } } @@ -469,7 +455,7 @@ public sealed class BSPrim : BSPhysObject // Return what gravity should be set to this very moment public OMV.Vector3 ComputeGravity(float buoyancy) { - OMV.Vector3 ret = PhysicsScene.DefaultGravity; + OMV.Vector3 ret = PhysicsScene.DefaultGravity * GravityModifier; if (!IsStatic) ret *= (1f - buoyancy); @@ -596,6 +582,74 @@ public sealed class BSPrim : BSPhysObject } return; } + public override void SetMaterial(int material) + { + base.SetMaterial(material); + PhysicsScene.TaintedObject("BSPrim.SetMaterial", delegate() + { + UpdatePhysicalParameters(); + }); + } + public override float Friction + { + get { return base.Friction; } + set + { + if (base.Friction != value) + { + base.Friction = value; + PhysicsScene.TaintedObject("BSPrim.setFriction", delegate() + { + UpdatePhysicalParameters(); + }); + } + } + } + public override float Restitution + { + get { return base.Restitution; } + set + { + if (base.Restitution != value) + { + base.Restitution = value; + PhysicsScene.TaintedObject("BSPrim.setRestitution", delegate() + { + UpdatePhysicalParameters(); + }); + } + } + } + public override float Density + { + get { return base.Density; } + set + { + if (base.Density != value) + { + base.Density = value; + PhysicsScene.TaintedObject("BSPrim.setDensity", delegate() + { + UpdatePhysicalParameters(); + }); + } + } + } + public override float GravityModifier + { + get { return base.GravityModifier; } + set + { + if (base.GravityModifier != value) + { + base.GravityModifier = value; + PhysicsScene.TaintedObject("BSPrim.setGravityModifier", delegate() + { + UpdatePhysicalParameters(); + }); + } + } + } public override OMV.Vector3 RawVelocity { get { return _velocity; } @@ -810,8 +864,8 @@ public sealed class BSPrim : BSPhysObject // Set various physical properties so other object interact properly MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false); - PhysicsScene.PE.SetFriction(PhysBody, matAttrib.friction); - PhysicsScene.PE.SetRestitution(PhysBody, matAttrib.restitution); + PhysicsScene.PE.SetFriction(PhysBody, Friction); + PhysicsScene.PE.SetRestitution(PhysBody, Restitution); // Mass is zero which disables a bunch of physics stuff in Bullet UpdatePhysicalMassProperties(0f, false); @@ -840,8 +894,8 @@ public sealed class BSPrim : BSPhysObject // Set various physical properties so other object interact properly MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, true); - PhysicsScene.PE.SetFriction(PhysBody, matAttrib.friction); - PhysicsScene.PE.SetRestitution(PhysBody, matAttrib.restitution); + PhysicsScene.PE.SetFriction(PhysBody, Friction); + PhysicsScene.PE.SetRestitution(PhysBody, Restitution); // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 // Since this can be called multiple times, only zero forces when becoming physical @@ -940,6 +994,11 @@ public sealed class BSPrim : BSPhysObject if (PhysBody.HasPhysicalBody) { PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); + + // Must set gravity after it has been added to the world because, for unknown reasons, + // adding the object resets the object's gravity to world gravity + OMV.Vector3 grav = ComputeGravity(Buoyancy); + PhysicsScene.PE.SetGravity(PhysBody, grav); } else { @@ -1581,7 +1640,7 @@ public sealed class BSPrim : BSPhysObject profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f; volume *= (profileEnd - profileBegin); - returnMass = _density * volume; + returnMass = Density * volume; /* Comment out code that computes the mass of the linkset. That is done in the Linkset class. if (IsRootOfLinkset) From b545e131846f38cc96757d5c4456c1ee8e7abe75 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 7 Feb 2013 14:44:12 -0800 Subject: [PATCH 03/10] BulletSim: fix exceptions caused by setting physical properties before the prim body is initialized. --- OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index a86932a10b..38adb72d63 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -587,7 +587,8 @@ public sealed class BSPrim : BSPhysObject base.SetMaterial(material); PhysicsScene.TaintedObject("BSPrim.SetMaterial", delegate() { - UpdatePhysicalParameters(); + if (PhysBody.HasPhysicalBody) + UpdatePhysicalParameters(); }); } public override float Friction @@ -600,7 +601,8 @@ public sealed class BSPrim : BSPhysObject base.Friction = value; PhysicsScene.TaintedObject("BSPrim.setFriction", delegate() { - UpdatePhysicalParameters(); + if (PhysBody.HasPhysicalBody) + UpdatePhysicalParameters(); }); } } @@ -615,7 +617,8 @@ public sealed class BSPrim : BSPhysObject base.Restitution = value; PhysicsScene.TaintedObject("BSPrim.setRestitution", delegate() { - UpdatePhysicalParameters(); + if (PhysBody.HasPhysicalBody) + UpdatePhysicalParameters(); }); } } @@ -630,7 +633,8 @@ public sealed class BSPrim : BSPhysObject base.Density = value; PhysicsScene.TaintedObject("BSPrim.setDensity", delegate() { - UpdatePhysicalParameters(); + if (PhysBody.HasPhysicalBody) + UpdatePhysicalParameters(); }); } } @@ -645,7 +649,8 @@ public sealed class BSPrim : BSPhysObject base.GravityModifier = value; PhysicsScene.TaintedObject("BSPrim.setGravityModifier", delegate() { - UpdatePhysicalParameters(); + if (PhysBody.HasPhysicalBody) + UpdatePhysicalParameters(); }); } } From 913965256fecd4e25e06fe374fa5d8b8712a3b15 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 7 Feb 2013 17:05:40 -0800 Subject: [PATCH 04/10] BulletSim: Adapt BulletSim to the newer physical properties. Viewer dialog setting of friction, restitution, ... working. --- .../Physics/BulletSPlugin/BSPhysObject.cs | 4 +- .../Region/Physics/BulletSPlugin/BSPrim.cs | 54 +++++++++---------- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 0b35f3a31f..0d8bb0304c 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -79,7 +79,7 @@ public abstract class BSPhysObject : PhysicsActor TypeName = typeName; // Initialize variables kept in base. - GravityModifier = 1.0f; + GravModifier = 1.0f; Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity); // We don't have any physical representation yet. @@ -170,6 +170,8 @@ public abstract class BSPhysObject : PhysicsActor public override void SetMaterial(int material) { Material = (MaterialAttributes.Material)material; + + // Setting the material sets the material attributes also. MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false); Friction = matAttrib.friction; Restitution = matAttrib.restitution; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 38adb72d63..85c2627f1c 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -423,8 +423,6 @@ public sealed class BSPrim : BSPhysObject } else { - OMV.Vector3 grav = ComputeGravity(Buoyancy); - if (inWorld) { // Changing interesting properties doesn't change proxy and collision cache @@ -434,15 +432,15 @@ public sealed class BSPrim : BSPhysObject } // The computation of mass props requires gravity to be set on the object. - PhysicsScene.PE.SetGravity(PhysBody, grav); + Gravity = ComputeGravity(Buoyancy); + PhysicsScene.PE.SetGravity(PhysBody, Gravity); Inertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); PhysicsScene.PE.SetMassProps(PhysBody, physMass, Inertia); PhysicsScene.PE.UpdateInertiaTensor(PhysBody); - // center of mass is at the zero of the object - // DEBUG DEBUG PhysicsScene.PE.SetCenterOfMassByPosRot(PhysBody, ForcePosition, ForceOrientation); - DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", LocalID, physMass, Inertia, grav, inWorld); + DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", + LocalID, physMass, Inertia, Gravity, inWorld); if (inWorld) { @@ -455,10 +453,13 @@ public sealed class BSPrim : BSPhysObject // Return what gravity should be set to this very moment public OMV.Vector3 ComputeGravity(float buoyancy) { - OMV.Vector3 ret = PhysicsScene.DefaultGravity * GravityModifier; + OMV.Vector3 ret = PhysicsScene.DefaultGravity; if (!IsStatic) + { ret *= (1f - buoyancy); + ret *= GravModifier; + } return ret; } @@ -587,8 +588,7 @@ public sealed class BSPrim : BSPhysObject base.SetMaterial(material); PhysicsScene.TaintedObject("BSPrim.SetMaterial", delegate() { - if (PhysBody.HasPhysicalBody) - UpdatePhysicalParameters(); + UpdatePhysicalParameters(); }); } public override float Friction @@ -601,8 +601,7 @@ public sealed class BSPrim : BSPhysObject base.Friction = value; PhysicsScene.TaintedObject("BSPrim.setFriction", delegate() { - if (PhysBody.HasPhysicalBody) - UpdatePhysicalParameters(); + UpdatePhysicalParameters(); }); } } @@ -617,8 +616,7 @@ public sealed class BSPrim : BSPhysObject base.Restitution = value; PhysicsScene.TaintedObject("BSPrim.setRestitution", delegate() { - if (PhysBody.HasPhysicalBody) - UpdatePhysicalParameters(); + UpdatePhysicalParameters(); }); } } @@ -633,24 +631,22 @@ public sealed class BSPrim : BSPhysObject base.Density = value; PhysicsScene.TaintedObject("BSPrim.setDensity", delegate() { - if (PhysBody.HasPhysicalBody) - UpdatePhysicalParameters(); + UpdatePhysicalParameters(); }); } } } - public override float GravityModifier + public override float GravModifier { - get { return base.GravityModifier; } + get { return base.GravModifier; } set { - if (base.GravityModifier != value) + if (base.GravModifier != value) { - base.GravityModifier = value; + base.GravModifier = value; PhysicsScene.TaintedObject("BSPrim.setGravityModifier", delegate() { - if (PhysBody.HasPhysicalBody) - UpdatePhysicalParameters(); + UpdatePhysicalParameters(); }); } } @@ -820,7 +816,12 @@ public sealed class BSPrim : BSPhysObject // collisionEvents: whether this object returns collision events public void UpdatePhysicalParameters() { - // DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape); + if (!PhysBody.HasPhysicalBody) + { + // This would only happen if updates are called for during initialization when the body is not set up yet. + DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID); + return; + } // Mangling all the physical properties requires the object not be in the physical world. // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). @@ -898,9 +899,9 @@ public sealed class BSPrim : BSPhysObject CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); // Set various physical properties so other object interact properly - MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, true); PhysicsScene.PE.SetFriction(PhysBody, Friction); PhysicsScene.PE.SetRestitution(PhysBody, Restitution); + // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution); // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 // Since this can be called multiple times, only zero forces when becoming physical @@ -999,16 +1000,11 @@ public sealed class BSPrim : BSPhysObject if (PhysBody.HasPhysicalBody) { PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); - - // Must set gravity after it has been added to the world because, for unknown reasons, - // adding the object resets the object's gravity to world gravity - OMV.Vector3 grav = ComputeGravity(Buoyancy); - PhysicsScene.PE.SetGravity(PhysBody, grav); } else { m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID); - DetailLog("{0},BSPrim.UpdatePhysicalParameters,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType); + DetailLog("{0},BSPrim.AddObjectToPhysicalWorld,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType); } } From 42f724f38011286733351a46dd8369951a581ce9 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 8 Feb 2013 01:59:27 +0000 Subject: [PATCH 05/10] Refine TestJsonReadNotecard() and use / instead of . to separate paths. An attack of the stupid meant that I was using / as a path separator. Fixing this makes the tests behave better, though still with some questions. Also, I imagine / shouldn't really put data in the root as that's not a valid identifier. This commit also fix the / mistake in other tests those this does not affect their outcomes. --- .../Tests/JsonStoreScriptModuleTests.cs | 61 ++++++++++++++----- 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs index 7e0f03c2d2..ca88d1a146 100644 --- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs @@ -283,7 +283,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests string notecardName = "nc1"; // Write notecard - UUID writeNotecardRequestId = (UUID)InvokeOpOnHost("JsonWriteNotecard", so.UUID, storeId, "/", notecardName); + UUID writeNotecardRequestId = (UUID)InvokeOpOnHost("JsonWriteNotecard", so.UUID, storeId, "", notecardName); Assert.That(writeNotecardRequestId, Is.Not.EqualTo(UUID.Zero)); TaskInventoryItem nc1Item = so.RootPart.Inventory.GetInventoryItem(notecardName); @@ -292,8 +292,10 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests // TODO: Should independently check the contents. } + // TODO: Write partial test + { - // Try to write notecard against bad path + // Try to write notecard for a bad path // In this case we do get a request id but no notecard is written. string badPathNotecardName = "badPathNotecardName"; @@ -312,7 +314,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests UUID fakeStoreId = TestHelpers.ParseTail(0x500); UUID fakeStoreWriteNotecardValue - = (UUID)InvokeOpOnHost("JsonWriteNotecard", so.UUID, fakeStoreId, "/", fakeStoreNotecardName); + = (UUID)InvokeOpOnHost("JsonWriteNotecard", so.UUID, fakeStoreId, "", fakeStoreNotecardName); Assert.That(fakeStoreWriteNotecardValue, Is.Not.EqualTo(UUID.Zero)); TaskInventoryItem fakeStoreItem = so.RootPart.Inventory.GetInventoryItem(fakeStoreNotecardName); @@ -341,12 +343,12 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests UUID creatingStoreId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello':'World' }"); // Write notecard - InvokeOpOnHost("JsonWriteNotecard", so.UUID, creatingStoreId, "/", notecardName); + InvokeOpOnHost("JsonWriteNotecard", so.UUID, creatingStoreId, "", notecardName); { // Read notecard - UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{ }"); - UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "/", notecardName); + UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{}"); + UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "", notecardName); Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero)); string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello"); @@ -354,23 +356,52 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests } { - // Read notecard to non-root path - UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{ }"); - UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "make/it/so", notecardName); + // Read notecard to new single component path + UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{}"); + UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "make", notecardName); Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero)); // These don't behave as I expect yet - reading to a path still seems to place the notecard contents at the root. -// string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello"); -// Assert.That(value, Is.EqualTo("")); -// -// value = (string)InvokeOp("JsonGetValue", receivingStoreId, "make/it/so/Hello"); -// Assert.That(value, Is.EqualTo("World")); + string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello"); + Assert.That(value, Is.EqualTo("")); + + value = (string)InvokeOp("JsonGetValue", receivingStoreId, "make.Hello"); + Assert.That(value, Is.EqualTo("World")); + } + + { + // Read notecard to new multi-component path + UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{}"); + UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "make.it", notecardName); + Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero)); + + // These don't behave as I expect yet - reading to a path still seems to place the notecard contents at the root. + string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello"); + Assert.That(value, Is.EqualTo("")); + + // TODO: Check that we are not expecting reading to a new path to work. + value = (string)InvokeOp("JsonGetValue", receivingStoreId, "make.it.Hello"); + Assert.That(value, Is.EqualTo("")); + } + + { + // Read notecard to existing multi-component path + UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{ 'make' : { 'it' : 'so' } }"); + UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "make.it", notecardName); + Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero)); + + // These don't behave as I expect yet - reading to a path still seems to place the notecard contents at the root. + string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello"); + Assert.That(value, Is.EqualTo("")); + + value = (string)InvokeOp("JsonGetValue", receivingStoreId, "make.it.Hello"); + Assert.That(value, Is.EqualTo("World")); } { // Try read notecard to fake store. UUID fakeStoreId = TestHelpers.ParseTail(0x500); - UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, fakeStoreId, "/", notecardName); + UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, fakeStoreId, "", notecardName); Assert.That(fakeStoreId, Is.Not.EqualTo(UUID.Zero)); string value = (string)InvokeOp("JsonGetValue", fakeStoreId, "Hello"); From 221a90e3a16a16708d183bab92bd4bff92c8139c Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 8 Feb 2013 02:34:13 +0000 Subject: [PATCH 06/10] On IAR loading, if loading of a coaleseced item entirely fails, then continue with the IAR load rather than failing completely. --- .../Archiver/InventoryArchiveReadRequest.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs index 50698031ad..ecbd07fab6 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs @@ -487,6 +487,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver { // m_log.DebugFormat( // "[INVENTORY ARCHIVER]: Loaded coalescence {0} has {1} objects", assetId, coa.Count); + + if (coa.Objects.Count == 0) + { + m_log.WarnFormat( + "[INVENTORY ARCHIVE READ REQUEST]: Aborting load of coalesced object from asset {0} as it has zero loaded components", + assetId); + return false; + } sceneObjects.AddRange(coa.Objects); } @@ -495,7 +503,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver SceneObjectGroup deserializedObject = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); if (deserializedObject != null) + { sceneObjects.Add(deserializedObject); + } + else + { + m_log.WarnFormat( + "[INVENTORY ARCHIVE READ REQUEST]: Aborting load of object from asset {0} as deserialization failed", + assetId); + + return false; + } } foreach (SceneObjectGroup sog in sceneObjects) From c2bf91c5e3bda35034a49f4cfacc30f73c0ee688 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 8 Feb 2013 02:45:30 +0000 Subject: [PATCH 07/10] If a component of a coalesced object fails to deserialization, do not add a null where the object should be. This prevents a later load IAR failure. This code is currently only used by IAR loading. --- .../CoalescedSceneObjectsSerializer.cs | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs index a4f730d375..5cb271ddad 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs @@ -42,9 +42,6 @@ namespace OpenSim.Region.Framework.Scenes.Serialization /// /// Serialize and deserialize coalesced scene objects. /// - /// - /// Deserialization not yet here. - /// public class CoalescedSceneObjectsSerializer { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -128,6 +125,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization // m_log.DebugFormat("[COALESCED SCENE OBJECTS SERIALIZER]: TryFromXml() deserializing {0}", xml); coa = null; + int i = 0; using (StringReader sr = new StringReader(xml)) { @@ -153,7 +151,23 @@ namespace OpenSim.Region.Framework.Scenes.Serialization if (reader.Name == "SceneObjectGroup") { string soXml = reader.ReadOuterXml(); - coa.Add(SceneObjectSerializer.FromOriginalXmlFormat(soXml)); + + SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(soXml); + + if (so != null) + { + coa.Add(so); + } + else + { + // XXX: Possibly we should fail outright here rather than continuing if a particular component of the + // coalesced object fails to load. + m_log.WarnFormat( + "[COALESCED SCENE OBJECTS SERIALIZER]: Deserialization of xml for component {0} failed. Continuing.", + i); + } + + i++; } } From 2b5eba9c7438ef0175c91c1910ce2d660d930fed Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Fri, 8 Feb 2013 12:00:16 -0800 Subject: [PATCH 08/10] Fix the return values for JsonDestroyStore, JsonRemoveValue, and JsonSetValue. Fix the link message status when reading a notecard. --- .../Scripting/JsonStore/JsonStore.cs | 17 +++++++++++++---- .../Scripting/JsonStore/JsonStoreModule.cs | 8 +++----- .../JsonStore/JsonStoreScriptModule.cs | 2 +- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs index 5808d46d51..c7f0001e06 100644 --- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs @@ -250,6 +250,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore return true; } + // pkey will be the final element in the path, we pull it out here to make sure + // that the assignment works correctly string pkey = path.Pop(); string pexpr = PathExpressionToKey(path); if (pexpr != "") @@ -259,7 +261,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore if (result == null) return false; - // Check for and extract array references + // Check pkey, the last element in the path, for and extract array references MatchCollection amatches = m_ArrayPattern.Matches(pkey,0); if (amatches.Count > 0) { @@ -307,16 +309,23 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore if (result is OSDMap) { + // this is the assignment case OSDMap hmap = result as OSDMap; if (ovalue != null) { hmap[hkey] = ovalue; InvokeNextCallback(pexpr + pkey); + return true; } - else if (hmap.ContainsKey(hkey)) + + // this is the remove case + if (hmap.ContainsKey(hkey)) + { hmap.Remove(hkey); - - return true; + return true; + } + + return false; } return false; diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs index 3b52e445b3..3249aa3216 100644 --- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs @@ -239,7 +239,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore if (! m_enabled) return false; lock (m_JsonValueStore) - m_JsonValueStore.Remove(storeID); + return m_JsonValueStore.Remove(storeID); return true; } @@ -311,8 +311,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore try { lock (map) - if (map.SetValue(path,value,useJson)) - return true; + return map.SetValue(path,value,useJson); } catch (Exception e) { @@ -344,8 +343,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore try { lock (map) - if (map.RemoveValue(path)) - return true; + return map.RemoveValue(path); } catch (Exception e) { diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs index 48b4a9f302..d75cd32e64 100644 --- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs @@ -504,7 +504,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore { string jsondata = SLUtil.ParseNotecardToString(Encoding.UTF8.GetString(a.Data)); int result = m_store.SetValue(storeID, path, jsondata,true) ? 1 : 0; - m_comms.DispatchReply(scriptID,result, "", reqID.ToString()); + m_comms.DispatchReply(scriptID, result, "", reqID.ToString()); return; } catch (Exception e) From b08977ea7d9e35066e3cbf367fad58c2d8bc227e Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 8 Feb 2013 21:21:20 +0000 Subject: [PATCH 09/10] Don't allow exceptions to propogate from FlotsamAssetCache which may occur when deleting expired files or stamping the region status file. Changes various error level log lines to warn since these are not fatal to the operation of OpenSimulator --- .../CoreModules/Asset/FlotsamAssetCache.cs | 93 ++++++++++++------- 1 file changed, 59 insertions(+), 34 deletions(-) diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index 00af1750e2..3cba9b4afd 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -299,7 +299,7 @@ namespace OpenSim.Region.CoreModules.Asset } catch (Exception e) { - m_log.ErrorFormat( + m_log.WarnFormat( "[FLOTSAM ASSET CACHE]: Failed to update cache for asset {0}. Exception {1} {2}", asset.ID, e.Message, e.StackTrace); } @@ -339,12 +339,13 @@ namespace OpenSim.Region.CoreModules.Asset /// Try to get an asset from the file cache. /// /// - /// + /// An asset retrieved from the file cache. null if there was a problem retrieving an asset. private AssetBase GetFromFileCache(string id) { AssetBase asset = null; - + string filename = GetFileName(id); + if (File.Exists(filename)) { FileStream stream = null; @@ -359,7 +360,7 @@ namespace OpenSim.Region.CoreModules.Asset } catch (System.Runtime.Serialization.SerializationException e) { - m_log.ErrorFormat( + m_log.WarnFormat( "[FLOTSAM ASSET CACHE]: Failed to get file {0} for asset {1}. Exception {2} {3}", filename, id, e.Message, e.StackTrace); @@ -371,7 +372,7 @@ namespace OpenSim.Region.CoreModules.Asset } catch (Exception e) { - m_log.ErrorFormat( + m_log.WarnFormat( "[FLOTSAM ASSET CACHE]: Failed to get file {0} for asset {1}. Exception {2} {3}", filename, id, e.Message, e.StackTrace); } @@ -469,7 +470,7 @@ namespace OpenSim.Region.CoreModules.Asset } catch (Exception e) { - m_log.ErrorFormat( + m_log.WarnFormat( "[FLOTSAM ASSET CACHE]: Failed to expire cached file {0}. Exception {1} {2}", id, e.Message, e.StackTrace); } @@ -520,29 +521,39 @@ namespace OpenSim.Region.CoreModules.Asset /// private void CleanExpiredFiles(string dir, DateTime purgeLine) { - foreach (string file in Directory.GetFiles(dir)) + try { - if (File.GetLastAccessTime(file) < purgeLine) + foreach (string file in Directory.GetFiles(dir)) { - File.Delete(file); + if (File.GetLastAccessTime(file) < purgeLine) + { + File.Delete(file); + } + } + + // Recurse into lower tiers + foreach (string subdir in Directory.GetDirectories(dir)) + { + CleanExpiredFiles(subdir, purgeLine); + } + + // Check if a tier directory is empty, if so, delete it + int dirSize = Directory.GetFiles(dir).Length + Directory.GetDirectories(dir).Length; + if (dirSize == 0) + { + Directory.Delete(dir); + } + else if (dirSize >= m_CacheWarnAt) + { + m_log.WarnFormat( + "[FLOTSAM ASSET CACHE]: Cache folder exceeded CacheWarnAt limit {0} {1}. Suggest increasing tiers, tier length, or reducing cache expiration", + dir, dirSize); } } - - // Recurse into lower tiers - foreach (string subdir in Directory.GetDirectories(dir)) + catch (Exception e) { - CleanExpiredFiles(subdir, purgeLine); - } - - // Check if a tier directory is empty, if so, delete it - int dirSize = Directory.GetFiles(dir).Length + Directory.GetDirectories(dir).Length; - if (dirSize == 0) - { - Directory.Delete(dir); - } - else if (dirSize >= m_CacheWarnAt) - { - m_log.WarnFormat("[FLOTSAM ASSET CACHE]: Cache folder exceeded CacheWarnAt limit {0} {1}. Suggest increasing tiers, tier length, or reducing cache expiration", dir, dirSize); + m_log.Warn( + string.Format("[FLOTSAM ASSET CACHE]: Could not complete clean of expired files in {0}, exception ", dir), e); } } @@ -601,7 +612,7 @@ namespace OpenSim.Region.CoreModules.Asset } catch (IOException e) { - m_log.ErrorFormat( + m_log.WarnFormat( "[FLOTSAM ASSET CACHE]: Failed to write asset {0} to temporary location {1} (final {2}) on cache in {3}. Exception {4} {5}.", asset.ID, tempname, filename, directory, e.Message, e.StackTrace); @@ -680,17 +691,31 @@ namespace OpenSim.Region.CoreModules.Asset /// /// This notes the last time the Region had a deep asset scan performed on it. /// - /// - private void StampRegionStatusFile(UUID RegionID) + /// + private void StampRegionStatusFile(UUID regionID) { - string RegionCacheStatusFile = Path.Combine(m_CacheDirectory, "RegionStatus_" + RegionID.ToString() + ".fac"); - if (File.Exists(RegionCacheStatusFile)) + string RegionCacheStatusFile = Path.Combine(m_CacheDirectory, "RegionStatus_" + regionID.ToString() + ".fac"); + + try { - File.SetLastWriteTime(RegionCacheStatusFile, DateTime.Now); + if (File.Exists(RegionCacheStatusFile)) + { + File.SetLastWriteTime(RegionCacheStatusFile, DateTime.Now); + } + else + { + File.WriteAllText( + RegionCacheStatusFile, + "Please do not delete this file unless you are manually clearing your Flotsam Asset Cache."); + } } - else + catch (Exception e) { - File.WriteAllText(RegionCacheStatusFile, "Please do not delete this file unless you are manually clearing your Flotsam Asset Cache."); + m_log.Warn( + string.Format( + "[FLOTSAM ASSET CACHE]: Could not stamp region status file for region {0}. Exception ", + regionID), + e); } } @@ -759,7 +784,7 @@ namespace OpenSim.Region.CoreModules.Asset } catch (Exception e) { - m_log.ErrorFormat( + m_log.WarnFormat( "[FLOTSAM ASSET CACHE]: Couldn't clear asset cache directory {0} from {1}. Exception {2} {3}", dir, m_CacheDirectory, e.Message, e.StackTrace); } @@ -773,7 +798,7 @@ namespace OpenSim.Region.CoreModules.Asset } catch (Exception e) { - m_log.ErrorFormat( + m_log.WarnFormat( "[FLOTSAM ASSET CACHE]: Couldn't clear asset cache file {0} from {1}. Exception {1} {2}", file, m_CacheDirectory, e.Message, e.StackTrace); } From e93defd0ca326754d1bd5a1a503d6d47428272be Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Fri, 8 Feb 2013 15:07:43 -0800 Subject: [PATCH 10/10] Adds size limits to JsonStore. Adds a separate configuration variable to enable binding to dynamic attributes. --- .../Scripting/JsonStore/JsonStore.cs | 51 ++++++++++++++++++- .../Scripting/JsonStore/JsonStoreModule.cs | 17 +++++++ bin/OpenSimDefaults.ini | 4 ++ 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs index c7f0001e06..088d0cdf88 100644 --- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs @@ -93,6 +93,15 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore // extract the internals of a has reference protected static Regex m_HashPattern = new Regex("{([^}]+)}"); + // ----------------------------------------------------------------- + /// + /// This is a simple estimator for the size of the stored data, it + /// is not precise, but should be close enough to implement reasonable + /// limits on the storage space used + /// + // ----------------------------------------------------------------- + public int StringSpace { get; set; } + // ----------------------------------------------------------------- /// /// @@ -110,6 +119,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore // ----------------------------------------------------------------- public JsonStore() { + StringSpace = 0; m_TakeStore = new List(); m_ReadStore = new List(); } @@ -247,6 +257,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore if (path.Count == 0) { ValueStore = ovalue; + StringSpace = 0; return true; } @@ -278,8 +289,13 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore { string npkey = String.Format("[{0}]",amap.Count); - amap.Add(ovalue); - InvokeNextCallback(pexpr + npkey); + if (ovalue != null) + { + StringSpace += ComputeSizeOf(ovalue); + + amap.Add(ovalue); + InvokeNextCallback(pexpr + npkey); + } return true; } @@ -287,9 +303,14 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore if (0 <= aval && aval < amap.Count) { if (ovalue == null) + { + StringSpace -= ComputeSizeOf(amap[aval]); amap.RemoveAt(aval); + } else { + StringSpace -= ComputeSizeOf(amap[aval]); + StringSpace += ComputeSizeOf(ovalue); amap[aval] = ovalue; InvokeNextCallback(pexpr + pkey); } @@ -313,6 +334,9 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore OSDMap hmap = result as OSDMap; if (ovalue != null) { + StringSpace -= ComputeSizeOf(hmap[hkey]); + StringSpace += ComputeSizeOf(ovalue); + hmap[hkey] = ovalue; InvokeNextCallback(pexpr + pkey); return true; @@ -321,6 +345,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore // this is the remove case if (hmap.ContainsKey(hkey)) { + StringSpace -= ComputeSizeOf(hmap[hkey]); hmap.Remove(hkey); return true; } @@ -531,8 +556,27 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore return pkey; } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + protected static int ComputeSizeOf(OSD value) + { + string sval; + + if (ConvertOutputValue(value,out sval,true)) + return sval.Length; + + return 0; + } } + // ----------------------------------------------------------------- + /// + /// + // ----------------------------------------------------------------- public class JsonObjectStore : JsonStore { private static readonly ILog m_log = @@ -566,6 +610,9 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore { m_scene = scene; m_objectID = oid; + + // the size limit is imposed on whatever is already in the store + StringSpace = ComputeSizeOf(ValueStore); } } diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs index 3249aa3216..f1ce856995 100644 --- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs @@ -54,6 +54,9 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore private IConfig m_config = null; private bool m_enabled = false; + private bool m_enableObjectStore = false; + private int m_maxStringSpace = Int32.MaxValue; + private Scene m_scene = null; private Dictionary m_JsonValueStore; @@ -90,6 +93,10 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore } m_enabled = m_config.GetBoolean("Enabled", m_enabled); + m_enableObjectStore = m_config.GetBoolean("EnableObjectStore", m_enableObjectStore); + m_maxStringSpace = m_config.GetInt("MaxStringSpace", m_maxStringSpace); + if (m_maxStringSpace == 0) + m_maxStringSpace = Int32.MaxValue; } catch (Exception e) { @@ -178,6 +185,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore public bool AttachObjectStore(UUID objectID) { if (! m_enabled) return false; + if (! m_enableObjectStore) return false; SceneObjectPart sop = m_scene.GetSceneObjectPart(objectID); if (sop == null) @@ -311,7 +319,16 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore try { lock (map) + { + if (map.StringSpace > m_maxStringSpace) + { + m_log.WarnFormat("[JsonStore] {0} exceeded string size; {1} bytes used of {2} limit", + storeID,map.StringSpace,m_maxStringSpace); + return false; + } + return map.SetValue(path,value,useJson); + } } catch (Exception e) { diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 7bdfd1ce30..2512428757 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -1652,6 +1652,10 @@ [JsonStore] Enabled = False +;; Enable direct access to the SOP dynamic attributes +EnableObjectStore = False +MaxStringSpace = 0 + ;; ;; These are defaults that are overwritten below in [Architecture]. ;; These defaults allow OpenSim to work out of the box with