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 b1e0eec678e3a345c807fa95999413065a93d07d
Author: Shad Storhaug <[email protected]>
AuthorDate: Tue Mar 23 03:12:11 2021 +0700

    SWEEP: Added Lucene.Net.Util.ThreadInterruptedException and re-throw it in 
all of the places that Lucene does.
---
 .../ByTask/Feeds/EnwikiContentSource.cs            | 20 +++++--
 src/Lucene.Net.Replicator/ReplicationClient.cs     | 13 ++++-
 .../Store/SlowClosingMockIndexInputWrapper.cs      |  8 ++-
 .../Store/SlowOpeningMockIndexInputWrapper.cs      |  2 +-
 .../Util/ThrottledIndexOutput.cs                   | 13 ++++-
 src/Lucene.Net.Tests.Facet/SlowRAMDirectory.cs     | 10 +++-
 .../IndexAndTaxonomyReplicationClientTest.cs       | 10 +++-
 .../IndexReplicationClientTest.cs                  | 10 +++-
 .../Index/TestDocumentsWriterDeleteQueue.cs        | 13 +++--
 .../Index/TestDocumentsWriterStallControl.cs       |  4 +-
 src/Lucene.Net.Tests/Index/TestIndexWriter.cs      | 34 ++++++++----
 .../Index/TestIndexWriterReader.cs                 | 14 ++++-
 .../Index/TestIndexWriterWithThreads.cs            | 10 +++-
 .../Index/TestSnapshotDeletionPolicy.cs            | 11 +++-
 .../Search/TestControlledRealTimeReopenThread.cs   | 14 +++--
 .../Search/TestTimeLimitingCollector.cs            | 12 +++-
 .../ExceptionHandling/TestExceptionExtensions.cs   |  2 +-
 src/Lucene.Net/Index/ConcurrentMergeScheduler.cs   | 32 +++++++----
 .../Index/DocumentsWriterFlushControl.cs           | 12 +++-
 .../Index/DocumentsWriterPerThreadPool.cs          | 10 +++-
 .../Index/DocumentsWriterStallControl.cs           | 24 +++++---
 src/Lucene.Net/Index/IndexWriter.cs                | 19 ++++---
 .../Search/ControlledRealTimeReopenThread.cs       | 20 +++++--
 src/Lucene.Net/Search/IndexSearcher.cs             |  3 +-
 src/Lucene.Net/Search/TimeLimitingCollector.cs     | 10 +++-
 src/Lucene.Net/Store/Lock.cs                       | 10 +++-
 src/Lucene.Net/Store/RateLimiter.cs                | 10 +++-
 .../ExceptionHandling/ExceptionExtensions.cs       | 10 +++-
 src/Lucene.Net/Util/ThreadInterruptedException.cs  | 64 ++++++++++++++++++++++
 29 files changed, 326 insertions(+), 98 deletions(-)

