LUCENE-4790: FieldCache.getDocTermOrds back to the future bug

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1448368 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Robert Muir 2013-02-20 19:44:28 +00:00
parent 4650d3aba4
commit 1ab4c5bc36
6 changed files with 54 additions and 21 deletions

View File

@ -238,6 +238,10 @@ Bug Fixes
is enhanced to roll up beyond the bottom cell level. (David Smiley, is enhanced to roll up beyond the bottom cell level. (David Smiley,
Florian Schilling) Florian Schilling)
* LUCENE-4790: Fix FieldCacheImpl.getDocTermOrds to not bake deletes into the
cached datastructure. Otherwise this can cause inconsistencies with readers
at different points in time. (Robert Muir)
Documentation Documentation
* LUCENE-4718: Fixed documentation of oal.queryparser.classic. * LUCENE-4718: Fixed documentation of oal.queryparser.classic.

View File

@ -173,30 +173,29 @@ public class DocTermOrds {
} }
/** Inverts all terms */ /** Inverts all terms */
public DocTermOrds(AtomicReader reader, String field) throws IOException { public DocTermOrds(AtomicReader reader, Bits liveDocs, String field) throws IOException {
this(reader, field, null, Integer.MAX_VALUE); this(reader, liveDocs, field, null, Integer.MAX_VALUE);
} }
/** Inverts only terms starting w/ prefix */ /** Inverts only terms starting w/ prefix */
public DocTermOrds(AtomicReader reader, String field, BytesRef termPrefix) throws IOException { public DocTermOrds(AtomicReader reader, Bits liveDocs, String field, BytesRef termPrefix) throws IOException {
this(reader, field, termPrefix, Integer.MAX_VALUE); this(reader, liveDocs, field, termPrefix, Integer.MAX_VALUE);
} }
/** Inverts only terms starting w/ prefix, and only terms /** Inverts only terms starting w/ prefix, and only terms
* whose docFreq (not taking deletions into account) is * whose docFreq (not taking deletions into account) is
* <= maxTermDocFreq */ * <= maxTermDocFreq */
public DocTermOrds(AtomicReader reader, String field, BytesRef termPrefix, int maxTermDocFreq) throws IOException { public DocTermOrds(AtomicReader reader, Bits liveDocs, String field, BytesRef termPrefix, int maxTermDocFreq) throws IOException {
this(reader, field, termPrefix, maxTermDocFreq, DEFAULT_INDEX_INTERVAL_BITS); this(reader, liveDocs, field, termPrefix, maxTermDocFreq, DEFAULT_INDEX_INTERVAL_BITS);
uninvert(reader, termPrefix);
} }
/** Inverts only terms starting w/ prefix, and only terms /** Inverts only terms starting w/ prefix, and only terms
* whose docFreq (not taking deletions into account) is * whose docFreq (not taking deletions into account) is
* <= maxTermDocFreq, with a custom indexing interval * <= maxTermDocFreq, with a custom indexing interval
* (default is every 128nd term). */ * (default is every 128nd term). */
public DocTermOrds(AtomicReader reader, String field, BytesRef termPrefix, int maxTermDocFreq, int indexIntervalBits) throws IOException { public DocTermOrds(AtomicReader reader, Bits liveDocs, String field, BytesRef termPrefix, int maxTermDocFreq, int indexIntervalBits) throws IOException {
this(field, maxTermDocFreq, indexIntervalBits); this(field, maxTermDocFreq, indexIntervalBits);
uninvert(reader, termPrefix); uninvert(reader, liveDocs, termPrefix);
} }
/** Subclass inits w/ this, but be sure you then call /** Subclass inits w/ this, but be sure you then call
@ -257,14 +256,14 @@ public class DocTermOrds {
protected void visitTerm(TermsEnum te, int termNum) throws IOException { protected void visitTerm(TermsEnum te, int termNum) throws IOException {
} }
/** Invoked during {@link #uninvert(AtomicReader,BytesRef)} /** Invoked during {@link #uninvert(AtomicReader,Bits,BytesRef)}
* to record the document frequency for each uninverted * to record the document frequency for each uninverted
* term. */ * term. */
protected void setActualDocFreq(int termNum, int df) throws IOException { protected void setActualDocFreq(int termNum, int df) throws IOException {
} }
/** Call this only once (if you subclass!) */ /** Call this only once (if you subclass!) */
protected void uninvert(final AtomicReader reader, final BytesRef termPrefix) throws IOException { protected void uninvert(final AtomicReader reader, Bits liveDocs, final BytesRef termPrefix) throws IOException {
final FieldInfo info = reader.getFieldInfos().fieldInfo(field); final FieldInfo info = reader.getFieldInfos().fieldInfo(field);
if (info != null && info.hasDocValues()) { if (info != null && info.hasDocValues()) {
throw new IllegalStateException("Type mismatch: " + field + " was indexed as " + info.getDocValuesType()); throw new IllegalStateException("Type mismatch: " + field + " was indexed as " + info.getDocValuesType());
@ -304,8 +303,6 @@ public class DocTermOrds {
boolean testedOrd = false; boolean testedOrd = false;
final Bits liveDocs = reader.getLiveDocs();
// we need a minimum of 9 bytes, but round up to 12 since the space would // we need a minimum of 9 bytes, but round up to 12 since the space would
// be wasted with most allocators anyway. // be wasted with most allocators anyway.
byte[] tempArr = new byte[12]; byte[] tempArr = new byte[12];

View File

@ -1399,7 +1399,7 @@ class FieldCacheImpl implements FieldCache {
@Override @Override
protected Object createValue(AtomicReader reader, CacheKey key, boolean setDocsWithField /* ignored */) protected Object createValue(AtomicReader reader, CacheKey key, boolean setDocsWithField /* ignored */)
throws IOException { throws IOException {
return new DocTermOrds(reader, key.field); return new DocTermOrds(reader, null, key.field);
} }
} }

View File

@ -63,7 +63,7 @@ public class TestDocTermOrds extends LuceneTestCase {
w.close(); w.close();
final AtomicReader ar = SlowCompositeReaderWrapper.wrap(r); final AtomicReader ar = SlowCompositeReaderWrapper.wrap(r);
final DocTermOrds dto = new DocTermOrds(ar, "field"); final DocTermOrds dto = new DocTermOrds(ar, ar.getLiveDocs(), "field");
SortedSetDocValues iter = dto.iterator(ar.terms("field").iterator(null)); SortedSetDocValues iter = dto.iterator(ar.terms("field").iterator(null));
iter.setDocument(0); iter.setDocument(0);
@ -295,7 +295,7 @@ public class TestDocTermOrds extends LuceneTestCase {
private void verify(AtomicReader r, int[][] idToOrds, BytesRef[] termsArray, BytesRef prefixRef) throws Exception { private void verify(AtomicReader r, int[][] idToOrds, BytesRef[] termsArray, BytesRef prefixRef) throws Exception {
final DocTermOrds dto = new DocTermOrds(r, final DocTermOrds dto = new DocTermOrds(r, r.getLiveDocs(),
"field", "field",
prefixRef, prefixRef,
Integer.MAX_VALUE, Integer.MAX_VALUE,
@ -372,4 +372,34 @@ public class TestDocTermOrds extends LuceneTestCase {
assertEquals(answers.length, upto); assertEquals(answers.length, upto);
} }
} }
public void testBackToTheFuture() throws Exception {
Directory dir = newDirectory();
IndexWriter iw = new IndexWriter(dir, newIndexWriterConfig(TEST_VERSION_CURRENT, null));
Document doc = new Document();
doc.add(newStringField("foo", "bar", Field.Store.NO));
iw.addDocument(doc);
doc = new Document();
doc.add(newStringField("foo", "baz", Field.Store.NO));
iw.addDocument(doc);
DirectoryReader r1 = DirectoryReader.open(iw, true);
iw.deleteDocuments(new Term("foo", "baz"));
DirectoryReader r2 = DirectoryReader.open(iw, true);
FieldCache.DEFAULT.getDocTermOrds(getOnlySegmentReader(r2), "foo");
SortedSetDocValues v = FieldCache.DEFAULT.getDocTermOrds(getOnlySegmentReader(r1), "foo");
assertEquals(2, v.getValueCount());
v.setDocument(1);
assertEquals(1, v.nextOrd());
iw.close();
r1.close();
r2.close();
dir.close();
}
} }

View File

@ -472,7 +472,7 @@ public class TestFieldCache extends LuceneTestCase {
} catch (IllegalStateException expected) {} } catch (IllegalStateException expected) {}
try { try {
new DocTermOrds(ar, "binary"); new DocTermOrds(ar, null, "binary");
fail(); fail();
} catch (IllegalStateException expected) {} } catch (IllegalStateException expected) {}
@ -486,7 +486,7 @@ public class TestFieldCache extends LuceneTestCase {
} catch (IllegalStateException expected) {} } catch (IllegalStateException expected) {}
try { try {
new DocTermOrds(ar, "sorted"); new DocTermOrds(ar, null, "sorted");
fail(); fail();
} catch (IllegalStateException expected) {} } catch (IllegalStateException expected) {}
@ -529,7 +529,7 @@ public class TestFieldCache extends LuceneTestCase {
} catch (IllegalStateException expected) {} } catch (IllegalStateException expected) {}
try { try {
new DocTermOrds(ar, "numeric"); new DocTermOrds(ar, null, "numeric");
fail(); fail();
} catch (IllegalStateException expected) {} } catch (IllegalStateException expected) {}
@ -554,7 +554,7 @@ public class TestFieldCache extends LuceneTestCase {
} catch (IllegalStateException expected) {} } catch (IllegalStateException expected) {}
try { try {
new DocTermOrds(ar, "sortedset"); new DocTermOrds(ar, null, "sortedset");
fail(); fail();
} catch (IllegalStateException expected) {} } catch (IllegalStateException expected) {}

View File

@ -23,6 +23,7 @@ import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import org.apache.lucene.index.AtomicReader;
import org.apache.lucene.index.DocTermOrds; import org.apache.lucene.index.DocTermOrds;
import org.apache.lucene.index.SortedDocValues; import org.apache.lucene.index.SortedDocValues;
import org.apache.lucene.index.Term; import org.apache.lucene.index.Term;
@ -174,7 +175,8 @@ public class UnInvertedField extends DocTermOrds {
final String prefix = TrieField.getMainValuePrefix(searcher.getSchema().getFieldType(field)); final String prefix = TrieField.getMainValuePrefix(searcher.getSchema().getFieldType(field));
this.searcher = searcher; this.searcher = searcher;
try { try {
uninvert(searcher.getAtomicReader(), prefix == null ? null : new BytesRef(prefix)); AtomicReader r = searcher.getAtomicReader();
uninvert(r, r.getLiveDocs(), prefix == null ? null : new BytesRef(prefix));
} catch (IllegalStateException ise) { } catch (IllegalStateException ise) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, ise.getMessage()); throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, ise.getMessage());
} }