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) @@ -207,13 +207,25 @@ @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 + // (needed at startup, until the LuceneIndexNodeManager is available) + NodeState node = root; + for (String name : PathUtils.elements(indexPath)) { + node = node.getChildNode(name); + } + if (!node.exists()) { + return null; + } + if (!isLuceneIndexNode(node)) { + return null; + } + return new LuceneIndexDefinition(root, node, indexPath); } public Set getIndexNodePaths(){ Index: oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexNodeManager.java =================================================================== --- oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexNodeManager.java (revision 1845889) +++ oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexNodeManager.java (working copy) @@ -166,7 +166,7 @@ refreshPolicy.refreshOnReadIfRequired(refreshCallback); SearcherHolder local = searcherHolder; int tryCount = 0; - while (!local.searcher.getIndexReader().tryIncRef()) { + while (!local.getSearcher().getIndexReader().tryIncRef()) { checkState(++tryCount < 10, "Not able to " + "get open searcher in %s attempts", tryCount); local = searcherHolder; @@ -258,7 +258,7 @@ } private SearcherHolder createHolder(List newNRTReaders) { - return new SearcherHolder(new IndexSearcher(createReader(newNRTReaders)), newNRTReaders); + return new SearcherHolder(this, newNRTReaders); } private void closeReaders(Iterable readers) { @@ -272,7 +272,7 @@ } private void releaseHolder(SearcherHolder holder) { - decrementSearcherUsageCount(holder.searcher); + decrementSearcherUsageCount(holder.getSearcher()); } private void decrementSearcherUsageCount(IndexSearcher searcher) { @@ -286,20 +286,34 @@ } private static class SearcherHolder { - final IndexSearcher searcher; - final List nrtReaders; final int searcherId = SEARCHER_ID_COUNTER.incrementAndGet(); - final LuceneIndexStatistics indexStatistics; - public SearcherHolder(IndexSearcher searcher, List nrtReaders) { - this.searcher = searcher; + private final LuceneIndexNodeManager manager; + private final List nrtReaders; + private IndexSearcher searcher; + private LuceneIndexStatistics indexStatistics; + + public SearcherHolder(LuceneIndexNodeManager manager, List nrtReaders) { + this.manager = manager; this.nrtReaders = nrtReaders; - this.indexStatistics = new LuceneIndexStatistics(searcher.getIndexReader()); } + public IndexSearcher getSearcher() { + // TODO not synchronized + if (searcher == null) { + searcher = new IndexSearcher(manager.createReader(nrtReaders)); + } + return searcher; + } + public LuceneIndexStatistics getIndexStatistics() { + // TODO not synchronized + if (indexStatistics == null) { + indexStatistics = new LuceneIndexStatistics(getSearcher().getIndexReader()); + } return indexStatistics; } + } private class IndexNodeImpl implements LuceneIndexNode { @@ -315,7 +329,7 @@ if (released.compareAndSet(false, true)) { try { //Decrement on each release - decrementSearcherUsageCount(holder.searcher); + decrementSearcherUsageCount(holder.getSearcher()); } finally { LuceneIndexNodeManager.this.release(); } @@ -324,7 +338,7 @@ @Override public IndexSearcher getSearcher() { - return holder.searcher; + return holder.getSearcher(); } @Override 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) @@ -46,11 +46,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; @@ -59,6 +61,7 @@ import org.apache.jackrabbit.oak.plugins.index.lucene.util.SpellcheckHelper; import org.apache.jackrabbit.oak.plugins.index.lucene.util.SuggestHelper; import org.apache.jackrabbit.oak.plugins.index.search.IndexNode; +import org.apache.jackrabbit.oak.plugins.index.search.IndexStatistics; import org.apache.jackrabbit.oak.plugins.index.search.PropertyDefinition; import org.apache.jackrabbit.oak.plugins.index.search.SizeEstimator; import org.apache.jackrabbit.oak.plugins.index.search.spi.query.FulltextIndex; @@ -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,83 @@ return null; } } + + static class LazyLuceneIndexNode implements LuceneIndexNode { + + private final IndexTracker tracker; + private final String indexPath; + private LuceneIndexNode indexNode; + + LazyLuceneIndexNode(IndexTracker tracker, String indexPath) { + this.tracker = tracker; + this.indexPath = indexPath; + } + + @Override + public void release() { + if (indexNode != null) { + indexNode.release(); + } + } + + @Override + public LuceneIndexDefinition getDefinition() { + return tracker.getIndexDefinition(indexPath); + } + + private LuceneIndexNode getIndexNode() { + if (indexNode == null) { + // TODO not synchronized + indexNode = tracker.acquireIndexNode(indexPath); + } + return indexNode; + } + + @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(); + } + + } + } Index: oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/directory/OakStreamingIndexFile.java =================================================================== --- oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/directory/OakStreamingIndexFile.java (revision 1845889) +++ oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/directory/OakStreamingIndexFile.java (working copy) @@ -197,7 +197,7 @@ } else if (pos < position) { LOG.warn("Seeking back on streaming index file {}. Current position {}, requested position {}. " + "Please make sure that CopyOnRead and prefetch of index files are enabled.", - getName(), position(), pos); + dirDetails + "/" + getName(), position(), pos); // seeking back on input stream. Close current one IOUtils.closeQuietly(blobInputStream); Index: oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/reader/DefaultIndexReader.java =================================================================== --- oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/reader/DefaultIndexReader.java (revision 1845889) +++ oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/reader/DefaultIndexReader.java (working copy) @@ -36,7 +36,7 @@ private final Closer closer; private final Directory directory; private final Directory suggestDirectory; - private final IndexReader reader; + private IndexReader reader; private final AnalyzingInfixSuggester lookup; public DefaultIndexReader(Directory directory, @Nullable Directory suggestDirectory, Analyzer analyzer) throws IOException { @@ -43,8 +43,6 @@ this.closer = Closer.create(); this.directory = directory; closer.register(this.directory); - this.reader = DirectoryReader.open(directory); - closer.register(this.reader); this.suggestDirectory = suggestDirectory; if (suggestDirectory != null) { //Directory is closed by AnalyzingInfixSuggester close call @@ -57,6 +55,14 @@ @Override public IndexReader getReader() { + if (reader == null) { + try { + this.reader = DirectoryReader.open(directory); + } catch (IOException e) { + throw new RuntimeException(e); + } + closer.register(this.reader); + } return reader; } Index: oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/FulltextIndexPlanner.java =================================================================== --- oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/FulltextIndexPlanner.java (revision 1845889) +++ oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/FulltextIndexPlanner.java (working copy) @@ -730,12 +730,13 @@ } private long estimatedEntryCount() { - int numOfDocs = getNumDocs(); if (useActualEntryCount) { - return definition.isEntryCountDefined() ? definition.getEntryCount() : numOfDocs; - } else { - return estimatedEntryCount_Compat(numOfDocs); + if (definition.isEntryCountDefined()) { + return definition.getEntryCount(); + } + return getNumDocs(); } + return estimatedEntryCount_Compat(getNumDocs()); } private long estimatedEntryCount_Compat(int numOfDocs) {