diff --git a/src/Lucene.Net.Benchmark/ByTask/Feeds/EnwikiContentSource.cs 
b/src/Lucene.Net.Benchmark/ByTask/Feeds/EnwikiContentSource.cs
index ce71b77..1e06701 100644
--- a/src/Lucene.Net.Benchmark/ByTask/Feeds/EnwikiContentSource.cs
+++ b/src/Lucene.Net.Benchmark/ByTask/Feeds/EnwikiContentSource.cs
@@ -77,8 +77,14 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
                 {
                     while (tuple == null && nmde == null && !threadDone && 
!stopped)
                     {
-                        Monitor.Wait(this);
-                        // LUCENENET NOTE: No need to catch and rethrow same 
excepton type ThreadInterruptedException. Note that it could be thrown above on 
lock (this).
+                        try
+                        {
+                            Monitor.Wait(this);
+                        }
+                        catch (Exception ie) when (ie.IsInterruptedException())
+                        {
+                            throw new Util.ThreadInterruptedException(ie);
+                        }
                     }
                     if (tuple != null)
                     {
@@ -142,8 +148,14 @@ namespace Lucene.Net.Benchmarks.ByTask.Feeds
                             {
                                 while (tuple != null && !stopped)
                                 {
-                                    Monitor.Wait(this);
-                                    // LUCENENET NOTE: No need to catch and 
rethrow same excepton type ThreadInterruptedException. Note that it could be 
thrown above on lock (this).
+                                    try
+                                    {
+                                        Monitor.Wait(this); //wait();
+                                    }
+                                    catch 
(System.Threading.ThreadInterruptedException ie)
+                                    {
+                                        throw new 
Util.ThreadInterruptedException(ie);
+                                    }
                                 }
                                 tuple = tmpTuple;
                                 Monitor.Pulse(this); //notify();
diff --git a/src/Lucene.Net.Replicator/ReplicationClient.cs 
b/src/Lucene.Net.Replicator/ReplicationClient.cs
index 51c07d5..e0c0164 100644
--- a/src/Lucene.Net.Replicator/ReplicationClient.cs
+++ b/src/Lucene.Net.Replicator/ReplicationClient.cs
@@ -44,6 +44,8 @@ namespace Lucene.Net.Replicator
     /// </remarks>
     public class ReplicationClient : IDisposable
     {
+        // LUCENENET TODO: Check to ensure ThreadInterruptException is being 
passed from the background worker to the current thread, as it is required by 
IndexWriter
+
         //Note: LUCENENET specific, .NET does not work with Threads in the 
same way as Java does, so we mimic the same behavior using the ThreadPool 
instead.
         private class ReplicationThread
         {
@@ -430,7 +432,16 @@ namespace Lucene.Net.Replicator
             // otherwise, if it's in the middle of replication, we wait for it 
to
             // stop.
             if (updateThread != null)
-                updateThread.Stop();
+            {
+                try
+                {
+                    updateThread.Stop();
+                }
+                catch (Exception ie) when (ie.IsInterruptedException())
+                {
+                    throw new Util.ThreadInterruptedException(ie);
+                }
+            }
             updateThread = null;
         }
 
diff --git 
a/src/Lucene.Net.TestFramework/Store/SlowClosingMockIndexInputWrapper.cs 
b/src/Lucene.Net.TestFramework/Store/SlowClosingMockIndexInputWrapper.cs
index 5e047cb..c65685d 100644
--- a/src/Lucene.Net.TestFramework/Store/SlowClosingMockIndexInputWrapper.cs
+++ b/src/Lucene.Net.TestFramework/Store/SlowClosingMockIndexInputWrapper.cs
@@ -1,4 +1,5 @@
-using System.Threading;
+using System;
+using System.Threading;
 
 namespace Lucene.Net.Store
 {
@@ -40,7 +41,10 @@ namespace Lucene.Net.Store
                 {
                     Thread.Sleep(50);
                 }
-                // LUCENENET NOTE: No need to catch and rethrow same excepton 
type ThreadInterruptedException 
+                catch (Exception ie) when (ie.IsInterruptedException())
+                {
+                    throw new Util.ThreadInterruptedException(ie);
+                }
                 finally
                 {
                     base.Dispose(disposing);
diff --git 
a/src/Lucene.Net.TestFramework/Store/SlowOpeningMockIndexInputWrapper.cs 
b/src/Lucene.Net.TestFramework/Store/SlowOpeningMockIndexInputWrapper.cs
index d6f7ef5..684e118 100644
--- a/src/Lucene.Net.TestFramework/Store/SlowOpeningMockIndexInputWrapper.cs
+++ b/src/Lucene.Net.TestFramework/Store/SlowOpeningMockIndexInputWrapper.cs
@@ -42,7 +42,7 @@ namespace Lucene.Net.Store
                 catch (Exception ignore) when (ignore.IsThrowable())
                 {
                 }
-                throw; // LUCENENET: CA2200: Rethrow to preserve stack details 
(https://docs.microsoft.com/en-us/visualstudio/code-quality/ca2200-rethrow-to-preserve-stack-details)
+                throw new Util.ThreadInterruptedException(ie);
             }
         }
     }
diff --git a/src/Lucene.Net.TestFramework/Util/ThrottledIndexOutput.cs 
b/src/Lucene.Net.TestFramework/Util/ThrottledIndexOutput.cs
index 37590e2..4892032 100644
--- a/src/Lucene.Net.TestFramework/Util/ThrottledIndexOutput.cs
+++ b/src/Lucene.Net.TestFramework/Util/ThrottledIndexOutput.cs
@@ -142,9 +142,16 @@ namespace Lucene.Net.Util
                 return;
             }
 
-            Thread.Sleep(TimeSpan.FromMilliseconds(ms));
-            // LUCENENET NOTE: No need to catch and rethrow same excepton type 
ThreadInterruptedException 
-
+            try
+            {
+                Thread.Sleep(TimeSpan.FromMilliseconds(ms));
+            }
+            catch (Exception e) when (e.IsInterruptedException())
+            {
+#pragma warning disable IDE0001 // Simplify name
+                throw new Util.ThreadInterruptedException(e);
+#pragma warning restore IDE0001 // Simplify name
+            }
         }
 
         public override long Length
diff --git a/src/Lucene.Net.Tests.Facet/SlowRAMDirectory.cs 
b/src/Lucene.Net.Tests.Facet/SlowRAMDirectory.cs
index b293c99..40e98a6 100644
--- a/src/Lucene.Net.Tests.Facet/SlowRAMDirectory.cs
+++ b/src/Lucene.Net.Tests.Facet/SlowRAMDirectory.cs
@@ -77,8 +77,14 @@ namespace Lucene.Net.Facet
                 sTime = random.Next(sTime);
             }
 
-            Thread.Sleep(sTime);
-            // LUCENENET NOTE: No need to catch and rethrow same excepton type 
ThreadInterruptedException 
+            try
+            {
+                Thread.Sleep(sTime);
+            }
+            catch (Exception ie) when (ie.IsInterruptedException())
+            {
+                throw new Util.ThreadInterruptedException(ie);
+            }
         }
 
         /// <summary>
diff --git 
a/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs 
b/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs
index 6a43d60..d19a252 100644
--- a/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs
+++ b/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs
@@ -138,8 +138,14 @@ namespace Lucene.Net.Replicator
             // introducing timeouts is not good, can easily lead to false 
