private DiskRangeList.MutateHelper getDataFromCacheAndDisk(DiskRangeList listToRead,
      long stripeOffset, boolean hasFileId, IdentityHashMap<ByteBuffer, Boolean> toRelease)
          throws IOException {
    DiskRangeList.MutateHelper toRead = new DiskRangeList.MutateHelper(listToRead);
    if (LOG.isDebugEnabled()) {
      LOG.debug("Resulting disk ranges to read (file " + fileKey + "): "
          + RecordReaderUtils.stringifyDiskRanges(toRead.next));
    }
    BooleanRef isAllInCache = new BooleanRef();
    if (hasFileId) {
      cacheWrapper.getFileData(fileKey, toRead.next, stripeOffset, CC_FACTORY, isAllInCache);
      if (!isAllInCache.value) {
        throwIfCacheOnlyRead(isReadCacheOnly);
      }
      if (LOG.isDebugEnabled()) {
        LOG.debug("Disk ranges after cache (found everything " + isAllInCache.value + "; file "
            + fileKey + ", base offset " + stripeOffset  + "): "
            + RecordReaderUtils.stringifyDiskRanges(toRead.next));
      }
      trace.logRanges(fileKey, stripeOffset, toRead.next, RangesSrc.CACHE);
    }

    // TODO: the memory release could be optimized - we could release original buffers after we
    //       are fully done with each original buffer from disk. For now release all at the end;
    //       it doesn't increase the total amount of memory we hold, just the duration a bit.
    //       This is much simpler - we can just remember original ranges after reading them, and
    //       release them at the end. In a few cases where it's easy to determine that a buffer
    //       can be freed in advance, we remove it from the map.
    if (!isAllInCache.value) {
      boolean hasError = true;
      try {
        if (!isDataReaderOpen) {
          this.dataReader.open();
          isDataReaderOpen = true;
        }
        dataReader.readFileData(toRead.next, stripeOffset,
            cacheWrapper.getAllocator().isDirectAlloc());
        DiskRangeList drl = toRead.next;
        while (drl != null) {
          if (drl instanceof BufferChunk) {
            toRelease.put(drl.getData(), true);
          }
          drl = drl.next;
        }
        hasError = false;
      } finally {
        // The FS can be closed from under us if the task is interrupted. Release cache buffers.
        // We are assuming here that toRelease will not be present in such cases.
        if (hasError) {
          releaseInitialRefcounts(toRead.next);
        }
      }
    }
    return toRead;
  }
Estimate the RowGroup offset given the next RG offset and isLast.

@param isCompressed is the RowGroup compressed
@param isLast is this the last RowGroup
@param nextGroupOffset the offset of the next RowGroup
@param streamLength the length of the whole Stream
@param bufferSize the size of the buffer
@return
ql/src/java/org/apache/hadoop/hive/ql/io/orc/encoded/EncodedReaderImpl.java