Skip to content

Fix descending fetch gap-range bounds and tail-mark#155

Closed
afrind wants to merge 3 commits into
facebookexperimental:mainfrom
afrind:export-D103210059
Closed

Fix descending fetch gap-range bounds and tail-mark#155
afrind wants to merge 3 commits into
facebookexperimental:mainfrom
afrind:export-D103210059

Conversation

@afrind

@afrind afrind commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

Summary:
Three bugs in the descending-fetch path of FetchWriteback / getGapRanges, found by review of the LocationIntervalSet conversion:

  1. getGapRanges DESC range Re-sync with internal repository #1 extended to {startGroup, MAX} regardless of the user's fetch end, marking positions above fetchEnd as nonexistent. Likewise range Convert directory fbcode/opensource to use the Ruff Formatter #3 started at {endGroup, 0} regardless of fetchStart. Either could shadow positions outside the requested range and suppress later upstream fetches. Fixed by adding fetchStart/fetchEnd parameters and clamping ranges Re-sync with internal repository #1 and Convert directory fbcode/opensource to use the Ruff Formatter #3 against them when start.group / end.group is the fetch boundary.

  2. cacheImpl streaming objectPayload finFetch path called markNonExistentTo(end_) without first advancing the iterator past the just-completed object, so the gap range overlapped it. Fixed by stepping fetchRangeIt_.next() before tail-marking.

  3. Both finFetch tail-marks called markNonExistentTo(end_), where end_ is the user's highest endpoint. In DESC iteration, the iteration end is the lowest position, so the wrong endpoint was used. Fixed by switching to fetchRangeIt_.end(), which returns the order-aware iteration end.

Adds three regression tests covering each bug.

Differential Revision: D103210059

afrind added 3 commits April 30, 2026 09:42
Summary:
Add a portable LocationIntervalSet class that stores disjoint intervals of
AbsoluteLocation. This is an alternative to quic::IntervalSet that works
with AbsoluteLocation (two uint64_t values) without requiring uint128_t,
making it portable to platforms without __int128 support (MSVC, 32-bit).

Key features:
- insert(start, end): Add an interval with automatic merging of overlapping/adjacent
- contains(loc): O(log n) check if a location is within any interval
- findIntervalEnd(loc): Find the end of the interval containing a location
- next()/prev(): Static helpers for location successor/predecessor

This will be used to efficiently track known gaps in MoQCache, enabling
O(log n) skipping over large gaps (e.g., from group 1 to group 2^60).

Reviewed By: sandarsh

Differential Revision: D91961632
Summary:
Refactors MoQCache to use LocationIntervalSet for tracking known-nonexistent
object/group ranges (gaps) instead of storing individual OBJECT_NOT_EXIST and
GROUP_NOT_EXIST cache entries.

Key changes:
- Add `gaps` field (LocationIntervalSet) to CacheTrack for O(1) gap lookups
- Process Prior Object ID Gap (0x3E) and Prior Group ID Gap (0x3C) extensions
  to populate the gaps set via processGapExtensions()
- getCachedObjectMaybe() now returns optional<CacheEntry*>:
  - nullopt = cache miss (need upstream fetch)
  - nullptr = known nonexistent (in gaps set)
  - valid ptr = cache hit
- Fetch loop skips gaps in O(1) using findInterval() and skipPastGap()
- Simplified endOfFetch() logic: call when !(lastObject && servedOneObject)
- Added helper functions: getGapRanges(), isGroupNonExistent(), skipPastGap()

This enables efficient handling of large gaps (e.g., group 1 to 2^60) without
O(n) iteration or memory overhead.

Differential Revision: D91961635
Summary:
Three bugs in the descending-fetch path of FetchWriteback / getGapRanges, found by review of the LocationIntervalSet conversion:

1. getGapRanges DESC range #1 extended to {startGroup, MAX} regardless of the user's fetch end, marking positions above fetchEnd as nonexistent. Likewise range #3 started at {endGroup, 0} regardless of fetchStart. Either could shadow positions outside the requested range and suppress later upstream fetches. Fixed by adding fetchStart/fetchEnd parameters and clamping ranges #1 and #3 against them when start.group / end.group is the fetch boundary.

2. cacheImpl streaming objectPayload finFetch path called markNonExistentTo(end_) without first advancing the iterator past the just-completed object, so the gap range overlapped it. Fixed by stepping fetchRangeIt_.next() before tail-marking.

3. Both finFetch tail-marks called markNonExistentTo(end_), where end_ is the user's highest endpoint. In DESC iteration, the iteration end is the lowest position, so the wrong endpoint was used. Fixed by switching to fetchRangeIt_.end(), which returns the order-aware iteration end.

Adds three regression tests covering each bug.

Differential Revision: D103210059
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Apr 30, 2026
@meta-codesync

meta-codesync Bot commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

@afrind has exported this pull request. If you are a Meta employee, you can view the originating Diff in D103210059.

@afrind

afrind commented May 6, 2026

Copy link
Copy Markdown
Contributor Author

This was merged as part of another commit

@afrind afrind closed this May 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot. fb-exported meta-exported

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant