protected CompletableFuture<List<IndexItem>> queryAsyncFromSegmentFile(
        String key, int maxCount, long beginTime, long endTime) {

        if (this.fileSegment == null || !UPLOAD.equals(this.fileStatus.get())) {
            return CompletableFuture.completedFuture(Collections.emptyList());
        }

        Stopwatch stopwatch = Stopwatch.createStarted();
        int hashCode = this.hashCode(key);
        int slotPosition = this.getSlotPosition(hashCode % this.hashSlotMaxCount);

        CompletableFuture<List<IndexItem>> future = this.fileSegment.readAsync(slotPosition, HASH_SLOT_SIZE)
            .thenCompose(slotBuffer -> {
                if (slotBuffer.remaining() < HASH_SLOT_SIZE) {
                    log.error("IndexStoreFile query from tiered storage return error slot buffer, " +
                        "key: {}, maxCount: {}, timestamp={}-{}", key, maxCount, beginTime, endTime);
                    return CompletableFuture.completedFuture(null);
                }
                int indexPosition = slotBuffer.getInt();
                int indexTotalSize = Math.min(slotBuffer.getInt(), COMPACT_INDEX_ITEM_SIZE * 1024);
                if (indexPosition <= INVALID_INDEX || indexTotalSize <= 0) {
                    return CompletableFuture.completedFuture(null);
                }
                return this.fileSegment.readAsync(indexPosition, indexTotalSize);
            })
            .thenApply(itemBuffer -> {
                List<IndexItem> result = new ArrayList<>();
                if (itemBuffer == null) {
                    return result;
                }

                if (itemBuffer.remaining() % COMPACT_INDEX_ITEM_SIZE != 0) {
                    log.error("IndexStoreFile query from tiered storage return error item buffer, " +
                        "key: {}, maxCount: {}, timestamp={}-{}", key, maxCount, beginTime, endTime);
                    return result;
                }

                int size = itemBuffer.remaining() / COMPACT_INDEX_ITEM_SIZE;
                byte[] bytes = new byte[COMPACT_INDEX_ITEM_SIZE];
                for (int i = 0; i < size; i++) {
                    itemBuffer.get(bytes);
                    IndexItem indexItem = new IndexItem(bytes);
                    long storeTimestamp = indexItem.getTimeDiff() + beginTimestamp.get();
                    if (hashCode == indexItem.getHashCode() &&
                        beginTime <= storeTimestamp && storeTimestamp <= endTime &&
                        result.size() < maxCount) {
                        result.add(indexItem);
                    }
                }
                return result;
            });

        return future.whenComplete((result, throwable) -> {
            long costTime = stopwatch.elapsed(TimeUnit.MILLISECONDS);
            if (throwable != null) {
                log.error("IndexStoreFile query from segment file, cost: {}ms, timestamp: {}, " +
                        "key: {}, hashCode: {}, maxCount: {}, timestamp={}-{}",
                    costTime, getTimestamp(), key, hashCode, maxCount, beginTime, endTime, throwable);
            } else {
                String details = Optional.ofNullable(result)
                    .map(r -> r.stream()
                        .map(item -> String.format("%d-%d", item.getQueueId(), item.getOffset()))
                        .collect(Collectors.joining(", ")))
                    .orElse("");

                log.debug("IndexStoreFile query from segment file, cost: {}ms, timestamp: {}, result size: {}, ({}), " +
                        "key: {}, hashCode: {}, maxCount: {}, timestamp={}-{}",
                    costTime, getTimestamp(), result != null ? result.size() : 0, details, key, hashCode, maxCount, beginTime, endTime);
            }
        });
    }
@Test
    public void queryAsyncFromSegmentFileTest() throws ExecutionException, InterruptedException {
        long timestamp = indexStoreFile.getTimestamp();
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 3; j++) {
                Assert.assertEquals(AppendResult.SUCCESS, indexStoreFile.putKey(TOPIC_NAME + i,
                    TOPIC_ID, QUEUE_ID, KEY_SET, MESSAGE_OFFSET, MESSAGE_SIZE, System.currentTimeMillis()));
            }
        }

        ByteBuffer byteBuffer = indexStoreFile.doCompaction();
        FileSegment fileSegment = new PosixFileSegment(
            storeConfig, FileSegmentType.INDEX, filePath, 0L);
        fileSegment.append(byteBuffer, timestamp);
        fileSegment.commitAsync().join();
        Assert.assertEquals(byteBuffer.limit(), fileSegment.getSize());
        indexStoreFile.destroy();

        indexStoreFile = new IndexStoreFile(storeConfig, fileSegment);

        // change topic
        List<IndexItem> itemList = indexStoreFile.queryAsync(
            TOPIC_NAME, KEY, 64, timestamp, System.currentTimeMillis()).get();
        Assert.assertEquals(0, itemList.size());

        // change key
        itemList = indexStoreFile.queryAsync(
            TOPIC_NAME, KEY + "1", 64, timestamp, System.currentTimeMillis()).get();
        Assert.assertEquals(0, itemList.size());

        itemList = indexStoreFile.queryAsync(
            TOPIC_NAME + "1", KEY, 64, timestamp, System.currentTimeMillis()).get();
        Assert.assertEquals(3, itemList.size());
    }