@@ -65,6 +65,9 @@ namespace Lucene.Net.Search.Suggest.Analyzing
6565 public class AnalyzingInfixSuggester : Lookup , IDisposable
6666 {
6767 private readonly object syncLock = new object ( ) ; //uses syncLock as substitute for Java's synchronized (method) keyword
68+ // LUCENENET specific - Support for LUCENE-7564.
69+ // Forces single-threaded access to the SearcherManager when performing an acquire() or reassigning.
70+ private readonly object searcherMgrLock = new object ( ) ;
6871
6972 /// <summary>
7073 /// Field name used for the indexed text. </summary>
@@ -295,74 +298,82 @@ protected internal virtual Directory GetDirectory(DirectoryInfo path)
295298
296299 public override void Build ( IInputEnumerator enumerator )
297300 {
298- if ( m_searcherMgr != null )
299- {
300- m_searcherMgr . Dispose ( ) ;
301- m_searcherMgr = null ;
302- }
303-
304- if ( writer != null )
305- {
306- writer . Dispose ( ) ;
307- writer = null ;
308- }
309-
310- AtomicReader r = null ;
311- bool success = false ;
301+ UninterruptableMonitor . Enter ( searcherMgrLock ) ;
312302 try
313303 {
314- // First pass: build a temporary normal Lucene index,
315- // just indexing the suggestions as they iterate:
316- writer = new IndexWriter ( dir , indexWriterConfigFactory . Get ( matchVersion , GetGramAnalyzer ( ) , OpenMode . CREATE ) ) ;
317- //long t0 = System.nanoTime();
318-
319- // TODO: use threads?
320- BytesRef text ;
321- while ( enumerator . MoveNext ( ) )
304+ if ( m_searcherMgr != null )
322305 {
323- text = enumerator . Current ;
324- BytesRef payload ;
325- if ( enumerator . HasPayloads )
326- {
327- payload = enumerator . Payload ;
328- }
329- else
330- {
331- payload = null ;
332- }
333-
334- Add ( text , enumerator . Contexts , enumerator . Weight , payload ) ;
306+ m_searcherMgr . Dispose ( ) ;
307+ m_searcherMgr = null ;
335308 }
336309
337- //System.out.println("initial indexing time: " + ((System.nanoTime()-t0)/1000000) + " msec");
338- if ( commitOnBuild || closeIndexWriterOnBuild ) // LUCENENET specific - Support for LUCENE-5889, LUCENE-7564.
310+ if ( writer != null )
339311 {
340- Commit ( ) ;
312+ writer . Dispose ( ) ;
313+ writer = null ;
341314 }
342- m_searcherMgr = new SearcherManager ( writer , true , null ) ;
343- success = true ;
344- }
345- finally
346- {
347- if ( success )
315+
316+ AtomicReader r = null ;
317+ bool success = false ;
318+ try
348319 {
349- if ( closeIndexWriterOnBuild ) // LUCENENET specific - Support for LUCENE-7564.
320+ // First pass: build a temporary normal Lucene index,
321+ // just indexing the suggestions as they iterate:
322+ writer = new IndexWriter ( dir , indexWriterConfigFactory . Get ( matchVersion , GetGramAnalyzer ( ) , OpenMode . CREATE ) ) ;
323+ //long t0 = System.nanoTime();
324+
325+ // TODO: use threads?
326+ BytesRef text ;
327+ while ( enumerator . MoveNext ( ) )
328+ {
329+ text = enumerator . Current ;
330+ BytesRef payload ;
331+ if ( enumerator . HasPayloads )
332+ {
333+ payload = enumerator . Payload ;
334+ }
335+ else
336+ {
337+ payload = null ;
338+ }
339+
340+ Add ( text , enumerator . Contexts , enumerator . Weight , payload ) ;
341+ }
342+
343+ //System.out.println("initial indexing time: " + ((System.nanoTime()-t0)/1000000) + " msec");
344+ if ( commitOnBuild || closeIndexWriterOnBuild ) // LUCENENET specific - Support for LUCENE-5889, LUCENE-7564.
350345 {
351- writer . Dispose ( ) ;
352- writer = null ;
346+ Commit ( ) ;
353347 }
354- IOUtils . Dispose ( r ) ;
348+ m_searcherMgr = new SearcherManager ( writer , true , null ) ;
349+ success = true ;
355350 }
356- else
351+ finally
357352 {
358- if ( writer != null )
353+ if ( success )
359354 {
360- writer . Rollback ( ) ;
361- writer = null ;
355+ if ( closeIndexWriterOnBuild ) // LUCENENET specific - Support for LUCENE-7564.
356+ {
357+ writer . Dispose ( ) ;
358+ writer = null ;
359+ }
360+ IOUtils . Dispose ( r ) ;
361+ }
362+ else
363+ {
364+ if ( writer != null )
365+ {
366+ writer . Rollback ( ) ;
367+ writer = null ;
368+ }
369+ IOUtils . DisposeWhileHandlingException ( r ) ;
362370 }
363- IOUtils . DisposeWhileHandlingException ( r ) ;
364371 }
365372 }
373+ finally
374+ {
375+ UninterruptableMonitor . Exit ( searcherMgrLock ) ;
376+ }
366377 }
367378
368379 // LUCENENET specific - Support for LUCENE-5889, LUCENE-7564.
@@ -438,11 +449,19 @@ private void EnsureOpen()
438449 {
439450 writer = new IndexWriter ( dir , indexWriterConfigFactory . Get ( matchVersion , GetGramAnalyzer ( ) , OpenMode . CREATE ) ) ;
440451 }
441- SearcherManager oldSearcherMgr = m_searcherMgr ;
442- m_searcherMgr = new SearcherManager ( writer , true , null ) ;
443- if ( oldSearcherMgr != null )
452+ UninterruptableMonitor . Enter ( searcherMgrLock ) ;
453+ try
454+ {
455+ SearcherManager oldSearcherMgr = m_searcherMgr ;
456+ m_searcherMgr = new SearcherManager ( writer , true , null ) ;
457+ if ( oldSearcherMgr != null )
458+ {
459+ oldSearcherMgr . Dispose ( ) ;
460+ }
461+ }
462+ finally
444463 {
445- oldSearcherMgr . Dispose ( ) ;
464+ UninterruptableMonitor . Exit ( searcherMgrLock ) ;
446465 }
447466 }
448467 }
@@ -704,8 +723,19 @@ public virtual IList<LookupResult> DoLookup(string key,
704723 // We sorted postings by weight during indexing, so we
705724 // only retrieve the first num hits now:
706725 ICollector c2 = new EarlyTerminatingSortingCollector ( c , SORT , num ) ;
707- IndexSearcher searcher = m_searcherMgr . Acquire ( ) ;
708726 IList < LookupResult > results = null ;
727+ SearcherManager mgr ; // LUCENENET specific - Support for LUCENE-7564: acquire & release on same SearcherManager, via local reference
728+ IndexSearcher searcher ;
729+ UninterruptableMonitor . Enter ( searcherMgrLock ) ;
730+ try
731+ {
732+ mgr = m_searcherMgr ;
733+ searcher = mgr . Acquire ( ) ;
734+ }
735+ finally
736+ {
737+ UninterruptableMonitor . Exit ( searcherMgrLock ) ;
738+ }
709739 try
710740 {
711741 //System.out.println("got searcher=" + searcher);
@@ -719,7 +749,7 @@ public virtual IList<LookupResult> DoLookup(string key,
719749 }
720750 finally
721751 {
722- m_searcherMgr . Release ( searcher ) ;
752+ mgr . Release ( searcher ) ;
723753 }
724754
725755 //System.out.println(((J2N.Time.NanoTime() / J2N.Time.MillisecondsPerNanosecond) - t0) + " msec for infix suggest"); // LUCENENET: Use NanoTime() rather than CurrentTimeMilliseconds() for more accurate/reliable results
@@ -964,7 +994,18 @@ public override long GetSizeInBytes()
964994 {
965995 if ( m_searcherMgr != null )
966996 {
967- IndexSearcher searcher = m_searcherMgr . Acquire ( ) ;
997+ SearcherManager mgr ; // LUCENENET specific - Support for LUCENE-7564: acquire & release on same SearcherManager, via local reference
998+ IndexSearcher searcher ;
999+ UninterruptableMonitor . Enter ( searcherMgrLock ) ;
1000+ try
1001+ {
1002+ mgr = m_searcherMgr ;
1003+ searcher = mgr . Acquire ( ) ;
1004+ }
1005+ finally
1006+ {
1007+ UninterruptableMonitor . Exit ( searcherMgrLock ) ;
1008+ }
9681009 try
9691010 {
9701011 foreach ( AtomicReaderContext context in searcher . IndexReader . Leaves )
@@ -978,7 +1019,7 @@ public override long GetSizeInBytes()
9781019 }
9791020 finally
9801021 {
981- m_searcherMgr . Release ( searcher ) ;
1022+ mgr . Release ( searcher ) ;
9821023 }
9831024 }
9841025 return mem ;
@@ -997,14 +1038,25 @@ public override long Count
9971038 {
9981039 return 0 ;
9991040 }
1000- IndexSearcher searcher = m_searcherMgr . Acquire ( ) ;
1041+ SearcherManager mgr ; // LUCENENET specific - Support for LUCENE-7564: acquire & release on same SearcherManager, via local reference
1042+ IndexSearcher searcher ;
1043+ UninterruptableMonitor . Enter ( searcherMgrLock ) ;
1044+ try
1045+ {
1046+ mgr = m_searcherMgr ;
1047+ searcher = mgr . Acquire ( ) ;
1048+ }
1049+ finally
1050+ {
1051+ UninterruptableMonitor . Exit ( searcherMgrLock ) ;
1052+ }
10011053 try
10021054 {
10031055 return searcher . IndexReader . NumDocs ;
10041056 }
10051057 finally
10061058 {
1007- m_searcherMgr . Release ( searcher ) ;
1059+ mgr . Release ( searcher ) ;
10081060 }
10091061 }
10101062 }
0 commit comments