private void mergeStripeInfos(StripeData to, StripeData from) {
    if (LlapIoImpl.CACHE_LOGGER.isTraceEnabled()) {
      LlapIoImpl.CACHE_LOGGER.trace("Merging slices data: old " + to + " and new " + from);
    }
    to.knownTornStart = Math.min(to.knownTornStart, from.knownTornStart);
    if (from.encodings.length != to.encodings.length) {
      throw new RuntimeException("Different encodings " + from + "; " + to);
    }
    for (int colIx = 0; colIx < from.encodings.length; ++colIx) {
      if (to.encodings[colIx] == null) {
        to.encodings[colIx] = from.encodings[colIx];
      } else if (from.encodings[colIx] != null
          && !to.encodings[colIx].equals(from.encodings[colIx])) {
        throw new RuntimeException("Different encodings at " + colIx + ": " + from + "; " + to);
      }
      LlapSerDeDataBuffer[][] fromColData = from.data[colIx];
      if (fromColData != null) {
        if (to.data[colIx] != null) {
          // Note: we assume here that the data that was returned to the caller from cache will not
          // be passed back in via put. Right now it's safe since we don't do anything. But if we
          // evict proactively, we will have to compare objects all the way down.
          handleRemovedColumnData(to.data[colIx]);
        }
        to.data[colIx] = fromColData;
      }
    } 
  }
RW lock ensures we have a consistent view of the file data, which is important given that
we generate "stripe" boundaries arbitrarily. Reading buffer data itself doesn't require
that this lock is held; however, everything else in stripes list does.
TODO: make more granular? We only care that each one reader sees consistent boundaries.
      So, we could shallow-copy the stripes list, then have individual locks inside each.
llap-server/src/java/org/apache/hadoop/hive/llap/cache/SerDeLowLevelCacheImpl.java