Jelajahi Sumber

Fear the lockless LLUDP implementation!

John Hurliman 14 tahun lalu
induk
melakukan
3a04d706c9

+ 60 - 192
OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs

@@ -30,6 +30,7 @@ using System.Collections.Generic;
 using System.Net;
 using OpenSim.Framework;
 using OpenMetaverse;
+using BclExtras.Collections;
 
 using ReaderWriterLockImpl = OpenMetaverse.ReaderWriterLockSlim;
 
@@ -37,246 +38,113 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 {
     public sealed class UDPClientCollection
     {
-        Dictionary<UUID, LLUDPClient> Dictionary1;
-        Dictionary<IPEndPoint, LLUDPClient> Dictionary2;
-        LLUDPClient[] Array;
-        ReaderWriterLockImpl rwLock = new ReaderWriterLockImpl();
-        object m_sync = new object();
+        #region IComparers
 
-        public UDPClientCollection()
-        {
-            Dictionary1 = new Dictionary<UUID, LLUDPClient>();
-            Dictionary2 = new Dictionary<IPEndPoint, LLUDPClient>();
-            Array = new LLUDPClient[0];
-        }
-
-        public UDPClientCollection(int capacity)
+        private sealed class UUIDComparer : IComparer<UUID>
         {
-            Dictionary1 = new Dictionary<UUID, LLUDPClient>(capacity);
-            Dictionary2 = new Dictionary<IPEndPoint, LLUDPClient>(capacity);
-            Array = new LLUDPClient[0];
+            public int Compare(UUID x, UUID y)
+            {
+                return x.Guid.CompareTo(y.Guid);
+            }
         }
 
-        public void Add(UUID key1, IPEndPoint key2, LLUDPClient value)
+        private sealed class IPEndPointComparer : IComparer<IPEndPoint>
         {
-            //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(); }
-
-            lock (m_sync)
+            public int Compare(IPEndPoint x, IPEndPoint y)
             {
-                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;
+                int result = x.Address.Address.CompareTo(y.Address.Address);
+                if (result == 0) result = x.Port.CompareTo(y.Port);
+                return result;
+            }
+        }
 
-                LLUDPClient[] newArray = new LLUDPClient[oldLength + 1];
-                for (int i = 0; i < oldLength; i++)
-                    newArray[i] = oldArray[i];
-                newArray[oldLength] = value;
+        #endregion IComparers
 
-                Array = newArray;
-            }
+        private ImmutableMap<UUID, LLUDPClient> m_dict1;
+        private ImmutableMap<IPEndPoint, LLUDPClient> m_dict2;
+        private LLUDPClient[] m_array;
 
+        public UDPClientCollection()
+        {
+            m_dict1 = new ImmutableMap<UUID, LLUDPClient>(new UUIDComparer());
+            m_dict2 = new ImmutableMap<IPEndPoint, LLUDPClient>(new IPEndPointComparer());
+            m_array = new LLUDPClient[0];
         }
 
-        public bool Remove(UUID key1, IPEndPoint key2)
+        public void Add(UUID key1, IPEndPoint key2, LLUDPClient value)
         {
-            //rwLock.EnterWriteLock();
-
-            //try
-            //{
-            //    LLUDPClient value;
-            //    if (Dictionary1.TryGetValue(key1, out value))
-            //    {
-            //        Dictionary1.Remove(key1);
-            //        Dictionary2.Remove(key2);
+            m_dict1 = m_dict1.Add(key1, value);
+            m_dict2 = m_dict2.Add(key2, value);
+
+            // Copy the array by hand
+            LLUDPClient[] oldArray = m_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;
+            
+            m_array = newArray;
+        }
 
-            //        LLUDPClient[] oldArray = Array;
-            //        int oldLength = oldArray.Length;
+        public void Remove(UUID key1, IPEndPoint key2)
+        {
+            m_dict1 = m_dict1.Delete(key1);
+            m_dict2 = m_dict2.Delete(key2);
 
-            //        LLUDPClient[] newArray = new LLUDPClient[oldLength - 1];
-            //        int j = 0;
-            //        for (int i = 0; i < oldLength; i++)
-            //        {
-            //            if (oldArray[i] != value)
-            //                newArray[j++] = oldArray[i];
-            //        }
+            LLUDPClient[] oldArray = m_array;
+            int oldLength = oldArray.Length;
 
-            //        Array = newArray;
-            //        return true;
-            //    }
-            //}
-            //finally { rwLock.ExitWriteLock(); }
+            // Copy the array by hand
 
-            //return false;
+            LLUDPClient[] newArray = new LLUDPClient[oldLength - 1];
+            int j = 0;
 
-            lock (m_sync)
+            for (int i = 0; i < oldLength; i++)
             {
-                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;
-                }
+                if (oldArray[i].AgentID != key1)
+                    newArray[j++] = oldArray[i];
             }
 
-            return false;
-
+            m_array = newArray;
         }
 
         public void Clear()
         {
-            //rwLock.EnterWriteLock();
-
-            //try
-            //{
-            //    Dictionary1.Clear();
-            //    Dictionary2.Clear();
-            //    Array = new LLUDPClient[0];
-            //}
-            //finally { rwLock.ExitWriteLock(); }
-
-            lock (m_sync)
-            {
-                Dictionary1.Clear();
-                Dictionary2.Clear();
-                Array = new LLUDPClient[0];
-            }
-
+            m_dict1 = new ImmutableMap<UUID, LLUDPClient>(new UUIDComparer());
+            m_dict2 = new ImmutableMap<IPEndPoint, LLUDPClient>(new IPEndPointComparer());
+            m_array = new LLUDPClient[0];
         }
 
         public int Count
         {
-            get { return Array.Length; }
+            get { return m_array.Length; }
         }
 
         public bool ContainsKey(UUID key)
         {
-            return Dictionary1.ContainsKey(key);
+            return m_dict1.ContainsKey(key);
         }
 
         public bool ContainsKey(IPEndPoint key)
         {
-            return Dictionary2.ContainsKey(key);
+            return m_dict2.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;
-
-            lock (m_sync)
-                return Dictionary1.TryGetValue(key, out value); 
-
-            //try
-            //{
-            //    return Dictionary1.TryGetValue(key, out value);
-            //}
-            //catch { }
-            //value = null;
-            //return false;
+            return m_dict1.TryGetValue(key, out value);
         }
 
         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;
