Zhang Zhenhao created IGNITE-29183:
--------------------------------------

             Summary: Inline size recommendation is never logged: operator 
precedence bug in InlineRecommender throttle condition
                 Key: IGNITE-29183
                 URL: https://issues.apache.org/jira/browse/IGNITE-29183
             Project: Ignite
          Issue Type: Bug
          Components: sql
    Affects Versions: 2.8
            Reporter: Zhang Zhenhao


{\{InlineRecommender.recommend()}} — the component that logs a recommendation 
when indexed columns of a row cannot be fully inlined into an index (or when 
the inline size is too big) — never performs its check with the default 
configuration, due to an operator precedence error in the throttle condition.

Code 
(\{{modules/core/src/main/java/org/apache/ignite/internal/cache/query/index/sorted/inline/InlineRecommender.java}},
 method \{{recommend()}}):

{code:java}
long invokeCnt = inlineSizeCalculationCntr.get();

if (!inlineSizeCalculationCntr.compareAndSet(invokeCnt, invokeCnt + 1))
return;

boolean throttle = invokeCnt + 1 % inlineSizeThrottleThreshold != 0;

if (throttle)
return;
{code}

In Java \{{%}} binds tighter than \{{+}}, so the condition parses as 
\{{invokeCnt + (1 % inlineSizeThrottleThreshold) != 0}} instead of the intended 
\{{(invokeCnt + 1) % inlineSizeThrottleThreshold != 0}}.

Consequences:

* With the default \{{IGNITE_THROTTLE_INLINE_SIZE_CALCULATION}} (1000), \{{1 % 
1000 == 1}}, so the condition is \{{invokeCnt + 1 != 0}} — always true, because 
the counter starts at 0 and only grows. \{{throttle}} is therefore always true 
and the method returns before doing any work, on every invocation. Neither the 
"Indexed columns of a row cannot be fully inlined ..." warning nor the "Inline 
size is too big ..." warning (added by IGNITE-23120) can ever be logged with 
default settings.
* With the system property set to \{{1}}, \{{1 % 1 == 0}}, so the condition 
becomes \{{invokeCnt != 0}}: only the very first invocation per index instance 
passes, all later ones are skipped. This is the only configuration in which the 
recommender produces any output at all, and it effectively inspects a single 
row per index.

Expected behavior, per the documented meaning of 
\{{IGNITE_THROTTLE_INLINE_SIZE_CALCULATION}} ("throttles inline size 
calculation and logging index inline size recommendation", default 1000): the 
check should run on every Nth invocation.

Steps to reproduce:

# Start a node with default settings.
# Create a query-enabled cache with a variable-length primary key, e.g. String.
# Put a row with a long key (> inline size), then update the same row several 
thousand times.
# No warning is ever logged.
# Repeat with \{{-DIGNITE_THROTTLE_INLINE_SIZE_CALCULATION=1}} — the "Indexed 
columns of a row cannot be fully inlined ..." warning appears, exactly once per 
index (first qualifying put).

Suggested fix:

{code:java}
boolean throttle = (invokeCnt + 1) % inlineSizeThrottleThreshold != 0;
{code}

The expression was introduced together with the class in August 2019 
(IGNITE-12061, initially in modules/indexing, later moved to core by 
IGNITE-13056), so releases since ~2.8 are affected.

The recently added \{{InlineRecommenderSelfTest}} (modules/indexing, [PR 
#13715|https://github.com/apache/ignite/pull/13715] for IGNITE-11355) already 
exercises the recommender with the workaround 
(\{{IGNITE_THROTTLE_INLINE_SIZE_CALCULATION=1}}) and can serve as a starting 
point for a regression test of the fixed sampling behavior (e.g. with a 
threshold of 2, every second qualifying put should trigger a check).



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

Reply via email to