[ 
https://issues.apache.org/jira/browse/KUDU-3782?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Gabriella Lotz updated KUDU-3782:
---------------------------------
    Description: 
h3. Summary

When a tablet server serves a counting scan
{noformat}
COUNT(*) or COUNT(<constant>), {noformat}
that also carries column predicates, MaterializingIterator::Init (in 
src/kudu/common/generic_iterators.cc) computes the number of projected columns 
minus the number of predicates using mismatched signed/unsigned types. When the 
projected column count is smaller than the predicate count, the subtraction 
underflows to a very large value, which is passed to std::vector::reserve, 
throwing an uncaught std::length_error and aborting the process.

 

This happens because the projection for a counting scan is tiny, while during 
initialization the rowset iterator (CFileSet::Iterator::OptimizePKPredicates → 
LiftPrimaryKeyBounds) re-adds predicates derived from the rowset's primary key 
bounds on key columns that are not in the projection. The guarding DCHECK_GE is 
compiled out in release builds, so release builds reach the underflow. It is 
intermittent because it depends on the rowset's on-disk key layout.

Trigger: a 
{code:java}
COUNT(*)/COUNT(<const>){code}
query with predicates on a non-contiguous subset of a composite primary key, 
against a rowset whose primary key bounds share a long constant prefix.
h3. Fix (in MaterializingIterator::Init)

Remove the invalid DCHECK_GE, compute the reservation so it cannot underflow, 
and skip predicates whose column is not in the projection (these are 
rowset-derived and already enforced by the key range) instead of failing the 
scan. A regression test covering a projection smaller than the predicate set 
passes with this change, and the existing generic_iterators-test suite 
continues to pass.
h3. Workaround

Rewrite affected counting queries so the scan projects real columns, for 
example by wrapping the count in a sub-query that selects actual rows. A 
non-empty projection avoids the code path entirely. Only COUNT(...) queries 
that include a WHERE clause can trigger this.

  was:
h3. Summary

When a tablet server serves a counting scan (`COUNT(*)` or COUNT(<constant>), 
which uses an empty projection) that also carries column predicates, 
MaterializingIterator::Init (in src/kudu/common/generic_iterators.cc) computes 
the number of projected columns minus the number of predicates using mismatched 
signed/unsigned types. When the projected column count is smaller than the 
predicate count, the subtraction underflows to a very large value, which is 
passed to std::vector::reserve, throwing an uncaught std::length_error and 
aborting the process.

This happens because the projection for a counting scan is tiny, while during 
initialization the rowset iterator (CFileSet::Iterator::OptimizePKPredicates → 
LiftPrimaryKeyBounds) re-adds predicates derived from the rowset's primary key 
bounds on key columns that are not in the projection. The guarding DCHECK_GE is 
compiled out in release builds, so release builds reach the underflow. It is 
intermittent because it depends on the rowset's on-disk key layout.

Trigger: a COUNT(*)/COUNT(<const>) query with predicates on a non-contiguous 
subset of a composite primary key, against a rowset whose primary key bounds 
share a long constant prefix.
h3. Fix (in MaterializingIterator::Init)

Remove the invalid DCHECK_GE, compute the reservation so it cannot underflow, 
and skip predicates whose column is not in the projection (these are 
rowset-derived and already enforced by the key range) instead of failing the 
scan. A regression test covering a projection smaller than the predicate set 
passes with this change, and the existing generic_iterators-test suite 
continues to pass.
h3. Workaround

Rewrite affected counting queries so the scan projects real columns, for 
example by wrapping the count in a sub-query that selects actual rows. A 
non-empty projection avoids the code path entirely. Only COUNT(...) queries 
that include a WHERE clause can trigger this.


> TServer aborts (SIGABRT / std::length_error) on COUNT(*) scans with predicates
> ------------------------------------------------------------------------------
>
>                 Key: KUDU-3782
>                 URL: https://issues.apache.org/jira/browse/KUDU-3782
>             Project: Kudu
>          Issue Type: Bug
>          Components: tserver
>            Reporter: Gabriella Lotz
>            Priority: Critical
>
> h3. Summary
> When a tablet server serves a counting scan
> {noformat}
> COUNT(*) or COUNT(<constant>), {noformat}
> that also carries column predicates, MaterializingIterator::Init (in 
> src/kudu/common/generic_iterators.cc) computes the number of projected 
> columns minus the number of predicates using mismatched signed/unsigned 
> types. When the projected column count is smaller than the predicate count, 
> the subtraction underflows to a very large value, which is passed to 
> std::vector::reserve, throwing an uncaught std::length_error and aborting the 
> process.
>  
> This happens because the projection for a counting scan is tiny, while during 
> initialization the rowset iterator (CFileSet::Iterator::OptimizePKPredicates 
> → LiftPrimaryKeyBounds) re-adds predicates derived from the rowset's primary 
> key bounds on key columns that are not in the projection. The guarding 
> DCHECK_GE is compiled out in release builds, so release builds reach the 
> underflow. It is intermittent because it depends on the rowset's on-disk key 
> layout.
> Trigger: a 
> {code:java}
> COUNT(*)/COUNT(<const>){code}
> query with predicates on a non-contiguous subset of a composite primary key, 
> against a rowset whose primary key bounds share a long constant prefix.
> h3. Fix (in MaterializingIterator::Init)
> Remove the invalid DCHECK_GE, compute the reservation so it cannot underflow, 
> and skip predicates whose column is not in the projection (these are 
> rowset-derived and already enforced by the key range) instead of failing the 
> scan. A regression test covering a projection smaller than the predicate set 
> passes with this change, and the existing generic_iterators-test suite 
> continues to pass.
> h3. Workaround
> Rewrite affected counting queries so the scan projects real columns, for 
> example by wrapping the count in a sub-query that selects actual rows. A 
> non-empty projection avoids the code path entirely. Only COUNT(...) queries 
> that include a WHERE clause can trigger this.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to