LUCENE-4740: Don't track clones of MMapIndexInput if unmapping is disabled. This reduces GC overhead.

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1441726 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Uwe Schindler 2013-02-02 10:35:54 +00:00
parent 722df2c1e7
commit 369f2379c2
3 changed files with 50 additions and 42 deletions

View File

@ -66,6 +66,9 @@ Optimizations
facets. Also added OrdinalPolicy.ALL_BUT_DIMENSION. facets. Also added OrdinalPolicy.ALL_BUT_DIMENSION.
(Shai Erera, Michael McCandless) (Shai Erera, Michael McCandless)
* LUCENE-4740: Don't track clones of MMapIndexInput if unmapping
is disabled. This reduces GC overhead. (Kristofer Karlsson, Uwe Schindler)
New Features New Features
* LUCENE-4686: New specialized DGapVInt8IntEncoder for facets (now the * LUCENE-4686: New specialized DGapVInt8IntEncoder for facets (now the

View File

@ -51,14 +51,15 @@ abstract class ByteBufferIndexInput extends IndexInput {
private ByteBuffer curBuf; // redundant for speed: buffers[curBufIndex] private ByteBuffer curBuf; // redundant for speed: buffers[curBufIndex]
private boolean isClone = false; private boolean isClone = false;
private final WeakIdentityMap<ByteBufferIndexInput,Boolean> clones = WeakIdentityMap.newConcurrentHashMap(); private final WeakIdentityMap<ByteBufferIndexInput,Boolean> clones;
ByteBufferIndexInput(String resourceDescription, ByteBuffer[] buffers, long length, int chunkSizePower) throws IOException { ByteBufferIndexInput(String resourceDescription, ByteBuffer[] buffers, long length, int chunkSizePower, boolean trackClones) throws IOException {
super(resourceDescription); super(resourceDescription);
this.buffers = buffers; this.buffers = buffers;
this.length = length; this.length = length;
this.chunkSizePower = chunkSizePower; this.chunkSizePower = chunkSizePower;
this.chunkSizeMask = (1L << chunkSizePower) - 1L; this.chunkSizeMask = (1L << chunkSizePower) - 1L;
this.clones = trackClones ? WeakIdentityMap.<ByteBufferIndexInput,Boolean>newConcurrentHashMap() : null;
assert chunkSizePower >= 0 && chunkSizePower <= 30; assert chunkSizePower >= 0 && chunkSizePower <= 30;
assert (length >>> chunkSizePower) < Integer.MAX_VALUE; assert (length >>> chunkSizePower) < Integer.MAX_VALUE;
@ -231,7 +232,9 @@ abstract class ByteBufferIndexInput extends IndexInput {
clone.length = length; clone.length = length;
// register the new clone in our clone list to clean it up on closing: // register the new clone in our clone list to clean it up on closing:
this.clones.put(clone, Boolean.TRUE); if (clones != null) {
this.clones.put(clone, Boolean.TRUE);
}
return clone; return clone;
} }
@ -272,17 +275,21 @@ abstract class ByteBufferIndexInput extends IndexInput {
// make local copy, then un-set early // make local copy, then un-set early
final ByteBuffer[] bufs = buffers; final ByteBuffer[] bufs = buffers;
unsetBuffers(); unsetBuffers();
clones.remove(this); if (clones != null) {
clones.remove(this);
}
if (isClone) return; if (isClone) return;
// for extra safety unset also all clones' buffers: // for extra safety unset also all clones' buffers:
for (Iterator<ByteBufferIndexInput> it = this.clones.keyIterator(); it.hasNext();) { if (clones != null) {
final ByteBufferIndexInput clone = it.next(); for (Iterator<ByteBufferIndexInput> it = this.clones.keyIterator(); it.hasNext();) {
assert clone.isClone; final ByteBufferIndexInput clone = it.next();
clone.unsetBuffers(); assert clone.isClone;
clone.unsetBuffers();
}
this.clones.clear();
} }
this.clones.clear();
for (final ByteBuffer b : bufs) { for (final ByteBuffer b : bufs) {
freeBuffer(b); freeBuffer(b);

View File

@ -177,36 +177,6 @@ public class MMapDirectory extends FSDirectory {
return useUnmapHack; return useUnmapHack;
} }
/**
* Try to unmap the buffer, this method silently fails if no support
* for that in the JVM. On Windows, this leads to the fact,
* that mmapped files cannot be modified or deleted.
*/
final void cleanMapping(final ByteBuffer buffer) throws IOException {
if (useUnmapHack) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
final Method getCleanerMethod = buffer.getClass()
.getMethod("cleaner");
getCleanerMethod.setAccessible(true);
final Object cleaner = getCleanerMethod.invoke(buffer);
if (cleaner != null) {
cleaner.getClass().getMethod("clean")
.invoke(cleaner);
}
return null;
}
});
} catch (PrivilegedActionException e) {
final IOException ioe = new IOException("unable to unmap the mapped buffer");
ioe.initCause(e.getCause());
throw ioe;
}
}
}
/** /**
* Returns the current mmap chunk size. * Returns the current mmap chunk size.
* @see #MMapDirectory(File, LockFactory, int) * @see #MMapDirectory(File, LockFactory, int)
@ -246,14 +216,42 @@ public class MMapDirectory extends FSDirectory {
} }
private final class MMapIndexInput extends ByteBufferIndexInput { private final class MMapIndexInput extends ByteBufferIndexInput {
private final boolean useUnmapHack;
MMapIndexInput(String resourceDescription, RandomAccessFile raf) throws IOException { MMapIndexInput(String resourceDescription, RandomAccessFile raf) throws IOException {
super(resourceDescription, map(raf, 0, raf.length()), raf.length(), chunkSizePower); super(resourceDescription, map(raf, 0, raf.length()), raf.length(), chunkSizePower, getUseUnmap());
this.useUnmapHack = getUseUnmap();
} }
/**
* Try to unmap the buffer, this method silently fails if no support
* for that in the JVM. On Windows, this leads to the fact,
* that mmapped files cannot be modified or deleted.
*/
@Override @Override
protected void freeBuffer(ByteBuffer buffer) throws IOException { protected void freeBuffer(final ByteBuffer buffer) throws IOException {
cleanMapping(buffer); if (useUnmapHack) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws Exception {
final Method getCleanerMethod = buffer.getClass()
.getMethod("cleaner");
getCleanerMethod.setAccessible(true);
final Object cleaner = getCleanerMethod.invoke(buffer);
if (cleaner != null) {
cleaner.getClass().getMethod("clean")
.invoke(cleaner);
}
return null;
}
});
} catch (PrivilegedActionException e) {
final IOException ioe = new IOException("unable to unmap the mapped buffer");
ioe.initCause(e.getCause());
throw ioe;
}
}
} }
} }