package org.elassandra.index.search; import java.io.IOException; import java.util.concurrent.ExecutionException; import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.FilterLeafReader; import org.apache.lucene.index.LeafReader; import org.apache.lucene.search.Query; import org.apache.lucene.util.BitSet; import org.apache.lucene.util.Bits; import org.elasticsearch.common.lucene.index.ElasticsearchDirectoryReader; /** * Per request LeafReader using cached token ranges bitset filter. */ public class TokenRangesLeafReader extends FilterLeafReader { /** * A {@link BitSet} matching the expected documents on the given * segment. This may {@code null} if no documents match */ private volatile int numDocs = -1; private final BitSet mask; private final boolean hasDeletions; private final Bits noBitMatch; public TokenRangesLeafReader(DirectoryReader directoryReader, LeafReader in, Query query, TokenRangesBitsetFilterCache cache) throws IOException { super(in); try { in.addCoreClosedListener(cache); ElasticsearchDirectoryReader.addReaderCloseListener(directoryReader, cache); //in.addReaderClosedListener(cache); this.mask = cache.getBitSet(query, in.getContext()); if (mask == null) { numDocs = 0; hasDeletions = true; noBitMatch = new Bits.MatchNoBits(in.maxDoc()); } else { numDocs = mask.cardinality(); hasDeletions = numDocs < in.numDocs(); noBitMatch = null; } } catch (ExecutionException e) { throw new IOException(e); } } /** Returns the number of documents in this index. */ @Override public int numDocs() { return numDocs; } /** Returns true if any documents have been deleted. Implementers should * consider overriding this method if {@link #maxDoc()} or {@link #numDocs()} * are not constant-time operations. */ @Override public boolean hasDeletions() { return hasDeletions; } /** Returns the {@link Bits} representing live (not * deleted) docs. A set bit indicates the doc ID has not * been deleted. If this method returns null it means * there are no deleted documents (all documents are * live). * * The returned instance has been safely published for * use by multiple threads without additional * synchronization. */ @Override public Bits getLiveDocs() { if (!hasDeletions) return null; return (mask == null) ? noBitMatch : mask; } @Override public Object getCoreCacheKey() { return in.getCoreCacheKey(); } @Override public String toString() { final StringBuilder buffer = new StringBuilder("TokenRangeLeafReader("); buffer.append(in); buffer.append(')'); return buffer.toString(); } }