LUCENE-1579: make sure cloned SegmentReaders share the same entry in FieldCache

git-svn-id: https://svn.apache.org/repos/asf/lucene/java/trunk@760486 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Michael McCandless 2009-03-31 15:41:08 +00:00
parent 7be6fa54f0
commit 12e212ccae
4 changed files with 126 additions and 2 deletions

View File

@ -1248,4 +1248,10 @@ public abstract class IndexReader implements Cloneable {
public IndexReader[] getSequentialSubReaders() {
return null;
}
/** Expert
* @deprecated */
public Object getFieldCacheKey() {
return this;
}
}

View File

@ -1250,4 +1250,11 @@ class SegmentReader extends DirectoryIndexReader {
norm.dirty = norm.rollbackDirty;
}
}
// This is necessary so that cloned SegmentReaders (which
// share the underlying postings data) will map to the
// same entry in the FieldCache. See LUCENE-1579.
public final Object getFieldCacheKey() {
return freqStream;
}
}

View File

@ -50,11 +50,13 @@ implements FieldCache {
public Object get(IndexReader reader, Object key) throws IOException {
Map innerCache;
Object value;
final Object readerKey = reader.getFieldCacheKey();
synchronized (readerCache) {
innerCache = (Map) readerCache.get(reader);
innerCache = (Map) readerCache.get(readerKey);
if (innerCache == null) {
innerCache = new HashMap();
readerCache.put(reader, innerCache);
readerCache.put(readerKey, innerCache);
value = null;
} else {
value = innerCache.get(key);

View File

@ -44,6 +44,7 @@ import org.apache.lucene.search.MultiReaderHitCollector;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.FieldCache;
import org.apache.lucene.store.AlreadyClosedException;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
@ -1685,4 +1686,112 @@ public class TestIndexReader extends LuceneTestCase
s.close();
r.close();
}
// LUCENE-1579: Ensure that on a cloned reader, segments
// reuse the doc values arrays in FieldCache
public void testFieldCacheReuseAfterClone() throws Exception {
Directory dir = new MockRAMDirectory();
IndexWriter writer = new IndexWriter(dir, new WhitespaceAnalyzer(), IndexWriter.MaxFieldLength.UNLIMITED);
Document doc = new Document();
doc.add(new Field("number", "17", Field.Store.NO, Field.Index.NOT_ANALYZED));
writer.addDocument(doc);
writer.close();
// Open reader
IndexReader r = IndexReader.open(dir);
assertTrue(r instanceof SegmentReader);
final int[] ints = FieldCache.DEFAULT.getInts(r, "number");
assertEquals(1, ints.length);
assertEquals(17, ints[0]);
// Clone reader
IndexReader r2 = (IndexReader) r.clone();
r.close();
assertTrue(r2 != r);
assertTrue(r2 instanceof SegmentReader);
final int[] ints2 = FieldCache.DEFAULT.getInts(r2, "number");
r2.close();
assertEquals(1, ints2.length);
assertEquals(17, ints2[0]);
assertTrue(ints == ints2);
dir.close();
}
// LUCENE-1579: Ensure that on a reopened reader, that any
// shared segments reuse the doc values arrays in
// FieldCache
public void testFieldCacheReuseAfterReopen() throws Exception {
Directory dir = new MockRAMDirectory();
IndexWriter writer = new IndexWriter(dir, new WhitespaceAnalyzer(), IndexWriter.MaxFieldLength.UNLIMITED);
Document doc = new Document();
doc.add(new Field("number", "17", Field.Store.NO, Field.Index.NOT_ANALYZED));
writer.addDocument(doc);
writer.commit();
// Open reader1
IndexReader r = IndexReader.open(dir);
assertTrue(r instanceof SegmentReader);
final int[] ints = FieldCache.DEFAULT.getInts(r, "number");
assertEquals(1, ints.length);
assertEquals(17, ints[0]);
// Add new segment
writer.addDocument(doc);
writer.commit();
// Reopen reader1 --> reader2
IndexReader r2 = (IndexReader) r.reopen();
r.close();
assertTrue(r2 instanceof MultiSegmentReader);
IndexReader sub0 = r2.getSequentialSubReaders()[0];
assertTrue(sub0 instanceof SegmentReader);
final int[] ints2 = FieldCache.DEFAULT.getInts(sub0, "number");
r2.close();
assertTrue(ints == ints2);
dir.close();
}
// LUCENE-1579: Make sure all SegmentReaders are new when
// reopen switches readOnly
public void testReopenChangeReadonly() throws Exception {
Directory dir = new MockRAMDirectory();
IndexWriter writer = new IndexWriter(dir, new WhitespaceAnalyzer(), IndexWriter.MaxFieldLength.UNLIMITED);
Document doc = new Document();
doc.add(new Field("number", "17", Field.Store.NO, Field.Index.NOT_ANALYZED));
writer.addDocument(doc);
writer.commit();
// Open reader1
IndexReader r = IndexReader.open(dir);
assertTrue(r instanceof SegmentReader);
final int[] ints = FieldCache.DEFAULT.getInts(r, "number");
assertEquals(1, ints.length);
assertEquals(17, ints[0]);
// Reopen to readonly w/ no chnages
IndexReader r3 = (IndexReader) r.reopen(true);
assertTrue(r3 instanceof ReadOnlySegmentReader);
r3.close();
// Add new segment
writer.addDocument(doc);
writer.commit();
// Reopen reader1 --> reader2
IndexReader r2 = (IndexReader) r.reopen(true);
r.close();
assertTrue(r2 instanceof MultiSegmentReader);
IndexReader[] subs = r2.getSequentialSubReaders();
final int[] ints2 = FieldCache.DEFAULT.getInts(subs[0], "number");
r2.close();
assertTrue(subs[0] instanceof ReadOnlySegmentReader);
assertTrue(subs[1] instanceof ReadOnlySegmentReader);
assertTrue(ints == ints2);
dir.close();
}
}