Index: src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractIndex.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractIndex.java (revision 548680) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractIndex.java (working copy) @@ -32,6 +32,8 @@ import java.io.StringReader; import java.util.BitSet; import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; /** * Implements common functionality for a lucene index. @@ -90,6 +92,9 @@ /** The shared IndexReader for all read-only IndexReaders */ private SharedIndexReader sharedReader; + /** Caches all read-only IndexReaders */ + private Map readOnlyReaders = new HashMap(); + /** * The indexing queue. */ @@ -205,7 +210,12 @@ CachingIndexReader cr = new CachingIndexReader(IndexReader.open(getDirectory()), cache); sharedReader = new SharedIndexReader(cr); } - return new ReadOnlyIndexReader(sharedReader, deleted); + ReadOnlyIndexReader cachedReadOnlyIndexReader = (ReadOnlyIndexReader) readOnlyReaders.get(deleted); + if (cachedReadOnlyIndexReader == null) { + cachedReadOnlyIndexReader = new ReadOnlyIndexReader(sharedReader, deleted); + readOnlyReaders.put(deleted, cachedReadOnlyIndexReader); + } + return cachedReadOnlyIndexReader; } /** @@ -317,6 +327,7 @@ sharedReader.close(); sharedReader = null; } + readOnlyReaders.clear(); } /** Index: src/main/java/org/apache/jackrabbit/core/query/lucene/CachingMultiReader.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/CachingMultiReader.java (revision 548680) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/CachingMultiReader.java (working copy) @@ -175,7 +175,15 @@ System.arraycopy(subReaders, 0, readers, 0, subReaders.length); return readers; } + + public IndexReader getSubReader(int doc) { + return subReaders[readerIndex(doc)]; + } + public int getSubReaderDocNum(int doc) { + return doc - starts[readerIndex(doc)]; + } + //------------------------< internal >-------------------------------------- /** Index: src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java (revision 548680) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java (working copy) @@ -992,6 +992,29 @@ return hi; } + public IndexReader getBaseReader(int doc) { + int i = readerIndex(doc); + CachingMultiReader subReader = subReaders[i]; + return subReader.getSubReader(doc - starts[i]); + } + + public int getBaseReaderDocNum(int doc) { + int i = readerIndex(doc); + CachingMultiReader subReader = subReaders[i]; + return subReader.getSubReaderDocNum(doc); + } + + public IndexReader[] getBaseReaders() { + List list = new ArrayList(); + for (int i = 0; i < subReaders.length; i++) { + IndexReader[] indexReaders = subReaders[i].getIndexReaders(); + for (int j = 0; j < indexReaders.length; j++) { + list.add(indexReaders[j]); + } + } + return (IndexReader[]) list.toArray(new IndexReader[0]); + } + public boolean equals(Object obj) { if (obj instanceof CombinedIndexReader) { CombinedIndexReader other = (CombinedIndexReader) obj; Index: src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldCache.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldCache.java (revision 548680) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldCache.java (working copy) @@ -20,7 +20,6 @@ import org.apache.lucene.index.Term; import org.apache.lucene.index.TermDocs; import org.apache.lucene.index.TermEnum; -import org.apache.lucene.search.FieldCache; import org.apache.lucene.search.SortComparator; import java.io.IOException; @@ -38,6 +37,22 @@ */ class SharedFieldCache { + /** Expert: Stores term text values and document ordering data. */ + public static class StringIndex { + + /** All the term values, in natural order. */ + public final String[] lookup; + + /** Terms indexed by document id. */ + public final String[] terms; + + /** Creates one of these objects */ + public StringIndex(String[] terms, String[] lookup) { + this.terms = terms; + this.lookup = lookup; + } + } + /** * Reference to the single instance of SharedFieldCache. */ @@ -72,7 +87,7 @@ * information. * @throws IOException if an error occurs while reading from the index. */ - public FieldCache.StringIndex getStringIndex(IndexReader reader, + public SharedFieldCache.StringIndex getStringIndex(IndexReader reader, String field, String prefix, SortComparator comparator, @@ -79,9 +94,9 @@ boolean includeLookup) throws IOException { field = field.intern(); - FieldCache.StringIndex ret = lookup(reader, field, prefix, comparator); + SharedFieldCache.StringIndex ret = lookup(reader, field, prefix, comparator); if (ret == null) { - final int[] retArray = new int[reader.maxDoc()]; + final String[] retArray = new String[reader.maxDoc()]; List mterms = null; if (includeLookup) { mterms = new ArrayList(); @@ -95,7 +110,6 @@ if (includeLookup) { mterms.add(null); // for documents with term number 0 } - int t = 1; // current term number try { if (termEnum.term() == null) { @@ -114,10 +128,8 @@ termDocs.seek(termEnum); while (termDocs.next()) { - retArray[termDocs.doc()] = t; + retArray[termDocs.doc()] = term.text().substring(prefix.length()); } - - t++; } while (termEnum.next()); } finally { termDocs.close(); @@ -128,7 +140,7 @@ if (includeLookup) { lookup = (String[]) mterms.toArray(new String[mterms.size()]); } - FieldCache.StringIndex value = new FieldCache.StringIndex(retArray, lookup); + SharedFieldCache.StringIndex value = new SharedFieldCache.StringIndex(retArray, lookup); store(reader, field, prefix, comparator, value); return value; } @@ -138,7 +150,7 @@ /** * See if a StringIndex object is in the cache. */ - FieldCache.StringIndex lookup(IndexReader reader, String field, + SharedFieldCache.StringIndex lookup(IndexReader reader, String field, String prefix, SortComparator comparer) { Key key = new Key(field, prefix, comparer); synchronized (this) { @@ -146,7 +158,7 @@ if (readerCache == null) { return null; } - return (FieldCache.StringIndex) readerCache.get(key); + return (SharedFieldCache.StringIndex) readerCache.get(key); } } @@ -154,7 +166,7 @@ * Put a StringIndex value to cache. */ Object store(IndexReader reader, String field, String prefix, - SortComparator comparer, FieldCache.StringIndex value) { + SortComparator comparer, SharedFieldCache.StringIndex value) { Key key = new Key(field, prefix, comparer); synchronized (this) { HashMap readerCache = (HashMap) cache.get(reader); Index: src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldSortComparator.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldSortComparator.java (revision 548680) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldSortComparator.java (working copy) @@ -16,8 +16,9 @@ */ package org.apache.jackrabbit.core.query.lucene; +import org.apache.jackrabbit.core.query.lucene.SearchIndex.CombinedIndexReader; +import org.apache.jackrabbit.core.query.lucene.SharedFieldCache.StringIndex; import org.apache.lucene.index.IndexReader; -import org.apache.lucene.search.FieldCache; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.ScoreDocComparator; import org.apache.lucene.search.SortComparator; @@ -24,6 +25,7 @@ import org.apache.lucene.search.SortField; import java.io.IOException; +import java.util.HashMap; /** * Implements a SortComparator which knows how to sort on a lucene @@ -88,26 +90,48 @@ * @return a ScoreDocComparator for the * @throws IOException */ - public ScoreDocComparator newComparator(final IndexReader reader, String propertyName) - throws IOException { - // get the StringIndex for propertyName - final FieldCache.StringIndex index - = SharedFieldCache.INSTANCE.getStringIndex(reader, field, - FieldNames.createNamedValue(propertyName, ""), - SharedFieldSortComparator.this, - createComparatorValues); - + public ScoreDocComparator newComparator(final IndexReader reader, final String propertyName) { + return new ScoreDocComparator() { + + private CombinedIndexReader combinedIndexReader = ((CombinedIndexReader) reader); + private HashMap indexes = new HashMap(); + public final int compare(final ScoreDoc i, final ScoreDoc j) { - final int fi = index.order[i.doc]; - final int fj = index.order[j.doc]; - if (fi < fj) { - return -1; - } else if (fi > fj) { - return 1; - } else { - return 0; + int iBaseReaderDoc = combinedIndexReader.getBaseReaderDocNum(i.doc); + SharedFieldCache.StringIndex iIndex = getIndex(i.doc); + + int jBaseReaderDoc = combinedIndexReader.getBaseReaderDocNum(j.doc); + SharedFieldCache.StringIndex jIndex = getIndex(j.doc); + + String iTerm = iIndex.terms[iBaseReaderDoc]; + String jTerm = jIndex.terms[jBaseReaderDoc]; + + if (iTerm == jTerm) return 0; + if (iTerm == null) return -1; + if (jTerm == null) return 1; + + return iTerm.compareTo(jTerm); + } + + private SharedFieldCache.StringIndex getIndex(int doc) { + IndexReader baseReader = combinedIndexReader.getBaseReader(doc); + StringIndex cachedIndex = (StringIndex) indexes.get(baseReader); + + if (cachedIndex == null) { + try { + // get the StringIndex for propertyName + cachedIndex = SharedFieldCache.INSTANCE.getStringIndex(baseReader, field, + FieldNames.createNamedValue(propertyName, ""), + SharedFieldSortComparator.this, + createComparatorValues); + indexes.put(baseReader, cachedIndex); + } catch (IOException e) { + throw new RuntimeException(e); + } } + + return cachedIndex; } /** @@ -118,8 +142,9 @@ * @return the sort value if available. */ public Comparable sortValue(final ScoreDoc i) { + StringIndex index = getIndex(i.doc); if (index.lookup != null) { - return index.lookup[index.order[i.doc]]; + return index.terms[i.doc]; } else { // return dummy value return "";