private OrcProto.StripeFooter getStripeFooterFromCacheOrDisk(
      StripeInformation si, OrcBatchKey stripeKey) throws IOException {
    boolean hasCache = fileKey != null && metadataCache != null;
    if (hasCache) {
      LlapBufferOrBuffers footerBuffers = metadataCache.getStripeTail(stripeKey);
      if (footerBuffers != null) {
        try {
          counters.incrCounter(LlapIOCounters.METADATA_CACHE_HIT);
          ensureCodecFromFileMetadata();
          MemoryBuffer footerBuffer = footerBuffers.getSingleBuffer();
          if (footerBuffer != null) {
            ByteBuffer bb = footerBuffer.getByteBufferDup();
            return buildStripeFooter(new BufferChunk(bb, 0),
                bb.remaining(), codec, fileMetadata.getCompressionBufferSize());
          } else {
            MemoryBuffer[] footerBufferArray = footerBuffers.getMultipleBuffers();
            int pos = 0;
            BufferChunkList bcs = new BufferChunkList();
            for (MemoryBuffer buf : footerBufferArray) {
              ByteBuffer bb = buf.getByteBufferDup();
              bcs.add(new BufferChunk(bb, pos));
              pos += bb.remaining();
            }
            return buildStripeFooter(bcs.get(), pos, codec, fileMetadata.getCompressionBufferSize());
          }
        } finally {
          metadataCache.decRefBuffer(footerBuffers);
        }
      }
      counters.incrCounter(LlapIOCounters.METADATA_CACHE_MISS);
      throwIfCacheOnlyRead(isReadCacheOnly);
    }
    long offset = si.getOffset() + si.getIndexLength() + si.getDataLength();
    long startTime = counters.startTimeCounter();
    ensureRawDataReader(true);
    // TODO: add this to metadatareader in ORC - SI => metadata buffer, not just metadata.
    if (LOG.isTraceEnabled()) {
      LOG.trace("Reading [" + offset + ", "
          + (offset + si.getFooterLength()) + ") based on " + si);
    }
    DiskRangeList footerRange = rawDataReader.readFileData(
        new DiskRangeList(offset, offset + si.getFooterLength()), 0, false);
    // LOG.error("Got " + RecordReaderUtils.stringifyDiskRanges(footerRange));
    counters.incrWallClockCounter(LlapIOCounters.HDFS_TIME_NS, startTime);
    assert footerRange.next == null; // Can only happens w/zcr for a single input buffer.
    if (hasCache) {
      LlapBufferOrBuffers cacheBuf = metadataCache.putStripeTail(
          stripeKey, footerRange.getData().duplicate(), cacheTag, isStopped);
      metadataCache.decRefBuffer(cacheBuf); // We don't use this one.
    }
    ByteBuffer bb = footerRange.getData().duplicate();

    CompressionKind kind = orcReader.getCompressionKind();
    boolean isPool = useCodecPool;
    CompressionCodec codec = isPool ? OrcCodecPool.getCodec(kind) : WriterImpl.createCodec(kind);
    boolean isCodecError = true;
    try {
      OrcProto.StripeFooter result = buildStripeFooter(new BufferChunk(bb, 0), bb.remaining(), codec,
          orcReader.getCompressionSize());
      isCodecError = false;
      return result;
    } finally {
      try {
        if (codec != null) {
          if (isPool && !isCodecError) {
            OrcCodecPool.returnCodec(kind, codec);
          } else {
            codec.close();
          }
        }
      } catch (Exception ex) {
        LOG.error("Ignoring codec cleanup error", ex);
      }
    }
  }
Reads the metadata for all stripes in the file.
llap-server/src/java/org/apache/hadoop/hive/llap/io/encoded/OrcEncodedDataReader.java