You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucenenet.apache.org by sy...@apache.org on 2016/10/02 10:17:18 UTC

[47/49] lucenenet git commit: Finished implementation of Core.Util.TestWeakIdenityMap and fixed some bugs with the enumerator logic of WeakIdenityMap (test still failing).

Finished implementation of Core.Util.TestWeakIdenityMap and fixed some bugs with the enumerator logic of WeakIdenityMap (test still failing).


Project: http://git-wip-us.apache.org/repos/asf/lucenenet/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucenenet/commit/e8b44e75
Tree: http://git-wip-us.apache.org/repos/asf/lucenenet/tree/e8b44e75
Diff: http://git-wip-us.apache.org/repos/asf/lucenenet/diff/e8b44e75

Branch: refs/heads/master
Commit: e8b44e751130bfe1e01489a7879e13eaf1090061
Parents: 44a5cb5
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Sun Sep 18 05:25:09 2016 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Sun Sep 18 07:28:41 2016 +0700

----------------------------------------------------------------------
 src/Lucene.Net.Core/Util/WeakIdentityMap.cs     | 175 ++++++++++---------
 .../core/Util/TestWeakIdentityMap.cs            | 146 +++++++++-------
 2 files changed, 179 insertions(+), 142 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e8b44e75/src/Lucene.Net.Core/Util/WeakIdentityMap.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Core/Util/WeakIdentityMap.cs b/src/Lucene.Net.Core/Util/WeakIdentityMap.cs
index aa4e1a8..7d2ce1c 100644
--- a/src/Lucene.Net.Core/Util/WeakIdentityMap.cs
+++ b/src/Lucene.Net.Core/Util/WeakIdentityMap.cs
@@ -2,7 +2,9 @@ using Lucene.Net.Support;
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
+using System.Linq;
 using System.Runtime.CompilerServices;
+using System.Collections;
 
 namespace Lucene.Net.Util
 {
@@ -72,7 +74,7 @@ namespace Lucene.Net.Util
         /// Creates a new {@code WeakIdentityMap} based on a non-synchronized <seealso cref="HashMap"/>.
         /// The map <a href="#reapInfo">cleans up the reference queue on every read operation</a>.
         /// </summary>
-        public static WeakIdentityMap<K, V> newHashMap()
+        public static WeakIdentityMap<K, V> NewHashMap()
         {
             return NewHashMap(false);
         }
@@ -162,20 +164,37 @@ namespace Lucene.Net.Util
 
         public IEnumerable<K> Keys
         {
-            // .NET port: using this method which mimics IDictionary instead of KeyIterator()
             get
             {
-                foreach (var key in BackingStore.Keys)
-                {
-                    var target = key.Target;
+                return new KeyWrapper(this);
+            }
+        }
 
-                    if (target == null)
-                        continue;
-                    else if (target == NULL)
-                        yield return null;
-                    else
-                        yield return (K)target;
-                }
+        /// <summary>
+        /// LUCENENET specific class to allow the 
+        /// GetEnumerator() method to be overridden
+        /// for the keys so we can return an enumerator
+        /// that is smart enough to clean up the dead keys
+        /// and also so that MoveNext() returns false in the
+        /// event there are no more values left (instead of returning
+        /// a null value in an extra enumeration).
+        /// </summary>
+        private class KeyWrapper : IEnumerable<K>
+        {
+            private readonly WeakIdentityMap<K, V> outerInstance;
+            public KeyWrapper(WeakIdentityMap<K, V> outerInstance)
+            {
+                this.outerInstance = outerInstance;
+            }
+            public IEnumerator<K> GetEnumerator()
+            {
+                outerInstance.Reap();
+                return new IteratorAnonymousInnerClassHelper(outerInstance);
+            }
+
+            IEnumerator IEnumerable.GetEnumerator()
+            {
+                return GetEnumerator();
             }
         }
 
@@ -229,93 +248,87 @@ namespace Lucene.Net.Util
             return BackingStore.Count;
         }
 
