package org.apache.lucene.search;
/**
* Copyright 2005 The Apache Software Foundation
*
* Licensed 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.
*/
import org.apache.lucene.index.IndexReader;
import java.io.IOException;
/**
* Wraps another SpanFilter's result and caches it. The purpose is to allow
* filters to simply filter, and then wrap with this class to add caching.
*/
public class CachingSpanFilter extends SpanFilter {
private SpanFilter filter;
/**
* A transient Filter cache (package private because of test)
*/
private final CachingWrapperFilter.FilterCache<SpanFilterResult> cache;
/**
* New deletions always result in a cache miss, by default
* ({@link CachingWrapperFilter.DeletesMode#RECACHE}.
* @param filter Filter to cache results of
*/
public CachingSpanFilter(SpanFilter filter) {
this(filter, CachingWrapperFilter.DeletesMode.RECACHE);
}
/**
* @param filter Filter to cache results of
* @param deletesMode See {@link CachingWrapperFilter.DeletesMode}
*/
public CachingSpanFilter(SpanFilter filter, CachingWrapperFilter.DeletesMode deletesMode) {
this.filter = filter;
if (deletesMode == CachingWrapperFilter.DeletesMode.DYNAMIC) {
throw new IllegalArgumentException("DeletesMode.DYNAMIC is not supported");
}
this.cache = new CachingWrapperFilter.FilterCache<SpanFilterResult>(deletesMode) {
@Override
protected SpanFilterResult mergeDeletes(final IndexReader reader, final SpanFilterResult value) {
throw new IllegalStateException("DeletesMode.DYNAMIC is not supported");
}
};
}
@Override
public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
SpanFilterResult result = getCachedResult(reader);
return result != null ? result.getDocIdSet() : null;
}
// for testing
int hitCount, missCount;
private SpanFilterResult getCachedResult(IndexReader reader) throws IOException {
final Object coreKey = reader.getCoreCacheKey();
final Object delCoreKey = reader.hasDeletions() ? reader.getDeletesCacheKey() : coreKey;
SpanFilterResult result = cache.get(reader, coreKey, delCoreKey);
if (result != null) {
hitCount++;
return result;
}
missCount++;
result = filter.bitSpans(reader);
cache.put(coreKey, delCoreKey, result);
return result;
}
@Override
public SpanFilterResult bitSpans(IndexReader reader) throws IOException {
return getCachedResult(reader);
}
@Override
public String toString() {
return "CachingSpanFilter("+filter+")";
}
@Override
public boolean equals(Object o) {
if (!(o instanceof CachingSpanFilter)) return false;
return this.filter.equals(((CachingSpanFilter)o).filter);
}
@Override
public int hashCode() {
return filter.hashCode() ^ 0x1117BF25;
}
}