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 89bad64c3d0058e7e648291db0d13e5de0b9205a
Author: Shad Storhaug <[email protected]>
AuthorDate: Thu Aug 12 21:30:20 2021 +0700

    BUG: Lucene.Net.Index.IndexReader: Use ConditionalWeakTable/WeakDictionary 
to ensure dead elements are pruned and garbage collected (fixes #506).
---
 src/Lucene.Net/Index/IndexReader.cs             | 29 +++++++++---
 src/Lucene.Net/Support/IdentityWeakReference.cs | 59 -------------------------
 2 files changed, 23 insertions(+), 65 deletions(-)

diff --git a/src/Lucene.Net/Index/IndexReader.cs 
b/src/Lucene.Net/Index/IndexReader.cs
index d97842f..c75c80b 100644
--- a/src/Lucene.Net/Index/IndexReader.cs
+++ b/src/Lucene.Net/Index/IndexReader.cs
@@ -100,7 +100,14 @@ namespace Lucene.Net.Index
 
         private readonly ISet<IReaderClosedListener> readerClosedListeners = 
new JCG.LinkedHashSet<IReaderClosedListener>().AsConcurrent();
 
-        private readonly ISet<IdentityWeakReference<IndexReader>> 
parentReaders = new ConcurrentHashSet<IdentityWeakReference<IndexReader>>();
+#if FEATURE_CONDITIONALWEAKTABLE_ENUMERATOR
+        private readonly ConditionalWeakTable<IndexReader, object> 
parentReaders = new ConditionalWeakTable<IndexReader, object>();
+#else
+        private readonly WeakDictionary<IndexReader, object> parentReaders = 
new WeakDictionary<IndexReader, object>();
+#endif
+        // LUCENENET specific - since neither WeakDictionary nor 
ConditionalWeakTable synchronize
+        // on the enumerator, we need to do external synchronization to make 
them threadsafe.
+        private readonly object parentReadersLock = new object();
 
         /// <summary>
         /// Expert: adds a <see cref="IReaderClosedListener"/>.  The
@@ -136,7 +143,14 @@ namespace Lucene.Net.Index
         public void RegisterParentReader(IndexReader reader)
         {
             EnsureOpen();
-            parentReaders.Add(new IdentityWeakReference<IndexReader>(reader));
+            // LUCENENET specific - since neither WeakDictionary nor 
ConditionalWeakTable synchronize
+            // on the enumerator, we need to do external synchronization to 
make them threadsafe.
+            lock (parentReadersLock)
+                // LUCENENET: Since there is a set Add operation (unique) in 
Lucene, the equivalent
+                // operation in .NET is AddOrUpdate, which effectively does 
nothing if the key exists.
+                // Null is passed as a value, since it is not used anyway and 
.NET doesn't have a boolean
+                // reference type.
+                parentReaders.AddOrUpdate(key: reader, value: null);
         }
 
         private void NotifyReaderClosedListeners(Exception th)
@@ -167,15 +181,18 @@ namespace Lucene.Net.Index
 
         private void ReportCloseToParentReaders()
         {
-            lock (parentReaders) // LUCENENET: This does not actually 
synchronize the set, it only ensures this method can only be entered by 1 thread
+            // LUCENENET specific - since neither WeakDictionary nor 
ConditionalWeakTable synchronize
+            // on the enumerator, we need to do external synchronization to 
make them threadsafe.
+            lock (parentReadersLock)
             {
-                foreach (IdentityWeakReference<IndexReader> parent in 
parentReaders)
+                foreach (var kvp in parentReaders)
                 {
-                    //Using weak references
-                    IndexReader target = parent.Target;
+                    IndexReader target = kvp.Key;
 
+                    // LUCENENET: This probably can't happen, but we are being 
defensive to avoid exceptions
                     if (target != null)
                     {
+                        //Using weak references
                         target.closedByChild = true;
                         // cross memory barrier by a fake write:
                         target.refCount.AddAndGet(0);
diff --git a/src/Lucene.Net/Support/IdentityWeakReference.cs 
b/src/Lucene.Net/Support/IdentityWeakReference.cs
deleted file mode 100644
index dac12b8..0000000
--- a/src/Lucene.Net/Support/IdentityWeakReference.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-using System;
-using System.Runtime.CompilerServices;
-
-namespace Lucene.Net.Support
-{
-    /*
-     * Licensed to the Apache Software Foundation (ASF) under one or more
-     * contributor license agreements.  See the NOTICE file distributed with
-     * this work for additional information regarding copyright ownership.
-     * The ASF licenses this file to You under the Apache License, Version 2.0
-     * (the "License"); you may not use this file except in compliance with
-     * the License.  You may obtain a copy of the License at
-     *
-     *     http://www.apache.org/licenses/LICENSE-2.0
-     *
-     * Unless required by applicable law or agreed to in writing, software
-     * distributed under the License is distributed on an "AS IS" BASIS,
-     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     * See the License for the specific language governing permissions and
-     * limitations under the License.
-     */
-
-    internal class IdentityWeakReference<T> : WeakReference
-        where T : class
-    {
-        private readonly int hash;
-        private static readonly object NULL = new object();
-
-        public IdentityWeakReference(T target)
-            : base(target ?? NULL)
-        {
-            hash = RuntimeHelpers.GetHashCode(target);
-        }
-
-        public override int GetHashCode()
-        {
-            return hash;
-        }
-
-        public override bool Equals(object o)
-        {
-            if (ReferenceEquals(this, o))
-            {
-                return true;
-            }
-            if (o is IdentityWeakReference<T> iwr && 
ReferenceEquals(this.Target, iwr.Target))
-            {
-                return true;
-            }
-            return false;
-        }
-
-        public new T Target
-        {   // note: if this.NULL is the target, it will not cast to T, so the 
"as" will return null as we would expect.
-            get => base.Target as T;
-            set => base.Target = value;
-        }
-    }
-}
\ No newline at end of file

Reply via email to