@VisibleForTesting
    void readCacheAt(long offset)
            throws IOException
    {
        DiskRange newCacheRange = regionFinder.getRangeFor(offset);
        cachePosition = newCacheRange.getOffset();
        cacheLength = newCacheRange.getLength();
        if (cache.length < cacheLength) {
            cache = new byte[cacheLength];
            systemMemoryContext.setBytes(cacheLength);
        }
        dataSource.readFully(newCacheRange.getOffset(), cache, 0, cacheLength);
    }
@Test
    public void testTinyStripesReadCacheAt()
            throws IOException
    {
        DataSize maxMergeDistance = new DataSize(1, Unit.MEGABYTE);
        DataSize tinyStripeThreshold = new DataSize(8, Unit.MEGABYTE);

        OrcAggregatedMemoryContext systemMemoryContext = new TestingHiveOrcAggregatedMemoryContext();

        TestingOrcDataSource testingOrcDataSource = new TestingOrcDataSource(NoopOrcDataSource.INSTANCE);
        CachingOrcDataSource cachingOrcDataSource = new CachingOrcDataSource(
                testingOrcDataSource,
                createTinyStripesRangeFinder(
                        ImmutableList.of(
                                new StripeInformation(123, 3, 10, 10, 10, OptionalLong.empty(), ImmutableList.of()),
                                new StripeInformation(123, 33, 10, 10, 10, OptionalLong.empty(), ImmutableList.of()),
                                new StripeInformation(123, 63, 1048576 * 8 - 20, 10, 10, OptionalLong.empty(), ImmutableList.of())),
                        maxMergeDistance,
                        tinyStripeThreshold),
                systemMemoryContext.newOrcLocalMemoryContext(CachingOrcDataSource.class.getSimpleName()));
        cachingOrcDataSource.readCacheAt(3);
        assertEquals(testingOrcDataSource.getLastReadRanges(), ImmutableList.of(new DiskRange(3, 60)));
        cachingOrcDataSource.readCacheAt(63);
        // The allocated cache size is the length of the merged disk range 1048576 * 8.
        assertEquals(systemMemoryContext.getBytes(), 8 * 1048576);
        assertEquals(testingOrcDataSource.getLastReadRanges(), ImmutableList.of(new DiskRange(63, 8 * 1048576)));

        testingOrcDataSource = new TestingOrcDataSource(NoopOrcDataSource.INSTANCE);
        cachingOrcDataSource = new CachingOrcDataSource(
                testingOrcDataSource,
                createTinyStripesRangeFinder(
                        ImmutableList.of(
                                new StripeInformation(123, 3, 10, 10, 10, OptionalLong.empty(), ImmutableList.of()),
                                new StripeInformation(123, 33, 10, 10, 10, OptionalLong.empty(), ImmutableList.of()),
                                new StripeInformation(123, 63, 1048576 * 8 - 20, 10, 10, OptionalLong.empty(), ImmutableList.of())),
                        maxMergeDistance,
                        tinyStripeThreshold),
                systemMemoryContext.newOrcLocalMemoryContext(CachingOrcDataSource.class.getSimpleName()));
        cachingOrcDataSource.readCacheAt(62); // read at the end of a stripe
        assertEquals(testingOrcDataSource.getLastReadRanges(), ImmutableList.of(new DiskRange(3, 60)));
        cachingOrcDataSource.readCacheAt(63);
        // The newly allocated cache size is the length of the merged disk range 1048576 * 8 so the total size is 8 * 1048576 * 2.
        assertEquals(systemMemoryContext.getBytes(), 8 * 1048576 * 2);
        assertEquals(testingOrcDataSource.getLastReadRanges(), ImmutableList.of(new DiskRange(63, 8 * 1048576)));

        testingOrcDataSource = new TestingOrcDataSource(NoopOrcDataSource.INSTANCE);
        cachingOrcDataSource = new CachingOrcDataSource(
                testingOrcDataSource,
                createTinyStripesRangeFinder(
                        ImmutableList.of(
                                new StripeInformation(123, 3, 1, 1, 1, OptionalLong.empty(), ImmutableList.of()),
                                new StripeInformation(123, 4, 1048576, 1048576, 1048576 * 3, OptionalLong.empty(), ImmutableList.of()),
                                new StripeInformation(123, 4 + 1048576 * 5, 1048576, 1048576, 1048576, OptionalLong.empty(), ImmutableList.of())),
                        maxMergeDistance,
                        tinyStripeThreshold),
                systemMemoryContext.newOrcLocalMemoryContext(CachingOrcDataSource.class.getSimpleName()));
        cachingOrcDataSource.readCacheAt(3);
        assertEquals(testingOrcDataSource.getLastReadRanges(), ImmutableList.of(new DiskRange(3, 1 + 1048576 * 5)));
        cachingOrcDataSource.readCacheAt(4 + 1048576 * 5);
        // The newly allocated cache size is the length of the first merged disk range 1048576 * 5 + 1.
        assertEquals(systemMemoryContext.getBytes(), 8 * 1048576 * 2 + 1048576 * 5 + 1);
        assertEquals(testingOrcDataSource.getLastReadRanges(), ImmutableList.of(new DiskRange(4 + 1048576 * 5, 3 * 1048576)));
    }