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)

Reply via email to