-
-            lock (m_sync)
-                return Dictionary2.TryGetValue(key, out value);
-
-            //try
-            //{
-            //    return Dictionary2.TryGetValue(key, out value);
-            //}
-            //catch { }
-            //value = null;
-            //return false;
-
+            return m_dict2.TryGetValue(key, out value);
         }
 
         public void ForEach(Action<LLUDPClient> action)
         {
-            //bool doLock = !rwLock.IsUpgradeableReadLockHeld;
-            //if (doLock) rwLock.EnterUpgradeableReadLock();
-
-            //try { Parallel.ForEach<LLUDPClient>(Array, action); }
-            //finally { if (doLock) rwLock.ExitUpgradeableReadLock(); }
-
-            LLUDPClient[] localArray = null;
-            lock (m_sync)
-            {
-                localArray = new LLUDPClient[Array.Length];
-                Array.CopyTo(localArray, 0);
-            }
-
-            Parallel.ForEach<LLUDPClient>(localArray, action); 
-
+            Parallel.ForEach<LLUDPClient>(m_array, action); 
         }
     }
 }

+ 60 - 0
ThirdPartyLicenses/BclExtras.txt

@@ -0,0 +1,60 @@
+MICROSOFT PUBLIC LICENSE (Ms-PL)
+
+This license governs use of the accompanying software. If you use the software, 
+you accept this license. If you do not accept the license, do not use the 
+software.
+
+1. Definitions
+
+The terms "reproduce," "reproduction," "derivative works," and "distribution" 
+have the same meaning here as under U.S. copyright law.
+
+A "contribution" is the original software, or any additions or changes to the 
+software.
+
+A "contributor" is any person that distributes its contribution under this 
+license.
+
+"Licensed patents" are a contributor's patent claims that read directly on its 
+contribution.
+
+2. Grant of Rights
+
+(A) Copyright Grant- Subject to the terms of this license, including the license
+conditions and limitations in section 3, each contributor grants you a 
+non-exclusive, worldwide, royalty-free copyright license to reproduce its 
+contribution, prepare derivative works of its contribution, and distribute its 
+contribution or any derivative works that you create.
+
+(B) Patent Grant- Subject to the terms of this license, including the license 
+conditions and limitations in section 3, each contributor grants you a 
+non-exclusive, worldwide, royalty-free license under its licensed patents to 
+make, have made, use, sell, offer for sale, import, and/or otherwise dispose of 
+its contribution in the software or derivative works of the contribution in the 
+software.
+
+3. Conditions and Limitations
+
+(A) No Trademark License- This license does not grant you rights to use any 
+contributors' name, logo, or trademarks.
+
+(B) If you bring a patent claim against any contributor over patents that you 
+claim are infringed by the software, your patent license from such contributor 
+to the software ends automatically.
+
+(C) If you distribute any portion of the software, you must retain all 
+copyright, patent, trademark, and attribution notices that are present in the 
+software.
+
+(D) If you distribute any portion of the software in source code form, you may 
+do so only under this license by including a complete copy of this license with 
+your distribution. If you distribute any portion of the software in compiled or 
+object code form, you may only do so under a license that complies with this 
+license.
+
+(E) The software is licensed "as-is." You bear the risk of using it. The 
+contributors give no express warranties, guarantees or conditions. You may have 
+additional consumer rights under your local laws which this license cannot 
+change. To the extent permitted under your local laws, the contributors exclude 
+the implied warranties of merchantability, fitness for a particular purpose and 
+non-infringement.