positives.
             while (client.IsUpdateThreadAlive)
             {
-                Thread.Sleep(100);
-                // LUCENENET NOTE: No need to catch and rethrow same excepton 
type ThreadInterruptedException.
+                try
+                {
+                    Thread.Sleep(100);
+                }
+                catch (Exception e) when (e.IsInterruptedException())
+                {
+                    throw new Util.ThreadInterruptedException(e);
+                }
 
                 try
                 {
diff --git a/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs 
b/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs
index 28450cf..de3040f 100644
--- a/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs
+++ b/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs
@@ -100,8 +100,14 @@ namespace Lucene.Net.Replicator
             while (client.IsUpdateThreadAlive)
             {
                 // give client a chance to update
-                Thread.Sleep(100);
-                // LUCENENET NOTE: No need to catch and rethrow same excepton 
type ThreadInterruptedException.
+                try
+                {
+                    Thread.Sleep(100);
+                }
+                catch (Exception e) when (e.IsInterruptedException())
+                {
+                    throw new Util.ThreadInterruptedException(e);
+                }
 
                 try
                 {
diff --git a/src/Lucene.Net.Tests/Index/TestDocumentsWriterDeleteQueue.cs 
b/src/Lucene.Net.Tests/Index/TestDocumentsWriterDeleteQueue.cs
index 5daaa7d..593a618 100644
--- a/src/Lucene.Net.Tests/Index/TestDocumentsWriterDeleteQueue.cs
+++ b/src/Lucene.Net.Tests/Index/TestDocumentsWriterDeleteQueue.cs
@@ -1,4 +1,4 @@
-using J2N.Threading;
+using J2N.Threading;
 using J2N.Threading.Atomic;
 using Lucene.Net.Search;
 using Lucene.Net.Support.Threading;
@@ -318,9 +318,14 @@ namespace Lucene.Net.Index
 
             public override void Run()
             {
-
-                latch.Wait();
-                // LUCENENET NOTE: No need to catch and rethrow same excepton 
type ThreadInterruptedException 
+                try
+                {
+                    latch.Wait();
+                }
+                catch (Exception ie) when (ie.IsInterruptedException())
+                {
+                    throw new Util.ThreadInterruptedException(ie);
+                }
 
                 int i = 0;
                 while ((i = index.GetAndIncrement()) < ids.Length)
diff --git a/src/Lucene.Net.Tests/Index/TestDocumentsWriterStallControl.cs 
b/src/Lucene.Net.Tests/Index/TestDocumentsWriterStallControl.cs
index 4f5dd18..3af2be4 100644
--- a/src/Lucene.Net.Tests/Index/TestDocumentsWriterStallControl.cs
+++ b/src/Lucene.Net.Tests/Index/TestDocumentsWriterStallControl.cs
@@ -275,7 +275,7 @@ namespace Lucene.Net.Index
                             catch (Exception e) when 
(e.IsInterruptedException())
                             {
                                 Console.WriteLine("[Waiter] got interrupted - 
wait count: " + sync.waiter.CurrentCount);
-                                throw; // LUCENENET: CA2200: Rethrow to 
preserve stack details 
(https://docs.microsoft.com/en-us/visualstudio/code-quality/ca2200-rethrow-to-preserve-stack-details)
+                                throw new Util.ThreadInterruptedException(e);
                             }
                         }
                     }
@@ -330,7 +330,7 @@ namespace Lucene.Net.Index
                             catch (Exception e) when 
(e.IsInterruptedException())
                             {
                                 Console.WriteLine("[Updater] got interrupted - 
wait count: " + sync.waiter.CurrentCount);
-                                throw; // LUCENENET: CA2200: Rethrow to 
preserve stack details 
(https://docs.microsoft.com/en-us/visualstudio/code-quality/ca2200-rethrow-to-preserve-stack-details)
+                                throw new Util.ThreadInterruptedException(e);
                             }
                             // LUCENENET: Not sure why this catch block was 
added, but I suspect it was for debugging purposes. Commented it rather than 
removing it because
                             // there may be some value to debugging this way.
diff --git a/src/Lucene.Net.Tests/Index/TestIndexWriter.cs 
b/src/Lucene.Net.Tests/Index/TestIndexWriter.cs
index 05f1b09..ce37594 100644
--- a/src/Lucene.Net.Tests/Index/TestIndexWriter.cs
+++ b/src/Lucene.Net.Tests/Index/TestIndexWriter.cs
@@ -1316,7 +1316,7 @@ namespace Lucene.Net.Index
                             w.Dispose();
                             w = null;
                             //DirectoryReader.Open(dir).Dispose();
-                            using (var reader = DirectoryReader.Open(dir)) { }
+                            using var reader = DirectoryReader.Open(dir);
 
                             // Strangely, if we interrupt a thread before
                             // all classes are loaded, the class loader
@@ -1330,7 +1330,7 @@ namespace Lucene.Net.Index
                             allowInterrupt = true;
                         }
                     }
-                    catch (ThreadInterruptedException re) // LUCENENET: This 
was a custom wrapper type named ThreadInterruptedException in Lucene, so 
leaving the catch block as is
+                    catch (Util.ThreadInterruptedException re)
                     {
                         // NOTE: important to leave this verbosity/noise
                         // on!!  this test doesn't repro easily so when
@@ -1339,17 +1339,28 @@ namespace Lucene.Net.Index
                         Console.WriteLine("TEST: got interrupt");
                         Console.WriteLine(re.ToString());
 
-                        // LUCENENET NOTE: Since our original exception is 
ThreadInterruptException instead of InterruptException
-                        // in .NET, our expectation is typically that the 
InnerException is null (but it doesn't have to be).
-                        // So, this assertion is not needed in .NET. And if we 
get to this catch block, we already know we have
-                        // the right exception type, so there is nothing to 
test here.
-                        //Exception e = re.InnerException;
-                        //Assert.IsTrue(e is ThreadInterruptedException);
+                        Exception e = re.InnerException;
+                        Assert.IsTrue(e is 
System.Threading.ThreadInterruptedException);
                         if (finish)
                         {
                             break;
                         }
                     }
+                    //// LUCENENET specific:
+                    //catch (System.Threading.ThreadInterruptedException re)
+                    //{
+                    //    // NOTE: important to leave this verbosity/noise
+                    //    // on!!  this test doesn't repro easily so when
+                    //    // Jenkins hits a fail we need to study where the
+                    //    // interrupts struck!
+                    //    Console.WriteLine("TEST: got .NET interrupt");
+                    //    Console.WriteLine(re.ToString());
+
+                    //    if (finish)
+                    //    {
+                    //        break;
+                    //    }
+                    //}
                     catch (Exception t) when (t.IsThrowable())
                     {
                         Console.WriteLine("FAILED; unexpected exception");
@@ -1378,7 +1389,7 @@ namespace Lucene.Net.Index
                     {
                         Thread.Sleep(0);
                     }
-                    catch (ThreadInterruptedException)
+                    catch (Exception ie) when (ie.IsInterruptedException())
                     {
                         // ignore
                     }
@@ -1449,7 +1460,7 @@ namespace Lucene.Net.Index
             // up front... else we can see a false failure if 2nd
             // interrupt arrives while class loader is trying to
             // init this class (in servicing a first interrupt):
-            //Assert.IsTrue((new ThreadInterruptedException(new 
Exception("Thread interrupted"))).InnerException is ThreadInterruptedException);
+            Assert.IsTrue(new Util.ThreadInterruptedException(new 
System.Threading.ThreadInterruptedException()).InnerException is 
System.Threading.ThreadInterruptedException);
 
             // issue 300 interrupts to child thread
             int numInterrupts = AtLeast(300);
@@ -1494,8 +1505,7 @@ namespace Lucene.Net.Index
             // up front... else we can see a false failure if 2nd
             // interrupt arrives while class loader is trying to
             // init this class (in servicing a first interrupt):
-            // C# does not have the late load problem.
-            //Assert.IsTrue((new ThreadInterruptedException(new 
Exception("Thread interrupted"))).InnerException is ThreadInterruptedException);
+            Assert.IsTrue((new Util.ThreadInterruptedException(new 
System.Threading.ThreadInterruptedException())).InnerException is 
System.Threading.ThreadInterruptedException);
 
             // issue 300 interrupts to child thread
             int numInterrupts = AtLeast(300);
diff --git a/src/Lucene.Net.Tests/Index/TestIndexWriterReader.cs 
b/src/Lucene.Net.Tests/Index/TestIndexWriterReader.cs
index b000cf5..9bd112c 100644
--- a/src/Lucene.Net.Tests/Index/TestIndexWriterReader.cs
+++ b/src/Lucene.Net.Tests/Index/TestIndexWriterReader.cs
@@ -508,12 +508,20 @@ namespace Lucene.Net.Index
             {
                 for (int i = 0; i < outerInstance.numThreads; i++)
                 {
-
-                    threads[i].Join();
-                    // LUCENENET NOTE: No need to catch and rethrow same 
excepton type ThreadInterruptedException 
+                    try
+                    {
+                        threads[i].Join();
+                    }
+                    catch (Exception ie) when (ie.IsInterruptedException())
+                    {
+#pragma warning disable IDE0001 // Simplify name
+                        throw new Util.ThreadInterruptedException(ie);
+#pragma warning restore IDE0001 // Simplify name
+                    }
                 }
             }
 
+
             internal virtual void Close(bool doWait)
             {
                 didClose = true;
diff --git a/src/Lucene.Net.Tests/Index/TestIndexWriterWithThreads.cs 
b/src/Lucene.Net.Tests/Index/TestIndexWriterWithThreads.cs
index f9b0a71..65b6416 100644
--- a/src/Lucene.Net.Tests/Index/TestIndexWriterWithThreads.cs
+++ b/src/Lucene.Net.Tests/Index/TestIndexWriterWithThreads.cs
@@ -119,8 +119,14 @@ namespace Lucene.Net.Index
                         {
                             diskFull = true;
 
-                            Thread.Sleep(1);
-                            // LUCENENET NOTE: No need to catch and rethrow 
same excepton type ThreadInterruptedException
+                            try
+                            {
+                                Thread.Sleep(1);
+                            }
+                            catch (Exception ie) when 
(ie.IsInterruptedException())
+                            {
+                                throw new Util.ThreadInterruptedException(ie);
+                            }
 
                             if (fullCount++ >= 5)
                             {
diff --git a/src/Lucene.Net.Tests/Index/TestSnapshotDeletionPolicy.cs 
b/src/Lucene.Net.Tests/Index/TestSnapshotDeletionPolicy.cs
index d330a09..ae923a1 100644
--- a/src/Lucene.Net.Tests/Index/TestSnapshotDeletionPolicy.cs
+++ b/src/Lucene.Net.Tests/Index/TestSnapshotDeletionPolicy.cs
@@ -226,9 +226,14 @@ namespace Lucene.Net.Index
                         }
                     }
 
-                    Thread.Sleep(1);
-                    // LUCENENET NOTE: No need to catch and rethrow same 
excepton type ThreadInterruptedException
-
+                    try
+                    {
+                        Thread.Sleep(1);
+                    }
+                    catch (Exception ie) when (ie.IsInterruptedException())
+                    {
+                        throw new Util.ThreadInterruptedException(ie);
+                    }
                 } while (J2N.Time.NanoTime() / 
J2N.Time.MillisecondsPerNanosecond < stopTime); // LUCENENET: Use NanoTime() 
rather than CurrentTimeMilliseconds() for more accurate/reliable results
             }
         }
