code: @GuardedBy("lock")
      private CacheReadResultEntry createMemoryRead(ReadIndexEntry entry, long streamSegmentOffset, int maxLength, boolean updateStats) {
          assert streamSegmentOffset >= entry.getStreamSegmentOffset() : String.format("streamSegmentOffset{%d} < entry.getStreamSegmentOffset{%d}", streamSegmentOffset, entry.getStreamSegmentOffset());
  
          int entryOffset = (int) (streamSegmentOffset - entry.getStreamSegmentOffset());
  
          int length = (int) Math.min(maxLength, entry.getLength() - entryOffset);
          assert length > 0 : String.format("length{%d} <= 0. streamSegmentOffset = %d, maxLength = %d, entry.offset = %d, entry.length = %d", length, streamSegmentOffset, maxLength, entry.getStreamSegmentOffset(), entry.getLength());
          byte[] data = this.cache.get(getCacheKey(entry));
          assert data != null : String.format("No Cache Entry could be retrieved for entry %s", entry);
  
          if (updateStats) {
              // Update its generation before returning it.
              int generation = this.summary.touchOne(entry.getGeneration());
              entry.setGeneration(generation);
          }
  
          return new CacheReadResultEntry(entry.getStreamSegmentOffset(), data, entryOffset, length);
      }
docs: Creates a ReadResultEntry for data that is readily available in memory.
  
  @param entry               The CacheIndexEntry to use.
  @param streamSegmentOffset The Offset in the StreamSegment where to the ReadResultEntry starts at.
  @param maxLength           The maximum length of the Read, from the Offset of this ReadResultEntry.
  @param updateStats         If true, the entry's cache generation is updated as a result of this call.