[ SEARCH-1859 ] Proper management of Lucene Searchers

This commit is contained in:
agazzarini
2019-10-02 19:36:44 +02:00
parent cff2b8b2ed
commit 11c815dbab

View File

@@ -28,18 +28,17 @@ import org.apache.lucene.document.Document;
import org.apache.lucene.document.LongPoint; import org.apache.lucene.document.LongPoint;
import org.apache.lucene.document.NumericDocValuesField; import org.apache.lucene.document.NumericDocValuesField;
import org.apache.lucene.document.StoredField; import org.apache.lucene.document.StoredField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.SearcherManager;
import org.apache.lucene.search.Sort; import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField; import org.apache.lucene.search.SortField;
import org.apache.lucene.search.SortedNumericSortField; import org.apache.lucene.search.SortedNumericSortField;
import org.apache.lucene.search.TopDocs; import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory; import org.apache.lucene.store.FSDirectory;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -89,30 +88,23 @@ public class ChangeSet implements AutoCloseable
ChangeSet build() ChangeSet build()
{ {
// Creates a transient changeset (no persistence); mainly used for reducing the changes during replication.
if (root == null) if (root == null)
{ {
// Creates a transient changeset (no persistence); mainly used for reducing the changes during replication.
return new ChangeSet( return new ChangeSet(
immutable ? emptySet() : new HashSet<>(), immutable ? emptySet() : new HashSet<>(),
immutable ? emptySet() : new HashSet<>()); immutable ? emptySet() : new HashSet<>());
} }
// Necessary evil: needed for making sure the Lucene stuff will be closed
// in case of initialisation exception.
IndexWriter writer = null; IndexWriter writer = null;
IndexSearcher searcher = null;
try try
{ {
File file = new File(root, CHANGESETS_ROOT_FOLDER_NAME); File indexDirectory = new File(root, CHANGESETS_ROOT_FOLDER_NAME);
writer = new IndexWriter(FSDirectory.open(indexDirectory.toPath()), new IndexWriterConfig());
Directory indexDirectory = FSDirectory.open(file.toPath());
writer = new IndexWriter(indexDirectory, new IndexWriterConfig());
writer.commit(); writer.commit();
searcher = new IndexSearcher(DirectoryReader.open(indexDirectory)); final SearcherManager searcher = new SearcherManager(writer, null);
LOGGER.info("ContentStore Changeset index has been correctly mounted on {}", indexDirectory.getAbsolutePath());
LOGGER.info("ContentStore Changeset index correctly mounted on {}", file.getAbsolutePath());
return new ChangeSet( return new ChangeSet(
searcher, searcher,
@@ -123,8 +115,7 @@ public class ChangeSet implements AutoCloseable
catch (Exception exception) catch (Exception exception)
{ {
ofNullable(writer).ifPresent(ChangeSet::silentyClose); ofNullable(writer).ifPresent(ChangeSet::silentyClose);
ofNullable(searcher).map(IndexSearcher::getIndexReader).ifPresent(ChangeSet::silentyClose); throw new IllegalArgumentException("Unable to create a ContentStore ChangeSet data structure. See further details in the stacktrack below.", exception);
throw new IllegalArgumentException("Unable to create the ContentStore ChangeSet data structure.", exception);
} }
} }
} }
@@ -138,7 +129,7 @@ public class ChangeSet implements AutoCloseable
final Set<String> deletes; final Set<String> deletes;
final Set<String> adds; final Set<String> adds;
private final IndexSearcher searcher; private final SearcherManager searcher;
private final IndexWriter writer; private final IndexWriter writer;
/** /**
@@ -157,13 +148,13 @@ public class ChangeSet implements AutoCloseable
/** /**
* Builds a new {@link ChangeSet} with the given Lucene facades. * Builds a new {@link ChangeSet} with the given Lucene facades.
* *
* @param searcher the index searcher. * @param searcher the searcher reference (actually a {@link SearcherManager} instance instead of dealing with {@link IndexSearcher} directly.
* @param writer the index writer. * @param writer the {@link IndexWriter} instance used for persisting the content store changes.
* @param deletesContainer the container which will hold the deletes. * @param deletesContainer the container which will hold the deletes.
* @param addsContainer the container which will hold the adds/updates. * @param addsContainer the container which will hold the adds/updates.
*/ */
private ChangeSet( private ChangeSet(
final IndexSearcher searcher, final SearcherManager searcher,
final IndexWriter writer, final IndexWriter writer,
final Set<String> deletesContainer, final Set<String> deletesContainer,
final Set<String> addsContainer) final Set<String> addsContainer)
@@ -213,6 +204,8 @@ public class ChangeSet implements AutoCloseable
{ {
final long version = System.currentTimeMillis(); final long version = System.currentTimeMillis();
LOGGER.debug("About to add a new Changeset entry (version = {}, deletes = {}, adds = {})", version, deletes.size(), adds.size());
final Document document = new Document(); final Document document = new Document();
document.add(new NumericDocValuesField(VERSION_FIELD_NAME, version)); document.add(new NumericDocValuesField(VERSION_FIELD_NAME, version));
document.add(new LongPoint(RVERSION_FIELD_NAME, version)); document.add(new LongPoint(RVERSION_FIELD_NAME, version));
@@ -226,15 +219,16 @@ public class ChangeSet implements AutoCloseable
writer.addDocument(document); writer.addDocument(document);
writer.commit(); writer.commit();
searcher.maybeRefresh();
LOGGER.debug("New Changeset entry added (version = {}, deletes = {}, adds = {})", version, deletes.size(), adds.size()); LOGGER.debug("New Changeset entry have been added (version = {}, deletes = {}, adds = {})", version, deletes.size(), adds.size());
} }
@Override @Override
public void close() public void close()
{ {
ofNullable(writer).ifPresent(ChangeSet::silentyClose); ofNullable(writer).ifPresent(ChangeSet::silentyClose);
ofNullable(searcher).map(IndexSearcher::getIndexReader).ifPresent(ChangeSet::silentyClose); ofNullable(searcher).ifPresent(ChangeSet::silentyClose);
} }
/** /**
@@ -246,7 +240,7 @@ public class ChangeSet implements AutoCloseable
{ {
try try
{ {
TopDocs hits = searcher.search( TopDocs hits = searcher().search(
new MatchAllDocsQuery(), new MatchAllDocsQuery(),
1, 1,
new Sort(new SortedNumericSortField(VERSION_FIELD_NAME, SortField.Type.LONG, true)), new Sort(new SortedNumericSortField(VERSION_FIELD_NAME, SortField.Type.LONG, true)),
@@ -281,7 +275,7 @@ public class ChangeSet implements AutoCloseable
try try
{ {
Query query = LongPoint.newRangeQuery(VERSION_FIELD_NAME, Math.addExact(version, 1), Long.MAX_VALUE); Query query = LongPoint.newRangeQuery(VERSION_FIELD_NAME, Math.addExact(version, 1), Long.MAX_VALUE);
TopDocs hits = searcher.search( TopDocs hits = searcher().search(
query, query,
100, 100,
new Sort(new SortedNumericSortField(VERSION_FIELD_NAME, SortField.Type.LONG)), new Sort(new SortedNumericSortField(VERSION_FIELD_NAME, SortField.Type.LONG)),
@@ -328,7 +322,7 @@ public class ChangeSet implements AutoCloseable
{ {
try try
{ {
return searcher.doc(hit.doc); return searcher().doc(hit.doc);
} }
catch (IOException e) catch (IOException e)
{ {
@@ -361,4 +355,9 @@ public class ChangeSet implements AutoCloseable
LOGGER.error("Unable to properly close the resource instance {}. See further details in the stacktrace below.", resource, exception); LOGGER.error("Unable to properly close the resource instance {}. See further details in the stacktrace below.", resource, exception);
} }
} }
private IndexSearcher searcher() throws IOException
{
return searcher.acquire();
}
} }