diff --git a/src/Lucene.Net.Tests/Search/TestControlledRealTimeReopenThread.cs 
b/src/Lucene.Net.Tests/Search/TestControlledRealTimeReopenThread.cs
index 302377d..441605a 100644
--- a/src/Lucene.Net.Tests/Search/TestControlledRealTimeReopenThread.cs
+++ b/src/Lucene.Net.Tests/Search/TestControlledRealTimeReopenThread.cs
@@ -521,12 +521,18 @@ namespace Lucene.Net.Search
             public override void UpdateDocument(Term term, 
IEnumerable<IIndexableField> doc, Analyzer analyzer)
             {
                 base.UpdateDocument(term, doc, analyzer);
-                if (waitAfterUpdate)
+                try
+                {
+                    if (waitAfterUpdate)
+                    {
+                        signal.Reset(signal.CurrentCount == 0 ? 0 : 
signal.CurrentCount - 1);
+                        latch.Wait();
+                    }
+                }
+                catch (Exception ie) when (ie.IsInterruptedException())
                 {
-                    signal.Reset(signal.CurrentCount == 0 ? 0 : 
signal.CurrentCount - 1);
-                    latch.Wait();
+                    throw new Util.ThreadInterruptedException(ie);
                 }
-                // LUCENENET NOTE: No need to catch and rethrow same excepton 
type ThreadInterruptedException 
             }
         }
 
