Added no-cache infrastucture the the filter cache.

During query parsing if a filter is encountered that extends from NoCacheFilter then the filter will not be given to the filter cache (also not wrapped in FilterCacheFilterWrapper).
Also if a filter directly or indirectly wraps a NoCacheFilter then that filter will also not be cached.

Relates to #4757
This commit is contained in:
Simon Willnauer 2014-01-15 22:33:45 +01:00 committed by Martijn van Groningen
parent e34a35244c
commit 0e418d18a4
2 changed files with 67 additions and 6 deletions

View File

@ -19,11 +19,61 @@
package org.elasticsearch.common.lucene.search;
import org.apache.lucene.index.AtomicReaderContext;
import org.apache.lucene.search.DocIdSet;
import org.apache.lucene.search.Filter;
import org.apache.lucene.util.Bits;
import java.io.IOException;
/**
* A marker interface for {@link org.apache.lucene.search.Filter} denoting the filter
* as one that should not be cached, ever.
*/
public abstract class NoCacheFilter extends Filter {
private static final class NoCacheFilterWrapper extends NoCacheFilter {
private final Filter delegate;
private NoCacheFilterWrapper(Filter delegate) {
this.delegate = delegate;
}
@Override
public DocIdSet getDocIdSet(AtomicReaderContext context, Bits acceptDocs) throws IOException {
return delegate.getDocIdSet(context, acceptDocs);
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof NoCacheFilterWrapper) {
return delegate.equals(((NoCacheFilterWrapper)obj).delegate);
}
return false;
}
@Override
public String toString() {
return "no_cache(" + delegate + ")";
}
}
/**
* Wraps a filter in a NoCacheFilter or returns it if it already is a NoCacheFilter.
*/
public static Filter wrap(Filter filter) {
if (filter instanceof NoCacheFilter) {
return filter;
}
return new NoCacheFilterWrapper(filter);
}
}

View File

@ -30,6 +30,7 @@ import org.apache.lucene.search.similarities.Similarity;
import org.elasticsearch.cache.recycler.CacheRecycler;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.lucene.search.NoCacheFilter;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.Index;
import org.elasticsearch.index.analysis.AnalysisService;
@ -75,6 +76,8 @@ public class QueryParseContext {
private final Index index;
private boolean propagateNoCache = false;
IndexQueryParserService indexQueryParser;
private final Map<String, Filter> namedFilters = Maps.newHashMap();
@ -168,6 +171,9 @@ public class QueryParseContext {
if (filter == null) {
return null;
}
if (this.propagateNoCache || filter instanceof NoCacheFilter) {
return filter;
}
if (cacheKey != null) {
filter = new CacheKeyFilter.Wrapper(filter, cacheKey);
}
@ -251,7 +257,7 @@ public class QueryParseContext {
if (filterParser == null) {
throw new QueryParsingException(index, "No filter registered for [" + filterName + "]");
}
Filter result = filterParser.parse(this);
Filter result = executeFilterParser(filterParser);
if (parser.currentToken() == XContentParser.Token.END_OBJECT || parser.currentToken() == XContentParser.Token.END_ARRAY) {
// if we are at END_OBJECT, move to the next one...
parser.nextToken();
@ -264,12 +270,17 @@ public class QueryParseContext {
if (filterParser == null) {
throw new QueryParsingException(index, "No filter registered for [" + filterName + "]");
}
return executeFilterParser(filterParser);
}
private Filter executeFilterParser(FilterParser filterParser) throws IOException {
final boolean propagateNoCache = this.propagateNoCache; // first safe the state that we need to restore
this.propagateNoCache = false; // parse the subfilter with caching, that's fine
Filter result = filterParser.parse(this);
// don't move to the nextToken in this case...
// if (parser.currentToken() == XContentParser.Token.END_OBJECT || parser.currentToken() == XContentParser.Token.END_ARRAY) {
// // if we are at END_OBJECT, move to the next one...
// parser.nextToken();
// }
// now make sure we set propagateNoCache to true if it is true already or if the result is
// an instance of NoCacheFilter or if we used to be true! all filters above will
// be not cached ie. wrappers of this filter!
this.propagateNoCache |= (result instanceof NoCacheFilter) || propagateNoCache;
return result;
}