/* * 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 System; namespace Lucene.Net.Search { ///

/// The TimeLimitedCollector is used to timeout search requests that take longer /// than the maximum allowed search time limit. After this time is exceeded, the /// search thread is stopped by throwing a TimeExceeded Exception. ///

/// ///

/// Use {@link TimeLimitingCollector} instead, which extends the new /// {@link Collector}. This class will be removed in 3.0. /// [Obsolete("Use TimeLimitingCollector instead, which extends the new Collector. This class will be removed in 3.0.")] public class TimeLimitedCollector:HitCollector { private void InitBlock() { greedy = DEFAULT_GREEDY; } /// Default timer resolution. /// /// public const int DEFAULT_RESOLUTION = 20; /// Default for {@link #IsGreedy()}. /// /// public bool DEFAULT_GREEDY = false; private static uint resolution = DEFAULT_RESOLUTION; private bool greedy; private class TimerThread:SupportClass.ThreadClass { // NOTE: we can avoid explicit synchronization here for several reasons: // * updates to volatile long variables are atomic // * only single thread modifies this value // * use of volatile keyword ensures that it does not reside in // a register, but in main memory (so that changes are visible to // other threads). // * visibility of changes does not need to be instantanous, we can // afford losing a tick or two. // // See section 17 of the Java Language Specification for details. private volatile uint time = 0; /// TimerThread provides a pseudo-clock service to all searching /// threads, so that they can count elapsed time with less overhead /// than repeatedly calling System.currentTimeMillis. A single /// thread should be created to be used for all searches. /// internal TimerThread():base("TimeLimitedCollector timer thread") { this.IsBackground = true; } override public void Run() { while (true) { // TODO: Use System.nanoTime() when Lucene moves to Java SE 5. time += Lucene.Net.Search.TimeLimitedCollector.resolution; try { System.Threading.Thread.Sleep(new System.TimeSpan((System.Int64) 10000 * Lucene.Net.Search.TimeLimitedCollector.resolution)); } catch (System.Threading.ThreadInterruptedException ie) { SupportClass.ThreadClass.Current().Interrupt(); throw new System.SystemException(ie.Message, ie); } } } /// Get the timer value in milliseconds. public virtual long GetMilliseconds() { return time; } } /// Thrown when elapsed search time exceeds allowed search time. [Serializable] public class TimeExceededException:System.SystemException { private long timeAllowed; private long timeElapsed; private int lastDocCollected; internal TimeExceededException(long timeAllowed, long timeElapsed, int lastDocCollected):base("Elapsed time: " + timeElapsed + "Exceeded allowed search time: " + timeAllowed + " ms.") { this.timeAllowed = timeAllowed; this.timeElapsed = timeElapsed; this.lastDocCollected = lastDocCollected; } /// Returns allowed time (milliseconds). public virtual long GetTimeAllowed() { return timeAllowed; } /// Returns elapsed time (milliseconds). public virtual long GetTimeElapsed() { return timeElapsed; } /// Returns last doc that was collected when the search time exceeded. public virtual int GetLastDocCollected() { return lastDocCollected; } } // Declare and initialize a single static timer thread to be used by // all TimeLimitedCollector instances. The JVM assures that // this only happens once. private static readonly TimerThread TIMER_THREAD = new TimerThread(); private long t0; private long timeout; private HitCollector hc; /// Create a TimeLimitedCollector wrapper over another HitCollector with a specified timeout. /// the wrapped HitCollector /// /// max time allowed for collecting hits after which {@link TimeExceededException} is thrown /// public TimeLimitedCollector(HitCollector hc, long timeAllowed) { InitBlock(); this.hc = hc; t0 = TIMER_THREAD.GetMilliseconds(); this.timeout = t0 + timeAllowed; } /// Calls collect() on the decorated HitCollector. /// /// /// TimeExceededException if the time allowed has been exceeded. public override void Collect(int doc, float score) { long time = TIMER_THREAD.GetMilliseconds(); if (timeout < time) { if (greedy) { //System.out.println(this+" greedy: before failing, collecting doc: "+doc+" "+(time-t0)); hc.Collect(doc, score); } //System.out.println(this+" failing on: "+doc+" "+(time-t0)); throw new TimeExceededException(timeout - t0, time - t0, doc); } //System.out.println(this+" collecting: "+doc+" "+(time-t0)); hc.Collect(doc, score); } /// Return the timer resolution. /// /// public static long GetResolution() { return resolution; } /// Set the timer resolution. /// The default timer resolution is 20 milliseconds. /// This means that a search required to take no longer than /// 800 milliseconds may be stopped after 780 to 820 milliseconds. ///
Note that: /// ///
public static void SetResolution(uint newResolution) { resolution = System.Math.Max(newResolution, 5); // 5 milliseconds is about the minimum reasonable time for a Object.wait(long) call. } /// Checks if this time limited collector is greedy in collecting the last hit. /// A non greedy collector, upon a timeout, would throw a {@link TimeExceededException} /// without allowing the wrapped collector to collect current doc. A greedy one would /// first allow the wrapped hit collector to collect current doc and only then /// throw a {@link TimeExceededException}. /// /// /// public virtual bool IsGreedy() { return greedy; } /// Sets whether this time limited collector is greedy. /// true to make this time limited greedy /// /// /// public virtual void SetGreedy(bool greedy) { this.greedy = greedy; } static TimeLimitedCollector() { { TIMER_THREAD.Start(); } } } }