diff --git a/src/Lucene.Net.Tests/Search/TestTimeLimitingCollector.cs 
b/src/Lucene.Net.Tests/Search/TestTimeLimitingCollector.cs
index 428855b..a41d341 100644
--- a/src/Lucene.Net.Tests/Search/TestTimeLimitingCollector.cs
+++ b/src/Lucene.Net.Tests/Search/TestTimeLimitingCollector.cs
@@ -401,8 +401,16 @@ namespace Lucene.Net.Search
                 int docId = doc + docBase;
                 if (slowdown > 0)
                 {
-                    ThreadJob.Sleep(slowdown);
-                    // LUCENENET NOTE: No need to catch and rethrow same 
excepton type ThreadInterruptedException
+                    try
+                    {
+                        ThreadJob.Sleep(slowdown);
+                    }
+                    catch (Exception ie) when (ie.IsInterruptedException())
+                    {
+#pragma warning disable IDE0001 // Simplify name
+                        throw new Util.ThreadInterruptedException(ie);
+#pragma warning restore IDE0001 // Simplify name
+                    }
                 }
 
                 if (Debugging.AssertsEnabled) Debugging.Assert(docId >= 0," 
base={0} doc={1}", docBase, doc);
diff --git 
a/src/Lucene.Net.Tests/Support/ExceptionHandling/TestExceptionExtensions.cs 
b/src/Lucene.Net.Tests/Support/ExceptionHandling/TestExceptionExtensions.cs
index 628b09e..2a9257f 100644
--- a/src/Lucene.Net.Tests/Support/ExceptionHandling/TestExceptionExtensions.cs
+++ b/src/Lucene.Net.Tests/Support/ExceptionHandling/TestExceptionExtensions.cs
@@ -318,7 +318,7 @@ namespace Lucene
                 typeof(Lucene.UnsupportedOperationException),
 
                 // Corresponds to Lucene's ThreadInterruptedException
-                typeof(ThreadInterruptedException),
+                typeof(Lucene.Net.Util.ThreadInterruptedException),
 
                 // Corresponds to SecurityException
                 typeof(SecurityException),
diff --git a/src/Lucene.Net/Index/ConcurrentMergeScheduler.cs 
b/src/Lucene.Net/Index/ConcurrentMergeScheduler.cs
index e873011..16c3b00 100644
--- a/src/Lucene.Net/Index/ConcurrentMergeScheduler.cs
+++ b/src/Lucene.Net/Index/ConcurrentMergeScheduler.cs
@@ -434,8 +434,14 @@ namespace Lucene.Net.Index
                         {
                             Message("    too many merges; stalling...");
                         }
-                        Monitor.Wait(this);
-                        // LUCENENET: Just let ThreadInterruptedException 
propagate. Note that it could be thrown above on lock (this).
+                        try
+                        {
+                            Monitor.Wait(this);
+                        }
+                        catch (Exception ie) when (ie.IsInterruptedException())
+                        {
+                            throw new Util.ThreadInterruptedException(ie);
+                        }
                     }
 
                     if (IsVerbose)
@@ -690,15 +696,21 @@ namespace Lucene.Net.Index
         /// </summary>
         protected virtual void HandleMergeException(Exception exc)
         {
-            // When an exception is hit during merge, IndexWriter
-            // removes any partial files and then allows another
-            // merge to run.  If whatever caused the error is not
-            // transient then the exception will keep happening,
-            // so, we sleep here to avoid saturating CPU in such
-            // cases:
-            Thread.Sleep(250);
+            try
+            {
+                // When an exception is hit during merge, IndexWriter
+                // removes any partial files and then allows another
+                // merge to run.  If whatever caused the error is not
+                // transient then the exception will keep happening,
+                // so, we sleep here to avoid saturating CPU in such
+                // cases:
+                Thread.Sleep(250);
+            }
+            catch (Exception ie) when (ie.IsInterruptedException())
+            {
+                throw new Util.ThreadInterruptedException(ie);
+            }
             throw new MergePolicy.MergeException(exc, m_dir);
-            // LUCENENET NOTE: No need to catch and rethrow same excepton type 
ThreadInterruptedException
         }
 
         private bool suppressExceptions;
