private void setStreamOptions(FSDataInputStream in) {
    try {
      in.setDropBehind(dropBehind);
    } catch (Exception e) {
      // Skipped.
    }
    if (readahead >= 0) {
      try {
        in.setReadahead(readahead);
      } catch (Exception e) {
        // Skipped.
      }
    }
  }
Two stream handles, one with and one without FS-level checksum. HDFS checksum setting is on FS
level, not single read level, so you have to keep two FS objects and two handles open to
interleave different reads freely, which is very sad. This is what we do: 1) First, we need to
read the trailer of HFile to determine checksum parameters. We always use FS checksum to do
that, so ctor opens {@link #stream}. 2.1) After that, if HBase checksum is not used, we'd just
always use {@link #stream}; 2.2) If HBase checksum can be used, we'll open
{@link #streamNoFsChecksum}, and close {@link #stream}. User MUST call prepareForBlockReader
for that to happen; if they don't, (2.1) will be the default. 3) The users can call
{@link #shouldUseHBaseChecksum()}, and pass its result to {@link #getStream(boolean)} to get
stream (if Java had out/pointer params we could return both in one call). This stream is
guaranteed to be set. 4) The first time HBase checksum fails, one would call
{@link #fallbackToFsChecksum(int)}. That will take lock, and open {@link #stream}. While this
is going on, others will continue to use the old stream; if they also want to fall back,
they'll also call {@link #fallbackToFsChecksum(int)}, and block until {@link #stream} is set.
5) After some number of checksumOk() calls, we will go back to using HBase checksum. We will
have 2 handles; however we presume checksums fail so rarely that we don't care.
hbase-server/src/main/java/org/apache/hadoop/hbase/io/FSDataInputStreamWrapper.java