diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/HFileBlock.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/HFileBlock.java index 7104267..21644fd 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/HFileBlock.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/HFileBlock.java @@ -721,6 +721,48 @@ public class HFileBlock implements Cacheable { } /** + * Read from an input stream. Analogous to + * {@link IOUtils#readFully(InputStream, byte[], int, int)}, but uses + * positional read and specifies a number of "extra" bytes that would be + * desirable but not absolutely necessary to read. + * + * @param in the input stream to read from + * @param position the position within the stream from which to start reading + * @param buf the buffer to read into + * @param bufOffset the destination offset in the buffer + * @param necessaryLen the number of bytes that are absolutely necessary to + * read + * @param extraLen the number of extra bytes that would be nice to read + * @return true if succeeded reading the extra bytes + * @throws IOException if failed to read the necessary bytes + */ + private static boolean positionalReadWithExtra(FSDataInputStream in, + long position, byte[] buf, int bufOffset, int necessaryLen, int extraLen) + throws IOException { + int bytesRemaining = necessaryLen + extraLen; + int bytesRead = 0; + while (bytesRemaining > 0) { + int ret = in.read(position, buf, bufOffset, bytesRemaining); + if (ret == -1 && bytesRemaining <= extraLen) { + // We could not read the "extra data", but that is OK. + break; + } + + if (ret < 0) { + throw new IOException("Premature EOF from inputStream (positional read " + + "returned " + ret + ", was trying to read " + necessaryLen + + " necessary bytes and " + extraLen + " extra bytes, " + + "successfully read " + bytesRead); + } + position += ret; + bufOffset += ret; + bytesRemaining -= ret; + bytesRead += ret; + } + return bytesRead != necessaryLen && bytesRemaining <= 0; + } + + /** * @return the on-disk size of the next block (including the header size) * that was read by peeking into the next block's header */ @@ -1443,14 +1485,8 @@ public class HFileBlock implements Cacheable { } else { // Positional read. Better for random reads; or when the streamLock is already locked. int extraSize = peekIntoNextBlock ? hdrSize : 0; - int ret = istream.read(fileOffset, dest, destOffset, size + extraSize); - if (ret < size) { - throw new IOException("Positional read of " + size + " bytes " + - "failed at offset " + fileOffset + " (returned " + ret + ")"); - } - - if (ret == size || ret < size + extraSize) { - // Could not read the next block's header, or did not try. + if (!positionalReadWithExtra(istream, fileOffset, dest, destOffset, + size, extraSize)) { return -1; } }