Skip to content

Gate ingestion Groovy compilation without blocking query Groovy - #19887

Draft
xiangfu0 wants to merge 1 commit into
apache:masterfrom
xiangfu0:xiangfu0/codex2/groovy-runtime-compiler
Draft

xiangfu0 wants to merge 1 commit into
apache:masterfrom
xiangfu0:xiangfu0/codex2/groovy-runtime-compiler

Conversation

@xiangfu0

@xiangfu0 xiangfu0 commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

PR flow

Gate disables new ingestion Groovy compilation while preserving query Groovy and legacy map extraction.

flowchart TD
  N0["GroovyFunctionEvaluator#46;setIngestionGroovyDisabled #38; flag #40;F3#41;"]:::stModified
  N1["GroovyFunctionEvaluator private constructor #40;F3#41;"]:::stModified
  N2["GroovyFunctionEvaluator#46;parseGroovyScript #40;F3#41;"]:::stModified
  N3["GroovyFunctionEvaluator#46;forQuery #38; parseGroovyScriptForQuery #40;F3#41;"]:::stModified
  N4["BaseSingleStageBrokerRequestHandler#46;validateGroovyScript #40;F1#41;"]:::stModified
  N5["GroovyTransformFunction#46;init #40;F4#41;"]:::stModified
  N6["FunctionEvaluatorFactory#46;getExpressionEvaluator #40;#95;#95;KEYS#47;#95;#95;VALUES#41; #40;F2#41;"]:::stModified
  N7["MapFunctionEvaluator#46;evaluate #40;F2#41;"]:::stModified
  N0 -->|"writes flag read by constructor"| N1
  N0 -->|"writes flag read by parseGroovyScript"| N2
  N4 -->|"calls parseGroovyScriptForQuery"| N3
  N5 -->|"calls forQuery"| N3
  N6 -->|"returns MapFunctionEvaluator whose evaluate is used"| N7
  classDef stAdded fill:#dafbe1,stroke:#1a7f37,color:#1f2328,stroke-width:2px
  classDef stModified fill:#fff8c5,stroke:#9a6700,color:#1f2328,stroke-width:2px
  classDef stRemoved fill:#ffebe9,stroke:#cf222e,color:#1f2328,stroke-width:2px
  classDef stUnchanged fill:#f6f8fa,stroke:#656d76,color:#1f2328,stroke-width:1px
Loading

AI-generated · Green: added · Yellow: modified · Red: removed · Gray: existing

Diff evidence
  • F1: pinot-broker/src/main/java/org/apache/pinot/broker/requesthandler/BaseSingleStageBrokerRequestHandler.java — before · after
  • F2: pinot-common/src/main/java/org/apache/pinot/common/evaluator/FunctionEvaluatorFactory.java — before · after
  • F3: pinot-common/src/main/java/org/apache/pinot/common/evaluator/GroovyFunctionEvaluator.java — before · after
  • F4: pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/GroovyTransformFunction.java — before · after
  • Regenerate PR flow

Add a shared gate that stops new ingestion Groovy compilation at evaluator construction and validation-script parsing. This protects ingestion of previously persisted configurations without passing policy parameters throughout ingestion APIs.

Query validation and both query evaluator construction paths explicitly retain query-time Groovy support under the existing query admission and static-analysis controls. Already compiled ingestion evaluators continue to execute.

Legacy Avro __KEYS/__VALUES extraction uses Java instead of implicit Groovy, preserving key ordering, SortedMap comparators, and null handling when ingestion compilation is disabled.

Usage

The service configuration layer controls the gate:

GroovyFunctionEvaluator.setIngestionGroovyDisabled(true);
// New ingestion evaluator construction and parseGroovyScript calls fail before compilation.
GroovyFunctionEvaluator.setIngestionGroovyDisabled(false);
// Subsequent ingestion compilation is allowed again.

The shared evaluator retains its historical enabled default until a service configures it. #19888 applies the sole cluster setting, controller.disable.ingestion.groovy, to servers and minions and disables ingestion compilation there by default. Controller admission is covered by #19235. No second Groovy enablement setting is introduced.

Validation

  • 69 focused evaluator, expression-transform, query-transform, and broker validation tests pass.
  • Regression cases cover disable/re-enable, existing evaluator execution, implicit map extraction, and query Groovy continuing to work while ingestion is disabled. Existing query-disable admission still rejects query Groovy.
  • Formatting, Checkstyle, license-format, license checks, and compilation with warning/deprecation reporting pass for common/core/broker.

