diff --git a/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt b/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt index ef2a5b80fb4..f3b97df0fa7 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt +++ b/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt @@ -329,6 +329,9 @@ Release 2.7.0 - UNRELEASED HDFS-7684. The host:port settings of the daemons should be trimmed before use. (Anu Engineer via aajisaka) + HDFS-7790. Do not create optional fields in DFSInputStream unless they are + needed (cmccabe) + OPTIMIZATIONS HDFS-7454. Reduce memory footprint for AclEntries in NameNode. diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/DFSInputStream.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/DFSInputStream.java index 25c23e13dd6..09d65135884 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/DFSInputStream.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/DFSInputStream.java @@ -127,8 +127,15 @@ public class DFSInputStream extends FSInputStream * The value type can be either ByteBufferPool or ClientMmap, depending on * whether we this is a memory-mapped buffer or not. */ - private final IdentityHashStore + private IdentityHashStore extendedReadBuffers; + + private synchronized IdentityHashStore + getExtendedReadBuffers() { + if (extendedReadBuffers == null) { extendedReadBuffers = new IdentityHashStore(0); + } + return extendedReadBuffers; + } public static class ReadStatistics { public ReadStatistics() { @@ -236,7 +243,7 @@ void clear() { private final ConcurrentHashMap deadNodes = new ConcurrentHashMap(); - private final byte[] oneByteBuf = new byte[1]; // used for 'int read()' + private byte[] oneByteBuf; // used for 'int read()' void addToDeadNodes(DatanodeInfo dnInfo) { deadNodes.put(dnInfo, dnInfo); @@ -670,7 +677,7 @@ public synchronized void close() throws IOException { } dfsClient.checkOpen(); - if (!extendedReadBuffers.isEmpty()) { + if ((extendedReadBuffers != null) && (!extendedReadBuffers.isEmpty())) { final StringBuilder builder = new StringBuilder(); extendedReadBuffers.visitAll(new IdentityHashStore.Visitor() { private String prefix = ""; @@ -690,6 +697,9 @@ public void accept(ByteBuffer k, Object v) { @Override public synchronized int read() throws IOException { + if (oneByteBuf == null) { + oneByteBuf = new byte[1]; + } int ret = read( oneByteBuf, 0, 1 ); return ( ret <= 0 ) ? -1 : (oneByteBuf[0] & 0xff); } @@ -1708,7 +1718,7 @@ public synchronized ByteBuffer read(ByteBufferPool bufferPool, } buffer = ByteBufferUtil.fallbackRead(this, bufferPool, maxLength); if (buffer != null) { - extendedReadBuffers.put(buffer, bufferPool); + getExtendedReadBuffers().put(buffer, bufferPool); } return buffer; } @@ -1787,7 +1797,7 @@ private synchronized ByteBuffer tryReadZeroCopy(int maxLength, buffer = clientMmap.getMappedByteBuffer().asReadOnlyBuffer(); buffer.position((int)blockPos); buffer.limit((int)(blockPos + length)); - extendedReadBuffers.put(buffer, clientMmap); + getExtendedReadBuffers().put(buffer, clientMmap); synchronized (infoLock) { readStatistics.addZeroCopyBytes(length); } @@ -1808,7 +1818,7 @@ private synchronized ByteBuffer tryReadZeroCopy(int maxLength, @Override public synchronized void releaseBuffer(ByteBuffer buffer) { if (buffer == EMPTY_BUFFER) return; - Object val = extendedReadBuffers.remove(buffer); + Object val = getExtendedReadBuffers().remove(buffer); if (val == null) { throw new IllegalArgumentException("tried to release a buffer " + "that was not created by this stream, " + buffer);