diff --git a/src/Lucene.Net/Index/DocumentsWriterFlushControl.cs 
b/src/Lucene.Net/Index/DocumentsWriterFlushControl.cs
index 8a23eac..124f8b7 100644
--- a/src/Lucene.Net/Index/DocumentsWriterFlushControl.cs
+++ b/src/Lucene.Net/Index/DocumentsWriterFlushControl.cs
@@ -309,12 +309,18 @@ namespace Lucene.Net.Index
 
         public void WaitForFlush()
         {
-             lock (this)
+            lock (this)
             {
                 while (flushingWriters.Count != 0)
                 {
-                    Monitor.Wait(this);
-                    // LUCENENET NOTE: No need to catch and rethrow same 
excepton type ThreadInterruptedException 
+                    try
+                    {
+                        Monitor.Wait(this);
+                    }
+                    catch (Exception ie) when (ie.IsInterruptedException())
+                    {
+                        throw new Util.ThreadInterruptedException(ie);
+                    }
                 }
             }
         }
diff --git a/src/Lucene.Net/Index/DocumentsWriterPerThreadPool.cs 
b/src/Lucene.Net/Index/DocumentsWriterPerThreadPool.cs
index 10240f8..349af3c 100644
--- a/src/Lucene.Net/Index/DocumentsWriterPerThreadPool.cs
+++ b/src/Lucene.Net/Index/DocumentsWriterPerThreadPool.cs
@@ -350,8 +350,14 @@ namespace Lucene.Net.Index
                     else
                     {
                         // Wait until a thread state frees up:
-                        Monitor.Wait(this);
-                        // LUCENENET NOTE: No need to catch and rethrow same 
excepton type ThreadInterruptedException
+                        try
+                        {
+                            Monitor.Wait(this);
+                        }
+                        catch (Exception ie) when (ie.IsInterruptedException())
+                        {
+                            throw new Util.ThreadInterruptedException(ie);
+                        }
                     }
                 }
             }
diff --git a/src/Lucene.Net/Index/DocumentsWriterStallControl.cs 
b/src/Lucene.Net/Index/DocumentsWriterStallControl.cs
index 77303bc..fad1ab4 100644
--- a/src/Lucene.Net/Index/DocumentsWriterStallControl.cs
+++ b/src/Lucene.Net/Index/DocumentsWriterStallControl.cs
@@ -1,6 +1,7 @@
 using J2N.Runtime.CompilerServices;
 using J2N.Threading;
 using Lucene.Net.Diagnostics;
+using System;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Threading;
@@ -81,15 +82,20 @@ namespace Lucene.Net.Index
                     if (stalled) // react on the first wakeup call!
                     {
                         // don't loop here, higher level logic will re-stall!
-
-                        // LUCENENET: make sure not to run IncWaiters / 
DecrWaiters in Debugging.Assert as that gets 
-                        // disabled in production
-                        var result = IncWaiters();
-                        if (Debugging.AssertsEnabled) Debugging.Assert(result);
-                        Monitor.Wait(this);
-                        result = DecrWaiters();
-                        if (Debugging.AssertsEnabled) Debugging.Assert(result);
-                        // LUCENENET NOTE: No need to catch and rethrow same 
excepton type ThreadInterruptedException 
+                        try
+                        {
+                            // LUCENENET: make sure not to run IncWaiters / 
DecrWaiters in Debugging.Assert as that gets 
+                            // disabled in production
+                            var result = IncWaiters();
+                            if (Debugging.AssertsEnabled) 
Debugging.Assert(result);
+                            Monitor.Wait(this);
+                            result = DecrWaiters();
+                            if (Debugging.AssertsEnabled) 
Debugging.Assert(result);
+                        }
+                        catch (Exception ie) when (ie.IsInterruptedException())
+                        {
+                            throw new Util.ThreadInterruptedException(ie);
+                        }
                     }
                 }
             }
diff --git a/src/Lucene.Net/Index/IndexWriter.cs 
b/src/Lucene.Net/Index/IndexWriter.cs
index 5daf4ba..adda7ea 100644
--- a/src/Lucene.Net/Index/IndexWriter.cs
+++ b/src/Lucene.Net/Index/IndexWriter.cs
@@ -157,8 +157,8 @@ namespace Lucene.Net.Index
     /// <para><b>NOTE</b>: If you call
     /// <see cref="Thread.Interrupt()"/> on a thread that's within
     /// <see cref="IndexWriter"/>, <see cref="IndexWriter"/> will try to catch 
this (eg, if
-    /// it's in a Wait() or <see cref="Thread.Sleep(int)"/>), and will then 
throw
-    /// the unchecked exception <see cref="ThreadInterruptedException"/>
+    /// it's in a <see cref="Monitor.Wait(object)"/> or <see 
cref="Thread.Sleep(int)"/>), and will then throw
+    /// the unchecked exception <see cref="Util.ThreadInterruptedException"/>
     /// and <b>clear</b> the interrupt status on the thread.</para>
     /// </remarks>
 
@@ -1178,7 +1178,7 @@ namespace Lucene.Net.Index
                                 // any pending merges are waiting:
                                 mergeScheduler.Merge(this, 
MergeTrigger.CLOSING, false);
                             }
-                            catch (ThreadInterruptedException) // LUCENENET: 
In Lucene, they caught their custom ThreadInterruptedException here, so we are 
leaving this catch block as is
+                            catch (Util.ThreadInterruptedException)
                             {
                                 // ignore any interruption, does not matter
                                 interrupted = true;
@@ -1198,7 +1198,7 @@ namespace Lucene.Net.Index
                                     FinishMerges(waitForMerges && 
!interrupted);
                                     break;
                                 }
-                                catch (ThreadInterruptedException) // 
LUCENENET: In Lucene, they caught their custom ThreadInterruptedException here, 
so we are leaving this catch block as is
+                                catch (Util.ThreadInterruptedException)
                                 {
                                     // by setting the interrupted status, the
                                     // next call to finishMerges will pass 
false,
@@ -5329,9 +5329,14 @@ namespace Lucene.Net.Index
                 // fails to be called, we wait for at most 1 second
                 // and then return so caller can check if wait
                 // conditions are satisfied:
-
-                Monitor.Wait(this, TimeSpan.FromMilliseconds(1000));
-                // LUCENENET NOTE: No need to catch and rethrow same excepton 
type ThreadInterruptedException 
+                try
+                {
+                    Monitor.Wait(this, TimeSpan.FromMilliseconds(1000));
+                }
+                catch (Exception ie) when (ie.IsInterruptedException())
+                {
+                    throw new Util.ThreadInterruptedException(ie);
+                }
             }
         }
 
diff --git a/src/Lucene.Net/Search/ControlledRealTimeReopenThread.cs 
b/src/Lucene.Net/Search/ControlledRealTimeReopenThread.cs
index 961ea84..954c018 100644
--- a/src/Lucene.Net/Search/ControlledRealTimeReopenThread.cs
+++ b/src/Lucene.Net/Search/ControlledRealTimeReopenThread.cs
@@ -135,13 +135,21 @@ namespace Lucene.Net.Search
             {
                 finish = true;
                 reopenCond.Set();
-                
-                Join();
-                // LUCENENET NOTE: No need to catch and rethrow same excepton 
type ThreadInterruptedException
 
-                // LUCENENET specific: dispose reset event
-                reopenCond.Dispose();
-                available.Dispose();
+                try
+                {
+                    Join();
+                }
+                catch (Exception ie) when (ie.IsInterruptedException())
+                {
+                    throw new Util.ThreadInterruptedException(ie);
+                }
+                finally
+                {
+                    // LUCENENET specific: dispose reset event
+                    reopenCond.Dispose();
+                    available.Dispose();
+                }
             }
         }
 
diff --git a/src/Lucene.Net/Search/IndexSearcher.cs 
b/src/Lucene.Net/Search/IndexSearcher.cs
index 50e9213..f76d991 100644
--- a/src/Lucene.Net/Search/IndexSearcher.cs
+++ b/src/Lucene.Net/Search/IndexSearcher.cs
@@ -880,8 +880,7 @@ namespace Lucene.Net.Search
                     }
                     catch (Exception e) when (e.IsInterruptedException())
                     {
-                        // LUCENENET: Throwing as same type, no need to wrap 
here
-                        throw; // LUCENENET: CA2200: Rethrow to preserve stack 
details 
(https://docs.microsoft.com/en-us/visualstudio/code-quality/ca2200-rethrow-to-preserve-stack-details)
+                        throw new Util.ThreadInterruptedException(e);
                     }
                     catch (Exception e)
                     {
diff --git a/src/Lucene.Net/Search/TimeLimitingCollector.cs 
b/src/Lucene.Net/Search/TimeLimitingCollector.cs
index 651d983..4549503 100644
--- a/src/Lucene.Net/Search/TimeLimitingCollector.cs
+++ b/src/Lucene.Net/Search/TimeLimitingCollector.cs
@@ -304,8 +304,14 @@ namespace Lucene.Net.Search
                     // TODO: Use System.nanoTime() when Lucene moves to Java 
SE 5.
                     counter.AddAndGet(resolution);
 
-                    
Thread.Sleep(TimeSpan.FromMilliseconds(Interlocked.Read(ref resolution)));
-                    // LUCENENET NOTE: No need to catch and rethrow same 
excepton type ThreadInterruptedException 
+                    try
+                    {
+                        
Thread.Sleep(TimeSpan.FromMilliseconds(Interlocked.Read(ref resolution)));
+                    }
+                    catch (Exception ie) when (ie.IsInterruptedException())
+                    {
+                        throw new Util.ThreadInterruptedException(ie);
+                    }
                 }
             }
 
diff --git a/src/Lucene.Net/Store/Lock.cs b/src/Lucene.Net/Store/Lock.cs
index 4ee94d0..0f9d167 100644
--- a/src/Lucene.Net/Store/Lock.cs
+++ b/src/Lucene.Net/Store/Lock.cs
@@ -136,8 +136,14 @@ namespace Lucene.Net.Store
                     throw e;
                 }
 
-                Thread.Sleep(TimeSpan.FromMilliseconds(LOCK_POLL_INTERVAL));
-                // LUCENENET NOTE: No need to catch and rethrow same excepton 
type ThreadInterruptedException
+                try
+                {
+                    
Thread.Sleep(TimeSpan.FromMilliseconds(LOCK_POLL_INTERVAL));
+                }
+                catch (Exception ie) when (ie.IsInterruptedException())
+                {
+                    throw new Util.ThreadInterruptedException(ie);
+                }
 
                 locked = Obtain();
             }
