From 2c36106675ad984ba5af674cbb970b17ffa320bb Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 15 Nov 2012 01:14:18 +0000 Subject: [PATCH 1/8] Add IncomingPacketsProcessedCount stat for diagnostics. Also puts some packet processing counts in a container named after the scene so that stats can be collected from more than one scene. --- .../ClientStack/Linden/UDP/LLUDPServer.cs | 103 +++++++++++++++--- .../ClientStack/Linden/UDP/OpenSimUDPBase.cs | 33 ++---- 2 files changed, 97 insertions(+), 39 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 14cc863f6b..f8391d77bd 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -70,6 +70,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void AddScene(IScene scene) { m_udpServer.AddScene(scene); + + StatsManager.RegisterStat( + new Stat( + "IncomingPacketsProcessedCount", + "Number of inbound UDP packets processed", + "Number of inbound UDP packets processed", + "", + "clientstack", + scene.Name, + StatType.Pull, + stat => stat.Value = m_udpServer.IncomingPacketsProcessed, + StatVerbosity.Debug)); } public bool HandlesRegion(Location x) @@ -170,6 +182,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP private Pool m_incomingPacketPool; + /// + /// Stat for number of packets in the main pool awaiting use. + /// + private Stat m_poolCountStat; + + /// + /// Stat for number of packets in the inbound packet pool awaiting use. + /// private Stat m_incomingPacketPoolStat; private int m_defaultRTO = 0; @@ -342,20 +362,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_incomingPacketPool = new Pool(() => new IncomingPacket(), 500); - m_incomingPacketPoolStat - = new Stat( - "IncomingPacketPoolCount", - "Objects within incoming packet pool", - "The number of objects currently stored within the incoming packet pool", - "", - "clientstack", - "packetpool", - StatType.Pull, - stat => stat.Value = m_incomingPacketPool.Count, - StatVerbosity.Debug); - - StatsManager.RegisterStat(m_incomingPacketPoolStat); - return true; } @@ -378,6 +384,53 @@ namespace OpenSim.Region.ClientStack.LindenUDP return false; } + /// + /// This is a seperate method so that it can be called once we have an m_scene to distinguish different scene + /// stats. + /// + private void EnablePoolStats() + { + m_poolCountStat + = new Stat( + "UDPPacketBufferPoolCount", + "Objects within the UDPPacketBuffer pool", + "The number of objects currently stored within the UDPPacketBuffer pool", + "", + "clientstack", + m_scene.Name, + StatType.Pull, + stat => stat.Value = Pool.Count, + StatVerbosity.Debug); + + StatsManager.RegisterStat(m_poolCountStat); + + m_incomingPacketPoolStat + = new Stat( + "IncomingPacketPoolCount", + "Objects within incoming packet pool", + "The number of objects currently stored within the incoming packet pool", + "", + "clientstack", + m_scene.Name, + StatType.Pull, + stat => stat.Value = m_incomingPacketPool.Count, + StatVerbosity.Debug); + + StatsManager.RegisterStat(m_incomingPacketPoolStat); + } + + /// + /// Disables pool stats. + /// + private void DisablePoolStats() + { + StatsManager.DeregisterStat(m_poolCountStat); + m_poolCountStat = null; + + StatsManager.DeregisterStat(m_incomingPacketPoolStat); + m_incomingPacketPoolStat = null; + } + /// /// If the outgoing UDP thread times out, then return client that was being processed to help with debugging. /// @@ -416,6 +469,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_scene = (Scene)scene; m_location = new Location(m_scene.RegionInfo.RegionHandle); + + // We delay enabling pool stats to AddScene() instead of Initialize() so that we can distinguish pool stats by + // scene name + if (UsePools) + EnablePoolStats(); MainConsole.Instance.Commands.AddCommand( "Debug", @@ -505,12 +563,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (enabled == "on") { if (EnablePools()) + { + EnablePoolStats(); MainConsole.Instance.OutputFormat("Packet pools enabled on {0}", m_scene.Name); + } } else if (enabled == "off") { if (DisablePools()) + { + DisablePoolStats(); MainConsole.Instance.OutputFormat("Packet pools disabled on {0}", m_scene.Name); + } } else { @@ -1556,6 +1620,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP private int npacksSent = 0; private int npackNotSent = 0; + /// + /// Number of inbound packets processed since startup. + /// + public long IncomingPacketsProcessed { get; private set; } + private void MonitoredClientOutgoingPacketHandler(IClientAPI client) { nticks++; @@ -1615,7 +1684,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP npacksSent++; } else + { npackNotSent++; + } watch2.Stop(); avgDequeueTicks = (nticks - 1) / (float)nticks * avgDequeueTicks + (watch2.ElapsedTicks / (float)nticks); @@ -1623,7 +1694,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP } else + { m_log.WarnFormat("[LLUDPSERVER]: Client is not connected"); + } } } catch (Exception ex) @@ -1687,6 +1760,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", packet.Type, client.Name, m_scene.RegionInfo.RegionName); } + + IncomingPacketsProcessed++; } protected void LogoutHandler(IClientAPI client) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs index 85cbb0659b..808d177dfa 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs @@ -60,16 +60,16 @@ namespace OpenMetaverse /// Flag to process packets asynchronously or synchronously private bool m_asyncPacketHandling; - /// - /// Pool to use for handling data. May be null if UsePools = false; - /// - protected OpenSim.Framework.Pool m_pool; - /// /// Are we to use object pool(s) to reduce memory churn when receiving data? /// public bool UsePools { get; protected set; } + /// + /// Pool to use for handling data. May be null if UsePools = false; + /// + protected OpenSim.Framework.Pool Pool { get; private set; } + /// Returns true if the server is currently listening for inbound packets, otherwise false public bool IsRunningInbound { get; private set; } @@ -77,8 +77,6 @@ namespace OpenMetaverse /// If IsRunningOut = false, then any request to send a packet is simply dropped. public bool IsRunningOutbound { get; private set; } - private Stat m_poolCountStat; - /// /// Default constructor /// @@ -182,21 +180,7 @@ namespace OpenMetaverse { if (!UsePools) { - m_pool = new Pool(() => new UDPPacketBuffer(), 500); - - m_poolCountStat - = new Stat( - "UDPPacketBufferPoolCount", - "Objects within the UDPPacketBuffer pool", - "The number of objects currently stored within the UDPPacketBuffer pool", - "", - "clientstack", - "packetpool", - StatType.Pull, - stat => stat.Value = m_pool.Count, - StatVerbosity.Debug); - - StatsManager.RegisterStat(m_poolCountStat); + Pool = new Pool(() => new UDPPacketBuffer(), 500); UsePools = true; @@ -211,7 +195,6 @@ namespace OpenMetaverse if (UsePools) { UsePools = false; - StatsManager.DeregisterStat(m_poolCountStat); // We won't null out the pool to avoid a race condition with code that may be in the middle of using it. @@ -226,7 +209,7 @@ namespace OpenMetaverse UDPPacketBuffer buf; if (UsePools) - buf = m_pool.GetObject(); + buf = Pool.GetObject(); else buf = new UDPPacketBuffer(); @@ -309,7 +292,7 @@ namespace OpenMetaverse finally { if (UsePools) - m_pool.ReturnObject(buffer); + Pool.ReturnObject(buffer); // Synchronous mode waits until the packet callback completes // before starting the receive to fetch another packet From 038528dc80e0fe03956d61872ba30a887b2890a1 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 15 Nov 2012 02:02:59 +0000 Subject: [PATCH 2/8] Make PacketPool class stats pull stats instead of push stats so they can be lifted up into LLUDPServer and be distiguished by scene name --- OpenSim/Framework/Monitoring/StatsManager.cs | 14 ++- .../ClientStack/Linden/UDP/LLUDPServer.cs | 54 +++++++++ .../ClientStack/Linden/UDP/OpenSimUDPBase.cs | 2 +- .../ClientStack/Linden/UDP/PacketPool.cs | 114 ++++++++---------- 4 files changed, 117 insertions(+), 67 deletions(-) diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs index 4844336e31..cebe905f18 100644 --- a/OpenSim/Framework/Monitoring/StatsManager.cs +++ b/OpenSim/Framework/Monitoring/StatsManager.cs @@ -382,14 +382,20 @@ namespace OpenSim.Framework.Monitoring public class PercentageStat : Stat { - public int Antecedent { get; set; } - public int Consequent { get; set; } + public long Antecedent { get; set; } + public long Consequent { get; set; } public override double Value { get { - int c = Consequent; + // Asking for an update here means that the updater cannot access this value without infinite recursion. + // XXX: A slightly messy but simple solution may be to flick a flag so we can tell if this is being + // called by the pull action and just return the value. + if (StatType == StatType.Pull) + PullAction(this); + + long c = Consequent; // Avoid any chance of a multi-threaded divide-by-zero if (c == 0) @@ -400,7 +406,7 @@ namespace OpenSim.Framework.Monitoring set { - throw new Exception("Cannot set value on a PercentageStat"); + throw new InvalidOperationException("Cannot set value on a PercentageStat"); } } diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index f8391d77bd..fcc69c0a4e 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -469,6 +469,60 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_scene = (Scene)scene; m_location = new Location(m_scene.RegionInfo.RegionHandle); + + // XXX: These stats are also pool stats but we register them separately since they are currently not + // turned on and off by EnablePools()/DisablePools() + StatsManager.RegisterStat( + new PercentageStat( + "PacketsReused", + "Packets reused", + "Number of packets reused out of all requests to the packet pool", + "clientstack", + m_scene.Name, + StatType.Pull, + stat => + { PercentageStat pstat = (PercentageStat)stat; + pstat.Consequent = PacketPool.Instance.PacketsRequested; + pstat.Antecedent = PacketPool.Instance.PacketsReused; }, + StatVerbosity.Debug)); + + StatsManager.RegisterStat( + new PercentageStat( + "PacketDataBlocksReused", + "Packet data blocks reused", + "Number of data blocks reused out of all requests to the packet pool", + "clientstack", + m_scene.Name, + StatType.Pull, + stat => + { PercentageStat pstat = (PercentageStat)stat; + pstat.Consequent = PacketPool.Instance.BlocksRequested; + pstat.Antecedent = PacketPool.Instance.BlocksReused; }, + StatVerbosity.Debug)); + + StatsManager.RegisterStat( + new Stat( + "PacketsPoolCount", + "Objects within the packet pool", + "The number of objects currently stored within the packet pool", + "", + "clientstack", + m_scene.Name, + StatType.Pull, + stat => stat.Value = PacketPool.Instance.PacketsPooled, + StatVerbosity.Debug)); + + StatsManager.RegisterStat( + new Stat( + "PacketDataBlocksPoolCount", + "Objects within the packet data block pool", + "The number of objects currently stored within the packet data block pool", + "", + "clientstack", + m_scene.Name, + StatType.Pull, + stat => stat.Value = PacketPool.Instance.BlocksPooled, + StatVerbosity.Debug)); // We delay enabling pool stats to AddScene() instead of Initialize() so that we can distinguish pool stats by // scene name diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs index 808d177dfa..3f7ca2b941 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs @@ -334,4 +334,4 @@ namespace OpenMetaverse catch (ObjectDisposedException) { } } } -} +} \ No newline at end of file diff --git a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs index 9f22fb48ec..1fdc410430 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs @@ -41,29 +41,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP private static readonly PacketPool instance = new PacketPool(); - private bool packetPoolEnabled = true; - private bool dataBlockPoolEnabled = true; - - private PercentageStat m_packetsReusedStat = new PercentageStat( - "PacketsReused", - "Packets reused", - "Number of packets reused out of all requests to the packet pool", - "clientstack", - "packetpool", - StatType.Push, - null, - StatVerbosity.Debug); - - private PercentageStat m_blocksReusedStat = new PercentageStat( - "PacketDataBlocksReused", - "Packet data blocks reused", - "Number of data blocks reused out of all requests to the packet pool", - "clientstack", - "packetpool", - StatType.Push, - null, - StatVerbosity.Debug); - /// /// Pool of packets available for reuse. /// @@ -76,46 +53,59 @@ namespace OpenSim.Region.ClientStack.LindenUDP get { return instance; } } - public bool RecyclePackets + public bool RecyclePackets { get; set; } + + public bool RecycleDataBlocks { get; set; } + + /// + /// The number of packets pooled + /// + public int PacketsPooled { - set { packetPoolEnabled = value; } - get { return packetPoolEnabled; } + get + { + lock (pool) + return pool.Count; + } } - public bool RecycleDataBlocks + /// + /// The number of blocks pooled. + /// + public int BlocksPooled { - set { dataBlockPoolEnabled = value; } - get { return dataBlockPoolEnabled; } + get + { + lock (DataBlocks) + return DataBlocks.Count; + } } + /// + /// Number of packets requested. + /// + public long PacketsRequested { get; private set; } + + /// + /// Number of packets reused. + /// + public long PacketsReused { get; private set; } + + /// + /// Number of packet blocks requested. + /// + public long BlocksRequested { get; private set; } + + /// + /// Number of packet blocks reused. + /// + public long BlocksReused { get; private set; } + private PacketPool() { - StatsManager.RegisterStat(m_packetsReusedStat); - StatsManager.RegisterStat(m_blocksReusedStat); - - StatsManager.RegisterStat( - new Stat( - "PacketsPoolCount", - "Objects within the packet pool", - "The number of objects currently stored within the packet pool", - "", - "clientstack", - "packetpool", - StatType.Pull, - stat => { lock (pool) { stat.Value = pool.Count; } }, - StatVerbosity.Debug)); - - StatsManager.RegisterStat( - new Stat( - "PacketDataBlocksPoolCount", - "Objects within the packet data block pool", - "The number of objects currently stored within the packet data block pool", - "", - "clientstack", - "packetpool", - StatType.Pull, - stat => { lock (DataBlocks) { stat.Value = DataBlocks.Count; } }, - StatVerbosity.Debug)); + // defaults + RecyclePackets = true; + RecycleDataBlocks = true; } /// @@ -125,11 +115,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Guaranteed to always return a packet, whether from the pool or newly constructed. public Packet GetPacket(PacketType type) { - m_packetsReusedStat.Consequent++; + PacketsRequested++; Packet packet; - if (!packetPoolEnabled) + if (!RecyclePackets) return Packet.BuildPacket(type); lock (pool) @@ -146,7 +136,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // m_log.DebugFormat("[PACKETPOOL]: Pulling {0} packet", type); // Recycle old packages - m_packetsReusedStat.Antecedent++; + PacketsReused++; packet = pool[type].Pop(); } @@ -215,7 +205,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// public void ReturnPacket(Packet packet) { - if (dataBlockPoolEnabled) + if (RecycleDataBlocks) { switch (packet.Type) { @@ -239,7 +229,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } - if (packetPoolEnabled) + if (RecyclePackets) { switch (packet.Type) { @@ -277,7 +267,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { lock (DataBlocks) { - m_blocksReusedStat.Consequent++; + BlocksRequested++; Stack s; @@ -285,7 +275,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { if (s.Count > 0) { - m_blocksReusedStat.Antecedent++; + BlocksReused++; return (T)s.Pop(); } } From df4da51f04ea2900032a6bd2749039bee5338f54 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 15 Nov 2012 03:04:46 +0000 Subject: [PATCH 3/8] Following on from 4f982596, launch map name requests on an async thread from LLClientView directly. This releases the inbound packet handling thread marginally quicker and is more consistent with the other async packet handling --- .../ClientStack/Linden/UDP/LLClientView.cs | 2 +- .../World/WorldMap/MapSearchModule.cs | 20 ++++++++----------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 7382e0935f..c93dbfc4d5 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -5322,7 +5322,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP AddLocalPacketHandler(PacketType.RezScript, HandleRezScript); AddLocalPacketHandler(PacketType.MapLayerRequest, HandleMapLayerRequest, false); AddLocalPacketHandler(PacketType.MapBlockRequest, HandleMapBlockRequest, false); - AddLocalPacketHandler(PacketType.MapNameRequest, HandleMapNameRequest, false); + AddLocalPacketHandler(PacketType.MapNameRequest, HandleMapNameRequest); AddLocalPacketHandler(PacketType.TeleportLandmarkRequest, HandleTeleportLandmarkRequest); AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel); AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest); diff --git a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs index 46b190e701..708a9a267f 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs @@ -115,19 +115,15 @@ namespace OpenSim.Region.CoreModules.World.WorldMap m_Clients.Add(remoteClient.AgentId); } - Util.FireAndForget(delegate + try { - try - { - OnMapNameRequest(remoteClient, mapName, flags); - } - finally - { - lock (m_Clients) - m_Clients.Remove(remoteClient.AgentId); - } - }); - + OnMapNameRequest(remoteClient, mapName, flags); + } + finally + { + lock (m_Clients) + m_Clients.Remove(remoteClient.AgentId); + } } private void OnMapNameRequest(IClientAPI remoteClient, string mapName, uint flags) From 57273ef7b24c5ae466ebb6051a5c614a3c07fe2d Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 15 Nov 2012 03:07:45 +0000 Subject: [PATCH 4/8] Do HandleMapLayerRequest on its own thread rather than on the main inbound udp packet handling thread. There's no obvious race condition reason for doing this on the main packet handling thread. --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index c93dbfc4d5..92a630f8ac 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -5320,7 +5320,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP AddLocalPacketHandler(PacketType.RemoveTaskInventory, HandleRemoveTaskInventory); AddLocalPacketHandler(PacketType.MoveTaskInventory, HandleMoveTaskInventory); AddLocalPacketHandler(PacketType.RezScript, HandleRezScript); - AddLocalPacketHandler(PacketType.MapLayerRequest, HandleMapLayerRequest, false); + AddLocalPacketHandler(PacketType.MapLayerRequest, HandleMapLayerRequest); AddLocalPacketHandler(PacketType.MapBlockRequest, HandleMapBlockRequest, false); AddLocalPacketHandler(PacketType.MapNameRequest, HandleMapNameRequest); AddLocalPacketHandler(PacketType.TeleportLandmarkRequest, HandleTeleportLandmarkRequest); From daf03bfb567a7a93a9259945386325fd924f8bd1 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 15 Nov 2012 03:09:20 +0000 Subject: [PATCH 5/8] Handle Map block requests on a separate thread rather than the main packet handling thread. This prevents a slow grid information network call from holding up the main packet handling thread. There's no obvious race condition reason for not doing this asynchronously. --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 92a630f8ac..4fd81fa616 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -5321,7 +5321,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP AddLocalPacketHandler(PacketType.MoveTaskInventory, HandleMoveTaskInventory); AddLocalPacketHandler(PacketType.RezScript, HandleRezScript); AddLocalPacketHandler(PacketType.MapLayerRequest, HandleMapLayerRequest); - AddLocalPacketHandler(PacketType.MapBlockRequest, HandleMapBlockRequest, false); + AddLocalPacketHandler(PacketType.MapBlockRequest, HandleMapBlockRequest); AddLocalPacketHandler(PacketType.MapNameRequest, HandleMapNameRequest); AddLocalPacketHandler(PacketType.TeleportLandmarkRequest, HandleTeleportLandmarkRequest); AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel); From 1aa027123982b710313ea0e15efe7fc85db1c9ea Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 15 Nov 2012 03:29:55 +0000 Subject: [PATCH 6/8] Implement folder version updating for the sqlite inventory plugin --- .../Data/SQLite/SQLiteGenericTableHandler.cs | 10 +- OpenSim/Data/SQLite/SQLiteXInventoryData.cs | 139 +++++++++++++++++- 2 files changed, 142 insertions(+), 7 deletions(-) diff --git a/OpenSim/Data/SQLite/SQLiteGenericTableHandler.cs b/OpenSim/Data/SQLite/SQLiteGenericTableHandler.cs index 917a0a1504..9fbeb100ce 100644 --- a/OpenSim/Data/SQLite/SQLiteGenericTableHandler.cs +++ b/OpenSim/Data/SQLite/SQLiteGenericTableHandler.cs @@ -120,12 +120,12 @@ namespace OpenSim.Data.SQLite } } - public T[] Get(string field, string key) + public virtual T[] Get(string field, string key) { return Get(new string[] { field }, new string[] { key }); } - public T[] Get(string[] fields, string[] keys) + public virtual T[] Get(string[] fields, string[] keys) { if (fields.Length != keys.Length) return new T[0]; @@ -213,7 +213,7 @@ namespace OpenSim.Data.SQLite return result.ToArray(); } - public T[] Get(string where) + public virtual T[] Get(string where) { using (SqliteCommand cmd = new SqliteCommand()) { @@ -226,7 +226,7 @@ namespace OpenSim.Data.SQLite } } - public bool Store(T row) + public virtual bool Store(T row) { using (SqliteCommand cmd = new SqliteCommand()) { @@ -270,7 +270,7 @@ namespace OpenSim.Data.SQLite return Delete(new string[] { field }, new string[] { key }); } - public bool Delete(string[] fields, string[] keys) + public virtual bool Delete(string[] fields, string[] keys) { if (fields.Length != keys.Length) return false; diff --git a/OpenSim/Data/SQLite/SQLiteXInventoryData.cs b/OpenSim/Data/SQLite/SQLiteXInventoryData.cs index 8eb1a63996..87eb31eb0f 100644 --- a/OpenSim/Data/SQLite/SQLiteXInventoryData.cs +++ b/OpenSim/Data/SQLite/SQLiteXInventoryData.cs @@ -137,16 +137,72 @@ namespace OpenSim.Data.SQLite { } + public override bool Store(XInventoryItem item) + { + if (!base.Store(item)) + return false; + + IncrementFolderVersion(item.parentFolderID); + + return true; + } + + public override bool Delete(string field, string val) + { + XInventoryItem[] retrievedItems = Get(new string[] { field }, new string[] { val }); + if (retrievedItems.Length == 0) + return false; + + if (!base.Delete(field, val)) + return false; + + // Don't increment folder version here since Delete(string, string) calls Delete(string[], string[]) +// IncrementFolderVersion(retrievedItems[0].parentFolderID); + + return true; + } + + public override bool Delete(string[] fields, string[] vals) + { + XInventoryItem[] retrievedItems = Get(fields, vals); + if (retrievedItems.Length == 0) + return false; + + if (!base.Delete(fields, vals)) + return false; + + HashSet deletedItemFolderUUIDs = new HashSet(); + + Array.ForEach(retrievedItems, i => deletedItemFolderUUIDs.Add(i.parentFolderID)); + + foreach (UUID deletedItemFolderUUID in deletedItemFolderUUIDs) + IncrementFolderVersion(deletedItemFolderUUID); + + return true; + } + public bool MoveItem(string id, string newParent) { + XInventoryItem[] retrievedItems = Get(new string[] { "inventoryID" }, new string[] { id }); + if (retrievedItems.Length == 0) + return false; + + UUID oldParent = retrievedItems[0].parentFolderID; + using (SqliteCommand cmd = new SqliteCommand()) { cmd.CommandText = String.Format("update {0} set parentFolderID = :ParentFolderID where inventoryID = :InventoryID", m_Realm); cmd.Parameters.Add(new SqliteParameter(":ParentFolderID", newParent)); cmd.Parameters.Add(new SqliteParameter(":InventoryID", id)); - return ExecuteNonQuery(cmd, m_Connection) == 0 ? false : true; + if (ExecuteNonQuery(cmd, m_Connection) == 0) + return false; } + + IncrementFolderVersion(oldParent); + IncrementFolderVersion(newParent); + + return true; } public XInventoryItem[] GetActiveGestures(UUID principalID) @@ -187,6 +243,34 @@ namespace OpenSim.Data.SQLite return perms; } + + private bool IncrementFolderVersion(UUID folderID) + { + return IncrementFolderVersion(folderID.ToString()); + } + + private bool IncrementFolderVersion(string folderID) + { +// m_log.DebugFormat("[MYSQL ITEM HANDLER]: Incrementing version on folder {0}", folderID); +// Util.PrintCallStack(); + + using (SqliteCommand cmd = new SqliteCommand()) + { + cmd.CommandText = "update inventoryfolders set version=version+1 where folderID = ?folderID"; + cmd.Parameters.Add(new SqliteParameter(":folderID", folderID)); + + try + { + cmd.ExecuteNonQuery(); + } + catch (Exception) + { + return false; + } + } + + return true; + } } public class SqliteFolderHandler : SQLiteGenericTableHandler @@ -196,16 +280,67 @@ namespace OpenSim.Data.SQLite { } + public override bool Store(XInventoryFolder folder) + { + if (!base.Store(folder)) + return false; + + IncrementFolderVersion(folder.parentFolderID); + + return true; + } + public bool MoveFolder(string id, string newParentFolderID) { + XInventoryFolder[] folders = Get(new string[] { "folderID" }, new string[] { id }); + + if (folders.Length == 0) + return false; + + UUID oldParentFolderUUID = folders[0].parentFolderID; + using (SqliteCommand cmd = new SqliteCommand()) { cmd.CommandText = String.Format("update {0} set parentFolderID = :ParentFolderID where folderID = :FolderID", m_Realm); cmd.Parameters.Add(new SqliteParameter(":ParentFolderID", newParentFolderID)); cmd.Parameters.Add(new SqliteParameter(":FolderID", id)); - return ExecuteNonQuery(cmd, m_Connection) == 0 ? false : true; + if (ExecuteNonQuery(cmd, m_Connection) == 0) + return false; } + + IncrementFolderVersion(oldParentFolderUUID); + IncrementFolderVersion(newParentFolderID); + + return true; + } + + private bool IncrementFolderVersion(UUID folderID) + { + return IncrementFolderVersion(folderID.ToString()); + } + + private bool IncrementFolderVersion(string folderID) + { +// m_log.DebugFormat("[MYSQL ITEM HANDLER]: Incrementing version on folder {0}", folderID); +// Util.PrintCallStack(); + + using (SqliteCommand cmd = new SqliteCommand()) + { + cmd.CommandText = "update inventoryfolders set version=version+1 where folderID = ?folderID"; + cmd.Parameters.Add(new SqliteParameter(":folderID", folderID)); + + try + { + cmd.ExecuteNonQuery(); + } + catch (Exception) + { + return false; + } + } + + return true; } } } \ No newline at end of file From 0c4efdc6a814d2d28e95f74a28d0b6759fc6a028 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 15 Nov 2012 03:32:03 +0000 Subject: [PATCH 7/8] Fix build break from 1aa0271 by adding System.Core to prebuild.xml --- prebuild.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/prebuild.xml b/prebuild.xml index 69fce41532..aca0c49690 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -2134,10 +2134,11 @@ ../../../bin/ - + - + + From 16dd94b9560d186a922b717d08c24f654f6e21aa Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 15 Nov 2012 03:39:17 +0000 Subject: [PATCH 8/8] Improve inventory folder version updating for mssql database plugin. I am not in a position to test this so the updates have been done blind. If it needs any fixing will probably require patches. --- OpenSim/Data/MSSQL/MSSQLXInventoryData.cs | 116 +++++++++++++++++++--- 1 file changed, 102 insertions(+), 14 deletions(-) diff --git a/OpenSim/Data/MSSQL/MSSQLXInventoryData.cs b/OpenSim/Data/MSSQL/MSSQLXInventoryData.cs index 7ab0ebbe7b..97970af325 100644 --- a/OpenSim/Data/MSSQL/MSSQLXInventoryData.cs +++ b/OpenSim/Data/MSSQL/MSSQLXInventoryData.cs @@ -131,6 +131,12 @@ namespace OpenSim.Data.MSSQL public bool MoveItem(string id, string newParent) { + XInventoryItem[] retrievedItems = Get(new string[] { "inventoryID" }, new string[] { id }); + if (retrievedItems.Length == 0) + return false; + + UUID oldParent = retrievedItems[0].parentFolderID; + using (SqlConnection conn = new SqlConnection(m_ConnectionString)) { using (SqlCommand cmd = new SqlCommand()) @@ -141,9 +147,16 @@ namespace OpenSim.Data.MSSQL cmd.Parameters.Add(m_database.CreateParameter("@InventoryID", id)); cmd.Connection = conn; conn.Open(); - return cmd.ExecuteNonQuery() == 0 ? false : true; + + if (cmd.ExecuteNonQuery() == 0) + return false; } } + + IncrementFolderVersion(oldParent); + IncrementFolderVersion(newParent); + + return true; } public XInventoryItem[] GetActiveGestures(UUID principalID) @@ -196,26 +209,43 @@ namespace OpenSim.Data.MSSQL if (!base.Store(item)) return false; - string sql = "update inventoryfolders set version=version+1 where folderID = @folderID"; + IncrementFolderVersion(item.parentFolderID); + + return true; + } + + private bool IncrementFolderVersion(UUID folderID) + { + return IncrementFolderVersion(folderID.ToString()); + } + + private bool IncrementFolderVersion(string folderID) + { +// m_log.DebugFormat("[MYSQL ITEM HANDLER]: Incrementing version on folder {0}", folderID); +// Util.PrintCallStack(); + + string sql = "update inventoryfolders set version=version+1 where folderID = ?folderID"; + using (SqlConnection conn = new SqlConnection(m_ConnectionString)) { using (SqlCommand cmd = new SqlCommand(sql, conn)) { conn.Open(); - cmd.Parameters.AddWithValue("@folderID", item.parentFolderID.ToString()); - try - { - cmd.ExecuteNonQuery(); - } - catch (Exception) - { - return false; - } - } + cmd.Parameters.AddWithValue("@folderID", folderID); - return true; + try + { + cmd.ExecuteNonQuery(); + } + catch (Exception) + { + return false; + } + } } + + return true; } } @@ -228,6 +258,13 @@ namespace OpenSim.Data.MSSQL public bool MoveFolder(string id, string newParentFolderID) { + XInventoryFolder[] folders = Get(new string[] { "folderID" }, new string[] { id }); + + if (folders.Length == 0) + return false; + + UUID oldParentFolderUUID = folders[0].parentFolderID; + using (SqlConnection conn = new SqlConnection(m_ConnectionString)) { using (SqlCommand cmd = new SqlCommand()) @@ -238,9 +275,60 @@ namespace OpenSim.Data.MSSQL cmd.Parameters.Add(m_database.CreateParameter("@folderID", id)); cmd.Connection = conn; conn.Open(); - return cmd.ExecuteNonQuery() == 0 ? false : true; + + if (cmd.ExecuteNonQuery() == 0) + return false; } } + + IncrementFolderVersion(oldParentFolderUUID); + IncrementFolderVersion(newParentFolderID); + + return true; + } + + public override bool Store(XInventoryFolder folder) + { + if (!base.Store(folder)) + return false; + + IncrementFolderVersion(folder.parentFolderID); + + return true; + } + + private bool IncrementFolderVersion(UUID folderID) + { + return IncrementFolderVersion(folderID.ToString()); + } + + private bool IncrementFolderVersion(string folderID) + { +// m_log.DebugFormat("[MYSQL ITEM HANDLER]: Incrementing version on folder {0}", folderID); +// Util.PrintCallStack(); + + string sql = "update inventoryfolders set version=version+1 where folderID = ?folderID"; + + using (SqlConnection conn = new SqlConnection(m_ConnectionString)) + { + using (SqlCommand cmd = new SqlCommand(sql, conn)) + { + conn.Open(); + + cmd.Parameters.AddWithValue("@folderID", folderID); + + try + { + cmd.ExecuteNonQuery(); + } + catch (Exception) + { + return false; + } + } + } + + return true; } } } \ No newline at end of file