mirror of https://github.com/apache/lucene.git
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:
parent
7be6fa54f0
commit
12e212ccae
|
@ -1248,4 +1248,10 @@ public abstract class IndexReader implements Cloneable {
|
||||||
public IndexReader[] getSequentialSubReaders() {
|
public IndexReader[] getSequentialSubReaders() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Expert
|
||||||
|
* @deprecated */
|
||||||
|
public Object getFieldCacheKey() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1250,4 +1250,11 @@ class SegmentReader extends DirectoryIndexReader {
|
||||||
norm.dirty = norm.rollbackDirty;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,11 +50,13 @@ implements FieldCache {
|
||||||
public Object get(IndexReader reader, Object key) throws IOException {
|
public Object get(IndexReader reader, Object key) throws IOException {
|
||||||
Map innerCache;
|
Map innerCache;
|
||||||
Object value;
|
Object value;
|
||||||
|
final Object readerKey = reader.getFieldCacheKey();
|
||||||
|
|
||||||
synchronized (readerCache) {
|
synchronized (readerCache) {
|
||||||
innerCache = (Map) readerCache.get(reader);
|
innerCache = (Map) readerCache.get(readerKey);
|
||||||
if (innerCache == null) {
|
if (innerCache == null) {
|
||||||
innerCache = new HashMap();
|
innerCache = new HashMap();
|
||||||
readerCache.put(reader, innerCache);
|
readerCache.put(readerKey, innerCache);
|
||||||
value = null;
|
value = null;
|
||||||
} else {
|
} else {
|
||||||
value = innerCache.get(key);
|
value = innerCache.get(key);
|
||||||
|
|
|
@ -44,6 +44,7 @@ import org.apache.lucene.search.MultiReaderHitCollector;
|
||||||
import org.apache.lucene.search.ScoreDoc;
|
import org.apache.lucene.search.ScoreDoc;
|
||||||
import org.apache.lucene.search.TermQuery;
|
import org.apache.lucene.search.TermQuery;
|
||||||
import org.apache.lucene.search.Query;
|
import org.apache.lucene.search.Query;
|
||||||
|
import org.apache.lucene.search.FieldCache;
|
||||||
import org.apache.lucene.store.AlreadyClosedException;
|
import org.apache.lucene.store.AlreadyClosedException;
|
||||||
import org.apache.lucene.store.Directory;
|
import org.apache.lucene.store.Directory;
|
||||||
import org.apache.lucene.store.FSDirectory;
|
import org.apache.lucene.store.FSDirectory;
|
||||||
|
@ -1685,4 +1686,112 @@ public class TestIndexReader extends LuceneTestCase
|
||||||
s.close();
|
s.close();
|
||||||
r.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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue