Index: hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/HFileBlock.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/HFileBlock.java (revision 1420533) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/HFileBlock.java (working copy) @@ -28,6 +28,8 @@ import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.fs.FSDataInputStream; @@ -1143,6 +1145,8 @@ /** The path (if any) where this data is coming from */ protected Path path; + private final Lock streamLock = new ReentrantLock(); + /** The default buffer size for our buffered streams */ public static final int DEFAULT_BUFFER_SIZE = 1 << 20; @@ -1217,23 +1221,9 @@ "-byte array at offset " + destOffset); } - if (pread) { - // Positional read. Better for random reads. - 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. - return -1; - } - } else { + if (!pread && streamLock.tryLock()) { // Seek + read. Better for scanning. - synchronized (istream) { + try { istream.seek(fileOffset); long realOffset = istream.getPos(); @@ -1251,7 +1241,23 @@ // Try to read the next block header. if (!readWithExtra(istream, dest, destOffset, size, hdrSize)) return -1; + } finally { + streamLock.unlock(); } + } 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. + return -1; + } } assert peekIntoNextBlock;