Index: pom.xml
===================================================================
--- pom.xml (revision 1875799)
+++ pom.xml (working copy)
@@ -23,7 +23,7 @@
org.apache.jackrabbit
oak-parent
- 1.10.8
+ 1.10.8-OAK-8978
../oak-parent/pom.xml
Index: src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/FacetTestHelper.java
===================================================================
Index: src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexNodeManager.java
===================================================================
--- src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexNodeManager.java (revision 1875799)
+++ src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexNodeManager.java (working copy)
@@ -64,6 +64,8 @@
private static final PerfLogger PERF_LOGGER =
new PerfLogger(LoggerFactory.getLogger(LuceneIndexNodeManager.class.getName() + ".perf"));
+ public final static String OLD_FACET_PROVIDER_TEST_FAILURE_SLEEP_INSTRUMENT_NAME = "oak.lucene.oldFacetProviderTestFailSleepInstrument";
+ private final static int OLD_FACET_PROVIDER_TEST_FAILURE_SLEEP_INSTRUMENT_VALUE = Integer.getInteger(OLD_FACET_PROVIDER_TEST_FAILURE_SLEEP_INSTRUMENT_NAME, 0);
static LuceneIndexNodeManager open(String indexPath, NodeState root, NodeState defnNodeState,
LuceneIndexReaderFactory readerFactory, @Nullable NRTIndexFactory nrtFactory)
@@ -113,10 +115,12 @@
private final Runnable refreshCallback = new Runnable() {
@Override
public void run() {
+ //Index reader gets closed when searching facets. This gets triggered in a multi threaded environment. Refer OAK-8898
+ FacetTestHelper.sleep(OLD_FACET_PROVIDER_TEST_FAILURE_SLEEP_INSTRUMENT_VALUE);
if (refreshLock.tryAcquire()) {
try {
refreshReaders();
- }finally {
+ } finally {
refreshLock.release();
}
}
Index: src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java
===================================================================
--- src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java (revision 1875799)
+++ src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java (working copy)
@@ -24,6 +24,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Deque;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -50,6 +51,7 @@
import org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants;
import org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition;
import org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition.IndexingRule;
+import org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition.SecureFacetConfiguration;
import org.apache.jackrabbit.oak.plugins.index.lucene.property.HybridPropertyIndexLookup;
import org.apache.jackrabbit.oak.plugins.index.lucene.score.ScorerProviderFactory;
import org.apache.jackrabbit.oak.plugins.index.lucene.spi.FulltextQueryTermsProvider;
@@ -186,6 +188,13 @@
*/
public class LucenePropertyIndex extends FulltextIndex {
+ public final static String OLD_FACET_PROVIDER_CONFIG_NAME = "oak.lucene.oldFacetProvider";
+ private final static boolean OLD_FACET_PROVIDER =
+ Boolean.getBoolean(OLD_FACET_PROVIDER_CONFIG_NAME);
+ public final static String CACHE_FACET_RESULTS_NAME = "oak.lucene.cacheFacetResults";
+ private final static boolean CACHE_FACET_RESULTS =
+ Boolean.parseBoolean(System.getProperty(CACHE_FACET_RESULTS_NAME, "true"));
+
private static double MIN_COST = 2.1;
private static final Logger LOG = LoggerFactory
@@ -209,6 +218,11 @@
private final IndexAugmentorFactory augmentorFactory;
+ static {
+ LOG.info(OLD_FACET_PROVIDER_CONFIG_NAME + " = " + OLD_FACET_PROVIDER);
+ LOG.info(CACHE_FACET_RESULTS_NAME + " = " + CACHE_FACET_RESULTS);
+ }
+
public LucenePropertyIndex(IndexTracker tracker) {
this(tracker, ScorerProviderFactory.DEFAULT);
}
@@ -251,7 +265,7 @@
private boolean noDocs = false;
private IndexSearcher indexSearcher;
private int indexNodeId = -1;
- private LuceneFacetProvider facetProvider = null;
+ private FacetProvider facetProvider;
private int rewoundCount = 0;
@Override
@@ -269,7 +283,7 @@
}
private FulltextResultRow convertToRow(ScoreDoc doc, IndexSearcher searcher, Map excerpts,
- LuceneFacetProvider facetProvider,
+ FacetProvider facetProvider,
String explanation) throws IOException {
IndexReader reader = searcher.getIndexReader();
//TODO Look into usage of field cache for retrieving the path
@@ -354,11 +368,18 @@
PERF_LOGGER.end(start, -1, "{} ...", docs.scoreDocs.length);
nextBatchSize = (int) Math.min(nextBatchSize * 2L, 100000);
- long f = PERF_LOGGER.start();
if (facetProvider == null) {
- facetProvider = new LuceneFacetProvider(
- FacetHelper.getFacets(searcher, query, plan, indexNode.getDefinition().getSecureFacetConfiguration())
- );
+ long f = PERF_LOGGER.start();
+ if (OLD_FACET_PROVIDER) {
+ // here the current searcher gets referenced for later
+ // but the searcher might get closed in the meantime
+ facetProvider = new LuceneFacetProvider(
+ FacetHelper.getFacets(searcher, query, plan, indexNode.getDefinition().getSecureFacetConfiguration())
+ );
+ } else {
+ // a new searcher is opened and closed when needed
+ facetProvider = new DelayedLuceneFacetProvider(LucenePropertyIndex.this, query, plan, indexNode.getDefinition().getSecureFacetConfiguration());
+ }
PERF_LOGGER.end(f, -1, "facets retrieved");
}
@@ -1548,6 +1569,59 @@
return Iterators.concat(propIndex.iterator(), itr);
}
+ static class DelayedLuceneFacetProvider implements FacetProvider {
+ private final LucenePropertyIndex index;
+ private final Query query;
+ private final IndexPlan plan;
+ private final SecureFacetConfiguration config;
+ private final HashMap> cachedResults = new HashMap<>();
+
+ DelayedLuceneFacetProvider(LucenePropertyIndex index, Query query, IndexPlan plan, SecureFacetConfiguration config) {
+ this.index = index;
+ this.query = query;
+ this.plan = plan;
+ this.config = config;
+ }
+
+ @Override
+ public List getFacets(int numberOfFacets, String columnName) throws IOException {
+ if (!CACHE_FACET_RESULTS) {
+ return getFacetsUncached(numberOfFacets, columnName);
+ }
+ String cacheKey = columnName + "/" + numberOfFacets;
+ if (cachedResults.containsKey(cacheKey)) {
+ return cachedResults.get(cacheKey);
+ }
+ List result = getFacetsUncached(numberOfFacets, columnName);
+ cachedResults.put(cacheKey, result);
+ return result;
+ }
+
+ private List getFacetsUncached(int numberOfFacets, String columnName) throws IOException {
+ LuceneIndexNode indexNode = index.acquireIndexNode(plan);
+ try {
+ IndexSearcher searcher = indexNode.getSearcher();
+ String facetFieldName = FulltextIndex.parseFacetField(columnName);
+ Facets facets = FacetHelper.getFacets(searcher, query, plan, config);
+ if (facets != null) {
+ ImmutableList.Builder res = new ImmutableList.Builder<>();
+ FacetResult topChildren = facets.getTopChildren(numberOfFacets, facetFieldName);
+ if (topChildren != null) {
+ for (LabelAndValue lav : topChildren.labelValues) {
+ res.add(new Facet(
+ lav.label, lav.value.intValue()
+ ));
+ }
+ return res.build();
+ }
+ }
+ return null;
+ } finally {
+ indexNode.release();
+ }
+ }
+ }
+
static class LuceneFacetProvider implements FacetProvider {
private final Facets facets;