From cb7a9eaa09fba301ba6b6838cb9e3cedfc29a32a Mon Sep 17 00:00:00 2001
From: Justin Clarke Casey
Date: Mon, 6 Oct 2008 19:52:54 +0000
Subject: * Stop the sim stats reporter reusing the same SimStatsPacket for all
 clients * I believe this was the cause of the remaining packet_out_of_order
 messages in the Linden client logs * There were race conditions where
 multiple clientstacks would overwrite each other's sequence numbers

---
 OpenSim/Framework/IClientAPI.cs                    |  8 +-
 OpenSim/Framework/SimStats.cs                      | 88 ++++++++++++++++++++++
 .../Framework/Statistics/SimExtraStatsCollector.cs | 48 ++++++------
 .../Region/ClientStack/LindenUDP/LLClientView.cs   | 14 +++-
 .../Environment/Modules/World/NPC/NPCAvatar.cs     |  2 +-
 OpenSim/Region/Environment/Scenes/Scene.cs         |  4 +-
 .../Region/Environment/Scenes/SimStatsReporter.cs  | 44 +++++------
 .../Region/Examples/SimpleModule/MyNpcCharacter.cs |  2 +-
 8 files changed, 155 insertions(+), 55 deletions(-)
 create mode 100644 OpenSim/Framework/SimStats.cs

diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs
index 1a6a5a4..4071e47 100644
--- a/OpenSim/Framework/IClientAPI.cs
+++ b/OpenSim/Framework/IClientAPI.cs
@@ -722,7 +722,13 @@ namespace OpenSim.Framework
         void SendImagePart(ushort numParts, UUID ImageUUID, uint ImageSize, byte[] ImageData, byte imageCodec);
 
         void SendShutdownConnectionNotice();
-        void SendSimStats(Packet pack);
+        
+        /// <summary>
+        /// Send statistical information about the sim to the client.
+        /// </summary>
+        /// <param name="stats"></param>
+        void SendSimStats(SimStats stats);
+        
         void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID,
                                                     uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask,
                                                     uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category,
