@@ -64,6 +64,9 @@ namespace Lucene.Net.Search.Suggest.Analyzing
6464 public class AnalyzingInfixSuggester : Lookup , IDisposable
6565 {
6666 private readonly object syncLock = new object ( ) ; //uses syncLock as substitute for Java's synchronized (method) keyword
67+ // LUCENENET specific - Support for LUCENE-7564.
68+ // Forces single-threaded access to the SearcherManager when performing an acquire() or reassigning.
69+ private readonly object searcherMgrLock = new object ( ) ;
6770
6871 /// <summary>
6972 /// Field name used for the indexed text. </summary>
@@ -294,74 +297,82 @@ protected internal virtual Directory GetDirectory(DirectoryInfo path)
294297
295298 public override void Build ( IInputEnumerator enumerator )
296299 {
297- if ( m_searcherMgr != null )
298- {
299- m_searcherMgr . Dispose ( ) ;
300- m_searcherMgr = null ;
301- }
302-
303- if ( writer != null )
304- {
305- writer . Dispose ( ) ;
306- writer = null ;
307- }
308-
309- AtomicReader r = null ;
310- bool success = false ;
300+ UninterruptableMonitor . Enter ( searcherMgrLock ) ;
311301 try
312302 {
313- // First pass: build a temporary normal Lucene index,
314- // just indexing the suggestions as they iterate:
315- writer = new IndexWriter ( dir , indexWriterConfigFactory . Get ( matchVersion , GetGramAnalyzer ( ) , OpenMode . CREATE ) ) ;
316- //long t0 = System.nanoTime();
317-
318- // TODO: use threads?
319- BytesRef text ;
320- while ( enumerator . MoveNext ( ) )
303+ if ( m_searcherMgr != null )
321304 {
322- text = enumerator . Current ;
323- BytesRef payload ;
324- if ( enumerator . HasPayloads )
325- {
326- payload = enumerator . Payload ;
327- }
328- else
329- {
330- payload = null ;
331- }
332-
333- Add ( text , enumerator . Contexts , enumerator . Weight , payload ) ;
305+ m_searcherMgr . Dispose ( ) ;
306+ m_searcherMgr = null ;
334307 }
335308
336- //System.out.println("initial indexing time: " + ((System.nanoTime()-t0)/1000000) + " msec");
337- if ( commitOnBuild || closeIndexWriterOnBuild ) // LUCENENET specific - Support for LUCENE-5889, LUCENE-7564.
309+ if ( writer != null )
338310 {
339- Commit ( ) ;
311+ writer . Dispose ( ) ;
312+ writer = null ;
340313 }
341- m_searcherMgr = new SearcherManager ( writer , true , null ) ;
342- success = true ;
343- }
344- finally
345- {
346- if ( success )
314+
315+ AtomicReader r = null ;
316+ bool success = false ;
317+ try
347318 {
348- if ( closeIndexWriterOnBuild ) // LUCENENET specific - Support for LUCENE-7564.
319+ // First pass: build a temporary normal Lucene index,
320+ // just indexing the suggestions as they iterate:
321+ writer = new IndexWriter ( dir , indexWriterConfigFactory . Get ( matchVersion , GetGramAnalyzer ( ) , OpenMode . CREATE ) ) ;
322+ //long t0 = System.nanoTime();
323+
324+ // TODO: use threads?
325+ BytesRef text ;
326+ while ( enumerator . MoveNext ( ) )
327+ {
328+ text = enumerator . Current ;
329+ BytesRef payload ;
330+ if ( enumerator . HasPayloads )
331+ {
332+ payload = enumerator . Payload ;
333+ }
334+ else
335+ {
336+ payload = null ;
337+ }
338+
339+ Add ( text , enumerator . Contexts , enumerator . Weight , payload ) ;
340+ }
341+
342+ //System.out.println("initial indexing time: " + ((System.nanoTime()-t0)/1000000) + " msec");
343+ if ( commitOnBuild || closeIndexWriterOnBuild ) // LUCENENET specific - Support for LUCENE-5889, LUCENE-7564.
349344 {
350- writer . Dispose ( ) ;
351- writer = null ;
345+ Commit ( ) ;
352346 }
353- IOUtils . Dispose ( r ) ;
347+ m_searcherMgr = new SearcherManager ( writer , true , null ) ;
348+ success = true ;
354349 }
355- else
350+ finally
356351 {
357- if ( writer != null )
352+ if ( success )
358353 {
359- writer . Rollback ( ) ;
360- writer = null ;
354+ if ( closeIndexWriterOnBuild ) // LUCENENET specific - Support for LUCENE-7564.
355+ {
356+ writer . Dispose ( ) ;
357+ writer = null ;
358+ }
359+ IOUtils . Dispose ( r ) ;
360+ }
361+ else
362+ {
363+ if ( writer != null )
364+ {
365+ writer . Rollback ( ) ;
366+ writer = null ;
367+ }
368+ IOUtils . DisposeWhileHandlingException ( r ) ;
361369 }
362- IOUtils . DisposeWhileHandlingException ( r ) ;
363370 }
364371 }
372+ finally
373+ {
374+ UninterruptableMonitor . Exit ( searcherMgrLock ) ;
375+ }
365376 }
366377
367378 // LUCENENET specific - Support for LUCENE-5889, LUCENE-7564.
@@ -437,11 +448,19 @@ private void EnsureOpen()
437448 {
438449 writer = new IndexWriter ( dir , indexWriterConfigFactory . Get ( matchVersion , GetGramAnalyzer ( ) , OpenMode . CREATE ) ) ;
439450 }
440- SearcherManager oldSearcherMgr = m_searcherMgr ;
441- m_searcherMgr = new SearcherManager ( writer , true , null ) ;
442- if ( oldSearcherMgr != null )
451+ UninterruptableMonitor . Enter ( searcherMgrLock ) ;
452+ try
453+ {
454+ SearcherManager oldSearcherMgr = m_searcherMgr ;
455+ m_searcherMgr = new SearcherManager ( writer , true , null ) ;
456+ if ( oldSearcherMgr != null )
457+ {
458+ oldSearcherMgr . Dispose ( ) ;
459+ }
460+ }
461+ finally
443462 {
444- oldSearcherMgr . Dispose ( ) ;
463+ UninterruptableMonitor . Exit ( searcherMgrLock ) ;
445464 }
446465 }
447466 }
@@ -691,8 +710,19 @@ public virtual IList<LookupResult> DoLookup(string key, IEnumerable<BytesRef> co
691710 // We sorted postings by weight during indexing, so we
692711 // only retrieve the first num hits now:
693712 ICollector c2 = new EarlyTerminatingSortingCollector ( c , SORT , num ) ;
694- IndexSearcher searcher = m_searcherMgr . Acquire ( ) ;
695713 IList < LookupResult > results = null ;
714+ SearcherManager mgr ; // LUCENENET specific - Support for LUCENE-7564: acquire & release on same SearcherManager, via local reference
715+ IndexSearcher searcher ;
716+ UninterruptableMonitor . Enter ( searcherMgrLock ) ;
717+ try
718+ {
719+ mgr = m_searcherMgr ;
720+ searcher = mgr . Acquire ( ) ;
721+ }
722+ finally
723+ {
724+ UninterruptableMonitor . Exit ( searcherMgrLock ) ;
725+ }
696726 try
697727 {
698728 //System.out.println("got searcher=" + searcher);
@@ -706,7 +736,7 @@ public virtual IList<LookupResult> DoLookup(string key, IEnumerable<BytesRef> co
706736 }
707737 finally
708738 {
709- m_searcherMgr . Release ( searcher ) ;
739+ mgr . Release ( searcher ) ;
710740 }
711741
712742 //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
@@ -951,7 +981,18 @@ public override long GetSizeInBytes()
951981 {
952982 if ( m_searcherMgr != null )
953983 {
954- IndexSearcher searcher = m_searcherMgr . Acquire ( ) ;
984+ SearcherManager mgr ; // LUCENENET specific - Support for LUCENE-7564: acquire & release on same SearcherManager, via local reference
985+ IndexSearcher searcher ;
986+ UninterruptableMonitor . Enter ( searcherMgrLock ) ;
987+ try
988+ {
989+ mgr = m_searcherMgr ;
990+ searcher = mgr . Acquire ( ) ;
991+ }
992+ finally
993+ {
994+ UninterruptableMonitor . Exit ( searcherMgrLock ) ;
995+ }
955996 try
956997 {
957998 foreach ( AtomicReaderContext context in searcher . IndexReader . Leaves )
@@ -965,7 +1006,7 @@ public override long GetSizeInBytes()
9651006 }
9661007 finally
9671008 {
968- m_searcherMgr . Release ( searcher ) ;
1009+ mgr . Release ( searcher ) ;
9691010 }
9701011 }
9711012 return mem ;
@@ -984,14 +1025,25 @@ public override long Count
9841025 {
9851026 return 0 ;
9861027 }
987- IndexSearcher searcher = m_searcherMgr . Acquire ( ) ;
1028+ SearcherManager mgr ; // LUCENENET specific - Support for LUCENE-7564: acquire & release on same SearcherManager, via local reference
1029+ IndexSearcher searcher ;
1030+ UninterruptableMonitor . Enter ( searcherMgrLock ) ;
1031+ try
1032+ {
1033+ mgr = m_searcherMgr ;
1034+ searcher = mgr . Acquire ( ) ;
1035+ }
1036+ finally
1037+ {
1038+ UninterruptableMonitor . Exit ( searcherMgrLock ) ;
1039+ }
9881040 try
9891041 {
9901042 return searcher . IndexReader . NumDocs ;
9911043 }
9921044 finally
9931045 {
994- m_searcherMgr . Release ( searcher ) ;
1046+ mgr . Release ( searcher ) ;
9951047 }
9961048 }
9971049 }
0 commit comments