@@ -70,6 +70,14 @@ namespace Lucene.Net.Search
7070 /// synchronize on the <see cref="IndexSearcher"/> instance;
7171 /// use your own (non-Lucene) objects instead.</p>
7272 /// </summary>
73+ /// <remarks>
74+ /// LUCENENET Specific - Search methods have had an optional <see cref="CancellationToken"/> parameter added
75+ /// to allow for cancellation of the search operation. For multithreaded search operations, the
76+ /// <see cref="TaskScheduler"/> passed to the constructor will be used to execute the search operations
77+ /// and the <see cref="CancellationToken"/> will be passed to the awaited tasks. If the <see cref="TaskScheduler"/>
78+ /// is <c>null</c>, the search operations will be executed synchronously, and the <see cref="CancellationToken"/>
79+ /// will throw if cancellation is requested upon entry to each leaf reader.
80+ /// </remarks>
7381 public class IndexSearcher
7482 {
7583 internal readonly IndexReader reader ; // package private for testing!
@@ -527,7 +535,7 @@ protected virtual TopDocs Search(Weight weight, ScoreDoc? after, int nDocs, Canc
527535
528536 HitQueue hq = new HitQueue ( nDocs , prePopulate : false ) ;
529537 ReentrantLock @lock = new ReentrantLock ( ) ;
530- ExecutionHelper < TopDocs > runner = new ExecutionHelper < TopDocs > ( executor ) ;
538+ ExecutionHelper < TopDocs > runner = new ExecutionHelper < TopDocs > ( executor , cancellationToken ) ;
531539
532540 for ( int i = 0 ; i < m_leafSlices . Length ; i ++ ) // search each sub
533541 {
@@ -637,7 +645,7 @@ protected virtual TopFieldDocs Search(Weight weight, FieldDoc? after, int nDocs,
637645 TopFieldCollector topCollector = TopFieldCollector . Create ( sort , nDocs , after , fillFields , doDocScores , doMaxScore , false ) ;
638646
639647 ReentrantLock @lock = new ReentrantLock ( ) ;
640- ExecutionHelper < TopFieldDocs > runner = new ExecutionHelper < TopFieldDocs > ( executor ) ;
648+ ExecutionHelper < TopFieldDocs > runner = new ExecutionHelper < TopFieldDocs > ( executor , cancellationToken ) ;
641649
642650 for ( int i = 0 ; i < m_leafSlices . Length ; i ++ ) // search each leaf slice
643651 {
@@ -722,6 +730,8 @@ protected virtual void Search(IList<AtomicReaderContext> leaves, Weight weight,
722730 // always use single thread:
723731 foreach ( AtomicReaderContext ctx in leaves ) // search each subreader
724732 {
733+ cancellationToken . ThrowIfCancellationRequested ( ) ; // LUCENENET specific - cancellation support at leaf level
734+
725735 try
726736 {
727737 collector . SetNextReader ( ctx ) ;
@@ -960,12 +970,14 @@ public TopFieldDocs Call()
960970 private sealed class ExecutionHelper < T > : IEnumerator < T > , IEnumerable < T >
961971 {
962972 private readonly TaskSchedulerCompletionService < T > service ;
973+ private readonly CancellationToken cancellationToken ;
963974 private int numTasks ;
964975 private T current ;
965976
966- internal ExecutionHelper ( TaskScheduler executor )
977+ internal ExecutionHelper ( TaskScheduler executor , CancellationToken cancellationToken )
967978 {
968979 this . service = new TaskSchedulerCompletionService < T > ( executor ) ;
980+ this . cancellationToken = cancellationToken ;
969981 }
970982
971983 public T Current => current ;
@@ -995,7 +1007,7 @@ public bool MoveNext()
9951007 try
9961008 {
9971009 var awaitable = service . Take ( ) ;
998- awaitable . Wait ( ) ;
1010+ awaitable . Wait ( cancellationToken ) ;
9991011 current = awaitable . Result ;
10001012
10011013 return true ;
0 commit comments