diff --git a/src/Lucene.Net/Store/RateLimiter.cs 
b/src/Lucene.Net/Store/RateLimiter.cs
index df7ccd0..61e2339 100644
--- a/src/Lucene.Net/Store/RateLimiter.cs
+++ b/src/Lucene.Net/Store/RateLimiter.cs
@@ -120,8 +120,14 @@ namespace Lucene.Net.Store
                     var pauseNS = targetNS - curNS;
                     if (pauseNS > 0)
                     {
-                        Thread.Sleep(TimeSpan.FromMilliseconds(pauseNS / 
1000000));
-                        // LUCENENET NOTE: No need to catch and rethrow same 
excepton type ThreadInterruptedException
+                        try
+                        {
+                            Thread.Sleep(TimeSpan.FromMilliseconds(pauseNS / 
1000000));
+                        }
+                        catch (Exception ie) when (ie.IsInterruptedException())
+                        {
+                            throw new Util.ThreadInterruptedException(ie);
+                        }
 
                         curNS = Time.NanoTime();
                         continue;
diff --git a/src/Lucene.Net/Support/ExceptionHandling/ExceptionExtensions.cs 
b/src/Lucene.Net/Support/ExceptionHandling/ExceptionExtensions.cs
index 3795b7a..5a25bf6 100644
--- a/src/Lucene.Net/Support/ExceptionHandling/ExceptionExtensions.cs
+++ b/src/Lucene.Net/Support/ExceptionHandling/ExceptionExtensions.cs
@@ -155,6 +155,10 @@ namespace Lucene
                 // .NET made IOException a SystemExcpetion, but those should 
not be included here
                 e.IsIOException() ||
 
+                // .NET made System.Threading.ThreadInterruptedException a 
SystemException, but we need to ignore it
+                // because InterruptedException in Java subclasses Exception, 
not RuntimeException
+                e is System.Threading.ThreadInterruptedException ||
+
                 // ObjectDisposedException is a special case because in Lucene 
the AlreadyClosedException derived
                 // from IOException and was therefore a checked excpetion type.
                 e is ObjectDisposedException ||
@@ -448,10 +452,10 @@ namespace Lucene
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public static bool IsInterruptedException(this Exception e)
         {
-            // LUCENENET: Special case - we only catch under certain scenarios 
and do not rethrow explicitly.
             // This exception is the shutdown signal for a thread and it is 
used in Lucene for control flow.
-            // However, in .NET it is thrown in more cases than in Java. So, 
rather than wrapping it in a new
-            // exception type, we don't catch it unless there is a specific 
reason to do something other than re-throw.
+            // Lucene uses a custom Lucene.Net.Util.ThreadInterruptedException 
exception to handle the signal.
+            // It is only thrown from certain blocks, and we use 
UninterruptableMonitor.Enter() to avoid getting
+            // the System.Threading.ThreadInterruptedException when obtaining 
locks.
             return e is ThreadInterruptedException;
         }
 
diff --git a/src/Lucene.Net/Util/ThreadInterruptedException.cs 
b/src/Lucene.Net/Util/ThreadInterruptedException.cs
new file mode 100644
index 0000000..85dbc89
--- /dev/null
+++ b/src/Lucene.Net/Util/ThreadInterruptedException.cs
@@ -0,0 +1,64 @@
+using System;
+#if FEATURE_SERIALIZABLE_EXCEPTIONS
+using System.Runtime.Serialization;
+#endif
+
+namespace Lucene.Net.Util
+{
+    /*
+     * 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.
+     */
+
+    /// <summary>
+    /// Thrown by Lucene on detecing that <see 
cref="System.Threading.Thread.Interrupt()"/> had been
+    /// called. This exception has the specific purpose of being allowed to 
pass through to the
+    /// calling thread of <see cref="J2N.Threading.ThreadJob"/> so it reaches 
the appropriate handler.
+    /// </summary>
+    // LUCENENET: In Lucene, this exception was so it could be re-thrown 
unchecked. It has been
+    // re-purposed in .NET but used in all the same scenerios.
+    // LUCENENET: It is no longer good practice to use binary serialization. 
+    // See: 
https://github.com/dotnet/corefx/issues/23584#issuecomment-325724568
+#if FEATURE_SERIALIZABLE_EXCEPTIONS
+    [Serializable]
+#endif
+    public class ThreadInterruptedException : Exception, IRuntimeException
+    {
+        public ThreadInterruptedException(Exception interruptedException)
+            : base(interruptedException.Message, interruptedException)
+        {
+        }
+
+        public ThreadInterruptedException(string message) : base(message)
+        {
+        }
+
+        public ThreadInterruptedException(string message, Exception 
innerException) : base(message, innerException)
+        {
+        }
+
+#if FEATURE_SERIALIZABLE_EXCEPTIONS
+        /// <summary>
+        /// Initializes a new instance of this class with serialized data.
+        /// </summary>
+        /// <param name="info">The <see cref="SerializationInfo"/> that holds 
the serialized object data about the exception being thrown.</param>
+        /// <param name="context">The <see cref="StreamingContext"/> that 
contains contextual information about the source or destination.</param>
+        protected ThreadInterruptedException(SerializationInfo info, 
StreamingContext context)
+            : base(info, context)
+        {
+        }
+#endif
+    }
+}

Reply via email to