You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucenenet.apache.org by ni...@apache.org on 2020/01/30 08:15:49 UTC

[lucenenet] branch master updated (b50b42e -> b0b2b23)

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

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


    from b50b42e  Updated README
     new 01ddd63  Lucene.Net.Spatial.Util.ShapeFieldCacheProvider: Simplified cache value creation by using ConditionalWeakTable<TKey, TValue>.GetValue(), and removed dependency on WeakDictionary (See LUCENENET-610, LUCENENET-640).
     new e73e44b  Lucene.Net.TestFramework.Search.AssertingScorer: Reverted back to using WeakReference for the value, since values are strongly referenced in ConditionalWeakTable
     new 6366760  Lucene.Net.Support.WeakDictionary: Removed unnecessary cast, marked class internal
     new b4e6f0f  Lucene.Net.Search.FieldCacheImpl: Switched to ConcurrentDictionary for the innerCache to try to reduce locking (LUCENENET-610)
     new c867278  Lucene.Net.Facet.Taxonomy.CachedOrdinalsReader: Removed locking for ordsCache when using ConditionalWeakTable (See LUCENENET-610, LUCENENET-640, LUCENENET-630)
     new bb873f4  Lucene.Net.Support: Renamed ConcurrentHashMapWrapper > ConcurrentDictionaryWrapper, marked internal, and added DictionaryExtensions.AsConcurrent() extension method to make usage simpler
     new a3f18b4  Lucene.Net.Support: Added compatibility for nullable attributes, which are not supported prior to .NET Standard 2.1
     new f1c1629  Fix duplicate FragNum value on Highlight.TextFragment
     new b0b2b23  Merge remote-tracking branch 'segovia/master'

The 9 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../Taxonomy/CachedOrdinalsReader.cs               |  30 ++---
 src/Lucene.Net.Facet/TopOrdAndFloatQueue.cs        |   2 +-
 src/Lucene.Net.Facet/TopOrdAndIntQueue.cs          |   2 +-
 .../Highlight/TextFragment.cs                      |   6 +-
 .../Util/ShapeFieldCacheProvider.cs                |  24 +---
 .../Index/ThreadedIndexingAndSearchingTestCase.cs  |   3 +-
 .../Search/AssertingScorer.cs                      |  13 +-
 src/Lucene.Net/Properties/AssemblyInfo.cs          |   3 +-
 src/Lucene.Net/Search/CachingWrapperFilter.cs      |   3 +-
 src/Lucene.Net/Search/FieldCacheImpl.cs            | 112 +++++++++--------
 .../Support/Compatibility/NullableAttributes.cs    | 140 +++++++++++++++++++++
 ...apWrapper.cs => ConcurrentDictionaryWrapper.cs} |  36 +++---
 src/Lucene.Net/Support/DictionaryExtensions.cs     |  51 +++++---
 src/Lucene.Net/Support/WeakDictionary.cs           |   6 +-
 14 files changed, 289 insertions(+), 142 deletions(-)
 create mode 100644 src/Lucene.Net/Support/Compatibility/NullableAttributes.cs
 rename src/Lucene.Net/Support/{ConcurrentHashMapWrapper.cs => ConcurrentDictionaryWrapper.cs} (83%)


[lucenenet] 08/09: Lucene.Net.Support: Added compatibility for nullable attributes, which are not supported prior to .NET Standard 2.1

Posted by ni...@apache.org.
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 a3f18b4ac03a62dcda50f9555fbed57146a7f730
Author: Shad Storhaug <sh...@shadstorhaug.com>
AuthorDate: Tue Jan 28 00:21:45 2020 +0700

    Lucene.Net.Support: Added compatibility for nullable attributes, which are not supported prior to .NET Standard 2.1
---
 .../Support/Compatibility/NullableAttributes.cs    | 140 +++++++++++++++++++++
 1 file changed, 140 insertions(+)

diff --git a/src/Lucene.Net/Support/Compatibility/NullableAttributes.cs b/src/Lucene.Net/Support/Compatibility/NullableAttributes.cs
new file mode 100644
index 0000000..fbfb4b9
--- /dev/null
+++ b/src/Lucene.Net/Support/Compatibility/NullableAttributes.cs
@@ -0,0 +1,140 @@
+#pragma warning disable MA0048 // File name must match type name
+#define INTERNAL_NULLABLE_ATTRIBUTES
+#if NETSTANDARD1_6 || NETSTANDARD2_0 || NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 || NET45 || NET451 || NET452 || NET6 || NET461 || NET462 || NET47 || NET471 || NET472 || NET48
+
+// https://github.com/dotnet/corefx/blob/48363ac826ccf66fbe31a5dcb1dc2aab9a7dd768/src/Common/src/CoreLib/System/Diagnostics/CodeAnalysis/NullableAttributes.cs
+
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Diagnostics.CodeAnalysis
+{
+    /// <summary>Specifies that null is allowed as an input even if the corresponding type disallows it.</summary>
+    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
+#if INTERNAL_NULLABLE_ATTRIBUTES
+    internal
+#else
+    public
+#endif
+        sealed class AllowNullAttribute : Attribute
+    { }
+
+    /// <summary>Specifies that null is disallowed as an input even if the corresponding type allows it.</summary>
+    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
+#if INTERNAL_NULLABLE_ATTRIBUTES
+    internal
+#else
+    public
+#endif
+        sealed class DisallowNullAttribute : Attribute
+    { }
+
+    /// <summary>Specifies that an output may be null even if the corresponding type disallows it.</summary>
+    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
+#if INTERNAL_NULLABLE_ATTRIBUTES
+    internal
+#else
+    public
+#endif
+        sealed class MaybeNullAttribute : Attribute
+    { }
+
+    /// <summary>Specifies that an output will not be null even if the corresponding type allows it.</summary>
+    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
+#if INTERNAL_NULLABLE_ATTRIBUTES
+    internal
+#else
+    public
+#endif
+        sealed class NotNullAttribute : Attribute
+    { }
+
+    /// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter may be null even if the corresponding type disallows it.</summary>
+    [AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
+#if INTERNAL_NULLABLE_ATTRIBUTES
+    internal
+#else
+    public
+#endif
+        sealed class MaybeNullWhenAttribute : Attribute
+    {
+        /// <summary>Initializes the attribute with the specified return value condition.</summary>
+        /// <param name="returnValue">
+        /// The return value condition. If the method returns this value, the associated parameter may be null.
+        /// </param>
+        public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
+
+        /// <summary>Gets the return value condition.</summary>
+        public bool ReturnValue { get; }
+    }
+
+    /// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter will not be null even if the corresponding type allows it.</summary>
+    [AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
+#if INTERNAL_NULLABLE_ATTRIBUTES
+    internal
+#else
+    public
+#endif
+        sealed class NotNullWhenAttribute : Attribute
+    {
+        /// <summary>Initializes the attribute with the specified return value condition.</summary>
+        /// <param name="returnValue">
+        /// The return value condition. If the method returns this value, the associated parameter will not be null.
+        /// </param>
+        public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
+
+        /// <summary>Gets the return value condition.</summary>
+        public bool ReturnValue { get; }
+    }
+
+    /// <summary>Specifies that the output will be non-null if the named parameter is non-null.</summary>
+    [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)]
+#if INTERNAL_NULLABLE_ATTRIBUTES
+    internal
+#else
+    public
+#endif
+        sealed class NotNullIfNotNullAttribute : Attribute
+    {
+        /// <summary>Initializes the attribute with the associated parameter name.</summary>
+        /// <param name="parameterName">
+        /// The associated parameter name.  The output will be non-null if the argument to the parameter specified is non-null.
+        /// </param>
+        public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName;
+
+        /// <summary>Gets the associated parameter name.</summary>
+        public string ParameterName { get; }
+    }
+
+    /// <summary>Applied to a method that will never return under any circumstance.</summary>
+    [AttributeUsage(AttributeTargets.Method, Inherited = false)]
+#if INTERNAL_NULLABLE_ATTRIBUTES
+    internal
+#else
+    public
+#endif
+        sealed class DoesNotReturnAttribute : Attribute
+    { }
+
+    /// <summary>Specifies that the method will not return if the associated Boolean parameter is passed the specified value.</summary>
+    [AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
+#if INTERNAL_NULLABLE_ATTRIBUTES
+    internal
+#else
+    public
+#endif
+        sealed class DoesNotReturnIfAttribute : Attribute
+    {
+        /// <summary>Initializes the attribute with the specified parameter value.</summary>
+        /// <param name="parameterValue">
+        /// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to
+        /// the associated parameter matches this value.
+        /// </param>
+        public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue;
+
+        /// <summary>Gets the condition parameter value.</summary>
+        public bool ParameterValue { get; }
+    }
+}
+#endif
\ No newline at end of file


[lucenenet] 06/09: Lucene.Net.Support: Renamed ConcurrentHashMapWrapper > ConcurrentDictionaryWrapper, marked internal, and added DictionaryExtensions.AsConcurrent() extension method to make usage simpler

Posted by ni...@apache.org.
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 bb873f48ea6217ff573c9d632bd176f760a41286
Author: Shad Storhaug <sh...@shadstorhaug.com>
AuthorDate: Mon Jan 27 05:44:13 2020 +0700

    Lucene.Net.Support: Renamed ConcurrentHashMapWrapper > ConcurrentDictionaryWrapper, marked internal, and added DictionaryExtensions.AsConcurrent() extension method to make usage simpler
---
 .../Index/ThreadedIndexingAndSearchingTestCase.cs  |  3 +-
 .../Search/AssertingScorer.cs                      |  2 +-
 src/Lucene.Net/Search/CachingWrapperFilter.cs      |  3 +-
 ...apWrapper.cs => ConcurrentDictionaryWrapper.cs} | 36 +++++++--------
 src/Lucene.Net/Support/DictionaryExtensions.cs     | 51 +++++++++++++++-------
 5 files changed, 57 insertions(+), 38 deletions(-)

diff --git a/src/Lucene.Net.TestFramework/Index/ThreadedIndexingAndSearchingTestCase.cs b/src/Lucene.Net.TestFramework/Index/ThreadedIndexingAndSearchingTestCase.cs
index 2dddef4..bade91d 100644
--- a/src/Lucene.Net.TestFramework/Index/ThreadedIndexingAndSearchingTestCase.cs
+++ b/src/Lucene.Net.TestFramework/Index/ThreadedIndexingAndSearchingTestCase.cs
@@ -549,8 +549,7 @@ namespace Lucene.Net.Index
 #if FEATURE_CONDITIONALWEAKTABLE_ADDORUPDATE
         private readonly ConditionalWeakTable<SegmentCoreReaders, BooleanRef> warmed = new ConditionalWeakTable<SegmentCoreReaders, BooleanRef>();
 #else
-        private readonly IDictionary<SegmentCoreReaders, BooleanRef> warmed = new ConcurrentHashMapWrapper<SegmentCoreReaders, BooleanRef>(new WeakDictionary<SegmentCoreReaders, BooleanRef>());
-                                                                                                                                    // Collections.synchronizedMap(new WeakHashMap<SegmentCoreReaders, BooleanRef>());
+        private readonly IDictionary<SegmentCoreReaders, BooleanRef> warmed = new WeakDictionary<SegmentCoreReaders, BooleanRef>().AsConcurrent();
 #endif
 
         public virtual void RunTest(string testName)
diff --git a/src/Lucene.Net.TestFramework/Search/AssertingScorer.cs b/src/Lucene.Net.TestFramework/Search/AssertingScorer.cs
index 023378e..df19e58 100644
--- a/src/Lucene.Net.TestFramework/Search/AssertingScorer.cs
+++ b/src/Lucene.Net.TestFramework/Search/AssertingScorer.cs
@@ -36,7 +36,7 @@ namespace Lucene.Net.Search
             new ConditionalWeakTable<Scorer, WeakReference<AssertingScorer>>();
 #else
         private static readonly IDictionary<Scorer, WeakReference<AssertingScorer>> ASSERTING_INSTANCES = 
-            new ConcurrentHashMapWrapper<Scorer, WeakReference<AssertingScorer>>(new WeakDictionary<Scorer, WeakReference<AssertingScorer>>());
+            new WeakDictionary<Scorer, WeakReference<AssertingScorer>>().AsConcurrent();
 #endif
 
         public static Scorer Wrap(Random random, Scorer other)
diff --git a/src/Lucene.Net/Search/CachingWrapperFilter.cs b/src/Lucene.Net/Search/CachingWrapperFilter.cs
index af4175e..b933d55 100644
--- a/src/Lucene.Net/Search/CachingWrapperFilter.cs
+++ b/src/Lucene.Net/Search/CachingWrapperFilter.cs
@@ -41,8 +41,7 @@ namespace Lucene.Net.Search
 #if FEATURE_CONDITIONALWEAKTABLE_ADDORUPDATE
         private readonly ConditionalWeakTable<object, DocIdSet> _cache = new ConditionalWeakTable<object, DocIdSet>();
 #else
-        //private readonly IDictionary<object, DocIdSet> Cache = Collections.synchronizedMap(new WeakHashMap<object, DocIdSet>());
-        private readonly IDictionary<object, DocIdSet> _cache = new ConcurrentHashMapWrapper<object, DocIdSet>(new WeakDictionary<object, DocIdSet>());
+        private readonly IDictionary<object, DocIdSet> _cache = new WeakDictionary<object, DocIdSet>().AsConcurrent();
 #endif
 
         /// <summary>
diff --git a/src/Lucene.Net/Support/ConcurrentHashMapWrapper.cs b/src/Lucene.Net/Support/ConcurrentDictionaryWrapper.cs
similarity index 83%
rename from src/Lucene.Net/Support/ConcurrentHashMapWrapper.cs
rename to src/Lucene.Net/Support/ConcurrentDictionaryWrapper.cs
index b257082..94e3a34 100644
--- a/src/Lucene.Net/Support/ConcurrentHashMapWrapper.cs
+++ b/src/Lucene.Net/Support/ConcurrentDictionaryWrapper.cs
@@ -7,28 +7,28 @@ using System.Threading;
 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.
-	 */
-
-    public class ConcurrentHashMapWrapper<TKey, TValue> : IDictionary<TKey, TValue>
+     * 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 ConcurrentDictionaryWrapper<TKey, TValue> : IDictionary<TKey, TValue>
     {
         private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
         private readonly IDictionary<TKey, TValue> _dict;
 
-        public ConcurrentHashMapWrapper(IDictionary<TKey, TValue> wrapped)
+        public ConcurrentDictionaryWrapper(IDictionary<TKey, TValue> wrapped)
         {
             this._dict = wrapped;
         }
diff --git a/src/Lucene.Net/Support/DictionaryExtensions.cs b/src/Lucene.Net/Support/DictionaryExtensions.cs
index d9365c2..e3e60ac 100644
--- a/src/Lucene.Net/Support/DictionaryExtensions.cs
+++ b/src/Lucene.Net/Support/DictionaryExtensions.cs
@@ -5,21 +5,21 @@ using System.IO;
 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.
-	 */
+     * 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.
+     */
 
     public static class DictionaryExtensions
     {
@@ -42,6 +42,27 @@ namespace Lucene.Net.Support
         }
 
         /// <summary>
+        /// Returns a concurrent wrapper for the current <see cref="IDictionary{TKey, TValue}"/>.
+        /// </summary>
+        /// <typeparam name="TKey">The type of keys in the dictionary.</typeparam>
+        /// <typeparam name="TValue">The type of values in the dictionary.</typeparam>
+        /// <param name="dictionary">The collection to make concurrent (thread-safe).</param>
+        /// <returns>An object that acts as a read-only wrapper around the current <see cref="ISet{T}"/>.</returns>
+        /// <exception cref="ArgumentNullException"><paramref name="dictionary"/> is <c>null</c>.</exception>
+        /// <remarks>
+        /// To synchronize any modifications to the <see cref="ISet{T}"/> object, expose it only through this wrapper.
+        /// <para/>
+        /// The set returned uses simple locking and may not be the most performant solution, but it provides a quick
+        /// way to make any set thread-safe.
+        /// <para/>
+        /// This method is an O(1) operation.
+        /// </remarks>
+        internal static IDictionary<TKey, TValue> AsConcurrent<TKey, TValue>(this IDictionary<TKey, TValue> dictionary)
+        {
+            return new ConcurrentDictionaryWrapper<TKey, TValue>(dictionary);
+        }
+
+        /// <summary>
         /// Loads properties from the specified <see cref="Stream"/>. The encoding is
         /// ISO8859-1. 
         /// </summary>


[lucenenet] 01/09: Lucene.Net.Spatial.Util.ShapeFieldCacheProvider: Simplified cache value creation by using ConditionalWeakTable.GetValue(), and removed dependency on WeakDictionary (See LUCENENET-610, LUCENENET-640).

Posted by ni...@apache.org.
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 01ddd63fb9350c14ddf3e94a198618bfc6754595
Author: Shad Storhaug <sh...@shadstorhaug.com>
AuthorDate: Sun Jan 26 19:41:42 2020 +0700

    Lucene.Net.Spatial.Util.ShapeFieldCacheProvider: Simplified cache value creation by using ConditionalWeakTable<TKey, TValue>.GetValue(), and removed dependency on WeakDictionary (See LUCENENET-610, LUCENENET-640).
---
 .../Util/ShapeFieldCacheProvider.cs                | 24 +++++-----------------
 1 file changed, 5 insertions(+), 19 deletions(-)

diff --git a/src/Lucene.Net.Spatial/Util/ShapeFieldCacheProvider.cs b/src/Lucene.Net.Spatial/Util/ShapeFieldCacheProvider.cs
index 55c076f..e36490f 100644
--- a/src/Lucene.Net.Spatial/Util/ShapeFieldCacheProvider.cs
+++ b/src/Lucene.Net.Spatial/Util/ShapeFieldCacheProvider.cs
@@ -1,6 +1,5 @@
 using Lucene.Net.Index;
 using Lucene.Net.Search;
-using Lucene.Net.Support;
 using Lucene.Net.Util;
 using Spatial4n.Core.Shapes;
 using System.Runtime.CompilerServices;
@@ -40,13 +39,8 @@ namespace Lucene.Net.Spatial.Util
     {
         //private Logger log = Logger.GetLogger(GetType().FullName);
 
-#if FEATURE_CONDITIONALWEAKTABLE_ADDORUPDATE
         private readonly ConditionalWeakTable<IndexReader, ShapeFieldCache<T>> sidx =
             new ConditionalWeakTable<IndexReader, ShapeFieldCache<T>>();
-#else
-        private readonly WeakDictionary<IndexReader, ShapeFieldCache<T>> sidx =
-            new WeakDictionary<IndexReader, ShapeFieldCache<T>>();
-#endif
 
         protected internal readonly int m_defaultSize;
         protected internal readonly string m_shapeField;
@@ -60,23 +54,17 @@ namespace Lucene.Net.Spatial.Util
 
         protected internal abstract T ReadShape(BytesRef term);
 
-        private readonly object locker = new object();
-
         public virtual ShapeFieldCache<T> GetCache(AtomicReader reader)
         {
-            lock (locker)
+            // LUCENENET: ConditionalWeakTable allows us to simplify and remove locks
+            return sidx.GetValue(reader, (key) =>
             {
-                ShapeFieldCache<T> idx;
-                if (sidx.TryGetValue(reader, out idx) && idx != null)
-                {
-                    return idx;
-                }
                 /*long startTime = Runtime.CurrentTimeMillis();
                 log.Fine("Building Cache [" + reader.MaxDoc() + "]");*/
-                idx = new ShapeFieldCache<T>(reader.MaxDoc, m_defaultSize);
+                ShapeFieldCache<T> idx = new ShapeFieldCache<T>(key.MaxDoc, m_defaultSize);
                 int count = 0;
                 DocsEnum docs = null;
-                Terms terms = reader.GetTerms(m_shapeField);
+                Terms terms = ((AtomicReader)key).GetTerms(m_shapeField);
                 TermsEnum te = null;
                 if (terms != null)
                 {
@@ -99,12 +87,10 @@ namespace Lucene.Net.Spatial.Util
                         term = te.Next();
                     }
                 }
-                sidx.AddOrUpdate(reader, idx);
-
                 /*long elapsed = Runtime.CurrentTimeMillis() - startTime;
                 log.Fine("Cached: [" + count + " in " + elapsed + "ms] " + idx);*/
                 return idx;
-            }
+            });
         }
     }
 }


[lucenenet] 04/09: Lucene.Net.Search.FieldCacheImpl: Switched to ConcurrentDictionary for the innerCache to try to reduce locking (LUCENENET-610)

Posted by ni...@apache.org.
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 b4e6f0fa994797f9e743ec23b191d43a06942b86
Author: Shad Storhaug <sh...@shadstorhaug.com>
AuthorDate: Mon Jan 27 03:35:31 2020 +0700

    Lucene.Net.Search.FieldCacheImpl: Switched to ConcurrentDictionary for the innerCache to try to reduce locking (LUCENENET-610)
---
 src/Lucene.Net/Search/FieldCacheImpl.cs | 112 ++++++++++++++++++--------------
 1 file changed, 63 insertions(+), 49 deletions(-)

diff --git a/src/Lucene.Net/Search/FieldCacheImpl.cs b/src/Lucene.Net/Search/FieldCacheImpl.cs
index eaa158e..87e6a95 100644
--- a/src/Lucene.Net/Search/FieldCacheImpl.cs
+++ b/src/Lucene.Net/Search/FieldCacheImpl.cs
@@ -2,11 +2,13 @@ using Lucene.Net.Index;
 using Lucene.Net.Support;
 using Lucene.Net.Support.IO;
 using System;
+using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.IO;
 using System.Linq;
 using System.Runtime.CompilerServices;
