package org.apache.lucene.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.
 */

import java.io.Closeable;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.NRTManager; // javadocs
import org.apache.lucene.store.AlreadyClosedException;
import org.apache.lucene.store.Directory;

/** Utility class to safely share {@link IndexSearcher} instances
 *  across multiple threads, while periodically reopening.
 *  This class ensures each IndexSearcher instance is not
 *  closed until it is no longer needed.
 *
 *  <p>Use {@link #get} to obtain the current searcher, and
 *  {@link #release} to release it, like this:
 *
 *  <pre>
 *    IndexSearcher s = manager.get();
 *    try {
 *      // Do searching, doc retrieval, etc. with s
 *    } finally {
 *      manager.release(s);
 *    }
 *    // Do not use s after this!
 *    s = null;
 *  </pre>
 *
 *  <p>In addition you should periodically call {@link
 *  #maybeReopen}.  While it's possible to call this just
 *  before running each query, this is discouraged since it
 *  penalizes the unlucky queries that do the reopen.  It's
 *  better to  use a separate background thread, that
 *  periodically calls maybeReopen.  Finally, be sure to
 *  call {@link #close} once you are done.
 *
 *  <p><b>NOTE</b>: if you have an {@link IndexWriter}, it's
 *  better to use {@link NRTManager} since that class pulls
 *  near-real-time readers from the IndexWriter.
 *
 *  @lucene.experimental
 */

public class SearcherManager implements Closeable {

  // Current searcher
  private volatile IndexSearcher currentSearcher;
  private final SearcherWarmer warmer;
  private final AtomicBoolean reopening = new AtomicBoolean();
  private final ExecutorService es;

  /** Opens an initial searcher from the Directory.
   *
   * @param dir Directory to open the searcher from
   *
   * @param warmer optional {@link SearcherWarmer}.  Pass
   *        null if you don't require the searcher to warmed
   *        before going live.
   *
   *  <p><b>NOTE</b>: the provided {@link SearcherWarmer} is
   *  not invoked for the initial searcher; you should
   *  warm it yourself if necessary.
   */
  public SearcherManager(Directory dir, SearcherWarmer warmer) throws IOException {
    this(dir, warmer, null);
  }

  /** Opens an initial searcher from the Directory.
   *
   * @param dir Directory to open the searcher from
   *
   * @param warmer optional {@link SearcherWarmer}.  Pass
   *        null if you don't require the searcher to warmed
   *        before going live.
   *
   * @param es optional ExecutorService so different segments can
   *        be searched concurrently (see {@link
   *        IndexSearcher#IndexSearcher(IndexReader,ExecutorService)}.  Pass null
   *        to search segments sequentially.
   *
   *  <p><b>NOTE</b>: the provided {@link SearcherWarmer} is
   *  not invoked for the initial searcher; you should
   *  warm it yourself if necessary.
   */
  public SearcherManager(Directory dir, SearcherWarmer warmer, ExecutorService es) throws IOException {
    this.es = es;
    currentSearcher = new IndexSearcher(IndexReader.open(dir), this.es);
    this.warmer = warmer;
  }

  /** You must call this, periodically, to perform a
   *  reopen.  This calls {@link IndexReader#reopen} on the
   *  underlying reader, and if that returns a new reader,
   *  it's warmed (if you provided a {@link SearcherWarmer}
   *  and then swapped into production.
   *
   *  <p><b>Threads</b>: it's fine for more than one thread to
   *  call this at once.  Only the first thread will attempt
   *  the reopen; subsequent threads will see that another
   *  thread is already handling reopen and will return
   *  immediately.  Note that this means if another thread
   *  is already reopening then subsequent threads will
   *  return right away without waiting for the reader
   *  reopen to complete.</p>
   *
   *  <p>This method returns true if a new reader was in
   *  fact opened.</p>
   */
  public boolean maybeReopen()
    throws  IOException {

    if (currentSearcher == null) {
      throw new AlreadyClosedException("this SearcherManager is closed");
    }

    // Ensure only 1 thread does reopen at once; other
    // threads just return immediately:
    if (!reopening.getAndSet(true)) {
      try {
        IndexReader newReader = currentSearcher.getIndexReader().reopen();
        if (newReader != currentSearcher.getIndexReader()) {
          IndexSearcher newSearcher = new IndexSearcher(newReader, es);
          if (warmer != null) {
            warmer.warm(newSearcher);
          }
          swapSearcher(newSearcher);
          return true;
        } else {
          return false;
        }
      } finally {
        reopening.set(false);
      }
    } else {
      return false;
    }
  }

  /** Obtain the current IndexSearcher.  You must match
   *  every call to get with one call to {@link #release};
   *  it's best to do so in a finally clause. */
  public IndexSearcher get() {
    IndexSearcher toReturn = currentSearcher;
    if (toReturn == null) {
      throw new AlreadyClosedException("this SearcherManager is closed");
    }
    toReturn.getIndexReader().incRef();
    return toReturn;
  }    

  /** Release the searcher previously obtained with {@link
   *  #get}.
   *
   *  <p><b>NOTE</b>: it's safe to call this after {@link
   *  #close}. */
  public void release(IndexSearcher searcher)
    throws IOException {
    searcher.getIndexReader().decRef();
  }

  // Replaces old searcher with new one
  private void swapSearcher(IndexSearcher newSearcher)
    throws IOException {
    IndexSearcher oldSearcher = currentSearcher;
    if (oldSearcher == null) {
      throw new AlreadyClosedException("this SearcherManager is closed");
    }
    currentSearcher = newSearcher;
    release(oldSearcher);
  }

  /** Close this SearcherManager to future searching.  Any
   *  searches still in process in other threads won't be
   *  affected, and they should still call {@link #release}
   *  after they are done. */
  @Override
  public void close() throws IOException {
    swapSearcher(null);
  }
}

@@ -6964,16 +6964,34 @@
 ne. */%0A 
+ // Not in Java 5:
  @Overri

Fix interface @Override