HADOOP-10591. Compression codecs must used pooled direct buffers or deallocate direct buffers when stream is closed (cmccabe)
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1611423 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
1e7ce76bba
commit
ef9e24f826
|
@ -441,6 +441,9 @@ Release 2.6.0 - UNRELEASED
|
||||||
HADOOP-9921. daemon scripts should remove pid file on stop call after stop
|
HADOOP-9921. daemon scripts should remove pid file on stop call after stop
|
||||||
or process is found not running ( vinayakumarb )
|
or process is found not running ( vinayakumarb )
|
||||||
|
|
||||||
|
HADOOP-10591. Compression codecs must used pooled direct buffers or
|
||||||
|
deallocate direct buffers when stream is closed (cmccabe)
|
||||||
|
|
||||||
Release 2.5.0 - UNRELEASED
|
Release 2.5.0 - UNRELEASED
|
||||||
|
|
||||||
INCOMPATIBLE CHANGES
|
INCOMPATIBLE CHANGES
|
||||||
|
|
|
@ -100,7 +100,8 @@ public class BZip2Codec implements Configurable, SplittableCompressionCodec {
|
||||||
@Override
|
@Override
|
||||||
public CompressionOutputStream createOutputStream(OutputStream out)
|
public CompressionOutputStream createOutputStream(OutputStream out)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return createOutputStream(out, createCompressor());
|
return CompressionCodec.Util.
|
||||||
|
createOutputStreamWithCodecPool(this, conf, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -153,7 +154,8 @@ public class BZip2Codec implements Configurable, SplittableCompressionCodec {
|
||||||
@Override
|
@Override
|
||||||
public CompressionInputStream createInputStream(InputStream in)
|
public CompressionInputStream createInputStream(InputStream in)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return createInputStream(in, createDecompressor());
|
return CompressionCodec.Util.
|
||||||
|
createInputStreamWithCodecPool(this, conf, in);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -24,6 +24,7 @@ import java.io.OutputStream;
|
||||||
|
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
import org.apache.hadoop.classification.InterfaceStability;
|
import org.apache.hadoop.classification.InterfaceStability;
|
||||||
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class encapsulates a streaming compression/decompression pair.
|
* This class encapsulates a streaming compression/decompression pair.
|
||||||
|
@ -113,4 +114,58 @@ public interface CompressionCodec {
|
||||||
* @return the extension including the '.'
|
* @return the extension including the '.'
|
||||||
*/
|
*/
|
||||||
String getDefaultExtension();
|
String getDefaultExtension();
|
||||||
|
|
||||||
|
static class Util {
|
||||||
|
/**
|
||||||
|
* Create an output stream with a codec taken from the global CodecPool.
|
||||||
|
*
|
||||||
|
* @param codec The codec to use to create the output stream.
|
||||||
|
* @param conf The configuration to use if we need to create a new codec.
|
||||||
|
* @param out The output stream to wrap.
|
||||||
|
* @return The new output stream
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
static CompressionOutputStream createOutputStreamWithCodecPool(
|
||||||
|
CompressionCodec codec, Configuration conf, OutputStream out)
|
||||||
|
throws IOException {
|
||||||
|
Compressor compressor = CodecPool.getCompressor(codec, conf);
|
||||||
|
CompressionOutputStream stream = null;
|
||||||
|
try {
|
||||||
|
stream = codec.createOutputStream(out, compressor);
|
||||||
|
} finally {
|
||||||
|
if (stream == null) {
|
||||||
|
CodecPool.returnCompressor(compressor);
|
||||||
|
} else {
|
||||||
|
stream.setTrackedCompressor(compressor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an input stream with a codec taken from the global CodecPool.
|
||||||
|
*
|
||||||
|
* @param codec The codec to use to create the input stream.
|
||||||
|
* @param conf The configuration to use if we need to create a new codec.
|
||||||
|
* @param in The input stream to wrap.
|
||||||
|
* @return The new input stream
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
static CompressionInputStream createInputStreamWithCodecPool(
|
||||||
|
CompressionCodec codec, Configuration conf, InputStream in)
|
||||||
|
throws IOException {
|
||||||
|
Decompressor decompressor = CodecPool.getDecompressor(codec);
|
||||||
|
CompressionInputStream stream = null;
|
||||||
|
try {
|
||||||
|
stream = codec.createInputStream(in, decompressor);
|
||||||
|
} finally {
|
||||||
|
if (stream == null) {
|
||||||
|
CodecPool.returnDecompressor(decompressor);
|
||||||
|
} else {
|
||||||
|
stream.setTrackedDecompressor(decompressor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,8 @@ public abstract class CompressionInputStream extends InputStream implements Seek
|
||||||
protected final InputStream in;
|
protected final InputStream in;
|
||||||
protected long maxAvailableData = 0L;
|
protected long maxAvailableData = 0L;
|
||||||
|
|
||||||
|
private Decompressor trackedDecompressor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a compression input stream that reads
|
* Create a compression input stream that reads
|
||||||
* the decompressed bytes from the given stream.
|
* the decompressed bytes from the given stream.
|
||||||
|
@ -58,6 +60,10 @@ public abstract class CompressionInputStream extends InputStream implements Seek
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
in.close();
|
in.close();
|
||||||
|
if (trackedDecompressor != null) {
|
||||||
|
CodecPool.returnDecompressor(trackedDecompressor);
|
||||||
|
trackedDecompressor = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -112,4 +118,8 @@ public abstract class CompressionInputStream extends InputStream implements Seek
|
||||||
public boolean seekToNewSource(long targetPos) throws UnsupportedOperationException {
|
public boolean seekToNewSource(long targetPos) throws UnsupportedOperationException {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setTrackedDecompressor(Decompressor decompressor) {
|
||||||
|
trackedDecompressor = decompressor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,13 @@ public abstract class CompressionOutputStream extends OutputStream {
|
||||||
* The output stream to be compressed.
|
* The output stream to be compressed.
|
||||||
*/
|
*/
|
||||||
protected final OutputStream out;
|
protected final OutputStream out;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If non-null, this is the Compressor object that we should call
|
||||||
|
* CodecPool#returnCompressor on when this stream is closed.
|
||||||
|
*/
|
||||||
|
private Compressor trackedCompressor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a compression output stream that writes
|
* Create a compression output stream that writes
|
||||||
* the compressed bytes to the given stream.
|
* the compressed bytes to the given stream.
|
||||||
|
@ -43,11 +49,19 @@ public abstract class CompressionOutputStream extends OutputStream {
|
||||||
protected CompressionOutputStream(OutputStream out) {
|
protected CompressionOutputStream(OutputStream out) {
|
||||||
this.out = out;
|
this.out = out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setTrackedCompressor(Compressor compressor) {
|
||||||
|
trackedCompressor = compressor;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
finish();
|
finish();
|
||||||
out.close();
|
out.close();
|
||||||
|
if (trackedCompressor != null) {
|
||||||
|
CodecPool.returnCompressor(trackedCompressor);
|
||||||
|
trackedCompressor = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -51,14 +51,8 @@ public class DefaultCodec implements Configurable, CompressionCodec, DirectDecom
|
||||||
@Override
|
@Override
|
||||||
public CompressionOutputStream createOutputStream(OutputStream out)
|
public CompressionOutputStream createOutputStream(OutputStream out)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
// This may leak memory if called in a loop. The createCompressor() call
|
return CompressionCodec.Util.
|
||||||
// may cause allocation of an untracked direct-backed buffer if native
|
createOutputStreamWithCodecPool(this, conf, out);
|
||||||
// libs are being used (even if you close the stream). A Compressor
|
|
||||||
// object should be reused between successive calls.
|
|
||||||
LOG.warn("DefaultCodec.createOutputStream() may leak memory. "
|
|
||||||
+ "Create a compressor first.");
|
|
||||||
return new CompressorStream(out, createCompressor(),
|
|
||||||
conf.getInt("io.file.buffer.size", 4*1024));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -82,8 +76,8 @@ public class DefaultCodec implements Configurable, CompressionCodec, DirectDecom
|
||||||
@Override
|
@Override
|
||||||
public CompressionInputStream createInputStream(InputStream in)
|
public CompressionInputStream createInputStream(InputStream in)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return new DecompressorStream(in, createDecompressor(),
|
return CompressionCodec.Util.
|
||||||
conf.getInt("io.file.buffer.size", 4*1024));
|
createInputStreamWithCodecPool(this, conf, in);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -159,10 +159,11 @@ public class GzipCodec extends DefaultCodec {
|
||||||
@Override
|
@Override
|
||||||
public CompressionOutputStream createOutputStream(OutputStream out)
|
public CompressionOutputStream createOutputStream(OutputStream out)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return (ZlibFactory.isNativeZlibLoaded(conf)) ?
|
if (!ZlibFactory.isNativeZlibLoaded(conf)) {
|
||||||
new CompressorStream(out, createCompressor(),
|
return new GzipOutputStream(out);
|
||||||
conf.getInt("io.file.buffer.size", 4*1024)) :
|
}
|
||||||
new GzipOutputStream(out);
|
return CompressionCodec.Util.
|
||||||
|
createOutputStreamWithCodecPool(this, conf, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -192,8 +193,9 @@ public class GzipCodec extends DefaultCodec {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompressionInputStream createInputStream(InputStream in)
|
public CompressionInputStream createInputStream(InputStream in)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return createInputStream(in, null);
|
return CompressionCodec.Util.
|
||||||
|
createInputStreamWithCodecPool(this, conf, in);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -84,7 +84,8 @@ public class Lz4Codec implements Configurable, CompressionCodec {
|
||||||
@Override
|
@Override
|
||||||
public CompressionOutputStream createOutputStream(OutputStream out)
|
public CompressionOutputStream createOutputStream(OutputStream out)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return createOutputStream(out, createCompressor());
|
return CompressionCodec.Util.
|
||||||
|
createOutputStreamWithCodecPool(this, conf, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -157,7 +158,8 @@ public class Lz4Codec implements Configurable, CompressionCodec {
|
||||||
@Override
|
@Override
|
||||||
public CompressionInputStream createInputStream(InputStream in)
|
public CompressionInputStream createInputStream(InputStream in)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return createInputStream(in, createDecompressor());
|
return CompressionCodec.Util.
|
||||||
|
createInputStreamWithCodecPool(this, conf, in);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -95,7 +95,8 @@ public class SnappyCodec implements Configurable, CompressionCodec, DirectDecomp
|
||||||
@Override
|
@Override
|
||||||
public CompressionOutputStream createOutputStream(OutputStream out)
|
public CompressionOutputStream createOutputStream(OutputStream out)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return createOutputStream(out, createCompressor());
|
return CompressionCodec.Util.
|
||||||
|
createOutputStreamWithCodecPool(this, conf, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -158,7 +159,8 @@ public class SnappyCodec implements Configurable, CompressionCodec, DirectDecomp
|
||||||
@Override
|
@Override
|
||||||
public CompressionInputStream createInputStream(InputStream in)
|
public CompressionInputStream createInputStream(InputStream in)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return createInputStream(in, createDecompressor());
|
return CompressionCodec.Util.
|
||||||
|
createInputStreamWithCodecPool(this, conf, in);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue