From e7c877407f2a72a9519eb53debca5aeef20cded9 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Tue, 6 Oct 2009 02:38:00 -0700 Subject: * Continued work on the new LLUDP implementation. Appears to be functioning, although not everything is reimplemented yet * Replaced logic in ThreadTracker with a call to System.Diagnostics that does the same thing * Added Util.StringToBytes256() and Util.StringToBytes1024() to clamp output at byte[256] and byte[1024], respectively * Fixed formatting for a MySQLAssetData error logging line --- .../ClientStack/LindenUDP/LLUDPClientCollection.cs | 185 +++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs new file mode 100644 index 0000000..7d2da68 --- /dev/null +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs @@ -0,0 +1,185 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Net; +using OpenSim.Framework; +using OpenMetaverse; + +using ReaderWriterLockImpl = OpenMetaverse.ReaderWriterLockSlim; + +namespace OpenSim.Region.ClientStack.LindenUDP +{ + public sealed class UDPClientCollection + { + Dictionary Dictionary1; + Dictionary Dictionary2; + LLUDPClient[] Array; + ReaderWriterLockImpl rwLock = new ReaderWriterLockImpl(); + + public UDPClientCollection() + { + Dictionary1 = new Dictionary(); + Dictionary2 = new Dictionary(); + Array = new LLUDPClient[0]; + } + + public UDPClientCollection(int capacity) + { + Dictionary1 = new Dictionary(capacity); + Dictionary2 = new Dictionary(capacity); + Array = new LLUDPClient[0]; + } + + public void Add(UUID key1, IPEndPoint key2, LLUDPClient value) + { + rwLock.EnterWriteLock(); + + try + { + if (Dictionary1.ContainsKey(key1)) + { + if (!Dictionary2.ContainsKey(key2)) + throw new ArgumentException("key1 exists in the dictionary but not key2"); + } + else if (Dictionary2.ContainsKey(key2)) + { + if (!Dictionary1.ContainsKey(key1)) + throw new ArgumentException("key2 exists in the dictionary but not key1"); + } + + Dictionary1[key1] = value; + Dictionary2[key2] = value; + + LLUDPClient[] oldArray = Array; + int oldLength = oldArray.Length; + + LLUDPClient[] newArray = new LLUDPClient[oldLength + 1]; + for (int i = 0; i < oldLength; i++) + newArray[i] = oldArray[i]; + newArray[oldLength] = value; + + Array = newArray; + } + finally { rwLock.ExitWriteLock(); } + } + + public bool Remove(UUID key1, IPEndPoint key2) + { + rwLock.EnterWriteLock(); + + try + { + LLUDPClient value; + if (Dictionary1.TryGetValue(key1, out value)) + { + Dictionary1.Remove(key1); + Dictionary2.Remove(key2); + + LLUDPClient[] oldArray = Array; + int oldLength = oldArray.Length; + + LLUDPClient[] newArray = new LLUDPClient[oldLength - 1]; + int j = 0; + for (int i = 0; i < oldLength; i++) + { + if (oldArray[i] != value) + newArray[j++] = oldArray[i]; + } + + Array = newArray; + return true; + } + } + finally { rwLock.ExitWriteLock(); } + + return false; + } + + public void Clear() + { + rwLock.EnterWriteLock(); + + try + { + Dictionary1.Clear(); + Dictionary2.Clear(); + Array = new LLUDPClient[0]; + } + finally { rwLock.ExitWriteLock(); } + } + + public int Count + { + get { return Array.Length; } + } + + public bool ContainsKey(UUID key) + { + return Dictionary1.ContainsKey(key); + } + + public bool ContainsKey(IPEndPoint key) + { + return Dictionary2.ContainsKey(key); + } + + public bool TryGetValue(UUID key, out LLUDPClient value) + { + bool success; + bool doLock = !rwLock.IsUpgradeableReadLockHeld; + if (doLock) rwLock.EnterReadLock(); + + try { success = Dictionary1.TryGetValue(key, out value); } + finally { if (doLock) rwLock.ExitReadLock(); } + + return success; + } + + public bool TryGetValue(IPEndPoint key, out LLUDPClient value) + { + bool success; + bool doLock = !rwLock.IsUpgradeableReadLockHeld; + if (doLock) rwLock.EnterReadLock(); + + try { success = Dictionary2.TryGetValue(key, out value); } + finally { if (doLock) rwLock.ExitReadLock(); } + + return success; + } + + public void ForEach(Action action) + { + bool doLock = !rwLock.IsUpgradeableReadLockHeld; + if (doLock) rwLock.EnterUpgradeableReadLock(); + + try { Parallel.ForEach(Array, action); } + finally { if (doLock) rwLock.ExitUpgradeableReadLock(); } + } + } +} -- cgit v1.1 From c71b3e730d8027b31eb3300c747d011a6e38030e Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 7 Oct 2009 18:54:08 -0700 Subject: Changed the locking mechanism, because the existing one is causing deadlocks to occur. --- .../ClientStack/LindenUDP/LLUDPClientCollection.cs | 125 ++++++++++++++++----- 1 file changed, 100 insertions(+), 25 deletions(-) (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs index 7d2da68..9be9480 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs @@ -41,6 +41,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP Dictionary Dictionary2; LLUDPClient[] Array; ReaderWriterLockImpl rwLock = new ReaderWriterLockImpl(); + object m_sync = new object(); public UDPClientCollection() { @@ -58,9 +59,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void Add(UUID key1, IPEndPoint key2, LLUDPClient value) { - rwLock.EnterWriteLock(); + //rwLock.EnterWriteLock(); - try + //try + //{ + // if (Dictionary1.ContainsKey(key1)) + // { + // if (!Dictionary2.ContainsKey(key2)) + // throw new ArgumentException("key1 exists in the dictionary but not key2"); + // } + // else if (Dictionary2.ContainsKey(key2)) + // { + // if (!Dictionary1.ContainsKey(key1)) + // throw new ArgumentException("key2 exists in the dictionary but not key1"); + // } + + // Dictionary1[key1] = value; + // Dictionary2[key2] = value; + + // LLUDPClient[] oldArray = Array; + // int oldLength = oldArray.Length; + + // LLUDPClient[] newArray = new LLUDPClient[oldLength + 1]; + // for (int i = 0; i < oldLength; i++) + // newArray[i] = oldArray[i]; + // newArray[oldLength] = value; + + // Array = newArray; + //} + //finally { rwLock.ExitWriteLock(); } + + lock (m_sync) { if (Dictionary1.ContainsKey(key1)) { @@ -86,14 +115,41 @@ namespace OpenSim.Region.ClientStack.LindenUDP Array = newArray; } - finally { rwLock.ExitWriteLock(); } + } public bool Remove(UUID key1, IPEndPoint key2) { - rwLock.EnterWriteLock(); + //rwLock.EnterWriteLock(); + + //try + //{ + // LLUDPClient value; + // if (Dictionary1.TryGetValue(key1, out value)) + // { + // Dictionary1.Remove(key1); + // Dictionary2.Remove(key2); + + // LLUDPClient[] oldArray = Array; + // int oldLength = oldArray.Length; + + // LLUDPClient[] newArray = new LLUDPClient[oldLength - 1]; + // int j = 0; + // for (int i = 0; i < oldLength; i++) + // { + // if (oldArray[i] != value) + // newArray[j++] = oldArray[i]; + // } + + // Array = newArray; + // return true; + // } + //} + //finally { rwLock.ExitWriteLock(); } - try + //return false; + + lock (m_sync) { LLUDPClient value; if (Dictionary1.TryGetValue(key1, out value)) @@ -116,22 +172,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP return true; } } - finally { rwLock.ExitWriteLock(); } return false; + } public void Clear() { - rwLock.EnterWriteLock(); + //rwLock.EnterWriteLock(); + + //try + //{ + // Dictionary1.Clear(); + // Dictionary2.Clear(); + // Array = new LLUDPClient[0]; + //} + //finally { rwLock.ExitWriteLock(); } - try + lock (m_sync) { Dictionary1.Clear(); Dictionary2.Clear(); Array = new LLUDPClient[0]; } - finally { rwLock.ExitWriteLock(); } + } public int Count @@ -151,35 +215,46 @@ namespace OpenSim.Region.ClientStack.LindenUDP public bool TryGetValue(UUID key, out LLUDPClient value) { - bool success; - bool doLock = !rwLock.IsUpgradeableReadLockHeld; - if (doLock) rwLock.EnterReadLock(); + //bool success; + //bool doLock = !rwLock.IsUpgradeableReadLockHeld; + //if (doLock) rwLock.EnterReadLock(); + + //try { success = Dictionary1.TryGetValue(key, out value); } + //finally { if (doLock) rwLock.ExitReadLock(); } - try { success = Dictionary1.TryGetValue(key, out value); } - finally { if (doLock) rwLock.ExitReadLock(); } + //return success; + + lock (m_sync) + return Dictionary1.TryGetValue(key, out value); - return success; } public bool TryGetValue(IPEndPoint key, out LLUDPClient value) { - bool success; - bool doLock = !rwLock.IsUpgradeableReadLockHeld; - if (doLock) rwLock.EnterReadLock(); + //bool success; + //bool doLock = !rwLock.IsUpgradeableReadLockHeld; + //if (doLock) rwLock.EnterReadLock(); + + //try { success = Dictionary2.TryGetValue(key, out value); } + //finally { if (doLock) rwLock.ExitReadLock(); } - try { success = Dictionary2.TryGetValue(key, out value); } - finally { if (doLock) rwLock.ExitReadLock(); } + //return success; - return success; + lock (m_sync) + return Dictionary2.TryGetValue(key, out value); } public void ForEach(Action action) { - bool doLock = !rwLock.IsUpgradeableReadLockHeld; - if (doLock) rwLock.EnterUpgradeableReadLock(); + //bool doLock = !rwLock.IsUpgradeableReadLockHeld; + //if (doLock) rwLock.EnterUpgradeableReadLock(); + + //try { Parallel.ForEach(Array, action); } + //finally { if (doLock) rwLock.ExitUpgradeableReadLock(); } + + lock (m_sync) + Parallel.ForEach(Array, action); - try { Parallel.ForEach(Array, action); } - finally { if (doLock) rwLock.ExitUpgradeableReadLock(); } } } } -- cgit v1.1 From dd80380df5e47c0d67466f7d509898a71e19abd0 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 7 Oct 2009 19:45:57 -0700 Subject: Another go at the deadlock: not locking TryGetValue, and just catch/ignore exceptions. --- .../ClientStack/LindenUDP/LLUDPClientCollection.cs | 46 +++++++++++++++------- 1 file changed, 31 insertions(+), 15 deletions(-) (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs index 9be9480..36e1f49 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs @@ -215,33 +215,49 @@ namespace OpenSim.Region.ClientStack.LindenUDP public bool TryGetValue(UUID key, out LLUDPClient value) { - //bool success; - //bool doLock = !rwLock.IsUpgradeableReadLockHeld; - //if (doLock) rwLock.EnterReadLock(); + ////bool success; + ////bool doLock = !rwLock.IsUpgradeableReadLockHeld; + ////if (doLock) rwLock.EnterReadLock(); - //try { success = Dictionary1.TryGetValue(key, out value); } - //finally { if (doLock) rwLock.ExitReadLock(); } + ////try { success = Dictionary1.TryGetValue(key, out value); } + ////finally { if (doLock) rwLock.ExitReadLock(); } - //return success; + ////return success; - lock (m_sync) - return Dictionary1.TryGetValue(key, out value); + //lock (m_sync) + // return Dictionary1.TryGetValue(key, out value); + try + { + return Dictionary1.TryGetValue(key, out value); + } + catch { } + value = null; + return false; } public bool TryGetValue(IPEndPoint key, out LLUDPClient value) { - //bool success; - //bool doLock = !rwLock.IsUpgradeableReadLockHeld; - //if (doLock) rwLock.EnterReadLock(); + ////bool success; + ////bool doLock = !rwLock.IsUpgradeableReadLockHeld; + ////if (doLock) rwLock.EnterReadLock(); - //try { success = Dictionary2.TryGetValue(key, out value); } - //finally { if (doLock) rwLock.ExitReadLock(); } + ////try { success = Dictionary2.TryGetValue(key, out value); } + ////finally { if (doLock) rwLock.ExitReadLock(); } - //return success; + ////return success; - lock (m_sync) + //lock (m_sync) + // return Dictionary2.TryGetValue(key, out value); + + try + { return Dictionary2.TryGetValue(key, out value); + } + catch { } + value = null; + return false; + } public void ForEach(Action action) -- cgit v1.1 From 68961ec0923fb613eae72f0f83ad3349e608cc05 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 7 Oct 2009 20:36:24 -0700 Subject: One last attempt at tunning the locking/no locking behaviour. The previous one was too lax and made the important login packets fail. --- .../ClientStack/LindenUDP/LLUDPClientCollection.cs | 26 +++++++++++++--------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs index 36e1f49..f6ccf01 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs @@ -247,16 +247,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP ////return success; - //lock (m_sync) - // return Dictionary2.TryGetValue(key, out value); - - try - { + lock (m_sync) return Dictionary2.TryGetValue(key, out value); - } - catch { } - value = null; - return false; + + //try + //{ + // return Dictionary2.TryGetValue(key, out value); + //} + //catch { } + //value = null; + //return false; } @@ -268,8 +268,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP //try { Parallel.ForEach(Array, action); } //finally { if (doLock) rwLock.ExitUpgradeableReadLock(); } + LLUDPClient[] localArray = null; lock (m_sync) - Parallel.ForEach(Array, action); + { + localArray = new LLUDPClient[Array.Length]; + Array.CopyTo(localArray, 0); + } + + Parallel.ForEach(localArray, action); } } -- cgit v1.1