Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/DocId.java =================================================================== --- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/DocId.java (revision 917557) +++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/DocId.java (working copy) @@ -20,6 +20,7 @@ import java.util.BitSet; import org.apache.jackrabbit.core.id.NodeId; +import org.apache.jackrabbit.spi.commons.name.HashCache; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,6 +33,22 @@ static final int[] EMPTY = new int[0]; /** + * All available DocIds that can be represented with a short. + */ + private static final ShortPlainDocId[] SHORT_DOC_IDS = new ShortPlainDocId[Short.MAX_VALUE]; + + /** + * Cache of most recently used {@link PlainDocId}s, with 2^13 (8192) slots. + */ + private static final HashCache DOC_ID_CACHE = new HashCache(13); + + static { + for (short i = 0; i < SHORT_DOC_IDS.length; i++) { + SHORT_DOC_IDS[i] = new ShortPlainDocId(i); + } + } + + /** * Indicates a null DocId. Will be returned if the root node is asked for * its parent. */ @@ -112,7 +129,11 @@ * @return a DocId based on a document number. */ static DocId create(int docNumber) { - return new PlainDocId(docNumber); + if (docNumber < Short.MAX_VALUE) { + return SHORT_DOC_IDS[docNumber]; + } else { + return (DocId) DOC_ID_CACHE.get(new PlainDocId(docNumber)); + } } /** @@ -201,9 +222,81 @@ public String toString() { return "PlainDocId(" + docNumber + ")"; } + + @Override + public int hashCode() { + // ensure a good distribution of hashCode values + int h = docNumber; + h ^= (h >>> 20) ^ (h >>> 12); + return h ^ (h >>> 7) ^ (h >>> 4); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof PlainDocId) { + PlainDocId other = (PlainDocId) obj; + return docNumber == other.docNumber; + } + return false; + } } /** + * DocId based on a document number using a short. + */ + private static final class ShortPlainDocId extends DocId { + + /** + * The document number or -1 if not set. + */ + private final short docNumber; + + /** + * Creates a DocId based on a document number. + * + * @param docNumber the lucene document number. + */ + ShortPlainDocId(short docNumber) { + this.docNumber = docNumber; + } + + /** + * @inheritDoc + */ + int[] getDocumentNumbers(MultiIndexReader reader, int[] docNumbers) { + if (docNumbers.length == 1) { + docNumbers[0] = docNumber; + return docNumbers; + } else { + return new int[]{docNumber}; + } + } + + /** + * @inheritDoc + */ + DocId applyOffset(int offset) { + return new PlainDocId(offset + docNumber); + } + + /** + * @inheritDoc + */ + boolean isValid(BitSet deleted) { + return !deleted.get(docNumber); + } + + /** + * Returns a String representation for this DocId. + * + * @return a String representation for this DocId. + */ + public String toString() { + return "ShortPlainDocId(" + docNumber + ")"; + } + } + + /** * DocId based on a node id. */ private static final class UUIDDocId extends DocId { Index: jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/name/HashCache.java =================================================================== --- jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/name/HashCache.java (revision 917557) +++ jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/name/HashCache.java (working copy) @@ -28,20 +28,28 @@ public class HashCache { /** - * Size of the cache (must be a power of two). Note that this is the - * maximum number of objects kept in the cache, but due to hashing it - * can well be that only a part of the cache array is filled even if - * many more distinct objects are being accessed. + * Array of cached objects, indexed by their hash codes + * (module size of the array). */ - private static final int SIZE_POWER_OF_2 = 1024; + private final Object[] array; /** - * Array of cached objects, indexed by their hash codes - * (module size of the array). + * Creates a hash cache with 1024 slots. */ - private final Object[] array = new Object[SIZE_POWER_OF_2]; + public HashCache() { + this(10); + } /** + * Creates a hash cache with 2^exponent slots. + * + * @param exponent the exponent. + */ + public HashCache(int exponent) { + this.array = new Object[2 << exponent]; + } + + /** * If a cached copy of the given object already exists, then returns * that copy. Otherwise the given object is cached and returned. * @@ -49,7 +57,7 @@ * @return the given object or a previously cached copy */ public Object get(Object object) { - int position = object.hashCode() & (SIZE_POWER_OF_2 - 1); + int position = object.hashCode() & (array.length - 1); Object previous = array[position]; if (object.equals(previous)) { return previous;