+ 28 - 0
ThirdPartyLicenses/CSJ2K.txt

@@ -0,0 +1,28 @@
+Copyright (c) 1999/2000 JJ2000 Partners.
+
+This software module was originally developed by Raphaël Grosbois and
+Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
+Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
+Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
+Centre France S.A) in the course of development of the JPEG2000
+standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
+software module is an implementation of a part of the JPEG 2000
+Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
+Systems AB and Canon Research Centre France S.A (collectively JJ2000
+Partners) agree not to assert against ISO/IEC and users of the JPEG
+2000 Standard (Users) any of their rights under the copyright, not
+including other intellectual property rights, for this software module
+with respect to the usage by ISO/IEC and Users of this software module
+or modifications thereof for use in hardware or software products
+claiming conformance to the JPEG 2000 Standard. Those intending to use
+this software module in hardware or software products are advised that
+their use may infringe existing patents. The original developers of
+this software module, JJ2000 Partners and ISO/IEC assume no liability
+for use of this software module or modifications thereof. No license
+or right to this software module is granted for non JPEG 2000 Standard
+conforming products. JJ2000 Partners have full right to use this
+software module for his/her own purpose, assign or donate this
+software module to any third party and to inhibit third parties from
+using this software module for non JPEG 2000 Standard conforming
+products. This copyright notice must be included in all copies or
+derivative works of this software module.

TEMPAT SAMPAH
bin/BclExtras.dll


+ 1 - 0
prebuild.xml

@@ -1767,6 +1767,7 @@
       <Reference name="OpenSim.Region.Communications.Local"/>
       <Reference name="OpenSim.Region.Physics.Manager"/>
       <Reference name="OpenSim.Services.Interfaces"/>
+      <Reference name="BclExtras.dll"/>
       <Reference name="XMLRPC.dll"/>
       <Reference name="Nini.dll" />
       <Reference name="log4net.dll"/>