private void fetchBlockByteRange(
      LocatedBlock block,
      long start,
      long end,
      byte[] buf,
      int offset,
      Map<ExtendedBlock, Set<DatanodeInfo>> corruptedBlockMap)
      throws IOException {
    //
    // Connect to best DataNode for desired Block, with potential offset
    //
    int refetchToken = 1; // only need to get a new access token once

    while (true) {
      // cached block locations may have been updated by chooseDataNode()
      // or fetchBlockAt(). Always get the latest list of locations at the
      // start of the loop.
      block = getBlockAt(block.getStartOffset(), false);
      DNAddrPair retval = chooseDataNode(block);
      DatanodeInfo chosenNode = retval.info;
      InetSocketAddress targetAddr = retval.addr;
      BlockReader reader = null;

      try {
        Token<BlockTokenIdentifier> blockToken = block.getBlockToken();

        int len = (int) (end - start + 1);
        reader =
            getBlockReader(
                targetAddr,
                chosenNode,
                src,
                block.getBlock(),
                blockToken,
                start,
                len,
                buffersize,
                verifyChecksum,
                dfsClient.clientName);
        int nread = reader.readAll(buf, offset, len);
        if (nread != len) {
          throw new IOException(
              "truncated return from reader.read(): " + "excpected " + len + ", got " + nread);
        }
        return;
      } catch (ChecksumException e) {
        DFSClient.LOG.warn(
            "fetchBlockByteRange(). Got a checksum exception for "
                + src
                + " at "
                + block.getBlock()
                + ":"
                + e.getPos()
                + " from "
                + chosenNode);
        // we want to remember what we have tried
        addIntoCorruptedBlockMap(block.getBlock(), chosenNode, corruptedBlockMap);
      } catch (AccessControlException ex) {
        DFSClient.LOG.warn("Short circuit access failed ", ex);
        dfsClient.disableShortCircuit();
        continue;
      } catch (IOException e) {
        if (e instanceof InvalidBlockTokenException && refetchToken > 0) {
          DFSClient.LOG.info(
              "Will get a new access token and retry, "
                  + "access token was invalid when connecting to "
                  + targetAddr
                  + " : "
                  + e);
          refetchToken--;
          fetchBlockAt(block.getStartOffset());
          continue;
        } else {
          DFSClient.LOG.warn(
              "Failed to connect to "
                  + targetAddr
                  + " for file "
                  + src
                  + " for block "
                  + block.getBlock()
                  + ":"
                  + e);
          if (DFSClient.LOG.isDebugEnabled()) {
            DFSClient.LOG.debug("Connection failure ", e);
          }
        }
      } finally {
        if (reader != null) {
          closeBlockReader(reader);
        }
      }
      // Put chosen node into dead list, continue
      addToDeadNodes(chosenNode);
    }
  }
  /**
   * Open a DataInputStream to a DataNode so that it can be read from. We get block ID and the IDs
   * of the destinations at startup, from the namenode.
   */
  private synchronized DatanodeInfo blockSeekTo(long target) throws IOException {
    if (target >= getFileLength()) {
      throw new IOException("Attempted to read past end of file");
    }

    // Will be getting a new BlockReader.
    if (blockReader != null) {
      closeBlockReader(blockReader);
      blockReader = null;
    }

    //
    // Connect to best DataNode for desired Block, with potential offset
    //
    DatanodeInfo chosenNode = null;
    int refetchToken = 1; // only need to get a new access token once

    boolean connectFailedOnce = false;

    while (true) {
      //
      // Compute desired block
      //
      LocatedBlock targetBlock = getBlockAt(target, true);
      assert (target == pos) : "Wrong postion " + pos + " expect " + target;
      long offsetIntoBlock = target - targetBlock.getStartOffset();

      DNAddrPair retval = chooseDataNode(targetBlock);
      chosenNode = retval.info;
      InetSocketAddress targetAddr = retval.addr;

      try {
        ExtendedBlock blk = targetBlock.getBlock();
        Token<BlockTokenIdentifier> accessToken = targetBlock.getBlockToken();
        blockReader =
            getBlockReader(
                targetAddr,
                chosenNode,
                src,
                blk,
                accessToken,
                offsetIntoBlock,
                blk.getNumBytes() - offsetIntoBlock,
                buffersize,
                verifyChecksum,
                dfsClient.clientName);
        if (connectFailedOnce) {
          DFSClient.LOG.info(
              "Successfully connected to " + targetAddr + " for block " + blk.getBlockId());
        }
        return chosenNode;
      } catch (IOException ex) {
        if (ex instanceof InvalidBlockTokenException && refetchToken > 0) {
          DFSClient.LOG.info(
              "Will fetch a new access token and retry, "
                  + "access token was invalid when connecting to "
                  + targetAddr
                  + " : "
                  + ex);
          /*
           * Get a new access token and retry. Retry is needed in 2 cases. 1)
           * When both NN and DN re-started while DFSClient holding a cached
           * access token. 2) In the case that NN fails to update its
           * access key at pre-set interval (by a wide margin) and
           * subsequently restarts. In this case, DN re-registers itself with
           * NN and receives a new access key, but DN will delete the old
           * access key from its memory since it's considered expired based on
           * the estimated expiration date.
           */
          refetchToken--;
          fetchBlockAt(target);
        } else {
          connectFailedOnce = true;
          DFSClient.LOG.warn(
              "Failed to connect to "
                  + targetAddr
                  + " for block"
                  + ", add to deadNodes and continue. "
                  + ex,
              ex);
          // Put chosen node into dead list, continue
          addToDeadNodes(chosenNode);
        }
      }
    }
  }