@Override
  public void readIndexStreams(OrcIndex index, StripeInformation stripe,
      List<OrcProto.Stream> streams, boolean[] physicalFileIncludes, boolean[] sargColumns)
          throws IOException {
    long stripeOffset = stripe.getOffset();
    DiskRangeList indexRanges = planIndexReading(fileSchema, streams, true, physicalFileIncludes,
        sargColumns, version, index.getBloomFilterKinds());
    if (indexRanges == null) {
      LOG.debug("Nothing to read for stripe [{}]", stripe);
      return;
    }
    ReadContext[] colCtxs = new ReadContext[physicalFileIncludes.length];
    int colRgIx = -1;
    for (int i = 0; i < physicalFileIncludes.length; ++i) {
      if (!physicalFileIncludes[i] && (sargColumns == null || !sargColumns[i])) continue;
      colCtxs[i] = new ReadContext(i, ++colRgIx);
      if (isTracingEnabled) {
        LOG.trace("Creating context: " + colCtxs[i].toString());
      }
      trace.logColumnRead(i, colRgIx, ColumnEncoding.Kind.DIRECT); // Bogus encoding.
    }
    long offset = 0;
    for (OrcProto.Stream stream : streams) {
      long length = stream.getLength();
      int colIx = stream.getColumn();
      OrcProto.Stream.Kind streamKind = stream.getKind();
      // See planIndexReading - only read non-row-index streams if involved in SARGs.
      if ((StreamName.getArea(streamKind) == StreamName.Area.INDEX)
          && ((sargColumns != null && sargColumns[colIx])
              || (physicalFileIncludes[colIx] && streamKind == Kind.ROW_INDEX))) {
        trace.logAddStream(colIx, streamKind, offset, length, -1, true);
        colCtxs[colIx].addStream(offset, stream, -1);
        if (isTracingEnabled) {
          LOG.trace("Adding stream for column " + colIx + ": "
              + streamKind + " at " + offset + ", " + length);
        }
      }
      offset += length;
    }

    boolean hasFileId = this.fileKey != null;

    // 2. Now, read all of the ranges from cache or disk.
    IdentityHashMap<ByteBuffer, Boolean> toRelease = new IdentityHashMap<>();
    MutateHelper toRead = getDataFromCacheAndDisk(indexRanges, stripeOffset, hasFileId, toRelease);

    // 3. For uncompressed case, we need some special processing before read.
    DiskRangeList iter = preReadUncompressedStreams(stripeOffset, colCtxs, toRead, toRelease);

    // 4. Decompress the data.
    boolean hasError = true;
    try {
      for (int colIx = 0; colIx < colCtxs.length; ++colIx) {
        ReadContext ctx = colCtxs[colIx];
        if (ctx == null) continue; // This column is not included.
        for (int streamIx = 0; streamIx < ctx.streamCount; ++streamIx) {
          StreamContext sctx = ctx.streams[streamIx];
          try {
            if (isTracingEnabled) {
              LOG.trace("Getting index stream " + sctx.kind + " for column " + ctx.colIx
                  + " at " + sctx.offset + ", " + sctx.length);
            }
            ColumnStreamData csd = POOLS.csdPool.take();
            long endCOffset = sctx.offset + sctx.length;
            DiskRangeList lastCached = readEncodedStream(stripeOffset, iter, sctx.offset,
                endCOffset, csd, endCOffset, sctx.offset, toRelease);
            if (lastCached != null) {
              iter = lastCached;
            }
            if (isTracingEnabled) {
              traceLogBuffersUsedToParse(csd);
            }
            CodedInputStream cis = CodedInputStream.newInstance(
                new IndexStream(csd.getCacheBuffers(), sctx.length));
            cis.setSizeLimit(InStream.PROTOBUF_MESSAGE_MAX_LIMIT);
            switch (sctx.kind) {
              case ROW_INDEX:
                OrcProto.RowIndex tmp = index.getRowGroupIndex()[colIx]
                    = OrcProto.RowIndex.parseFrom(cis);
                if (isTracingEnabled) {
                  LOG.trace("Index is " + tmp.toString().replace('\n', ' '));
                }
                break;
              case BLOOM_FILTER:
              case BLOOM_FILTER_UTF8:
                index.getBloomFilterIndex()[colIx] = OrcProto.BloomFilterIndex.parseFrom(cis);
                break;
              default:
                throw new AssertionError("Unexpected index stream type " + sctx.kind);
            }
            // We are done with the buffers; unlike data blocks, we are also the consumer. Release.
            for (MemoryBuffer buf : csd.getCacheBuffers()) {
              if (buf == null) continue;
              cacheWrapper.releaseBuffer(buf);
            }
          } catch (Exception ex) {
            DiskRangeList drl = toRead == null ? null : toRead.next;
            LOG.error("Error getting stream " + sctx.kind + " for column " + ctx.colIx
                + " at " + sctx.offset + ", " + sctx.length + "; toRead "
                + RecordReaderUtils.stringifyDiskRanges(drl), ex);
            throw (ex instanceof IOException) ? (IOException)ex : new IOException(ex);
          }
        }
      }

      if (isTracingEnabled) {
        LOG.trace("Disk ranges after preparing all the data "
            + RecordReaderUtils.stringifyDiskRanges(toRead.next));
      }
      hasError = false;
    } finally {
      // Release the unreleased buffers. See class comment about refcounts.
      try {
        if (toRead != null) {
          releaseInitialRefcounts(toRead.next);
        }
        releaseBuffers(toRelease.keySet(), true);
      } catch (Throwable t) {
        if (!hasError) throw new IOException(t);
        LOG.error("Error during the cleanup after another error; ignoring", t);
      }
    }
  }
Pool factory that is used if another one isn't specified - just creates the objects.
ql/src/java/org/apache/hadoop/hive/ql/io/orc/encoded/EncodedReaderImpl.java