Lucene.Net.Core.Search.ControlledRealTimeReopenThread: Changed implementation 
to be more .NETified, which fixes the TestCRTReopen() test (fix provided by 
Vincent Van Den Berghe). Updated documentation comments.


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

Branch: refs/heads/api-work
Commit: dfb2e92839dd29cbdc47d8c37af9325ea351709b
Parents: e30f52d
Author: Shad Storhaug <[email protected]>
Authored: Fri Mar 24 17:36:12 2017 +0700
Committer: Shad Storhaug <[email protected]>
Committed: Fri Mar 24 17:36:12 2017 +0700

----------------------------------------------------------------------
 .../Search/ControlledRealTimeReopenThread.cs    | 241 ++++++++-----------
 1 file changed, 95 insertions(+), 146 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/dfb2e928/src/Lucene.Net.Core/Search/ControlledRealTimeReopenThread.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Core/Search/ControlledRealTimeReopenThread.cs 
b/src/Lucene.Net.Core/Search/ControlledRealTimeReopenThread.cs
index 294c1eb..79fb237 100644
--- a/src/Lucene.Net.Core/Search/ControlledRealTimeReopenThread.cs
+++ b/src/Lucene.Net.Core/Search/ControlledRealTimeReopenThread.cs
@@ -5,42 +5,41 @@ using System.Threading;
 namespace Lucene.Net.Search
 {
     /*
-     * 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.
+        */
 
     using TrackingIndexWriter = Lucene.Net.Index.TrackingIndexWriter;
 
     /// <summary>
-    /// Utility class that runs a thread to manage periodicc
-    ///  reopens of a <seealso cref="ReferenceManager"/>, with methods to wait 
for a specific
-    ///  index changes to become visible.  To use this class you
-    ///  must first wrap your <seealso cref="Index.IndexWriter"/> with a {@link
-    ///  TrackingIndexWriter} and always use it to make changes
-    ///  to the index, saving the returned generation.  Then,
-    ///  when a given search request needs to see a specific
-    ///  index change, call the {#waitForGeneration} to wait for
-    ///  that change to be visible.  Note that this will only
-    ///  scale well if most searches do not need to wait for a
-    ///  specific index generation.
-    ///
+    /// Utility class that runs a thread to manage periodic
+    /// reopens of a <see cref="ReferenceManager{T}"/>, with methods to wait 
for a specific
+    /// index changes to become visible.  To use this class you
+    /// must first wrap your <see cref="Index.IndexWriter"/> with a
+    /// <see cref="TrackingIndexWriter"/> and always use it to make changes
+    /// to the index, saving the returned generation.  Then,
+    /// when a given search request needs to see a specific
+    /// index change, call the <see cref="WaitForGeneration(long)"/> to wait 
for
+    /// that change to be visible.  Note that this will only
+    /// scale well if most searches do not need to wait for a
+    /// specific index generation.
+    /// <para/>
     /// @lucene.experimental
     /// </summary>
-
     public class ControlledRealTimeReopenThread<T> : ThreadClass, IDisposable
-        where T : class
+         where T : class
     {
         private readonly ReferenceManager<T> manager;
         private readonly long targetMaxStaleNS;
@@ -51,14 +50,14 @@ namespace Lucene.Net.Search
         private long searchingGen;
         private long refreshStartGen;
 
-        private readonly ReentrantLock reopenLock = new ReentrantLock();
         private EventWaitHandle reopenCond = new AutoResetEvent(false);
+        private EventWaitHandle available = new AutoResetEvent(false);
 
         private const long MILLISECONDS_PER_NANOSECOND = 1000000;
 
         /// <summary>
-        /// Create ControlledRealTimeReopenThread, to periodically
-        /// reopen the a <seealso cref="ReferenceManager"/>.
+        /// Create <see cref="ControlledRealTimeReopenThread{T}"/>, to 
periodically
+        /// reopen the a <see cref="ReferenceManager{T}"/>.
         /// </summary>
         /// <param name="targetMaxStaleSec"> Maximum time until a new
         ///        reader must be opened; this sets the upper bound
@@ -107,50 +106,32 @@ namespace Lucene.Net.Search
         {
             lock (this)
             {
-                // LUCENENET specific - reading searchingGen not thread safe, 
so use Interlocked.Exchange()
-                Interlocked.Exchange(ref searchingGen, refreshStartGen);
-                Monitor.PulseAll(this);
+                // if we're finishing, , make it out so that all waiting 
search threads will return
+                searchingGen = finish ? long.MaxValue : refreshStartGen;
+                available.Set();
             }
+            reopenCond.Reset();
         }
 
         public void Dispose() // LUCENENET TODO: Implement disposable pattern
         {
-            lock (this)
-            {
-                //System.out.println("NRT: set finish");
-
-                finish = true;
-
-                // So thread wakes up and notices it should finish:
-                reopenLock.Lock();
-                try
-                {
-                    reopenCond.Set();
-                }
-                finally
-                {
-                    reopenLock.Unlock();
-                }
-
+            finish = true;
+            reopenCond.Set();
 #if !NETSTANDARD
-                try
-                {
+            try
+            {
 #endif
-                    Join();
+                Join();
 #if !NETSTANDARD
-                }
-                catch (ThreadInterruptedException ie)
-                {
-                    throw new ThreadInterruptedException(ie.ToString(), ie);
-                }
-#endif
-                // Max it out so any waiting search threads will return:
-                searchingGen = long.MaxValue;
-                Monitor.PulseAll(this);
-
-                // LUCENENET specific: dispose reset event
-                reopenCond.Dispose();
             }
+            catch (ThreadInterruptedException ie)
+            {
+                throw new ThreadInterruptedException(ie.ToString(), ie);
+            }
+#endif
+            // LUCENENET specific: dispose reset event
+            reopenCond.Dispose();
+            available.Dispose();
         }
 
         /// <summary>
@@ -159,7 +140,7 @@ namespace Lucene.Net.Search
         /// If the current searcher is older than the
         /// target generation, this method will block
         /// until the searcher is reopened, by another via
-        /// <seealso cref="ReferenceManager#maybeRefresh"/> or until the 
<seealso cref="ReferenceManager"/> is closed.
+        /// <see cref="ReferenceManager{T}.MaybeRefresh()"/> or until the <see 
cref="ReferenceManager{T}"/> is closed.
         /// </summary>
         /// <param name="targetGen"> the generation to wait for </param>
         public virtual void WaitForGeneration(long targetGen)
@@ -173,74 +154,59 @@ namespace Lucene.Net.Search
         /// If the current searcher is older than the target
         /// generation, this method will block until the
         /// searcher has been reopened by another thread via
-        /// <seealso cref="ReferenceManager#maybeRefresh"/>, the given waiting 
time has elapsed, or until
-        /// the <seealso cref="ReferenceManager"/> is closed.
-        /// <p>
+        /// <see cref="ReferenceManager{T}.MaybeRefresh()"/>, the given 
waiting time has elapsed, or until
+        /// the <seealso cref="ReferenceManager{T}"/> is closed.
+        /// <para/>
         /// NOTE: if the waiting time elapses before the requested target 
generation is
-        /// available the current <seealso cref="SearcherManager"/> is 
returned instead.
+        /// available the current <see cref="SearcherManager"/> is returned 
instead.
         /// </summary>
         /// <param name="targetGen">
         ///          the generation to wait for </param>
         /// <param name="maxMS">
         ///          maximum milliseconds to wait, or -1 to wait indefinitely 
</param>
-        /// <returns> true if the targetGeneration is now available,
-        ///         or false if maxMS wait time was exceeded </returns>
+        /// <returns> true if the <paramref name="targetGen"/> is now 
available,
+        ///         or false if <paramref name="maxMS"/> wait time was 
exceeded </returns>
         public virtual bool WaitForGeneration(long targetGen, int maxMS)
         {
-            lock (this)
+            long curGen = writer.Generation;
+            if (targetGen > curGen)
             {
-                long curGen = writer.Generation;
-                if (targetGen > curGen)
+                throw new System.ArgumentException("targetGen=" + targetGen + 
" was never returned by the ReferenceManager instance (current gen=" + curGen + 
")");
+            }
+            lock (this)
+                if (targetGen <= searchingGen)
+                    return true;
+                else
                 {
-                    throw new System.ArgumentException("targetGen=" + 
targetGen + " was never returned by the ReferenceManager instance (current 
gen=" + curGen + ")");
+                    waitingGen = Math.Max(waitingGen, targetGen);
+                    reopenCond.Set();
+                    available.Reset();
                 }
-                // LUCENENET specific - reading searchingGen not thread safe, 
so use Interlocked.Read()
-                if (targetGen > Interlocked.Read(ref searchingGen))
-                {
-                    // Notify the reopen thread that the waitingGen has
-                    // changed, so it may wake up and realize it should
-                    // not sleep for much or any longer before reopening:
-                    reopenLock.Lock();
 
-                    // Need to find waitingGen inside lock as its used to 
determine
-                    // stale time
-                    waitingGen = Math.Max(waitingGen, targetGen);
+            long startMS = Environment.TickCount;//System.nanoTime() / 1000000;
 
-                    try
-                    {
-                        reopenCond.Set();
-                    }
-                    finally
+            // LUCENENET specific - reading searchingGen not thread safe, so 
use Interlocked.Read()
+            while (targetGen > Interlocked.Read(ref searchingGen))
+            {
+                if (maxMS < 0)
+                {
+                    available.WaitOne();
+                }
+                else
+                {
+                    long msLeft = (startMS + maxMS) - 
Environment.TickCount;//(System.nanoTime()) / 1000000;
+                    if (msLeft <= 0)
                     {
-                        reopenLock.Unlock();
+                        return false;
                     }
-
-                    long startMS = Environment.TickCount;//System.nanoTime() / 
1000000;
-
-                    // LUCENENET specific - reading searchingGen not thread 
safe, so use Interlocked.Read()
-                    while (targetGen > Interlocked.Read(ref searchingGen))
+                    else
                     {
-                        if (maxMS < 0)
-                        {
-                            Monitor.Wait(this);
-                        }
-                        else
-                        {
-                            long msLeft = (startMS + maxMS) - 
Environment.TickCount;//(System.nanoTime()) / 1000000;
-                            if (msLeft <= 0)
-                            {
-                                return false;
-                            }
-                            else
-                            {
-                                Monitor.Wait(this, 
TimeSpan.FromMilliseconds(msLeft));
-                            }
-                        }
+                        available.WaitOne(TimeSpan.FromMilliseconds(msLeft));
                     }
                 }
-
-                return true;
             }
+
+            return true;
         }
 
         public override void Run()
@@ -252,36 +218,22 @@ namespace Lucene.Net.Search
             //System.out.println("reopen: start");
             while (!finish)
             {
-                // TODO: try to guestimate how long reopen might
-                // take based on past data?
+                bool hasWaiting;
 
-                // Loop until we've waiting long enough before the
-                // next reopen:
-                while (!finish)
-                {
-                    // Need lock before finding out if has waiting
+                lock (this)
+                    hasWaiting = waitingGen > searchingGen;
 
-                    reopenLock.Lock();
+                long nextReopenStartNS = lastReopenStartNS + (hasWaiting ? 
targetMinStaleNS : targetMaxStaleNS);
+                long sleepNS = nextReopenStartNS - (Environment.TickCount * 
MILLISECONDS_PER_NANOSECOND);
 
+                if (sleepNS > 0)
+#if !NETSTANDARD
                     try
                     {
-                        // True if we have someone waiting for reopened 
searcher:
-                        bool hasWaiting = waitingGen > searchingGen;
-                        long nextReopenStartNS = lastReopenStartNS + 
(hasWaiting ? targetMinStaleNS : targetMaxStaleNS);
-
-                        long sleepNS = nextReopenStartNS - 
(Environment.TickCount * MILLISECONDS_PER_NANOSECOND);
-
-                        if (sleepNS > 0)
-                        {
-                            
reopenCond.WaitOne(TimeSpan.FromMilliseconds(sleepNS / 
MILLISECONDS_PER_NANOSECOND));//Convert NS to Ticks
-                        }
-                        else
-                        {
-                            break;
-                        }
-
-                    }
+#endif
+                        reopenCond.WaitOne(TimeSpan.FromMilliseconds(sleepNS / 
MILLISECONDS_PER_NANOSECOND));//Convert NS to Ticks
 #if !NETSTANDARD
+                    }
 #pragma warning disable 168
                     catch (ThreadInterruptedException ie)
 #pragma warning restore 168
@@ -290,11 +242,6 @@ namespace Lucene.Net.Search
                         return;
                     }
 #endif
-                    finally
-                    {
-                        reopenLock.Unlock();
-                    }
-                }
 
                 if (finish)
                 {
@@ -315,6 +262,8 @@ namespace Lucene.Net.Search
                     throw new Exception(ioe.ToString(), ioe);
                 }
             }
+            // this will set the searchingGen so that all waiting threads will 
exit
+            RefreshDone();
         }
     }
 }
\ No newline at end of file

Reply via email to