diff --git a/OpenSim/Framework/SimStats.cs b/OpenSim/Framework/SimStats.cs
new file mode 100644
index 0000000..c77d0d4
--- /dev/null
+++ b/OpenSim/Framework/SimStats.cs
@@ -0,0 +1,88 @@
+/*
+ * 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 OpenSim 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 OpenMetaverse.Packets;
+
+namespace OpenSim.Framework
+{
+    /// <summary>
+    /// Enapsulate statistics for a simulator/scene.
+    /// 
+    /// TODO: This looks very much like the OpenMetaverse SimStatsPacket.  It should be much more generic stats
+    /// storage.
+    /// </summary>        
+    public class SimStats
+    {                 
+        public uint RegionX
+        {
+            get { return m_regionX; }
+        }
+        private uint m_regionX;
+
+        public uint RegionY
+        {
+            get { return m_regionY; }
+        }        
+        private uint m_regionY;
+        
+        public SimStatsPacket.RegionBlock RegionBlock
+        {
+            get { return m_regionBlock; }
+        }                
+        private SimStatsPacket.RegionBlock m_regionBlock;
+        
+        public SimStatsPacket.StatBlock[] StatsBlock
+        {
+            get { return m_statsBlock; }
+        }        
+        private SimStatsPacket.StatBlock[] m_statsBlock;
+        
+        public uint RegionFlags
+        {
+            get { return m_regionFlags; }
+        }        
+        private uint m_regionFlags;
+            
+        public uint ObjectCapacity
+        {
+            get { return m_objectCapacity; }
+        }
+        private uint m_objectCapacity;
+                
+        public SimStats(
+            uint regionX, uint regionY, uint regionFlags, uint objectCapacity, 
+            SimStatsPacket.RegionBlock regionBlock, SimStatsPacket.StatBlock[] statsBlock)
+        {
+            m_regionX = regionX;
+            m_regionY = regionY;
+            m_regionFlags = regionFlags;
+            m_objectCapacity = objectCapacity;
+            m_regionBlock = regionBlock;
+            m_statsBlock = statsBlock;
+        }
+    }
+}
diff --git a/OpenSim/Framework/Statistics/SimExtraStatsCollector.cs b/OpenSim/Framework/Statistics/SimExtraStatsCollector.cs
index 2f6bb7e..48bed81 100644
--- a/OpenSim/Framework/Statistics/SimExtraStatsCollector.cs
+++ b/OpenSim/Framework/Statistics/SimExtraStatsCollector.cs
@@ -216,31 +216,31 @@ namespace OpenSim.Framework.Statistics
         /// client purposes) sends information to listeners.
         /// </summary>
         /// <param name="pack"></param>
-        public void ReceiveClassicSimStatsPacket(SimStatsPacket statsPacket)
+        public void ReceiveClassicSimStatsPacket(SimStats stats)
         {
-            // FIXME: Really shouldn't rely on the probably arbitrary order in which
-            // stats are packed into the packet
-            timeDilation            = statsPacket.Stat[0].StatValue;
-            simFps                  = statsPacket.Stat[1].StatValue;
-            physicsFps              = statsPacket.Stat[2].StatValue;
-            agentUpdates            = statsPacket.Stat[3].StatValue;
-            rootAgents              = statsPacket.Stat[4].StatValue;
-            childAgents             = statsPacket.Stat[5].StatValue;
-            totalPrims              = statsPacket.Stat[6].StatValue;
-            activePrims             = statsPacket.Stat[7].StatValue;
-            totalFrameTime          = statsPacket.Stat[8].StatValue;
-            netFrameTime            = statsPacket.Stat[9].StatValue;
-            physicsFrameTime        = statsPacket.Stat[10].StatValue;
-            otherFrameTime          = statsPacket.Stat[11].StatValue;
-            imageFrameTime          = statsPacket.Stat[12].StatValue;
-            inPacketsPerSecond      = statsPacket.Stat[13].StatValue;
-            outPacketsPerSecond     = statsPacket.Stat[14].StatValue;
-            unackedBytes            = statsPacket.Stat[15].StatValue;
-            agentFrameTime          = statsPacket.Stat[16].StatValue;
-            pendingDownloads        = statsPacket.Stat[17].StatValue;
-            pendingUploads          = statsPacket.Stat[18].StatValue;
-            activeScripts           = statsPacket.Stat[19].StatValue;
-            scriptLinesPerSecond    = statsPacket.Stat[20].StatValue;
+            // FIXME: SimStats shouldn't allow an arbitrary stat packing order (which is inherited from the original
+            // SimStatsPacket that was being used).
+            timeDilation            = stats.StatsBlock[0].StatValue;
+            simFps                  = stats.StatsBlock[1].StatValue;
+            physicsFps              = stats.StatsBlock[2].StatValue;
+            agentUpdates            = stats.StatsBlock[3].StatValue;
+            rootAgents              = stats.StatsBlock[4].StatValue;
+            childAgents             = stats.StatsBlock[5].StatValue;
+            totalPrims              = stats.StatsBlock[6].StatValue;
+            activePrims             = stats.StatsBlock[7].StatValue;
+            totalFrameTime          = stats.StatsBlock[8].StatValue;
+            netFrameTime            = stats.StatsBlock[9].StatValue;
+            physicsFrameTime        = stats.StatsBlock[10].StatValue;
+            otherFrameTime          = stats.StatsBlock[11].StatValue;
+            imageFrameTime          = stats.StatsBlock[12].StatValue;
+            inPacketsPerSecond      = stats.StatsBlock[13].StatValue;
+            outPacketsPerSecond     = stats.StatsBlock[14].StatValue;
+            unackedBytes            = stats.StatsBlock[15].StatValue;
+            agentFrameTime          = stats.StatsBlock[16].StatValue;
+            pendingDownloads        = stats.StatsBlock[17].StatValue;
+            pendingUploads          = stats.StatsBlock[18].StatValue;
+            activeScripts           = stats.StatsBlock[19].StatValue;
+            scriptLinesPerSecond    = stats.StatsBlock[20].StatValue;
         }
 
         /// <summary>
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
index ff35c32..cbba661 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
@@ -2610,9 +2610,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
             OutPacket(PacketPool.Instance.GetPacket(PacketType.DisableSimulator), ThrottleOutPacketType.Unknown);
         }
 
-        public void SendSimStats(Packet pack)
-        {
+        public void SendSimStats(SimStats stats)
+        {
+            SimStatsPacket pack = new SimStatsPacket();
+            
+            pack.Region.RegionX = stats.RegionX;
+            pack.Region.RegionY = stats.RegionY;
+            pack.Region.RegionFlags = stats.RegionFlags;
+            pack.Region.ObjectCapacity = stats.ObjectCapacity;
+            pack.Region = stats.RegionBlock;
+            pack.Stat = stats.StatsBlock;
+            
             pack.Header.Reliable = false;
+            
             OutPacket(pack, ThrottleOutPacketType.Task);
         }
 
diff --git a/OpenSim/Region/Environment/Modules/World/NPC/NPCAvatar.cs b/OpenSim/Region/Environment/Modules/World/NPC/NPCAvatar.cs
index a236ccd..b59b013 100644
--- a/OpenSim/Region/Environment/Modules/World/NPC/NPCAvatar.cs
+++ b/OpenSim/Region/Environment/Modules/World/NPC/NPCAvatar.cs
@@ -706,7 +706,7 @@ namespace OpenSim.Region.Environment.Modules.World.NPC
         {
         }
 
-        public void SendSimStats(Packet pack)
+        public void SendSimStats(SimStats stats)
         {
         }
 
diff --git a/OpenSim/Region/Environment/Scenes/Scene.cs b/OpenSim/Region/Environment/Scenes/Scene.cs
index bf1dbcd..da6da1e 100644
--- a/OpenSim/Region/Environment/Scenes/Scene.cs
+++ b/OpenSim/Region/Environment/Scenes/Scene.cs
@@ -837,14 +837,14 @@ namespace OpenSim.Region.Environment.Scenes
             }
         }
 
-        private void SendSimStatsPackets(SimStatsPacket pack)
+        private void SendSimStatsPackets(SimStats stats)
         {
             List<ScenePresence> StatSendAgents = GetScenePresences();
             foreach (ScenePresence agent in StatSendAgents)
             {
                 if (!agent.IsChildAgent)
                 {
-                    agent.ControllingClient.SendSimStats(pack);
+                    agent.ControllingClient.SendSimStats(stats);
                 }
             }
         }
diff --git a/OpenSim/Region/Environment/Scenes/SimStatsReporter.cs b/OpenSim/Region/Environment/Scenes/SimStatsReporter.cs
index 5f0f316..4c9c59d 100644
--- a/OpenSim/Region/Environment/Scenes/SimStatsReporter.cs
+++ b/OpenSim/Region/Environment/Scenes/SimStatsReporter.cs
@@ -36,7 +36,7 @@ namespace OpenSim.Region.Environment.Scenes
 {
     public class SimStatsReporter
     {
-        public delegate void SendStatResult(SimStatsPacket pack);
+        public delegate void SendStatResult(SimStats stats);
 
         public event SendStatResult OnSendStatsResult;
 
@@ -100,12 +100,6 @@ namespace OpenSim.Region.Environment.Scenes
 
         private int objectCapacity = 45000;
 
-
-        SimStatsPacket.StatBlock[] sb = new SimStatsPacket.StatBlock[21];
-        SimStatsPacket.RegionBlock rb = new SimStatsPacket.RegionBlock();
-        SimStatsPacket statpack = (SimStatsPacket)PacketPool.Instance.GetPacket(PacketType.SimStats);
-
-
         private Scene m_scene;
 
         private RegionInfo ReportingRegion;
@@ -118,10 +112,7 @@ namespace OpenSim.Region.Environment.Scenes
             statsUpdateFactor = (float)(statsUpdatesEveryMS / 1000);
             m_scene = scene;
             ReportingRegion = scene.RegionInfo;
-            for (int i = 0; i<21;i++)
-            {
-                sb[i] = new SimStatsPacket.StatBlock();
-            }
+
             m_report.AutoReset = true;
             m_report.Interval = statsUpdatesEveryMS;
             m_report.Elapsed += new ElapsedEventHandler(statsHeartBeat);
@@ -140,26 +131,24 @@ namespace OpenSim.Region.Environment.Scenes
 
         private void statsHeartBeat(object sender, EventArgs e)
         {
+            SimStatsPacket.StatBlock[] sb = new SimStatsPacket.StatBlock[21];
+            SimStatsPacket.RegionBlock rb = new SimStatsPacket.RegionBlock();
+            
             // Know what's not thread safe in Mono... modifying timers.
             // System.Console.WriteLine("Firing Stats Heart Beat");
             lock (m_report)
             {
-                // Packet is already initialized and ready for data insert
-
-
-                statpack.Region = rb;
-                statpack.Region.RegionX = ReportingRegion.RegionLocX;
-                statpack.Region.RegionY = ReportingRegion.RegionLocY;
+                uint regionFlags = 0;
+                
                 try
                 {
                     IEstateModule estateModule = m_scene.RequestModuleInterface<IEstateModule>();
-                    statpack.Region.RegionFlags = estateModule != null ? estateModule.GetRegionFlags() : (uint) 0;
+                    regionFlags = estateModule != null ? estateModule.GetRegionFlags() : (uint) 0;
                 }
                 catch (Exception)
                 {
-                    statpack.Region.RegionFlags = (uint) 0;
+                    // leave region flags at 0
                 }
-                statpack.Region.ObjectCapacity = (uint) objectCapacity;
 
 #region various statistic googly moogly
 
@@ -182,7 +171,7 @@ namespace OpenSim.Region.Environment.Scenes
                     physfps = 0;
 
 #endregion
-
+                
                 //Our time dilation is 0.91 when we're running a full speed,
                 // therefore to make sure we get an appropriate range,
                 // we have to factor in our error.   (0.10f * statsUpdateFactor)
@@ -190,6 +179,11 @@ namespace OpenSim.Region.Environment.Scenes
                 // / 10 divides the value by the number of times the sim heartbeat runs (10fps)
                 // Then we divide the whole amount by the amount of seconds pass in between stats updates.
 
+                for (int i = 0; i<21;i++)
+                {
+                    sb[i] = new SimStatsPacket.StatBlock();
+                }
+                
                 sb[0].StatID = (uint) Stats.TimeDilation;
                 sb[0].StatValue = m_timeDilation ; //((((m_timeDilation + (0.10f * statsUpdateFactor)) /10)  / statsUpdateFactor));
 
@@ -252,13 +246,15 @@ namespace OpenSim.Region.Environment.Scenes
 
                 sb[20].StatID = (uint)Stats.ScriptLinesPerSecond;
                 sb[20].StatValue = m_scriptLinesPerSecond / statsUpdateFactor;
-
-                statpack.Stat = sb;
+              
+                SimStats simStats 
+                    = new SimStats(
+                        ReportingRegion.RegionLocX, ReportingRegion.RegionLocY, regionFlags, (uint)objectCapacity, rb, sb);
 
                 handlerSendStatResult = OnSendStatsResult;
                 if (handlerSendStatResult != null)
                 {
-                    handlerSendStatResult(statpack);
+                    handlerSendStatResult(simStats);
                 }
                 resetvalues();
             }
diff --git a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs
index 9c8152d..87478c7 100644
--- a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs
+++ b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs
@@ -625,7 +625,7 @@ namespace OpenSim.Region.Examples.SimpleModule
         {
         }
 
-        public void SendSimStats(Packet pack)
+        public void SendSimStats(SimStats stats)
         {
         }
 
-- 
cgit v1.1