Before Creating the Bug Report
Runtime platform environment
Linux
RocketMQ version
master branch, tieredstore module
JDK Version
JDK 8+
Describe the Bug
In IndexStoreService.queryAsync() (tieredstore/src/main/java/org/apache/rocketmq/tieredstore/index/IndexStoreService.java), the file selection logic uses:
ConcurrentNavigableMap<Long, IndexFile> pendingMap =
this.timeStoreTable.subMap(beginTime, true, endTime, true);
This is incorrect because timeStoreTable uses each IndexFile's begin time as its key. The subMap(beginTime, endTime) query only returns files whose begin time falls within [queryBeginTime, queryEndTime].
Two time intervals overlap if and only if:
file.beginTime <= query.endTime && file.endTime >= query.beginTime
The current code only checks whether file.beginTime is within the query range, which means any file whose beginTime is before queryBeginTime (but whose endTime still covers part or all of the query range) will be silently excluded.
Example:
File A: beginTime=1770792994354, endTime=1776162863167
Query: beginTime=1773804163000, endTime=1776109687001
subMap(1773804163000, true, 1776109687001, true) returns EMPTY
because File A's key (1770792994354) < query beginTime (1773804163000).
But File A fully covers the query range and SHOULD be queried.
Steps to Reproduce
- Enable tiered store and let
IndexStoreService accumulate multiple index files with different time ranges.
- Query index with a time range where
queryBeginTime is later than some file's beginTime but earlier than its endTime.
- The query returns empty or incomplete results because that file is excluded at the
subMap level, even though the file's time range overlaps with the query.
What Did You Expect to See?
The query should return all IndexItems from any IndexFile whose time range overlaps with the requested [beginTime, endTime].
What Did You See Instead?
Files whose beginTime is less than queryBeginTime are silently excluded, even if they fully contain the query range. This leads to missing or empty query results.
Additional Context
The fix should change the file selection logic to:
ConcurrentNavigableMap<Long, IndexFile> pendingMap =
this.timeStoreTable.headMap(endTime, true);
for (Map.Entry<Long, IndexFile> entry : pendingMap.descendingMap().entrySet()) {
if (entry.getValue().getEndTimestamp() < beginTime) {
break;
}
// queryAsync...
}
headMap(endTime, true) selects all files with beginTime <= queryEndTime.
- During descending iteration,
break early when file.endTime < queryBeginTime — since files are sorted by beginTime descending, all remaining older files will also fail this check, enabling early termination.
Before Creating the Bug Report
Runtime platform environment
Linux
RocketMQ version
master branch, tieredstore module
JDK Version
JDK 8+
Describe the Bug
In
IndexStoreService.queryAsync()(tieredstore/src/main/java/org/apache/rocketmq/tieredstore/index/IndexStoreService.java), the file selection logic uses:This is incorrect because
timeStoreTableuses eachIndexFile's begin time as its key. ThesubMap(beginTime, endTime)query only returns files whose begin time falls within[queryBeginTime, queryEndTime].Two time intervals overlap if and only if:
The current code only checks whether
file.beginTimeis within the query range, which means any file whosebeginTimeis beforequeryBeginTime(but whoseendTimestill covers part or all of the query range) will be silently excluded.Example:
Steps to Reproduce
IndexStoreServiceaccumulate multiple index files with different time ranges.queryBeginTimeis later than some file'sbeginTimebut earlier than itsendTime.subMaplevel, even though the file's time range overlaps with the query.What Did You Expect to See?
The query should return all
IndexItems from anyIndexFilewhose time range overlaps with the requested[beginTime, endTime].What Did You See Instead?
Files whose
beginTimeis less thanqueryBeginTimeare silently excluded, even if they fully contain the query range. This leads to missing or empty query results.Additional Context
The fix should change the file selection logic to:
headMap(endTime, true)selects all files withbeginTime <= queryEndTime.breakearly whenfile.endTime < queryBeginTime— since files are sorted bybeginTimedescending, all remaining older files will also fail this check, enabling early termination.