@xiangfu0
xiangfu0 force-pushed the xiangfu0/codex2/groovy-runtime-compiler branch from a9b963c to e1a4d05 Compare October 15, 2026 19:07
@xiangfu0 xiangfu0 changed the title Add a runtime switch for Groovy evaluator compilation Gate ingestion Groovy compilation without blocking query Groovy Oct 15, 2026
@xiangfu0 xiangfu0 added enhancement Improvement to existing functionality security Related to security hardening ingestion Related to data ingestion pipeline functions Related to scalar or aggregation functions query Related to query processing java Pull requests that update Java code labels Oct 15, 2026
@codecov-commenter

codecov-commenter commented Oct 15, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 69.45%. Comparing base (ae34ff9) to head (3a90f69).

Additional details and impacted files
@@             Coverage Diff              @@
##             master   #19887      +/-   ##
============================================
+ Coverage     69.42%   69.45%   +0.02%     
  Complexity     1491     1491              
============================================
  Files          3545     3545              
  Lines        233979   233998      +19     
  Branches      37442    37446       +4     
============================================
+ Hits         162448   162514      +66     
+ Misses        58984    58939      -45     
+ Partials      12547    12545       -2     
Flag Coverage Δ
integration 100.00% <ø> (ø)
integration1 100.00% <ø> (ø)
integration2 0.00% <ø> (ø)
java-25 69.45% <100.00%> (+0.02%) ⬆️
lane-a 100.00% <ø> (ø)
lane-b 0.00% <ø> (ø)
temurin 69.45% <100.00%> (+0.02%) ⬆️
unittests 69.44% <100.00%> (+0.02%) ⬆️
unittests1 58.96% <92.85%> (+0.03%) ⬆️
unittests2 41.20% <75.86%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@xiangfu0 xiangfu0 left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated code review at e1a4d05 (CI green, 14/14). Verdict: LGTM / approve-equivalent — only minor, non-blocking notes below. GitHub blocks a formal APPROVE here because this review runs under the PR author's token, so this is posted as a comment.

Well-scoped hardening: the ingestion gate fails before compilation; query construction and validation correctly bypass it via forQuery/parseGroovyScriptForQuery while retaining the static-analysis controls; the legacy Avro __KEYS/__VALUES path moves off implicit Groovy without changing results.

I verified the map-extraction behavior against Groovy 3.0.25 directly: map.sort() preserves an existing SortedMap comparator and otherwise sorts by natural key order, which is exactly what MapFunctionEvaluator reproduces (reverse-ordered SortedMap, LinkedHashMap, HashMap, and empty map all match). No wire/serialization/SPI changes, so no mixed-version compatibility concern. Correctness, compatibility, and concurrency all look good.

Map<?, ?> map = (Map<?, ?>) value;
// Groovy's sort() preserves the comparator of an existing SortedMap.
Map<?, ?> sortedMap = map instanceof SortedMap<?, ?> ? map : new TreeMap<>(map);
return new ArrayList<>(_extractKeys ? sortedMap.keySet() : sortedMap.values());

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice call reusing the map's own comparator here. I confirmed against Groovy 3.0.25 that map.sort() keeps an existing SortedMap comparator and natural-orders everything else, so this TreeMap fallback matches the old Groovy({...sort()...}) output exactly, including the reverse-ordered case. Behavior-preserving.

private static final String SCRIPT_GROUP_NAME = "script";
private static final String ARGUMENTS_SEPARATOR = ",";
private static GroovyStaticAnalyzerConfig _groovyStaticAnalyzerConfig;
private static volatile boolean _ingestionGroovyDisabled;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a JVM-wide latch toggled by a static setter. Fine for the service-config use, but the tests flip it and reset it in finally, so if any of these classes ever run in parallel in the same JVM they could observe each other's state. Just worth keeping in mind if test parallelism gets enabled later.

Expose GroovyFunctionEvaluator.setIngestionGroovyDisabled(boolean) for service
runtime policy. Calling it with true rejects new ingestion evaluator construction
and parseGroovyScript calls before compilation; calling it with false permits
later ingestion compilation. Existing evaluators continue to execute. Ingestion
Groovy stays enabled until a service configures the gate.

Use forQuery and parseGroovyScriptForQuery at query execution and broker validation
entry points so ingestion policy does not override query admission or Groovy
static-analysis controls.

Extract implicit Avro map keys and values directly in Java so disabling ingestion
Groovy preserves legacy map ingestion, including SortedMap comparators.

Validation: 66 focused evaluator, query-transform, expression-transform, and broker
query-validation tests; affected-module formatting, checkstyle, and license checks.
@xiangfu0
xiangfu0 force-pushed the xiangfu0/codex2/groovy-runtime-compiler branch from e1a4d05 to 3a90f69 Compare October 16, 2026 22:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Improvement to existing functionality functions Related to scalar or aggregation functions ingestion Related to data ingestion pipeline java Pull requests that update Java code query Related to query processing security Related to security hardening

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants