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)