This is an automated email from the ASF dual-hosted git repository.

nightowl888 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/lucenenet.git

commit 1fe3b485e6210ab440e82e8e486dbbd0368928cb
Author: Shad Storhaug <[email protected]>
AuthorDate: Fri Aug 13 01:58:38 2021 +0700

    Lucene.Net.Support.WeakDictionary: Changed WeakKey to use WeakReference<T> 
instead of WeakReference to avoid problems with garbage collection (see #506).
---
 src/Lucene.Net/Support/WeakDictionary.cs | 52 +++++++++++++++++---------------
 1 file changed, 28 insertions(+), 24 deletions(-)

diff --git a/src/Lucene.Net/Support/WeakDictionary.cs 
b/src/Lucene.Net/Support/WeakDictionary.cs
index 12673ad..1633499 100644
--- a/src/Lucene.Net/Support/WeakDictionary.cs
+++ b/src/Lucene.Net/Support/WeakDictionary.cs
@@ -19,12 +19,10 @@
  *
 */
 
-
 #if !FEATURE_CONDITIONALWEAKTABLE_ENUMERATOR
 using System;
 using System.Collections;
 using System.Collections.Generic;
-using System.Linq;
 using JCG = J2N.Collections.Generic;
 
 namespace Lucene.Net.Support
@@ -66,9 +64,16 @@ namespace Lucene.Net.Support
         {
             if (_hm.Count == 0) return;
             var newHm = new JCG.Dictionary<WeakKey<TKey>, TValue>(_hm.Count);
-            foreach (var entry in _hm.Where(x => x.Key != null && 
x.Key.IsAlive))
+            foreach (var kvp in _hm)
             {
-                newHm.Add(entry.Key, entry.Value);
+                if (kvp.Key.TryGetTarget(out TKey _))
+                {
+                    // LUCENENET: There is a tiny chance that a call to remove 
the item
+                    // from the dictionary can happen before this line is 
executed. Therefore,
+                    // just discard the reference and add it as is, even if it 
is no longer valid
+                    // in this edge case. It is far more efficient to re-use 
the same instances, anyway.
+                    newHm.Add(kvp.Key, kvp.Value);
+                }
             }
             _hm = newHm;
         }
@@ -85,9 +90,12 @@ namespace Lucene.Net.Support
 
         public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
         {
-            foreach (var kvp in _hm.Where(x => x.Key.IsAlive))
+            foreach (var kvp in _hm)
             {
-                yield return new KeyValuePair<TKey, TValue>(kvp.Key.Target, 
kvp.Value);
+                if (kvp.Key.TryGetTarget(out TKey key))
+                {
+                    yield return new KeyValuePair<TKey, TValue>(key, 
kvp.Value);
+                }
             }
         }
 
@@ -185,7 +193,7 @@ namespace Lucene.Net.Support
             throw new NotSupportedException();
         }
 
-#region KeyCollection
+        #region Nested Class: KeyCollection
 
         private class KeyCollection : ICollection<TKey>
         {
@@ -200,7 +208,8 @@ namespace Lucene.Net.Support
             {
                 foreach (var key in _internalDict.Keys)
                 {
-                    yield return key.Target;
+                    if (key.TryGetTarget(out TKey target))
+                        yield return target;
                 }
             }
 
@@ -243,7 +252,7 @@ namespace Lucene.Net.Support
 #endregion Explicit Interface Definitions
         }
 
-#endregion KeyCollection
+        #endregion Nested Class: KeyCollection
 
         /// <summary>
         /// A weak reference wrapper for the hashtable keys. Whenever a 
key\value pair
@@ -252,7 +261,7 @@ namespace Lucene.Net.Support
         /// </summary>
         private class WeakKey<T> where T : class
         {
-            private readonly WeakReference reference;
+            private readonly WeakReference<T> reference;
             private readonly int hashCode;
 
             public WeakKey(T key)
@@ -260,8 +269,8 @@ namespace Lucene.Net.Support
                 if (key is null)
                     throw new ArgumentNullException(nameof(key));
 
-                hashCode = key.GetHashCode();
-                reference = new WeakReference(key);
+                hashCode = key is null ? 0 : key.GetHashCode();
+                reference = new WeakReference<T>(key);
             }
 
             public override int GetHashCode()
@@ -271,25 +280,20 @@ namespace Lucene.Net.Support
 
             public override bool Equals(object obj)
             {
-                if (!reference.IsAlive || obj is null) return false;
-
-                if (object.ReferenceEquals(this, obj))
-                {
-                    return true;
-                }
-
+                if (obj is null) return false;
                 if (obj is WeakKey<T> other)
                 {
-                    var referenceTarget = reference.Target; // Careful: can be 
null in the mean time...
-                    return referenceTarget != null && 
referenceTarget.Equals(other.Target);
+                    bool gotThis = this.TryGetTarget(out T thisTarget), 
gotOther = other.TryGetTarget(out T otherTarget);
+                    if (gotThis && gotOther && thisTarget.Equals(otherTarget))
+                        return true;
+                    else if (gotThis == false && gotOther == false)
+                        return true;
                 }
 
                 return false;
             }
 
-            public T Target => (T)reference.Target;
-
-            public bool IsAlive => reference.IsAlive;
+            public bool TryGetTarget(out T target) => 
reference.TryGetTarget(out target);
         }
     }
 }

Reply via email to