Index: oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexTracker.java =================================================================== --- oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexTracker.java (revision 1845889) +++ oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexTracker.java (working copy) @@ -40,6 +40,7 @@ import org.apache.jackrabbit.oak.spi.mount.Mounts; import org.apache.jackrabbit.oak.spi.state.EqualsDiff; import org.apache.jackrabbit.oak.spi.state.NodeState; +import org.apache.jackrabbit.oak.spi.state.NodeStateUtils; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -207,13 +208,26 @@ @Nullable public LuceneIndexDefinition getIndexDefinition(String indexPath){ - LuceneIndexNodeManager node = indices.get(indexPath); - if (node != null){ + LuceneIndexNodeManager indexNodeManager = indices.get(indexPath); + if (indexNodeManager != null){ //Accessing the definition should not require //locking as its immutable state - return node.getDefinition(); + return indexNodeManager.getDefinition(); } - return null; + // fallback - create definition from scratch + NodeState node = NodeStateUtils.getNode(root, indexPath); + if (!node.exists()) { + return null; + } + // only if there exists a stored index definition + if (!node.hasChildNode(INDEX_DEFINITION_NODE)) { + return null; + } + if (!isLuceneIndexNode(node)) { + return null; + } + // this will internally use the stored index definition + return new LuceneIndexDefinition(root, node, indexPath); } public Set getIndexNodePaths(){ Index: oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java =================================================================== --- oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java (revision 1845889) +++ oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java (working copy) @@ -29,6 +29,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Predicate; @@ -46,11 +47,13 @@ import org.apache.jackrabbit.oak.commons.PathUtils; import org.apache.jackrabbit.oak.commons.PerfLogger; import org.apache.jackrabbit.oak.plugins.index.lucene.util.fv.SimSearchUtils; +import org.apache.jackrabbit.oak.plugins.index.lucene.writer.LuceneIndexWriter; import org.apache.jackrabbit.oak.plugins.index.search.FieldNames; 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.lucene.property.HybridPropertyIndexLookup; +import org.apache.jackrabbit.oak.plugins.index.lucene.reader.LuceneIndexReader; import org.apache.jackrabbit.oak.plugins.index.lucene.score.ScorerProviderFactory; import org.apache.jackrabbit.oak.plugins.index.lucene.spi.FulltextQueryTermsProvider; import org.apache.jackrabbit.oak.plugins.index.lucene.util.FacetHelper; @@ -120,6 +123,8 @@ import org.apache.lucene.search.postingshighlight.PostingsHighlighter; import org.apache.lucene.search.spell.SuggestWord; import org.apache.lucene.search.suggest.Lookup; +import org.apache.lucene.search.suggest.analyzing.AnalyzingInfixSuggester; +import org.apache.lucene.store.Directory; import org.apache.lucene.util.Version; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -654,8 +659,8 @@ } @Override - protected LuceneIndexNode acquireIndexNode(String indexPath) { - return tracker.acquireIndexNode(indexPath); + protected LazyLuceneIndexNode acquireIndexNode(String indexPath) { + return new LazyLuceneIndexNode(tracker, indexPath); } @Override @@ -1518,4 +1523,113 @@ return null; } } + + /** + * A index node implementation that acquires the underlying index only if + * actually needed. This is to avoid downloading the index for the planning + * phase, if there is no chance that the index is actually used. + */ + static class LazyLuceneIndexNode implements LuceneIndexNode { + + private AtomicBoolean released = new AtomicBoolean(); + private IndexTracker tracker; + private String indexPath; + private volatile LuceneIndexNode indexNode; + + LazyLuceneIndexNode(IndexTracker tracker, String indexPath) { + this.tracker = tracker; + this.indexPath = indexPath; + } + + @Override + public void release() { + if (released.getAndSet(true)) { + // already released + return; + } + if (indexNode != null) { + indexNode.release(); + } + // to ensure it is not used after releasing + indexNode = null; + tracker = null; + indexPath = null; + } + + private void checkNotReleased() { + if (released.get()) { + throw new IllegalStateException("Already released"); + } + } + + @Override + public LuceneIndexDefinition getDefinition() { + checkNotReleased(); + return tracker.getIndexDefinition(indexPath); + } + + private LuceneIndexNode getIndexNode() { + checkNotReleased(); + LuceneIndexNode n = indexNode; + // double checked locking implemented in the correct way for Java 5 + // and newer (actually I don't think this is ever called + // concurrently right now, but better be save) + if (n == null) { + synchronized (this) { + n = indexNode; + if (n == null) { + n = indexNode = tracker.acquireIndexNode(indexPath); + } + } + } + return n; + } + + @Override + public int getIndexNodeId() { + return getIndexNode().getIndexNodeId(); + } + + @Override + public LuceneIndexStatistics getIndexStatistics() { + return getIndexNode().getIndexStatistics(); + } + + @Override + public IndexSearcher getSearcher() { + return getIndexNode().getSearcher(); + } + + @Override + public List getPrimaryReaders() { + return getIndexNode().getPrimaryReaders(); + } + + @Override + public @Nullable Directory getSuggestDirectory() { + return getIndexNode().getSuggestDirectory(); + } + + @Override + public List getNRTReaders() { + return getIndexNode().getNRTReaders(); + } + + @Override + public @Nullable AnalyzingInfixSuggester getLookup() { + return getIndexNode().getLookup(); + } + + @Override + public @Nullable LuceneIndexWriter getLocalWriter() throws IOException { + return getIndexNode().getLocalWriter(); + } + + @Override + public void refreshReadersOnWriteIfRequired() { + getIndexNode().refreshReadersOnWriteIfRequired(); + } + + } + }