protected SelectBufferResult getMessageFromCache(FlatMessageFile flatFile, long offset) {
        MessageQueue mq = flatFile.getMessageQueue();
        SelectBufferResult buffer = this.fetcherCache.getIfPresent(
            String.format(CACHE_KEY_FORMAT, mq.getTopic(), mq.getQueueId(), offset));
        // return duplicate buffer here
        if (buffer == null) {
            return null;
        }
        long count = buffer.getAccessCount().incrementAndGet();
        if (count % 1000L == 0L) {
            log.warn("MessageFetcher fetch same offset message too many times, " +
                "topic={}, queueId={}, offset={}, count={}", mq.getTopic(), mq.getQueueId(), offset, count);
        }
        return new SelectBufferResult(
            buffer.getByteBuffer().asReadOnlyBuffer(), buffer.getStartOffset(), buffer.getSize(), buffer.getTagCode());
    }
@Test
    public void getMessageFromCacheTest() throws Exception {
        this.getMessageFromTieredStoreTest();
        mq = dispatcherTest.mq;
        messageStore = dispatcherTest.messageStore;
        storeConfig = dispatcherTest.storeConfig;

        storeConfig.setReadAheadCacheEnable(true);
        storeConfig.setReadAheadMessageCountThreshold(32);
        storeConfig.setReadAheadMessageSizeThreshold(Integer.MAX_VALUE);

        int batchSize = 4;
        AtomicLong times = new AtomicLong(0L);
        AtomicLong offset = new AtomicLong(100L);
        FlatMessageFile flatFile = dispatcherTest.fileStore.getFlatFile(mq);
        Awaitility.await().atMost(Duration.ofSeconds(10)).until(() -> {
            GetMessageResult getMessageResult =
                fetcher.getMessageFromCacheAsync(flatFile, groupName, offset.get(), batchSize, null).join();
            offset.set(getMessageResult.getNextBeginOffset());
            times.incrementAndGet();
            return offset.get() == 200L;
        });
        Assert.assertEquals(100 / times.get(), batchSize);
    }