Skip to content

Commit c4f28b7

Browse files
peterzhuamazonBukhtawar
authored andcommitted
Onboarding calcite opensearch revision publishing setups (opensearch-project#21549)
* Onboarding calcite opensearch revision publishing setups Signed-off-by: Peter Zhu <zhujiaxi@amazon.com> * Update a comment Signed-off-by: Peter Zhu <zhujiaxi@amazon.com> * Update default ref to use commit ids Signed-off-by: Peter Zhu <zhujiaxi@amazon.com> * Make patch file more dynamic now Signed-off-by: Peter Zhu <zhujiaxi@amazon.com> --------- Signed-off-by: Peter Zhu <zhujiaxi@amazon.com>
1 parent 5697d48 commit c4f28b7

3 files changed

Lines changed: 242 additions & 0 deletions

File tree

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# This workflow will check out, build, and publish snapshots of calcite.
2+
3+
name: OpenSearch Lucene snapshots
4+
5+
on:
6+
workflow_dispatch:
7+
# Inputs the workflow accepts.
8+
inputs:
9+
ref:
10+
description: 'Calcite ref in github.com/apache/calcite, default to calcite-1.41.0 tag (c838dd471ca36f5648ef13e5c3c34c6ca0815322)'
11+
type: string
12+
required: false
13+
default: 'c838dd471ca36f5648ef13e5c3c34c6ca0815322'
14+
java_version:
15+
description: 'Java version to use'
16+
type: string
17+
required: false
18+
default: '21'
19+
patch_file_path:
20+
description: 'The patch file, default to sandbox/patches/calcite/0001-CALCITE-3745-prefer-TCCL-for-Janino-parent-classloader.patch'
21+
type: string
22+
required: false
23+
default: 'sandbox/patches/calcite/0001-CALCITE-3745-prefer-TCCL-for-Janino-parent-classloader.patch'
24+
25+
jobs:
26+
publish-snapshots:
27+
if: github.repository == 'opensearch-project/OpenSearch'
28+
runs-on: ubuntu-latest
29+
# These permissions are needed to interact with GitHub's OIDC Token endpoint.
30+
permissions:
31+
id-token: write
32+
contents: read
33+
34+
steps:
35+
- name: Checkout Calcite ref:${{ github.event.inputs.ref }}
36+
uses: actions/checkout@v6
37+
with:
38+
repository: 'apache/calcite'
39+
ref: ${{ github.event.inputs.ref }}
40+
persist-credentials: false
41+
42+
- name: Checkout OpenSearch main
43+
uses: actions/checkout@v6
44+
with:
45+
repository: 'opensearch-project/OpenSearch'
46+
ref: 'main'
47+
persist-credentials: false
48+
path: 'os_main'
49+
50+
- name: Setup JDK ${{ github.event.inputs.java_version }}
51+
uses: actions/setup-java@v5
52+
with:
53+
java-version: ${{ github.event.inputs.java_version }}
54+
distribution: 'temurin'
55+
56+
- name: Apply Patches and build calcite jars
57+
run: |
58+
git apply os_main/${{ github.event.inputs.patch_file_path }}
59+
BASE_VER=`cat os_main/gradle/libs.versions.toml | grep -E "^calcite" | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+"`
60+
REV=`cat os_main/gradle/libs.versions.toml | grep -E "^calcite_os_rev" | grep -Eo "[0-9]+"`
61+
CALCITE_VER=$BASE_VER-opensearch-$REV
62+
sed -i "s/calcite\.version.*/calcite.version=$CALCITE_VER/" gradle.properties
63+
./gradlew :core:publishToMavenLocal :linq4j:publishToMavenLocal -Prelease -PskipSign -PskipJavadoc -x test --no-daemon
64+
65+
- name: Configure AWS credentials
66+
uses: aws-actions/configure-aws-credentials@v6
67+
with:
68+
role-to-assume: ${{ secrets.LUCENE_SNAPSHOTS_SECRET_ROLE }}
69+
aws-region: us-east-1
70+
71+
- name: Get S3 Bucket
72+
id: get_s3_bucket
73+
run: |
74+
lucene_snapshots_bucket=`aws secretsmanager get-secret-value --secret-id jenkins-artifact-bucket-name --query SecretString --output text`
75+
echo "::add-mask::$lucene_snapshots_bucket"
76+
echo "LUCENE_SNAPSHOTS_BUCKET=$lucene_snapshots_bucket" >> $GITHUB_OUTPUT
77+
78+
- name: Configure AWS credentials
79+
uses: aws-actions/configure-aws-credentials@v6
80+
with:
81+
role-to-assume: ${{ secrets.LUCENE_SNAPSHOTS_S3_ROLE }}
82+
aws-region: us-east-1
83+
84+
- name: Copy files to S3 with the aws CLI
85+
run: |
86+
aws s3 cp ~/.m2/repository/org/apache/calcite/ s3://${{ steps.get_s3_bucket.outputs.LUCENE_SNAPSHOTS_BUCKET }}/snapshots/maven/org/apache/calcite/ --recursive --no-progress

gradle/libs.versions.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ opentelemetrysemconv = "1.40.0"
104104
arrow = "18.1.0"
105105
flatbuffers = "2.0.0"
106106

107+
# calcite is locally patched and published to OpenSearch maven snapshots; see .github/workflows/calcite-snapshots.yml.
108+
# Published as org.apache.calcite:calcite-core:${calcite}-opensearch-${calcite_os_rev}.
109+
calcite = "1.41.0"
110+
calcite_os_rev = "1"
111+
107112
[libraries]
108113
antlr4-runtime = { group = "org.antlr", name = "antlr4-runtime", version.ref = "antlr4" }
109114
asm-analysis = { group = "org.ow2.asm", name = "asm-analysis", version.ref = "asm" }
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2+
From: Mustang <mustang@opensearch.local>
3+
Date: Wed, 6 May 2026 00:00:00 -0700
4+
Subject: [PATCH] CALCITE-3745: TCCL-chained classloader for Janino parent CL
5+
6+
Introduce a TcclChainedClassLoader utility that resolves classes via the
7+
thread context classloader first, falling back to the Calcite-local CL
8+
if a name is not found on TCCL. Every site that configures Janino's
9+
parent classloader (EnumerableInterpretable, JaninoRexCompiler,
10+
RexExecutable, JaninoRelMetadataProvider) now uses the chained loader.
11+
12+
This keeps Calcite's internal types always resolvable while making
13+
child-plugin UDFs visible when the host (OpenSearch's extendedPlugins)
14+
sets TCCL to the child classloader.
15+
---
16+
.../enumerable/EnumerableInterpretable.java | 3 +-
17+
.../interpreter/JaninoRexCompiler.java | 3 +-
18+
.../metadata/JaninoRelMetadataProvider.java | 4 +-
19+
.../org/apache/calcite/rex/RexExecutable.java | 4 +-
20+
.../calcite/util/TcclChainedClassLoader.java | 61 +++++++++++++++++++
21+
5 files changed, 71 insertions(+), 4 deletions(-)
22+
create mode 100644 core/src/main/java/org/apache/calcite/util/TcclChainedClassLoader.java
23+
24+
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableInterpretable.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableInterpretable.java
25+
index 5f32ab1..1c9ce19 100644
26+
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableInterpretable.java
27+
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableInterpretable.java
28+
@@ -145,7 +145,8 @@ static Bindable getBindable(ClassDeclaration expr, String classBody, int fieldCo
29+
"Unable to instantiate java compiler", e);
30+
}
31+
final ISimpleCompiler compiler = compilerFactory.newSimpleCompiler();
32+
- compiler.setParentClassLoader(classLoader);
33+
+ compiler.setParentClassLoader(
34+
+ org.apache.calcite.util.TcclChainedClassLoader.chain(classLoader));
35+
final String s = "public final class " + expr.name + " implements "
36+
+ (fieldCount == 1
37+
? Bindable.class.getCanonicalName() + ", " + Typed.class.getCanonicalName()
38+
diff --git a/core/src/main/java/org/apache/calcite/interpreter/JaninoRexCompiler.java b/core/src/main/java/org/apache/calcite/interpreter/JaninoRexCompiler.java
39+
index bca4f85..d6de426 100644
40+
--- a/core/src/main/java/org/apache/calcite/interpreter/JaninoRexCompiler.java
41+
+++ b/core/src/main/java/org/apache/calcite/interpreter/JaninoRexCompiler.java
42+
@@ -211,7 +211,8 @@ static Scalar.Producer getScalar(ClassDeclaration expr, String s)
43+
IClassBodyEvaluator cbe = compilerFactory.newClassBodyEvaluator();
44+
cbe.setClassName(expr.name);
45+
cbe.setImplementedInterfaces(new Class[] {Scalar.Producer.class});
46+
- cbe.setParentClassLoader(classLoader);
47+
+ cbe.setParentClassLoader(
48+
+ org.apache.calcite.util.TcclChainedClassLoader.chain(classLoader));
49+
if (CalciteSystemProperty.DEBUG.value()) {
50+
// Add line numbers to the generated janino class
51+
cbe.setDebuggingInformation(true, true, true);
52+
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/JaninoRelMetadataProvider.java b/core/src/main/java/org/apache/calcite/rel/metadata/JaninoRelMetadataProvider.java
53+
index 135b11e..34a5e4b 100644
54+
--- a/core/src/main/java/org/apache/calcite/rel/metadata/JaninoRelMetadataProvider.java
55+
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/JaninoRelMetadataProvider.java
56+
@@ -157,7 +157,9 @@ static <MH extends MetadataHandler<?>> MH compile(String className,
57+
}
58+
59+
final ISimpleCompiler compiler = compilerFactory.newSimpleCompiler();
60+
- compiler.setParentClassLoader(JaninoRexCompiler.class.getClassLoader());
61+
+ compiler.setParentClassLoader(
62+
+ org.apache.calcite.util.TcclChainedClassLoader.chain(
63+
+ JaninoRexCompiler.class.getClassLoader()));
64+
65+
if (CalciteSystemProperty.DEBUG.value()) {
66+
// Add line numbers to the generated janino class
67+
diff --git a/core/src/main/java/org/apache/calcite/rex/RexExecutable.java b/core/src/main/java/org/apache/calcite/rex/RexExecutable.java
68+
index 8828654..1e91951 100644
69+
--- a/core/src/main/java/org/apache/calcite/rex/RexExecutable.java
70+
+++ b/core/src/main/java/org/apache/calcite/rex/RexExecutable.java
71+
@@ -60,7 +60,9 @@ public RexExecutable(String code, Object reason) {
72+
cbe.setClassName(GENERATED_CLASS_NAME);
73+
cbe.setExtendedClass(Utilities.class);
74+
cbe.setImplementedInterfaces(new Class[] {Function1.class, Serializable.class});
75+
- cbe.setParentClassLoader(RexExecutable.class.getClassLoader());
76+
+ cbe.setParentClassLoader(
77+
+ org.apache.calcite.util.TcclChainedClassLoader.chain(
78+
+ RexExecutable.class.getClassLoader()));
79+
cbe.cook(new Scanner(null, new StringReader(code)));
80+
Class c = cbe.getClazz();
81+
//noinspection unchecked
82+
diff --git a/core/src/main/java/org/apache/calcite/util/TcclChainedClassLoader.java b/core/src/main/java/org/apache/calcite/util/TcclChainedClassLoader.java
83+
new file mode 100644
84+
index 0000000..259d71c
85+
--- /dev/null
86+
+++ b/core/src/main/java/org/apache/calcite/util/TcclChainedClassLoader.java
87+
@@ -0,0 +1,61 @@
88+
+/*
89+
+ * Licensed to the Apache Software Foundation (ASF) under one or more
90+
+ * contributor license agreements. See the NOTICE file distributed with
91+
+ * this work for additional information regarding copyright ownership.
92+
+ * The ASF licenses this file to you under the Apache License, Version 2.0
93+
+ * (the "License"); you may not use this file except in compliance with
94+
+ * the License. You may obtain a copy of the License at
95+
+ *
96+
+ * http://www.apache.org/licenses/LICENSE-2.0
97+
+ *
98+
+ * Unless required by applicable law or agreed to in writing, software
99+
+ * distributed under the License is distributed on an "AS IS" BASIS,
100+
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
101+
+ * See the License for the specific language governing permissions and
102+
+ * limitations under the License.
103+
+ */
104+
+package org.apache.calcite.util;
105+
+
106+
+/**
107+
+ * CALCITE-3745 (OpenSearch patch): helper to build a classloader that
108+
+ * prefers the thread context classloader for name resolution but falls back
109+
+ * to a supplied Calcite-local classloader for Calcite's own internal types.
110+
+ *
111+
+ * <p>When Calcite is embedded under a parent plugin classloader (e.g. in
112+
+ * OpenSearch's {@code extendedPlugins} layout), child plugins register UDFs
113+
+ * that end up referenced by name in Janino-generated code. The default
114+
+ * {@code SomeCalciteClass.class.getClassLoader()} cannot see those UDFs.
115+
+ * Using TCCL alone breaks in contexts where TCCL is a stripped-down
116+
+ * classloader that has no view of Calcite's own internal types. Chaining
117+
+ * solves both cases.
118+
+ */
119+
+public final class TcclChainedClassLoader {
120+
+ private TcclChainedClassLoader() {}
121+
+
122+
+ /**
123+
+ * Returns a classloader that resolves classes by consulting the thread
124+
+ * context classloader first, then falling back to {@code fallback}. If
125+
+ * TCCL is unset or identical to {@code fallback}, the fallback is
126+
+ * returned unchanged.
127+
+ */
128+
+ public static ClassLoader chain(ClassLoader fallback) {
129+
+ final ClassLoader tccl = Thread.currentThread().getContextClassLoader();
130+
+ if (tccl == null || tccl == fallback) {
131+
+ return fallback;
132+
+ }
133+
+ return new ClassLoader(fallback) {
134+
+ @Override protected Class<?> loadClass(String name, boolean resolve)
135+
+ throws ClassNotFoundException {
136+
+ try {
137+
+ Class<?> c = tccl.loadClass(name);
138+
+ if (resolve) {
139+
+ resolveClass(c);
140+
+ }
141+
+ return c;
142+
+ } catch (ClassNotFoundException e) {
143+
+ return super.loadClass(name, resolve);
144+
+ }
145+
+ }
146+
+ };
147+
+ }
148+
+}
149+
--
150+
2.50.1 (Apple Git-155)
151+

0 commit comments

Comments
 (0)