+using System.Threading;
 
 namespace Lucene.Net.Search
 {
@@ -114,9 +116,11 @@ namespace Lucene.Net.Search
                 {
                     Cache cache = cacheEntry.Value;
                     Type cacheType = cacheEntry.Key;
+#if !FEATURE_CONDITIONALWEAKTABLE_ENUMERATOR
                     lock (cache.readerCache)
                     {
-                        foreach (KeyValuePair<object, IDictionary<CacheKey, object>> readerCacheEntry in cache.readerCache)
+#endif
+                        foreach (var readerCacheEntry in cache.readerCache)
                         {
                             object readerKey = readerCacheEntry.Key;
                             if (readerKey == null)
@@ -130,7 +134,9 @@ namespace Lucene.Net.Search
                                 result.Add(new FieldCache.CacheEntry(readerKey, entry.field, cacheType, entry.custom, mapEntry.Value));
                             }
                         }
+#if !FEATURE_CONDITIONALWEAKTABLE_ENUMERATOR
                     }
+#endif
                 }
                 return result.ToArray();
             }
@@ -208,9 +214,9 @@ namespace Lucene.Net.Search
             internal readonly FieldCacheImpl wrapper;
 
 #if FEATURE_CONDITIONALWEAKTABLE_ENUMERATOR
-            internal ConditionalWeakTable<object, IDictionary<CacheKey, object>> readerCache = new ConditionalWeakTable<object, IDictionary<CacheKey, object>>();
+            internal ConditionalWeakTable<object, ConcurrentDictionary<CacheKey, object>> readerCache = new ConditionalWeakTable<object, ConcurrentDictionary<CacheKey, object>>();
 #else
-            internal WeakDictionary<object, IDictionary<CacheKey, object>> readerCache = new WeakDictionary<object, IDictionary<CacheKey, object>>();
+            internal WeakDictionary<object, ConcurrentDictionary<CacheKey, object>> readerCache = new WeakDictionary<object, ConcurrentDictionary<CacheKey, object>>();
 #endif
 
             protected abstract object CreateValue(AtomicReader reader, CacheKey key, bool setDocsWithField);
@@ -219,10 +225,10 @@ namespace Lucene.Net.Search
             /// Remove this reader from the cache, if present. </summary>
             public virtual void PurgeByCacheKey(object coreCacheKey)
             {
+#if !FEATURE_CONDITIONALWEAKTABLE_ENUMERATOR
                 lock (readerCache)
-                {
+#endif
                     readerCache.Remove(coreCacheKey);
-                }
             }
 
             /// <summary>
@@ -231,79 +237,87 @@ namespace Lucene.Net.Search
             /// </summary>
             public virtual void Put(AtomicReader reader, CacheKey key, object value)
             {
+                ConcurrentDictionary<CacheKey, object> innerCache;
                 object readerKey = reader.CoreCacheKey;
+#if FEATURE_CONDITIONALWEAKTABLE_ENUMERATOR
+                innerCache = readerCache.GetValue(readerKey, (readerKey) =>
+                {
+                    // First time this reader is using FieldCache
+                    wrapper.InitReader(reader);
+                    return new ConcurrentDictionary<CacheKey, object>
+                    {
+                        [key] = value
+                    };
+                });
+#else
                 lock (readerCache)
                 {
-                    if (!readerCache.TryGetValue(readerKey, out IDictionary<CacheKey, object> innerCache) || innerCache == null)
+                    if (!readerCache.TryGetValue(readerKey, out innerCache) || innerCache == null)
                     {
                         // First time this reader is using FieldCache
-                        innerCache = new Dictionary<CacheKey, object>();
-                        readerCache.AddOrUpdate(readerKey, innerCache);
+                        innerCache = new ConcurrentDictionary<CacheKey, object>
+                        {
+                            [key] = value
+                        };
+                        readerCache.Add(readerKey, innerCache);
                         wrapper.InitReader(reader);
                     }
-                    // LUCENENET NOTE: We declare a temp variable here so we 
-                    // don't overwrite value variable with the null
-                    // that will result when this if block succeeds; otherwise
-                    // we won't have a value to put in the cache.
-                    if (!innerCache.TryGetValue(key, out object temp))
-                    {
-                        innerCache[key] = value;
-                    }
-                    else
-                    {
-                        // Another thread beat us to it; leave the current
-                        // value
-                    }
                 }
+#endif
+                // If another thread beat us to it, leave the current value
+                innerCache.TryAdd(key, value);
             }
 
             public virtual object Get(AtomicReader reader, CacheKey key, bool setDocsWithField)
             {
-                IDictionary<CacheKey, object> innerCache;
-                object value;
+                ConcurrentDictionary<CacheKey, object> innerCache;
                 object readerKey = reader.CoreCacheKey;
+#if FEATURE_CONDITIONALWEAKTABLE_ENUMERATOR
+                innerCache = readerCache.GetValue(readerKey, (readerKey) =>
+                {
+                    // First time this reader is using FieldCache
+                    wrapper.InitReader(reader);
+                    return new ConcurrentDictionary<CacheKey, object>
+                    {
+                        [key] = new FieldCache.CreationPlaceholder()
+                    };
+                });
+
+#else
                 lock (readerCache)
                 {
                     if (!readerCache.TryGetValue(readerKey, out innerCache) || innerCache == null)
                     {
                         // First time this reader is using FieldCache
-                        innerCache = new Dictionary<CacheKey, object>();
-                        readerCache.AddOrUpdate(readerKey, innerCache);
+                        innerCache = new ConcurrentDictionary<CacheKey, object>
+                        {
+                            [key] = new FieldCache.CreationPlaceholder()
+                        };
+                        readerCache[readerKey] = innerCache;
                         wrapper.InitReader(reader);
-                        value = null;
-                    }
-                    else
-                    {
-                        innerCache.TryGetValue(key, out value);
-                    }
-                    if (value == null)
-                    {
-                        value = new FieldCache.CreationPlaceholder();
-                        innerCache[key] = value;
                     }
                 }
-                if (value is FieldCache.CreationPlaceholder)
+#endif
+                object value = innerCache.GetOrAdd(key, (cacheKey) => new FieldCache.CreationPlaceholder());
+                if (value is FieldCache.CreationPlaceholder progress)
                 {
                     lock (value)
                     {
-                        FieldCache.CreationPlaceholder progress = (FieldCache.CreationPlaceholder)value;
                         if (progress.Value == null)
                         {
                             progress.Value = CreateValue(reader, key, setDocsWithField);
-                            lock (readerCache)
-                            {
-                                innerCache[key] = progress.Value;
-                            }
-
-                            // Only check if key.custom (the parser) is
-                            // non-null; else, we check twice for a single
-                            // call to FieldCache.getXXX
-                            if (key.custom != null && wrapper != null)
+                            if (innerCache.TryUpdate(key, progress.Value, value))
                             {
-                                TextWriter infoStream = wrapper.InfoStream;
-                                if (infoStream != null)
+                                // Only check if key.custom (the parser) is
+                                // non-null; else, we check twice for a single
+                                // call to FieldCache.getXXX
+                                if (key.custom != null && wrapper != null)
                                 {
-                                    PrintNewInsanity(infoStream, progress.Value);
+                                    TextWriter infoStream = wrapper.InfoStream;
+                                    if (infoStream != null)
+                                    {
+                                        PrintNewInsanity(infoStream, progress.Value);
+                                    }
                                 }
                             }
                         }


[lucenenet] 02/09: Lucene.Net.TestFramework.Search.AssertingScorer: Reverted back to using WeakReference for the value, since values are strongly referenced in ConditionalWeakTable

Posted by ni...@apache.org.
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 e73e44b977a2863f1cdabe372c389d7f837bf525
Author: Shad Storhaug <sh...@shadstorhaug.com>
AuthorDate: Sun Jan 26 20:15:27 2020 +0700

    Lucene.Net.TestFramework.Search.AssertingScorer: Reverted back to using WeakReference for the value, since values are strongly referenced in ConditionalWeakTable
---
 src/Lucene.Net.TestFramework/Search/AssertingScorer.cs | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/src/Lucene.Net.TestFramework/Search/AssertingScorer.cs b/src/Lucene.Net.TestFramework/Search/AssertingScorer.cs
index e15df60..023378e 100644
--- a/src/Lucene.Net.TestFramework/Search/AssertingScorer.cs
+++ b/src/Lucene.Net.TestFramework/Search/AssertingScorer.cs
@@ -32,8 +32,8 @@ namespace Lucene.Net.Search
         // could loose references because of eg.
         // AssertingScorer.Score(Collector) which needs to delegate to work correctly
 #if FEATURE_CONDITIONALWEAKTABLE_ADDORUPDATE
-        private static readonly ConditionalWeakTable<Scorer, AssertingScorer> ASSERTING_INSTANCES = 
-            new ConditionalWeakTable<Scorer, AssertingScorer>();
+        private static readonly ConditionalWeakTable<Scorer, WeakReference<AssertingScorer>> ASSERTING_INSTANCES =
+            new ConditionalWeakTable<Scorer, WeakReference<AssertingScorer>>();
 #else
         private static readonly IDictionary<Scorer, WeakReference<AssertingScorer>> ASSERTING_INSTANCES = 
             new ConcurrentHashMapWrapper<Scorer, WeakReference<AssertingScorer>>(new WeakDictionary<Scorer, WeakReference<AssertingScorer>>());
@@ -47,7 +47,7 @@ namespace Lucene.Net.Search
             }
             AssertingScorer assertScorer = new AssertingScorer(random, other);
 #if FEATURE_CONDITIONALWEAKTABLE_ADDORUPDATE
-            ASSERTING_INSTANCES.AddOrUpdate(other, assertScorer);
+            ASSERTING_INSTANCES.AddOrUpdate(other, new WeakReference<AssertingScorer>(assertScorer));
 #else
             ASSERTING_INSTANCES[other] = new WeakReference<AssertingScorer>(assertScorer);
 #endif
@@ -61,13 +61,8 @@ namespace Lucene.Net.Search
             {
                 return other;
             }
-
-#if FEATURE_CONDITIONALWEAKTABLE_ADDORUPDATE
-            if (!ASSERTING_INSTANCES.TryGetValue(other, out AssertingScorer assertingScorer) || assertingScorer == null)
-#else
             if (!ASSERTING_INSTANCES.TryGetValue(other, out WeakReference<AssertingScorer> assertingScorerRef) || assertingScorerRef == null ||
                 !assertingScorerRef.TryGetTarget(out AssertingScorer assertingScorer) || assertingScorer == null)
-#endif
             {
                 // can happen in case of memory pressure or if
                 // scorer1.Score(collector) calls


[lucenenet] 09/09: Merge remote-tracking branch 'segovia/master'

Posted by ni...@apache.org.
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 b0b2b23bd3e163224c3af3bd0b332bab20bbb144
Merge: a3f18b4 f1c1629
Author: Shad Storhaug <sh...@shadstorhaug.com>
AuthorDate: Thu Jan 30 10:23:28 2020 +0700

    Merge remote-tracking branch 'segovia/master'

 src/Lucene.Net.Highlighter/Highlight/TextFragment.cs | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)


[lucenenet] 05/09: Lucene.Net.Facet.Taxonomy.CachedOrdinalsReader: Removed locking for ordsCache when using ConditionalWeakTable (See LUCENENET-610, LUCENENET-640, LUCENENET-630)

Posted by ni...@apache.org.
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 c867278bc317fe808615a2fe17acc20b5e161a23
Author: Shad Storhaug <sh...@shadstorhaug.com>
AuthorDate: Mon Jan 27 05:03:10 2020 +0700

    Lucene.Net.Facet.Taxonomy.CachedOrdinalsReader: Removed locking for ordsCache when using ConditionalWeakTable (See LUCENENET-610, LUCENENET-640, LUCENENET-630)
---
 .../Taxonomy/CachedOrdinalsReader.cs               | 30 ++++++++--------------
 1 file changed, 10 insertions(+), 20 deletions(-)

diff --git a/src/Lucene.Net.Facet/Taxonomy/CachedOrdinalsReader.cs b/src/Lucene.Net.Facet/Taxonomy/CachedOrdinalsReader.cs
index 92909f7..d67b7ff 100644
--- a/src/Lucene.Net.Facet/Taxonomy/CachedOrdinalsReader.cs
+++ b/src/Lucene.Net.Facet/Taxonomy/CachedOrdinalsReader.cs
@@ -1,6 +1,7 @@
 using Lucene.Net.Support;
 using System;
 using System.Diagnostics.CodeAnalysis;
+using System.Linq;
 using System.Runtime.CompilerServices;
 using System.Threading;
 
@@ -78,26 +79,24 @@ namespace Lucene.Net.Facet.Taxonomy
 
         private CachedOrds GetCachedOrds(AtomicReaderContext context)
         {
+            object cacheKey = context.Reader.CoreCacheKey;
+#if FEATURE_CONDITIONALWEAKTABLE_ENUMERATOR
+            return ordsCache.GetValue(cacheKey, (cacheKey) => new CachedOrds(source.GetReader(context), context.Reader.MaxDoc));
+#else
             lock (this)
             {
-                object cacheKey = context.Reader.CoreCacheKey;
                 if (!ordsCache.TryGetValue(cacheKey, out CachedOrds ords) || ords == null)
                 {
                     ords = new CachedOrds(source.GetReader(context), context.Reader.MaxDoc);
-                    ordsCache.AddOrUpdate(cacheKey, ords);
+                    ordsCache[cacheKey] =  ords;
                 }
 
                 return ords;
             }
+#endif
         }
 
-        public override string IndexFieldName
-        {
-            get
-            {
-                return source.IndexFieldName;
-            }
-        }
+        public override string IndexFieldName => source.IndexFieldName;
 
         public override OrdinalsSegmentReader GetReader(AtomicReaderContext context)
         {
@@ -199,19 +198,10 @@ namespace Lucene.Net.Facet.Taxonomy
 
         public virtual long RamBytesUsed()
         {
+#if !FEATURE_CONDITIONALWEAKTABLE_ENUMERATOR
             lock (this)
-            {
-                long bytes = 0;
-#if FEATURE_CONDITIONALWEAKTABLE_ENUMERATOR
-                foreach (var pair in ordsCache)
-                    bytes += pair.Value.RamBytesUsed();
-#else
-                foreach (CachedOrds ords in ordsCache.Values)
-                    bytes += ords.RamBytesUsed();
 #endif
-
-                return bytes;
-            }
+                return ordsCache.Sum(pair => pair.Value.RamBytesUsed());
         }
     }
 }
\ No newline at end of file


[lucenenet] 07/09: Fix duplicate FragNum value on Highlight.TextFragment

Posted by ni...@apache.org.
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 f1c1629d627bcbe5546bc43a5c7623439bce391e
Author: Gustavo Segovia <gu...@ti8m.ch>
AuthorDate: Wed Jan 29 10:57:38 2020 +0100

    Fix duplicate FragNum value on Highlight.TextFragment
---
 src/Lucene.Net.Highlighter/Highlight/TextFragment.cs | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/src/Lucene.Net.Highlighter/Highlight/TextFragment.cs b/src/Lucene.Net.Highlighter/Highlight/TextFragment.cs
index d4a97ad..3edd11e 100644
--- a/src/Lucene.Net.Highlighter/Highlight/TextFragment.cs
+++ b/src/Lucene.Net.Highlighter/Highlight/TextFragment.cs
@@ -50,7 +50,11 @@ namespace Lucene.Net.Search.Highlight
         /// <summary>
         /// the fragment sequence number
         /// </summary>
-        public virtual int FragNum { get; protected internal set; }
+        public virtual int FragNum
+        {
+	        get { return fragNum; }
+	        protected internal set { fragNum = value; }
+        }
 
         /// <param name="frag2">Fragment to be merged into this one</param>
         public virtual void Merge(TextFragment frag2)


[lucenenet] 03/09: Lucene.Net.Support.WeakDictionary: Removed unnecessary cast, marked class internal

Posted by ni...@apache.org.
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 6366760dae8a0a46ee59fc044875f3ee0423a82f
Author: Shad Storhaug <sh...@shadstorhaug.com>
AuthorDate: Mon Jan 27 03:15:23 2020 +0700

    Lucene.Net.Support.WeakDictionary: Removed unnecessary cast, marked class internal
---
 src/Lucene.Net.Facet/TopOrdAndFloatQueue.cs | 2 +-
 src/Lucene.Net.Facet/TopOrdAndIntQueue.cs   | 2 +-
 src/Lucene.Net/Properties/AssemblyInfo.cs   | 3 ++-
 src/Lucene.Net/Support/WeakDictionary.cs    | 6 ++----
 4 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/src/Lucene.Net.Facet/TopOrdAndFloatQueue.cs b/src/Lucene.Net.Facet/TopOrdAndFloatQueue.cs
index 62fb389..72db2d8 100644
--- a/src/Lucene.Net.Facet/TopOrdAndFloatQueue.cs
+++ b/src/Lucene.Net.Facet/TopOrdAndFloatQueue.cs
@@ -55,7 +55,7 @@ namespace Lucene.Net.Facet
         {
         }
 
-        protected override bool LessThan(OrdAndValue a, OrdAndValue b)
+        protected internal override bool LessThan(OrdAndValue a, OrdAndValue b)
         {
             if (a.Value < b.Value)
             {
diff --git a/src/Lucene.Net.Facet/TopOrdAndIntQueue.cs b/src/Lucene.Net.Facet/TopOrdAndIntQueue.cs
index cb78b69..4f93a10 100644
--- a/src/Lucene.Net.Facet/TopOrdAndIntQueue.cs
+++ b/src/Lucene.Net.Facet/TopOrdAndIntQueue.cs
@@ -56,7 +56,7 @@ namespace Lucene.Net.Facet
         {
         }
 
-        protected override bool LessThan(OrdAndValue a, OrdAndValue b)
+        protected internal override bool LessThan(OrdAndValue a, OrdAndValue b)
         {
             if (a.Value < b.Value)
             {
diff --git a/src/Lucene.Net/Properties/AssemblyInfo.cs b/src/Lucene.Net/Properties/AssemblyInfo.cs
index f6c7729..f4ead0d 100644
--- a/src/Lucene.Net/Properties/AssemblyInfo.cs
+++ b/src/Lucene.Net/Properties/AssemblyInfo.cs
@@ -33,6 +33,8 @@ using System.Runtime.CompilerServices;
 // We need InternalsVisibleTo in order to prevent making everything public just for the sake of testing.
 // This has broad implications because many methods are marked "protected internal", which means other assemblies
 // must update overridden methods to match.
+[assembly: InternalsVisibleTo("Lucene.Net.Facet, PublicKey=" + AssemblyKeys.PublicKey)]
+[assembly: InternalsVisibleTo("Lucene.Net.Misc, PublicKey=" + AssemblyKeys.PublicKey)]
 [assembly: InternalsVisibleTo("Lucene.Net.Tests._A-D, PublicKey=" + AssemblyKeys.PublicKey)]
 [assembly: InternalsVisibleTo("Lucene.Net.Tests._E-I, PublicKey=" + AssemblyKeys.PublicKey)]
 [assembly: InternalsVisibleTo("Lucene.Net.Tests._J-S, PublicKey=" + AssemblyKeys.PublicKey)]
@@ -42,7 +44,6 @@ using System.Runtime.CompilerServices;
 [assembly: InternalsVisibleTo("Lucene.Net.TestFramework.MSTest, PublicKey=" + AssemblyKeys.PublicKey)]
 [assembly: InternalsVisibleTo("Lucene.Net.TestFramework.NUnit, PublicKey=" + AssemblyKeys.PublicKey)]
 [assembly: InternalsVisibleTo("Lucene.Net.TestFramework.xUnit, PublicKey=" + AssemblyKeys.PublicKey)]
-[assembly: InternalsVisibleTo("Lucene.Net.Misc, PublicKey=" + AssemblyKeys.PublicKey)]
 [assembly: InternalsVisibleTo("Lucene.Net.Tests.ICU, PublicKey=" + AssemblyKeys.PublicKey)] // For Analysis.Util.TestSegmentingTokenizerBase
 [assembly: InternalsVisibleTo("Lucene.Net.Tests.Misc, PublicKey=" + AssemblyKeys.PublicKey)]
 [assembly: InternalsVisibleTo("Lucene.Net.Tests.QueryParser, PublicKey=" + AssemblyKeys.PublicKey)]
diff --git a/src/Lucene.Net/Support/WeakDictionary.cs b/src/Lucene.Net/Support/WeakDictionary.cs
index 2aa467f..b4abc18 100644
--- a/src/Lucene.Net/Support/WeakDictionary.cs
+++ b/src/Lucene.Net/Support/WeakDictionary.cs
@@ -32,7 +32,7 @@ namespace Lucene.Net.Support
 #if FEATURE_SERIALIZABLE
     [Serializable]
 #endif
-    public sealed class WeakDictionary<TKey, TValue> : IDictionary<TKey, TValue> where TKey : class 
+    internal sealed class WeakDictionary<TKey, TValue> : IDictionary<TKey, TValue> where TKey : class 
     {
         private IDictionary<WeakKey<TKey>, TValue> _hm;
         private int _gcCollections = 0;
@@ -287,10 +287,8 @@ namespace Lucene.Net.Support
                     return true;
                 }
 
-                if (obj is WeakKey<T>)
+                if (obj is WeakKey<T> other)
                 {
-                    var other = (WeakKey<T>)obj;
-
                     var referenceTarget = reference.Target; // Careful: can be null in the mean time...
                     return referenceTarget != null && referenceTarget.Equals(other.Target);
                 }