Author: mreutegg Date: Wed Mar 21 06:17:12 2007 New Revision: 520878 URL: http://svn.apache.org/viewvc?view=rev&rev=520878 Log: JCR-805: Introduce a temprary cache for intermediate query results Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/PerQueryCache.java (with props) Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MatchAllScorer.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryHits.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/RangeQuery.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/WildcardQuery.java Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MatchAllScorer.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MatchAllScorer.java?view=diff&rev=520878&r1=520877&r2=520878 ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MatchAllScorer.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MatchAllScorer.java Wed Mar 21 06:17:12 2007 @@ -27,12 +27,12 @@ import java.io.IOException; import java.util.BitSet; +import java.util.Map; +import java.util.HashMap; /** * The MatchAllScorer implements a Scorer that scores / collects all * documents in the index that match a field. - * In case there are no filters, this MatchAllScores simply collects - * all documents in the index that are not marked as deleted. */ class MatchAllScorer extends Scorer { @@ -136,6 +136,21 @@ * the search index. */ private void calculateDocFilter() throws IOException { + PerQueryCache cache = PerQueryCache.getInstance(); + Map readerCache = (Map) cache.get(MatchAllScorer.class, reader); + if (readerCache == null) { + readerCache = new HashMap(); + cache.put(MatchAllScorer.class, reader, readerCache); + } + // get BitSet for field + docFilter = (BitSet) readerCache.get(field); + + if (docFilter != null) { + // use cached BitSet; + return; + } + + // otherwise calculate new docFilter = new BitSet(reader.maxDoc()); // we match all terms TermEnum terms = reader.terms(new Term(FieldNames.PROPERTIES, field)); @@ -157,5 +172,8 @@ } finally { terms.close(); } + + // put BitSet into cache + readerCache.put(field, docFilter); } } Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/PerQueryCache.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/PerQueryCache.java?view=auto&rev=520878 ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/PerQueryCache.java (added) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/PerQueryCache.java Wed Mar 21 06:17:12 2007 @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.core.query.lucene; + +import java.util.HashMap; +import java.util.Map; + +/** + * PerQueryCache implements a hash map on a per thread basis for + * the purpose of caching results while a query is executed. When the query + * finished the cache can be disposed by calling: + * PerQueryCache.getInstance().dispose(). + */ +class PerQueryCache { + + /** + * The internal map of this PerQueryCache. + */ + private final Map map = new HashMap(); + + /** + * Private constructor. + */ + private PerQueryCache() { + } + + /** + * The per thread cache instance. + */ + private static final ThreadLocal CACHE = new ThreadLocal(); + + /** + * @return PerQueryCache for the current thread. + */ + static PerQueryCache getInstance() { + PerQueryCache cache = (PerQueryCache) CACHE.get(); + if (cache == null) { + cache = new PerQueryCache(); + CACHE.set(cache); + } + return cache; + } + + /** + * Returns the value from the cache with the given type and + * key. + * + * @param type the query type. + * @param key the key object. + * @return the value assigned to type and key or + * null if it does not exist in the cache. + */ + Object get(Class type, Object key) { + return map.get(new Key(type, key)); + } + + /** + * Puts the value into the cache and assigns it to + * type and key. + * + * @param type the query type. + * @param key the key object. + * @param value the value to cache. + * @return the existing value in the cache assigned to type and + * key or null if there was none. + */ + Object put(Class type, Object key, Object value) { + return map.put(new Key(type, key), value); + } + + /** + * Disposes the PerQueryCache for the current thread. + */ + void dispose() { + CACHE.set(null); + } + + /** + * Simple key class. + */ + private static final class Key { + + /** + * The query type. + */ + private final Class type; + + /** + * The key object. + */ + private final Object key; + + /** + * Creates a new internal Key object. + * + * @param type the query type. + * @param key the key object. + */ + private Key(Class type, Object key) { + this.type = type; + this.key = key; + } + + /** + * {@inheritDoc} + */ + public int hashCode() { + return type.hashCode() ^ key.hashCode(); + } + + /** + * {@inheritDoc} + */ + public boolean equals(Object obj) { + if (obj instanceof Key) { + Key other = (Key) obj; + return type == other.type && key.equals(other.key); + } + return false; + } + } +} Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/PerQueryCache.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryHits.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryHits.java?view=diff&rev=520878&r1=520877&r2=520878 ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryHits.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryHits.java Wed Mar 21 06:17:12 2007 @@ -62,6 +62,7 @@ */ public final void close() throws IOException { reader.close(); + PerQueryCache.getInstance().dispose(); } /** Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/RangeQuery.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/RangeQuery.java?view=diff&rev=520878&r1=520877&r2=520878 ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/RangeQuery.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/RangeQuery.java Wed Mar 21 06:17:12 2007 @@ -29,15 +29,14 @@ import org.apache.lucene.index.TermDocs; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.apache.commons.collections.map.LRUMap; import java.io.IOException; import java.util.BitSet; import java.util.Map; -import java.util.WeakHashMap; import java.util.List; import java.util.ArrayList; import java.util.Iterator; +import java.util.HashMap; /** * Implements a variant of the lucene class {@link org.apache.lucene.search.RangeQuery}. @@ -53,12 +52,6 @@ private static final Logger log = LoggerFactory.getLogger(RangeQuery.class); /** - * Simple result cache for previously calculated hits. - * key=IndexReader value=Map{key=String:range,value=BitSet:hits} - */ - private static final Map cache = new WeakHashMap(); - - /** * The lower term. May be null if upperTerm is not * null. */ @@ -292,15 +285,14 @@ key.append(transform); this.cacheKey = key.toString(); // check cache - synchronized (cache) { - Map m = (Map) cache.get(reader); + PerQueryCache cache = PerQueryCache.getInstance(); + Map m = (Map) cache.get(RangeQueryScorer.class, reader); if (m == null) { - m = new LRUMap(10); - cache.put(reader, m); + m = new HashMap(); + cache.put(RangeQueryScorer.class, reader, m); } resultMap = m; - } - synchronized (resultMap) { + BitSet result = (BitSet) resultMap.get(cacheKey); if (result == null) { result = new BitSet(reader.maxDoc()); @@ -308,7 +300,6 @@ hitsCalculated = true; } hits = result; - } } /** Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/WildcardQuery.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/WildcardQuery.java?view=diff&rev=520878&r1=520877&r2=520878 ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/WildcardQuery.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/WildcardQuery.java Wed Mar 21 06:17:12 2007 @@ -31,12 +31,11 @@ import org.apache.lucene.search.Similarity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.apache.commons.collections.map.LRUMap; import java.io.IOException; import java.util.BitSet; -import java.util.WeakHashMap; import java.util.Map; +import java.util.HashMap; /** * Implements a wildcard query on a lucene field with an embedded property name @@ -77,12 +76,6 @@ private final int transform; /** - * Simple result cache for previously calculated hits. - * key=IndexReader value=Map{key=String:pattern,value=BitSet:hits} - */ - private static final Map cache = new WeakHashMap(); - - /** * Creates a new WildcardQuery. * * @param field the name of the field to search. @@ -255,15 +248,14 @@ this.reader = reader; this.cacheKey = field + '\uFFFF' + propName + '\uFFFF' + transform +'\uFFFF' + pattern; // check cache - synchronized (cache) { - Map m = (Map) cache.get(reader); + PerQueryCache cache = PerQueryCache.getInstance(); + Map m = (Map) cache.get(WildcardQueryScorer.class, reader); if (m == null) { - m = new LRUMap(10); - cache.put(reader, m); + m = new HashMap(); + cache.put(WildcardQueryScorer.class, reader, m); } resultMap = m; - } - synchronized (resultMap) { + BitSet result = (BitSet) resultMap.get(cacheKey); if (result == null) { result = new BitSet(reader.maxDoc()); @@ -271,7 +263,6 @@ hitsCalculated = true; } hits = result; - } } /**