LUCENE-2135: forcefully evict IndexReader from FieldCache when it's closed

git-svn-id: https://svn.apache.org/repos/asf/lucene/java/trunk@889866 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Michael McCandless 2009-12-12 00:08:18 +00:00
parent 2c675012fe
commit 53ce286a25
8 changed files with 75 additions and 3 deletions

View File

@ -12,6 +12,10 @@ Changes in backwards compatibility policy
FuzzyQuery. The class was never intended to be public.
(Uwe Schindler, Mike McCandless)
* LUCENE-2135: Added FieldCache.purge(IndexReader) method to the
interface. Anyone implementing FieldCache externally will need to
fix their code to implement this, on upgrading. (Mike McCandless)
Changes in runtime behavior
API Changes
@ -92,6 +96,10 @@ Optimizations
MTQ. This also fixes a slowdown / memory issue added by LUCENE-504.
(Uwe Schindler, Robert Muir, Mike McCandless)
* LUCENE-2135: On IndexReader.close, forcefully evict any entries from
the FieldCache rather than waiting for the WeakHashMap to release
the reference (Mike McCandless)
Build
* LUCENE-2124: Moved the JDK-based collation support from contrib/collation

View File

@ -36,6 +36,7 @@ import org.apache.lucene.store.AlreadyClosedException;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.Lock;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.search.FieldCache; // not great (circular); used only to purge FieldCache entry on close
/**
* An IndexReader which reads indexes with multiple segments.
@ -854,6 +855,12 @@ class DirectoryReader extends IndexReader implements Cloneable {
if (ioe == null) ioe = e;
}
}
// NOTE: only needed in case someone had asked for
// FieldCache for top-level reader (which is generally
// not a good idea):
FieldCache.DEFAULT.purge(this);
// throw the first exception
if (ioe != null) throw ioe;
}

View File

@ -20,6 +20,7 @@ package org.apache.lucene.index;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.FieldSelector;
import org.apache.lucene.store.Directory;
import org.apache.lucene.search.FieldCache; // not great (circular); used only to purge FieldCache entry on close
import java.io.IOException;
import java.util.Collection;
@ -241,7 +242,14 @@ public class FilterIndexReader extends IndexReader {
protected void doCommit(Map<String,String> commitUserData) throws IOException { in.commit(commitUserData); }
@Override
protected void doClose() throws IOException { in.close(); }
protected void doClose() throws IOException {
in.close();
// NOTE: only needed in case someone had asked for
// FieldCache for top-level reader (which is generally
// not a good idea):
FieldCache.DEFAULT.purge(this);
}
@Override
@ -272,4 +280,12 @@ public class FilterIndexReader extends IndexReader {
public IndexReader[] getSequentialSubReaders() {
return in.getSequentialSubReaders();
}
/** If the subclass of FilteredIndexReader modifies the
* contents of the FieldCache, you must override this
* method to provide a different key */
@Override
public Object getFieldCacheKey() {
return in.getFieldCacheKey();
}
}

View File

@ -29,6 +29,7 @@ import org.apache.lucene.index.DirectoryReader.MultiTermDocs;
import org.apache.lucene.index.DirectoryReader.MultiTermEnum;
import org.apache.lucene.index.DirectoryReader.MultiTermPositions;
import org.apache.lucene.search.Similarity;
import org.apache.lucene.search.FieldCache; // not great (circular); used only to purge FieldCache entry on close
/** An IndexReader which reads multiple indexes, appending
* their content. */
@ -415,6 +416,11 @@ public class MultiReader extends IndexReader implements Cloneable {
subReaders[i].close();
}
}
// NOTE: only needed in case someone had asked for
// FieldCache for top-level reader (which is generally
// not a good idea):
FieldCache.DEFAULT.purge(this);
}
@Override

View File

@ -21,6 +21,7 @@ import org.apache.lucene.document.Document;
import org.apache.lucene.document.FieldSelector;
import org.apache.lucene.document.FieldSelectorResult;
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.search.FieldCache; // not great (circular); used only to purge FieldCache entry on close
import java.io.IOException;
import java.util.*;
@ -470,6 +471,8 @@ public class ParallelReader extends IndexReader {
readers.get(i).close();
}
}
FieldCache.DEFAULT.purge(this);
}
@Override

View File

@ -38,6 +38,7 @@ import org.apache.lucene.store.IndexInput;
import org.apache.lucene.store.IndexOutput;
import org.apache.lucene.util.BitVector;
import org.apache.lucene.util.CloseableThreadLocal;
import org.apache.lucene.search.FieldCache; // not great (circular); used only to purge FieldCache entry on close
/** @version $Id */
/**
@ -93,16 +94,19 @@ public class SegmentReader extends IndexReader implements Cloneable {
final int readBufferSize;
final int termsIndexDivisor;
private final SegmentReader origInstance;
TermInfosReader tis;
FieldsReader fieldsReaderOrig;
TermVectorsReader termVectorsReaderOrig;
CompoundFileReader cfsReader;
CompoundFileReader storeCFSReader;
CoreReaders(Directory dir, SegmentInfo si, int readBufferSize, int termsIndexDivisor) throws IOException {
CoreReaders(SegmentReader origInstance, Directory dir, SegmentInfo si, int readBufferSize, int termsIndexDivisor) throws IOException {
segment = si.name;
this.readBufferSize = readBufferSize;
this.dir = dir;
this.origInstance = origInstance;
boolean success = false;
@ -233,6 +237,11 @@ public class SegmentReader extends IndexReader implements Cloneable {
if (storeCFSReader != null) {
storeCFSReader.close();
}
// Force FieldCache to evict our entries at this point
if (freqStream != null) {
FieldCache.DEFAULT.purge(origInstance);
}
}
}
@ -549,7 +558,7 @@ public class SegmentReader extends IndexReader implements Cloneable {
boolean success = false;
try {
instance.core = new CoreReaders(dir, si, readBufferSize, termInfosIndexDivisor);
instance.core = new CoreReaders(instance, dir, si, readBufferSize, termInfosIndexDivisor);
if (doOpenStores) {
instance.core.openDocStores(si);
}

View File

@ -593,6 +593,15 @@ public interface FieldCache {
*/
public abstract void purgeAllCaches();
/**
* Expert: drops all cache entries associated with this
* reader. NOTE: this reader must precisely match the
* reader that the cache entry is keyed on. If you pass a
* top-level reader, it usually will have no effect as
* Lucene now caches at the segment reader level.
*/
public abstract void purge(IndexReader r);
/**
* If non-null, FieldCacheImpl will warn whenever
* entries are created that are not sane according to

View File

@ -61,6 +61,12 @@ class FieldCacheImpl implements FieldCache {
public void purgeAllCaches() {
init();
}
public void purge(IndexReader r) {
for(Cache c : caches.values()) {
c.purge(r);
}
}
public CacheEntry[] getCacheEntries() {
List<CacheEntry> result = new ArrayList<CacheEntry>(17);
@ -144,6 +150,14 @@ class FieldCacheImpl implements FieldCache {
protected abstract Object createValue(IndexReader reader, Entry key)
throws IOException;
/** Remove this reader from the cache, if present. */
public void purge(IndexReader r) {
Object readerKey = r.getFieldCacheKey();
synchronized(readerCache) {
readerCache.remove(readerKey);
}
}
public Object get(IndexReader reader, Entry key) throws IOException {
Map<Entry,Object> innerCache;
Object value;