-        /*LUCENE TO-DO I don't think necessary
-        /// <summary>
-        /// Returns an iterator over all weak keys of this map.
-        /// Keys already garbage collected will not be returned.
-        /// this Iterator does not support removals.
-        /// </summary>
-        public IEnumerator<K> KeyIterator()
-        {
-          Reap();
-          IEnumerator<IdentityWeakReference> iterator = BackingStore.Keys.GetEnumerator();
-          // IMPORTANT: Don't use oal.util.FilterIterator here:
-          // We need *strong* reference to current key after setNext()!!!
-          return new IteratorAnonymousInnerClassHelper(this, iterator);
-        }
-
-        private class IteratorAnonymousInnerClassHelper : Iterator<K>
+        private class IteratorAnonymousInnerClassHelper : IEnumerator<K>
         {
-            private readonly WeakIdentityMap<K,V> OuterInstance;
-
-            private IEnumerator<IdentityWeakReference> Iterator;
+            private readonly WeakIdentityMap<K,V> outerInstance;
 
-            public IteratorAnonymousInnerClassHelper(WeakIdentityMap<K,V> outerInstance, IEnumerator<IdentityWeakReference> iterator)
+            public IteratorAnonymousInnerClassHelper(WeakIdentityMap<K,V> outerInstance)
             {
-                this.OuterInstance = outerInstance;
-                this.Iterator = iterator;
-                next = null;
-                nextIsSet = false;
+                this.outerInstance = outerInstance;
             }
 
-              // holds strong reference to next element in backing iterator:
-            private object next;
-            // the backing iterator was already consumed:
-            private bool nextIsSet;
-            /
-            public virtual bool HasNext()
+            // holds strong reference to next element in backing iterator:
+            private object next = null;
+            private int position = -1; // start before the beginning of the set
+
+            public K Current
             {
-              return nextIsSet || SetNext();
+                get
+                {
+                    return (K)next;
+                }
             }
 
-            public virtual K Next()
+            object IEnumerator.Current
             {
-              if (!HasNext())
-              {
-                throw new Exception();
-              }
-              Debug.Assert(nextIsSet);
-              try
-              {
-                return (K) next;
-              }
-              finally
-              {
-                 // release strong reference and invalidate current value:
-                nextIsSet = false;
-                next = null;
-              }
+                get
+                {
+                    return Current;
+                }
             }
 
-            public virtual void Remove()
+            public void Dispose()
             {
-              throw new System.NotSupportedException();
+                // Nothing to do
             }
 
-            private bool SetNext()
+            
+            public bool MoveNext()
             {
-              Debug.Assert(!nextIsSet);
-              while (Iterator.MoveNext())
-              {
-                next = Iterator.Current;
-                if (next == null)
-                {
-                  // the key was already GCed, we can remove it from backing map:
-                  Iterator.remove();
-                }
-                else
+                while (true)
                 {
-                  // unfold "null" special value:
-                  if (next == NULL)
-                  {
-                    next = null;
-                  }
-                  return nextIsSet = true;
+                    IdentityWeakReference key;
+
+                    // If the next position doesn't exist, exit
+                    if (++position >= outerInstance.BackingStore.Count)
+                    {
+                        position--;
+                        return false;
+                    }
+                    try
+                    {
+                        key = outerInstance.BackingStore.Keys.ElementAt(position);
+                    }
+                    catch (ArgumentOutOfRangeException)
+                    {
+                        // some other thread beat us to the last element (or removed a prior element) - fail gracefully.
+                        position--;
+                        return false;
+                    }
+                    if (!key.IsAlive)
+                    {
+                        outerInstance.BackingStore.Remove(key);
+                        position--;
+                        continue;
+                    }
+                    // unfold "null" special value:
+                    if (key.Target == NULL)
+                    {
+                        next = null;
+                    }
+                    else
+                    {
+                        next = key.Target;
+                    }
+                    return true;
                 }
-              }
-              return false;
             }
-        }*/
+
+            public void Reset()
+            {
+                throw new NotSupportedException();
+            }
+        }
 
         /// <summary>
         /// Returns an iterator over all values of this map.

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e8b44e75/src/Lucene.Net.Tests/core/Util/TestWeakIdentityMap.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests/core/Util/TestWeakIdentityMap.cs b/src/Lucene.Net.Tests/core/Util/TestWeakIdentityMap.cs
index 82c5c4c..3eff002 100644
--- a/src/Lucene.Net.Tests/core/Util/TestWeakIdentityMap.cs
+++ b/src/Lucene.Net.Tests/core/Util/TestWeakIdentityMap.cs
@@ -2,7 +2,9 @@ using Lucene.Net.Randomized.Generators;
 using Lucene.Net.Support;
 using NUnit.Framework;
 using System;
+using System.Collections.Concurrent;
 using System.Collections.Generic;
+using System.Globalization;
 using System.Threading;
 
 namespace Lucene.Net.Util
@@ -103,12 +105,12 @@ namespace Lucene.Net.Util
             Assert.AreEqual(3, map.Size());
 
             int c = 0, keysAssigned = 0;
-            for (IEnumerator<string> iter = map.Keys.GetEnumerator(); iter.MoveNext(); )
+            for (IEnumerator<string> iter = map.Keys.GetEnumerator(); iter.MoveNext();)
             {
                 //Assert.IsTrue(iter.hasNext()); // try again, should return same result!
                 string k = iter.Current;
-                Assert.IsTrue(k == key1 || k == key2 | k == key3);
                 // LUCENENET NOTE: Need object.ReferenceEquals here because the == operator does more than check reference equality
+                Assert.IsTrue(object.ReferenceEquals(k, key1) || object.ReferenceEquals(k, key2) | object.ReferenceEquals(k, key3));
                 keysAssigned += object.ReferenceEquals(k, key1) ? 1 : (object.ReferenceEquals(k, key2) ? 2 : 4);
                 c++;
             }
@@ -116,7 +118,7 @@ namespace Lucene.Net.Util
             Assert.AreEqual(1 + 2 + 4, keysAssigned, "all keys must have been seen");
 
             c = 0;
-            for (IEnumerator<string> iter = map.Values.GetEnumerator(); iter.MoveNext(); )
+            for (IEnumerator<string> iter = map.Values.GetEnumerator(); iter.MoveNext();)
             {
                 string v = iter.Current;
                 Assert.IsTrue(v.StartsWith("bar"));
@@ -133,15 +135,13 @@ namespace Lucene.Net.Util
             {
                 try
                 {
-                    //System.RunFinalization();
-                    //System.gc();
                     GC.Collect();
                     int newSize = map.Size();
                     Assert.IsTrue(size >= newSize, "previousSize(" + size + ")>=newSize(" + newSize + ")");
                     size = newSize;
-                    Thread.Sleep(new TimeSpan(0, 0, 1));
+                    Thread.Sleep(TimeSpan.FromSeconds(1));
                     c = 0;
-                    for (IEnumerator<string> iter = map.Keys.GetEnumerator(); iter.MoveNext(); )
+                    for (IEnumerator<string> iter = map.Keys.GetEnumerator(); iter.MoveNext();)
                     {
                         Assert.IsNotNull(iter.Current);
                         c++;
@@ -188,22 +188,20 @@ namespace Lucene.Net.Util
             Assert.IsTrue(map.Empty);
         }
 
-        /* LUCENENET TODO: Compile issues
         [Test]
         public virtual void TestConcurrentHashMap()
         {
             // don't make threadCount and keyCount random, otherwise easily OOMs or fails otherwise:
             const int threadCount = 8, keyCount = 1024;
 
-            System.Threading.ThreadPool.QueueUserWorkItem(;
-            //ExecutorService exec = Executors.newFixedThreadPool(threadCount, new NamedThreadFactory("testConcurrentHashMap"));
+            RunnableAnonymousInnerClassHelper[] workers = new RunnableAnonymousInnerClassHelper[threadCount];
             WeakIdentityMap<object, int?> map = WeakIdentityMap<object, int?>.NewConcurrentHashMap(Random().NextBoolean());
             // we keep strong references to the keys,
             // so WeakIdentityMap will not forget about them:
             AtomicReferenceArray<object> keys = new AtomicReferenceArray<object>(keyCount);
             for (int j = 0; j < keyCount; j++)
             {
-                keys.Set(j, new object());
+                keys[j] = new object();
             }
 
             try
@@ -211,19 +209,33 @@ namespace Lucene.Net.Util
                 for (int t = 0; t < threadCount; t++)
                 {
                     Random rnd = new Random(Random().Next());
-                    exec.execute(new RunnableAnonymousInnerClassHelper(this, keyCount, map, keys, rnd));
+                    var worker = new RunnableAnonymousInnerClassHelper(this, keyCount, map, keys, rnd);
+                    workers[t] = worker;
+                    worker.Start();
                 }
             }
             finally
             {
-                exec.shutdown();
-                while (!exec.awaitTermination(1000L, TimeUnit.MILLISECONDS)) ;
+                foreach (var w in workers)
+                {
+                    w.Join(1000L);
+                }
             }
 
+            // LUCENENET: Since assertions were done on the other threads, we need to check the
+            // results here.
+            for (int i = 0; i < workers.Length; i++)
+            {
+                assertTrue(string.Format(CultureInfo.InvariantCulture,
+                    "worker thread {0} of {1} failed \n" + workers[i].Error, i, workers.Length),
+                    workers[i].Error == null);
+            }
+
+
             // clear strong refs
             for (int j = 0; j < keyCount; j++)
             {
-                keys.Set(j, null);
+                keys[j] = null;
             }
 
             // check that GC does not cause problems in reap() method:
@@ -232,8 +244,6 @@ namespace Lucene.Net.Util
             {
                 try
                 {
-                    //System.runFinalization();
-                    //System.gc();
                     GC.Collect();
                     int newSize = map.Size();
                     Assert.IsTrue(size >= newSize, "previousSize(" + size + ")>=newSize(" + newSize + ")");
@@ -256,63 +266,77 @@ namespace Lucene.Net.Util
             }
         }
 
-        private class RunnableAnonymousInnerClassHelper : IThreadRunnable
+        private class RunnableAnonymousInnerClassHelper : ThreadClass
         {
-            private readonly TestWeakIdentityMap OuterInstance;
+            private readonly TestWeakIdentityMap outerInstance;
 
-            private int KeyCount;
-            private WeakIdentityMap<object, int?> Map;
-            private AtomicReferenceArray<object> Keys;
-            private Random Rnd;
+            private readonly int keyCount;
+            private readonly WeakIdentityMap<object, int?> map;
+            private AtomicReferenceArray<object> keys;
+            private readonly Random rnd;
+            private volatile Exception error;
 
             public RunnableAnonymousInnerClassHelper(TestWeakIdentityMap outerInstance, int keyCount, WeakIdentityMap<object, int?> map, AtomicReferenceArray<object> keys, Random rnd)
             {
-                this.OuterInstance = outerInstance;
-                this.KeyCount = keyCount;
-                this.Map = map;
-                this.Keys = keys;
-                this.Rnd = rnd;
+                this.outerInstance = outerInstance;
+                this.keyCount = keyCount;
+                this.map = map;
+                this.keys = keys;
+                this.rnd = rnd;
             }
 
-            public void Run()
+            public Exception Error
             {
-                int count = AtLeast(Rnd, 10000);
-                for (int i = 0; i < count; i++)
+                get { return error; }
+            }
+
+
+            public override void Run()
+            {
+                int count = AtLeast(rnd, 10000);
+                try
                 {
-                    int j = Rnd.Next(KeyCount);
-                    switch (Rnd.Next(5))
+                    for (int i = 0; i < count; i++)
                     {
-                        case 0:
-                            Map.Put(Keys.Get(j), Convert.ToInt32(j));
-                            break;
-                        case 1:
-                            int? v = Map.Get(Keys.Get(j));
-                            if (v != null)
-                            {
-                                Assert.AreEqual(j, (int)v);
-                            }
-                            break;
-                        case 2:
-                            Map.Remove(Keys.Get(j));
-                            break;
-                        case 3:
-                            // renew key, the old one will be GCed at some time:
-                            Keys.Set(j, new object());
-                            break;
-                        case 4:
-                            // check iterator still working
-                            for (IEnumerator<object> it = Map.Keys.GetEnumerator(); it.MoveNext();)
-                            {
-                                Assert.IsNotNull(it.Current);
-                            }
-                            break;
-                        default:
-                            Assert.Fail("Should not get here.");
-                            break;
+                        int j = rnd.Next(keyCount);
+                        switch (rnd.Next(5))
+                        {
+                            case 0:
+                                map.Put(keys[j], Convert.ToInt32(j));
+                                break;
+                            case 1:
+                                int? v = map.Get(keys[j]);
+                                if (v != null)
+                                {
+                                    Assert.AreEqual(j, (int)v);
+                                }
+                                break;
+                            case 2:
+                                map.Remove(keys[j]);
+                                break;
+                            case 3:
+                                // renew key, the old one will be GCed at some time:
+                                keys[j] = new object();
+                                break;
+                            case 4:
+                                // check iterator still working
+                                for (IEnumerator<object> it = map.Keys.GetEnumerator(); it.MoveNext();)
+                                {
+                                    Assert.IsNotNull(it.Current);
+                                }
+                                break;
+                            default:
+                                Assert.Fail("Should not get here.");
+                                break;
+                        }
                     }
                 }
+                catch (Exception e)
+                {
+                    e.printStackTrace();
+                    this.error = e;
+                }
             }
         }
-        */
     }
 }
\ No newline at end of file