Andrew Kyle Purtell created PHOENIX-8042:
--------------------------------------------
Summary: Server-side LIMIT queries executed over covered global
indexes can terminate prematurely and return fewer rows than requested
Key: PHOENIX-8042
URL: https://issues.apache.org/jira/browse/PHOENIX-8042
Project: Phoenix
Issue Type: Bug
Components: core
Affects Versions: 5.3.2
Reporter: Andrew Kyle Purtell
Assignee: Andrew Kyle Purtell
Fix For: 5.4.0, 5.3.3
When a query spans multiple regions, the client attempts to satisfy the
remaining limit by reading from subsequent regions. For ordered scans, this
silently violates order semantics by pulling rows from downstream regions that
are not among the first global {{LIMIT}} results.
When a query applies a filter on covered columns and relies on index order to
satisfy a row limit, {{GlobalIndexChecker}} wraps the region scanner. Rather
than delegating row counting to HBase's {{{}PageFilter{}}},
{{GlobalIndexScanner}} strips the filter from the underlying scan and tracks
delivered rows internally, returning false once its counter reaches the
configured limit. The coordination breaks down when the scanner encounters
unverified index rows that must be reconciled via read repair. During repair,
the engine opens a subordinate scanner to reevaluate the row against the query
filter. If the rebuilt row is rejected by the filter and the server-side paging
limit ({{{}PagingFilter{}}}) trips, the underlying {{PagingRegionScanner}}
returns a dummy marker row to preserve client scan positioning.
While dummy rows emitted by the primary scanner are recognized as non-data
markers and bypassed before counting, dummy rows returned through the read
repair path bypass this safeguard. The verification layer treats any non-empty
return as a valid row, causing {{GlobalIndexScanner.next()}} to increment its
counter for a control marker rather than actual payload data.
The internal row counter can reach the limit prematurely, causing the region
scan to exit before delivering the required number of actual records. If the
row count hits the limit precisely on a dummy marker, the outer region scanner
yields {{true}} (standard behavior for paging markers). The counter
subsequently exceeds the limit value and never matches it again, causing the
scanner to read the remainder of the region without ever enforcing the limit.
The fix requires improving dummy marker handling across all scanner paths. In
{{{}GlobalIndexScanner.next(){}}}, when read repair yields a dummy row, the
scanner should immediately return the marker without incrementing the row count
or evaluating the limit threshold. This preserves scan position markers across
region boundaries without exhausting the query's server-side row budget.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)