voonhous commented on code in PR #19674:
URL: https://github.com/apache/hudi/pull/19674#discussion_r3818397612


##########
.github/workflows/bot.yml:
##########
@@ -1354,7 +1390,7 @@ jobs:
           FLINK_AVRO_VERSION: ${{ matrix.flinkAvroVersion }}
           FLINK_PARQUET_VERSION: ${{ matrix.flinkParquetVersion }}
         run: |
-          mvn clean package -T 2 -Pjava17 -D"$SCALA_PROFILE" 
-D"$SPARK_PROFILE" -DdeployArtifacts=true -DskipTests=true 
-Dmaven.javadoc.skip=true $MVN_ARGS -pl 
packaging/hudi-hadoop-mr-bundle,packaging/hudi-spark-bundle,packaging/hudi-utilities-bundle,packaging/hudi-utilities-slim-bundle,packaging/hudi-cli-bundle
 -am
+          mvn clean package -T 2 -Pjava17 -D"$SCALA_PROFILE" 
-D"$SPARK_PROFILE" -DdeployArtifacts=true -DskipTests=true 
-Dmaven.javadoc.skip=true $MVN_ARGS -pl 
packaging/hudi-hadoop-mr-bundle,packaging/hudi-spark-bundle,packaging/hudi-native-spark-bundle,packaging/hudi-utilities-bundle,packaging/hudi-utilities-slim-bundle,packaging/hudi-cli-bundle
 -am

Review Comment:
   This addition is a no-op as the matrix stands: the only live entry in 
`validate-bundle-spark4` is `spark4.2`, where the native module has no Comet 
profile and skips. Net effect: `hudi-native-spark4.0-bundle_2.13`, `4.1_2.13` 
(and `3.4_2.12`, which no lane builds either) are first compiled and shaded on 
release day -- the miss class of HUDI-7766 (#11234). Side note: with 
`-DdeployArtifacts=true` the skipped module still emits a lone `-sources.jar` 
and no main jar, contrary to the pom comment that it yields no bundle at all.
   
   Please drop the module from this `-pl` list and instead add build-only 
matrix entries (no docker run needed) to `validate-native-bundle` for spark3.4 
(JDK 11) and spark4.0/spark4.1 (JDK 17), so every published coordinate is at 
least shaded in CI.



##########
scripts/release/validate_staged_bundles.sh:
##########
@@ -87,7 +87,10 @@ declare -a extensions=("-javadoc.jar" "-javadoc.jar.asc" 
"-javadoc.jar.md5" "-ja
 declare -a bundles=("hudi-aws-bundle" "hudi-azure-bundle" 
"hudi-cli-bundle_2.12" "hudi-cli-bundle_2.13" "hudi-datahub-sync-bundle"
 "hudi-flink1.18-bundle" "hudi-flink1.19-bundle" "hudi-flink1.20-bundle"
 "hudi-flink2.0-bundle" "hudi-flink2.1-bundle" "hudi-gcp-bundle" 
"hudi-hadoop-mr-bundle" "hudi-hive-sync-bundle" "hudi-integ-test-bundle"
-"hudi-kafka-connect-bundle" "hudi-metaserver-server-bundle" 
"hudi-presto-bundle"
+"hudi-kafka-connect-bundle" "hudi-metaserver-server-bundle"
+"hudi-native-spark3.4-bundle_2.12" "hudi-native-spark3.5-bundle_2.12" 
"hudi-native-spark3.5-bundle_2.13"

Review Comment:
   These five coordinates are now existence-checked at staging, but nothing 
ever runs them from staging: `native_spark/ci_run.sh` implements only the 
local-jar leg, and no release workflow calls it 
(`release_candidate_validation.yml` drives 
`packaging/bundle-validation/ci_run.sh`, which has no native entry). Combined 
with the CI build gap on 3.4/4.0/4.1, four of the five published bundles are 
never executed anywhere.
   
   Please either add staging-repo download handling (mirroring 
`packaging/bundle-validation/ci_run.sh`'s `STAGING_REPO_NUM` leg) to 
`native_spark/ci_run.sh` plus a step in `release_candidate_validation.yml`, or 
add a comment here stating the native bundles are existence-checked only and 
file a follow-up.



##########
packaging/hudi-native-spark-bundle/pom.xml:
##########
@@ -0,0 +1,493 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+  <parent>
+    <artifactId>hudi</artifactId>
+    <groupId>org.apache.hudi</groupId>
+    <version>1.3.0-SNAPSHOT</version>
+    <relativePath>../../pom.xml</relativePath>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  
<artifactId>hudi-native-spark${sparkbundle.version}-bundle_${scala.binary.version}</artifactId>
+  <packaging>jar</packaging>
+
+  <properties>
+    <checkstyle.skip>true</checkstyle.skip>
+    <main.basedir>${project.parent.basedir}</main.basedir>
+    <skipTests>true</skipTests>
+    <javax.servlet.version>3.1.0</javax.servlet.version>
+    <!-- Apache DataFusion Comet releases one artifact per Spark minor 
version, and does not
+         cover every Spark version Hudi builds against. Default to producing 
nothing, so that a
+         build for an uncovered Spark version yields no bundle at all rather 
than one named
+         "native" that carries no native code. The comet-spark<version> 
profiles below opt in. -->
+    <hudi.native.bundle.skip>true</hudi.native.bundle.skip>
+    <hudi.native.bundle.jar.phase>none</hudi.native.bundle.jar.phase>
+    <maven.install.skip>${hudi.native.bundle.skip}</maven.install.skip>
+    <maven.deploy.skip>${hudi.native.bundle.skip}</maven.deploy.skip>
+  </properties>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.rat</groupId>
+        <artifactId>apache-rat-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>default-jar</id>
+            <!-- none when this module produces no bundle. Without it 
maven-jar-plugin still emits
+                 a jar named as if it were a bundle, holding nothing but the 
generated META-INF.
+                 skipIfEmpty does not help: remote-resources populates 
target/classes regardless. -->
+            <phase>${hudi.native.bundle.jar.phase}</phase>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-shade-plugin</artifactId>
+        <version>${maven-shade-plugin.version}</version>
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <goals>
+              <goal>shade</goal>
+            </goals>
+            <configuration>
+              <skip>${hudi.native.bundle.skip}</skip>
+              <createSourcesJar>${shadeSources}</createSourcesJar>
+              
<dependencyReducedPomLocation>${project.build.directory}/dependency-reduced-pom.xml
+              </dependencyReducedPomLocation>
+              <transformers>
+                <transformer 
implementation="org.apache.maven.plugins.shade.resource.ApacheLicenseResourceTransformer"
 />
+                <transformer 
implementation="org.apache.maven.plugins.shade.resource.ApacheNoticeResourceTransformer">
+                  <addHeader>true</addHeader>
+                </transformer>
+                <transformer 
implementation="org.apache.maven.plugins.shade.resource.IncludeResourceTransformer">
+                  <resource>META-INF/LICENSE</resource>
+                  <file>target/classes/META-INF/LICENSE</file>
+                </transformer>
+                <transformer 
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
+                  
<resource>META-INF/services/org.apache.spark.sql.sources.DataSourceRegister</resource>
+                </transformer>
+                <transformer 
implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
+              </transformers>
+              <artifactSet>
+                <includes combine.children="append">
+                  <include>org.apache.hudi:hudi-hadoop-common</include>
+                  <include>org.apache.hudi:hudi-common</include>
+                  <include>org.apache.hudi:hudi-client-common</include>
+                  <include>org.apache.hudi:hudi-spark-client</include>
+                  
<include>org.apache.hudi:hudi-spark-common_${scala.binary.version}</include>
+                  
<include>org.apache.hudi:hudi-spark_${scala.binary.version}</include>
+                  
<include>org.apache.hudi:${hudi.spark.module}_${scala.binary.version}</include>
+                  
<include>org.apache.hudi:${hudi.spark.common.module}</include>
+                  <include>org.apache.hudi:hudi-hive-sync</include>
+                  <include>org.apache.hudi:hudi-sync-common</include>
+                  <include>org.apache.hudi:hudi-hadoop-mr</include>
+                  <include>org.apache.hudi:hudi-timeline-service</include>
+
+                  <!-- NOTE: Comet must never be relocated. Its native library 
is bound through JNI
+                             symbols named Java_org_apache_comet_Native_*, and 
the shared objects are
+                             resolved as classpath resources under 
org/apache/comet/<os>/<arch>/, so a
+                             relocation of org.apache.comet builds cleanly and 
then fails on the first
+                             native call. The same applies to 
org.apache.arrow.c, which Comet carries
+                             unshaded for the Arrow C data interface JNI 
bindings. -->
+                  <include>org.apache.datafusion:*</include>
+
+                  <include>javax.servlet:javax.servlet-api</include>
+                  <include>com.beust:jcommander</include>
+                  <include>io.javalin:javalin</include>
+                  <!-- Spark only has mortbay jetty -->
+                  <include>org.eclipse.jetty:*</include>
+                  <include>org.eclipse.jetty.websocket:*</include>
+                  <include>org.jetbrains.kotlin:*</include>
+                  <include>org.rocksdb:rocksdbjni</include>
+                  <!-- Bundle Jackson JSR310 library since it is not present 
in spark 2.x. For spark 3.x this will
+                       bundle the same JSR310 version that is included in 
spark runtime -->
+                  
<include>com.fasterxml.jackson.datatype:jackson-datatype-jsr310</include>
+                  <include>com.lmax:disruptor</include>
+                  <include>com.github.davidmoten:guava-mini</include>
+                  <include>com.github.davidmoten:hilbert-curve</include>
+                  <include>com.github.ben-manes.caffeine:caffeine</include>
+                  <include>org.apache.parquet:parquet-avro</include>
+                  <include>com.twitter:chill-protobuf</include>
+
+                  <include>io.dropwizard.metrics:metrics-core</include>
+                  <include>io.dropwizard.metrics:metrics-graphite</include>
+                  <include>io.dropwizard.metrics:metrics-jmx</include>
+                  <include>io.prometheus:simpleclient</include>
+                  <include>io.prometheus:simpleclient_httpserver</include>
+                  <include>io.prometheus:simpleclient_dropwizard</include>
+                  <include>io.prometheus:simpleclient_pushgateway</include>
+                  <include>io.prometheus:simpleclient_common</include>
+                  <include>com.uber.m3:tally-m3</include>
+                  <include>com.uber.m3:tally-core</include>
+
+                  <include>org.apache.hive:hive-common</include>
+                  <include>org.apache.hive:hive-service</include>
+                  <include>org.apache.hive:hive-service-rpc</include>
+                  <include>org.apache.hive:hive-metastore</include>
+                  <include>org.apache.hive:hive-jdbc</include>
+
+                  <include>org.apache.curator:curator-framework</include>
+                  <include>org.apache.curator:curator-client</include>
+                  <include>org.apache.curator:curator-recipes</include>
+                  <include>commons-codec:commons-codec</include>
+                  <include>commons-io:commons-io</include>
+                  <include>org.openjdk.jol:jol-core</include>
+                </includes>
+              </artifactSet>
+              <relocations combine.children="append">
+                <!-- NOTE: We have to relocate all classes w/in 
org.apache.spark.sql.avro to avoid
+                           potential classpath collisions in case users would 
like to also use "spark-avro" w/in
+                           their runtime, since Hudi carries some of the same 
classes as "spark-avro" -->
+                <relocation>
+                  <pattern>org.apache.spark.sql.avro.</pattern>
+                  
<shadedPattern>org.apache.hudi.org.apache.spark.sql.avro.</shadedPattern>
+                </relocation>
+                <relocation>
+                  <pattern>javax.servlet.</pattern>
+                  <shadedPattern>org.apache.hudi.javax.servlet.</shadedPattern>
+                </relocation>
+                <relocation>
+                  <pattern>com.beust.jcommander.</pattern>
+                  
<shadedPattern>org.apache.hudi.com.beust.jcommander.</shadedPattern>
+                </relocation>
+                <relocation>
+                  <pattern>org.apache.commons.io.</pattern>
+                  
<shadedPattern>org.apache.hudi.org.apache.commons.io.</shadedPattern>
+                </relocation>
+                <!-- TODO: clean up hive dep - Revisit GH ISSUE #533 & 
PR#633-->
+                <relocation>
+                  <pattern>org.apache.hive.jdbc.</pattern>
+                  
<shadedPattern>${spark.bundle.hive.shade.prefix}org.apache.hive.jdbc.</shadedPattern>
+                </relocation>
+                <relocation>
+                  <pattern>org.apache.hadoop.hive.metastore.</pattern>
+                  
<shadedPattern>${spark.bundle.hive.shade.prefix}org.apache.hadoop.hive.metastore.</shadedPattern>
+                </relocation>
+                <relocation>
+                  <pattern>org.apache.hive.common.</pattern>
+                  
<shadedPattern>${spark.bundle.hive.shade.prefix}org.apache.hive.common.</shadedPattern>
+                </relocation>
+                <relocation>
+                  <pattern>org.apache.hadoop.hive.common.</pattern>
+                  
<shadedPattern>${spark.bundle.hive.shade.prefix}org.apache.hadoop.hive.common.</shadedPattern>
+                </relocation>
+                <relocation>
+                  <pattern>org.apache.hadoop.hive.conf.</pattern>
+                  
<shadedPattern>${spark.bundle.hive.shade.prefix}org.apache.hadoop.hive.conf.</shadedPattern>
+                </relocation>
+                <relocation>
+                  <pattern>org.apache.hive.service.</pattern>
+                  
<shadedPattern>${spark.bundle.hive.shade.prefix}org.apache.hive.service.</shadedPattern>
+                </relocation>
+                <relocation>
+                  <pattern>org.apache.hadoop.hive.service.</pattern>
+                  
<shadedPattern>${spark.bundle.hive.shade.prefix}org.apache.hadoop.hive.service.</shadedPattern>
+                </relocation>
+                <relocation>
+                  <pattern>com.codahale.metrics.</pattern>

Review Comment:
   **blocker** Including `org.apache.datafusion:*` under this inherited 
relocation breaks Comet's Spark metrics integration. Shade rewrites Comet's 
`org.apache.spark.CometSource$` (which implements Spark's 
`org.apache.spark.metrics.source.Source`), so its `metricRegistry()` returns 
`org.apache.hudi.com.codahale.metrics.MetricRegistry` and no longer matches the 
interface descriptor. With `spark.comet.metrics.enabled=true`, 
`MetricsSystem.registerSource` then throws `AbstractMethodError` at 
SparkContext init (its catch handles only IllegalArgumentException). Off by 
default, which is why validation stays green.
   
   Evidence: javap on `comet-spark-spark3.5_2.12-1.0.0` shows `CometSource$ 
implements org.apache.spark.metrics.source.Source` with 
`com.codahale.metrics.*` members, and the released 
`hudi-spark3.5-bundle_2.12-1.0.2` demonstrably rewrites third-party classes 
under this same pattern (`io.prometheus.client.dropwizard.DropwizardExports` 
takes the relocated MetricRegistry). Same bug class as the flink dropwizard 
relocation fix, #18982.
   
   Since Comet itself must not be relocated, please either (a) drop 
`io.dropwizard.metrics:*` from the artifactSet and this `com.codahale.metrics.` 
relocation in this module only, or (b) document under the README "Shading" 
section that `spark.comet.metrics.enabled` is unsupported in this bundle, and 
add that config to validate.sh so the failure mode is pinned.



##########
packaging/bundle-validation/native_spark/validate.scala:
##########
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.spark.sql.SaveMode._
+import org.apache.hudi.DataSourceWriteOptions._
+import org.apache.hudi.config.HoodieWriteConfig._
+
+val outputDir = "/tmp/native-spark-bundle"
+
+// Force a real join rather than a broadcast, so the plan exercises Comet's 
join, shuffle and sort.
+spark.conf.set("spark.sql.autoBroadcastJoinThreshold", "-1")
+
+// Deterministic input, so the query result can be asserted exactly. 300 rows 
spread evenly over
+// three partitions, fare equal to the row id.
+def writeTable(name: String): String = {

Review Comment:
   Validation covers copy-on-write only, but the module README documents 
merge-on-read-specific behavior (`Batched: false`, `CometSparkRowToColumnar` 
per-cell bridging) that nothing exercises. The existing spark-bundle lane does 
validate MOR (`packaging/bundle-validation/validate.sh:158`), so the bar exists.
   
   Please write one of the two tables as MERGE_ON_READ (add the table type 
option plus a second commit so a log file exists), keep the exact-row 
assertion, and assert `CometSparkRowToColumnar` appears in the MOR plan the 
same way `CometSortMergeJoin` is asserted today.



##########
.github/workflows/bot.yml:
##########
@@ -1310,6 +1310,42 @@ jobs:
           HUDI_VERSION=$(mvn help:evaluate -Dexpression=project.version -q 
-DforceStdout)
           ./packaging/bundle-validation/ci_run.sh hudi_docker_java17 
$HUDI_VERSION openjdk17
 
+  validate-native-bundle:
+    runs-on: ubuntu-latest
+    needs: changes
+    strategy:
+      matrix:
+        include:
+          - scalaProfile: 'scala-2.12'
+            sparkProfile: 'spark3.5'
+            sparkRuntime: '3.5.5'

Review Comment:
   nit, feel free to ignore: every other lane's `sparkRuntime` uses the 
`sparkX.Y.Z` grammar (e.g. `'spark3.5.1'`) that the shared `ci_run.sh` 
string-matches on; this one is bare `'3.5.5'`, and the same version is also 
hardcoded as the Dockerfile `ARG` default and in the `ci_run.sh` doc comment. 
Consider naming it `sparkVersion` and keeping the value only here.



##########
packaging/bundle-validation/native_spark/ci_run.sh:
##########
@@ -0,0 +1,56 @@
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##
+# Builds a glibc Java 17 image and validates the native spark bundle inside it.
+#
+# env vars:
+#   SPARK_RUNTIME:        spark version to validate against, e.g. 3.5.5
+#   SPARK_HADOOP_VERSION: hadoop version suffix of the spark distribution, 
defaults to 3
+#   GITHUB_WORKSPACE:     repository root
+##
+set -o errexit
+set -o nounset
+
+SPARK_HADOOP_VERSION=${SPARK_HADOOP_VERSION:-3}
+WORKDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
+CONTAINER_NAME=hudi-native-bundle-validation

Review Comment:
   nit, feel free to ignore: this variable holds an image name, not a container 
name (it is only used as `-t $CONTAINER_NAME:$SPARK_RUNTIME`, and `docker run 
--rm` never names a container). Rename to `IMAGE_NAME`.



##########
packaging/hudi-native-spark-bundle/pom.xml:
##########
@@ -0,0 +1,493 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+  <parent>
+    <artifactId>hudi</artifactId>
+    <groupId>org.apache.hudi</groupId>
+    <version>1.3.0-SNAPSHOT</version>
+    <relativePath>../../pom.xml</relativePath>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  
<artifactId>hudi-native-spark${sparkbundle.version}-bundle_${scala.binary.version}</artifactId>
+  <packaging>jar</packaging>
+
+  <properties>
+    <checkstyle.skip>true</checkstyle.skip>
+    <main.basedir>${project.parent.basedir}</main.basedir>
+    <skipTests>true</skipTests>
+    <javax.servlet.version>3.1.0</javax.servlet.version>
+    <!-- Apache DataFusion Comet releases one artifact per Spark minor 
version, and does not
+         cover every Spark version Hudi builds against. Default to producing 
nothing, so that a
+         build for an uncovered Spark version yields no bundle at all rather 
than one named
+         "native" that carries no native code. The comet-spark<version> 
profiles below opt in. -->
+    <hudi.native.bundle.skip>true</hudi.native.bundle.skip>
+    <hudi.native.bundle.jar.phase>none</hudi.native.bundle.jar.phase>
+    <maven.install.skip>${hudi.native.bundle.skip}</maven.install.skip>
+    <maven.deploy.skip>${hudi.native.bundle.skip}</maven.deploy.skip>
+  </properties>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.rat</groupId>
+        <artifactId>apache-rat-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>default-jar</id>
+            <!-- none when this module produces no bundle. Without it 
maven-jar-plugin still emits
+                 a jar named as if it were a bundle, holding nothing but the 
generated META-INF.
+                 skipIfEmpty does not help: remote-resources populates 
target/classes regardless. -->
+            <phase>${hudi.native.bundle.jar.phase}</phase>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-shade-plugin</artifactId>
+        <version>${maven-shade-plugin.version}</version>
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <goals>
+              <goal>shade</goal>
+            </goals>
+            <configuration>
+              <skip>${hudi.native.bundle.skip}</skip>
+              <createSourcesJar>${shadeSources}</createSourcesJar>
+              
<dependencyReducedPomLocation>${project.build.directory}/dependency-reduced-pom.xml
+              </dependencyReducedPomLocation>
+              <transformers>
+                <transformer 
implementation="org.apache.maven.plugins.shade.resource.ApacheLicenseResourceTransformer"
 />
+                <transformer 
implementation="org.apache.maven.plugins.shade.resource.ApacheNoticeResourceTransformer">
+                  <addHeader>true</addHeader>
+                </transformer>
+                <transformer 
implementation="org.apache.maven.plugins.shade.resource.IncludeResourceTransformer">
+                  <resource>META-INF/LICENSE</resource>
+                  <file>target/classes/META-INF/LICENSE</file>
+                </transformer>
+                <transformer 
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
+                  
<resource>META-INF/services/org.apache.spark.sql.sources.DataSourceRegister</resource>
+                </transformer>
+                <transformer 
implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
+              </transformers>
+              <artifactSet>
+                <includes combine.children="append">
+                  <include>org.apache.hudi:hudi-hadoop-common</include>
+                  <include>org.apache.hudi:hudi-common</include>
+                  <include>org.apache.hudi:hudi-client-common</include>
+                  <include>org.apache.hudi:hudi-spark-client</include>
+                  
<include>org.apache.hudi:hudi-spark-common_${scala.binary.version}</include>
+                  
<include>org.apache.hudi:hudi-spark_${scala.binary.version}</include>
+                  
<include>org.apache.hudi:${hudi.spark.module}_${scala.binary.version}</include>
+                  
<include>org.apache.hudi:${hudi.spark.common.module}</include>
+                  <include>org.apache.hudi:hudi-hive-sync</include>
+                  <include>org.apache.hudi:hudi-sync-common</include>
+                  <include>org.apache.hudi:hudi-hadoop-mr</include>
+                  <include>org.apache.hudi:hudi-timeline-service</include>
+
+                  <!-- NOTE: Comet must never be relocated. Its native library 
is bound through JNI
+                             symbols named Java_org_apache_comet_Native_*, and 
the shared objects are
+                             resolved as classpath resources under 
org/apache/comet/<os>/<arch>/, so a
+                             relocation of org.apache.comet builds cleanly and 
then fails on the first
+                             native call. The same applies to 
org.apache.arrow.c, which Comet carries
+                             unshaded for the Arrow C data interface JNI 
bindings. -->
+                  <include>org.apache.datafusion:*</include>
+
+                  <include>javax.servlet:javax.servlet-api</include>
+                  <include>com.beust:jcommander</include>
+                  <include>io.javalin:javalin</include>
+                  <!-- Spark only has mortbay jetty -->
+                  <include>org.eclipse.jetty:*</include>
+                  <include>org.eclipse.jetty.websocket:*</include>
+                  <include>org.jetbrains.kotlin:*</include>
+                  <include>org.rocksdb:rocksdbjni</include>
+                  <!-- Bundle Jackson JSR310 library since it is not present 
in spark 2.x. For spark 3.x this will
+                       bundle the same JSR310 version that is included in 
spark runtime -->
+                  
<include>com.fasterxml.jackson.datatype:jackson-datatype-jsr310</include>
+                  <include>com.lmax:disruptor</include>
+                  <include>com.github.davidmoten:guava-mini</include>
+                  <include>com.github.davidmoten:hilbert-curve</include>
+                  <include>com.github.ben-manes.caffeine:caffeine</include>
+                  <include>org.apache.parquet:parquet-avro</include>
+                  <include>com.twitter:chill-protobuf</include>
+
+                  <include>io.dropwizard.metrics:metrics-core</include>
+                  <include>io.dropwizard.metrics:metrics-graphite</include>
+                  <include>io.dropwizard.metrics:metrics-jmx</include>
+                  <include>io.prometheus:simpleclient</include>
+                  <include>io.prometheus:simpleclient_httpserver</include>
+                  <include>io.prometheus:simpleclient_dropwizard</include>
+                  <include>io.prometheus:simpleclient_pushgateway</include>
+                  <include>io.prometheus:simpleclient_common</include>
+                  <include>com.uber.m3:tally-m3</include>
+                  <include>com.uber.m3:tally-core</include>
+
+                  <include>org.apache.hive:hive-common</include>
+                  <include>org.apache.hive:hive-service</include>
+                  <include>org.apache.hive:hive-service-rpc</include>
+                  <include>org.apache.hive:hive-metastore</include>
+                  <include>org.apache.hive:hive-jdbc</include>
+
+                  <include>org.apache.curator:curator-framework</include>
+                  <include>org.apache.curator:curator-client</include>
+                  <include>org.apache.curator:curator-recipes</include>
+                  <include>commons-codec:commons-codec</include>
+                  <include>commons-io:commons-io</include>
+                  <include>org.openjdk.jol:jol-core</include>
+                </includes>
+              </artifactSet>
+              <relocations combine.children="append">
+                <!-- NOTE: We have to relocate all classes w/in 
org.apache.spark.sql.avro to avoid
+                           potential classpath collisions in case users would 
like to also use "spark-avro" w/in
+                           their runtime, since Hudi carries some of the same 
classes as "spark-avro" -->
+                <relocation>
+                  <pattern>org.apache.spark.sql.avro.</pattern>
+                  
<shadedPattern>org.apache.hudi.org.apache.spark.sql.avro.</shadedPattern>
+                </relocation>
+                <relocation>
+                  <pattern>javax.servlet.</pattern>
+                  <shadedPattern>org.apache.hudi.javax.servlet.</shadedPattern>
+                </relocation>
+                <relocation>
+                  <pattern>com.beust.jcommander.</pattern>
+                  
<shadedPattern>org.apache.hudi.com.beust.jcommander.</shadedPattern>
+                </relocation>
+                <relocation>
+                  <pattern>org.apache.commons.io.</pattern>
+                  
<shadedPattern>org.apache.hudi.org.apache.commons.io.</shadedPattern>
+                </relocation>
+                <!-- TODO: clean up hive dep - Revisit GH ISSUE #533 & 
PR#633-->
+                <relocation>
+                  <pattern>org.apache.hive.jdbc.</pattern>
+                  
<shadedPattern>${spark.bundle.hive.shade.prefix}org.apache.hive.jdbc.</shadedPattern>
+                </relocation>
+                <relocation>
+                  <pattern>org.apache.hadoop.hive.metastore.</pattern>
+                  
<shadedPattern>${spark.bundle.hive.shade.prefix}org.apache.hadoop.hive.metastore.</shadedPattern>
+                </relocation>
+                <relocation>
+                  <pattern>org.apache.hive.common.</pattern>
+                  
<shadedPattern>${spark.bundle.hive.shade.prefix}org.apache.hive.common.</shadedPattern>
+                </relocation>
+                <relocation>
+                  <pattern>org.apache.hadoop.hive.common.</pattern>
+                  
<shadedPattern>${spark.bundle.hive.shade.prefix}org.apache.hadoop.hive.common.</shadedPattern>
+                </relocation>
+                <relocation>
+                  <pattern>org.apache.hadoop.hive.conf.</pattern>
+                  
<shadedPattern>${spark.bundle.hive.shade.prefix}org.apache.hadoop.hive.conf.</shadedPattern>
+                </relocation>
+                <relocation>
+                  <pattern>org.apache.hive.service.</pattern>
+                  
<shadedPattern>${spark.bundle.hive.shade.prefix}org.apache.hive.service.</shadedPattern>
+                </relocation>
+                <relocation>
+                  <pattern>org.apache.hadoop.hive.service.</pattern>
+                  
<shadedPattern>${spark.bundle.hive.shade.prefix}org.apache.hadoop.hive.service.</shadedPattern>
+                </relocation>
+                <relocation>
+                  <pattern>com.codahale.metrics.</pattern>
+                  
<shadedPattern>org.apache.hudi.com.codahale.metrics.</shadedPattern>
+                </relocation>
+                <relocation>
+                  <pattern>org.apache.commons.codec.</pattern>
+                  
<shadedPattern>org.apache.hudi.org.apache.commons.codec.</shadedPattern>
+                </relocation>
+                <relocation>
+                  <pattern>org.eclipse.jetty.</pattern>
+                  
<shadedPattern>org.apache.hudi.org.apache.jetty.</shadedPattern>
+                </relocation>
+                <relocation>
+                  <pattern>org.openjdk.jol.</pattern>
+                  
<shadedPattern>org.apache.hudi.org.openjdk.jol.</shadedPattern>
+                </relocation>
+                <relocation>
+                  <pattern>com.uber.m3.</pattern>
+                  <shadedPattern>org.apache.hudi.com.uber.m3.</shadedPattern>
+                </relocation>
+              </relocations>
+              <filters>

Review Comment:
   nit, feel free to ignore: the Comet jar ships 
`META-INF/maven/org.apache.arrow/**/pom.properties` (declaring 18.3.0) and 
`META-INF/maven/com.google.guava/guava/pom.properties` (33.2.1-jre) while the 
corresponding classes are relocated under `org/apache/comet/shaded/**` -- the 
version-probe trap `HoodieAvroUtils` was hardened against. Consider adding 
those two `META-INF/maven` paths to the excludes for `org.apache.datafusion:*`.



##########
pom.xml:
##########
@@ -55,6 +55,7 @@
     <module>packaging/hudi-gcp-bundle</module>
     <module>packaging/hudi-azure-bundle</module>
     <module>packaging/hudi-spark-bundle</module>
+    <module>packaging/hudi-native-spark-bundle</module>

Review Comment:
   With the module in the default `<modules>`, every full-reactor CI lane 
already passes `-Dspark3.5`, which activates the Comet profile: an 88 MB Comet 
download plus a ~200 MB uber jar shaded on every PR run (the full-reactor build 
in `test-spark-java-tests`-style jobs, and the Azure jacoco job -- 
`azure-pipelines-20230430.yml:98` excludes `!packaging/hudi-spark-bundle` but 
not this module), with the artifacts also landing in the shared maven caches.
   
   Please gate the module behind a profile so it only enters the reactor when 
explicitly requested; at minimum add `- '!packaging/hudi-native-spark-bundle'` 
to the Azure `jacocoModules` list and exclude it from the full-reactor PR 
builds.



##########
packaging/bundle-validation/native_spark/ci_run.sh:
##########
@@ -0,0 +1,56 @@
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##
+# Builds a glibc Java 17 image and validates the native spark bundle inside it.
+#
+# env vars:
+#   SPARK_RUNTIME:        spark version to validate against, e.g. 3.5.5
+#   SPARK_HADOOP_VERSION: hadoop version suffix of the spark distribution, 
defaults to 3
+#   GITHUB_WORKSPACE:     repository root
+##
+set -o errexit
+set -o nounset
+
+SPARK_HADOOP_VERSION=${SPARK_HADOOP_VERSION:-3}
+WORKDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
+CONTAINER_NAME=hudi-native-bundle-validation
+
+NATIVE_BUNDLE_JAR=$(ls 
${GITHUB_WORKSPACE}/packaging/hudi-native-spark-bundle/target/hudi-native-spark*-bundle_*.jar
 \

Review Comment:
   This glob has no scala-binary filter, and the Dockerfile has no scala-2.13 
tarball branch (the 2.13 Spark distro filename differs; `base/Dockerfile:55-64` 
handles it). `hudi-native-spark3.5-bundle_2.13` is a released coordinate, so a 
future scala-2.13 matrix entry would pick an arbitrary jar here and validate it 
against 2.12 Spark.
   
   Please plumb a `SCALA_VERSION` arg through the glob and the Dockerfile, or 
fail fast when the selected jar name contains `_2.13`.



##########
packaging/bundle-validation/native_spark/Dockerfile:
##########
@@ -0,0 +1,37 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# A glibc image with Java 17, which the native bundle needs and the shared 
bundle-validation base
+# image cannot provide: that one is Alpine based, so its JVMs are musl linked 
and Comet's
+# glibc-linked libcomet.so cannot load into them. Kept separate from the 
shared base image so this
+# does not change how any other bundle is validated.
+FROM eclipse-temurin:17-jdk
+
+ARG SPARK_VERSION=3.5.5
+ARG SPARK_HADOOP_VERSION=3
+
+RUN apt-get update \
+    && apt-get install -y --no-install-recommends wget \
+    && rm -rf /var/lib/apt/lists/*
+
+RUN mkdir /opt/native-bundle-validation
+ENV WORKDIR=/opt/native-bundle-validation
+
+RUN wget -q 
https://archive.apache.org/dist/spark/spark-$SPARK_VERSION/spark-$SPARK_VERSION-bin-hadoop$SPARK_HADOOP_VERSION.tgz
 -P "$WORKDIR" \

Review Comment:
   This pulls a 400 MB Spark tarball from `archive.apache.org` inside a docker 
build that runs on every PR. Every other bundle-validation lane consumes the 
pre-published `apachehudi/hudi-ci-bundle-validation-base` image precisely to 
avoid repeating these downloads, and CI was deliberately moved off the archive 
host in #17723 (it is the ASF cold archive, discouraged for CI).
   
   Also worth noting: `dlcdn.apache.org` no longer carries 3.5.5 (404) but has 
3.5.9, and 3.5.9 is the exact version `comet-spark-spark3.5_2.12:1.0.0` is 
compiled against (its pom declares `spark-sql_2.12:3.5.9` provided), while this 
lane validates 3.5.5.
   
   Please publish a glibc/JDK17 base image alongside 
`packaging/bundle-validation/base` and `FROM` it here; at minimum switch to 
`dlcdn.apache.org` and bump the runtime to Spark 3.5.9.



##########
packaging/hudi-native-spark-bundle/README.md:
##########
@@ -0,0 +1,118 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+# hudi-native-spark-bundle
+
+Everything in `hudi-spark-bundle`, plus [Apache DataFusion 
Comet](https://datafusion.apache.org/comet/)
+for native vectorized execution. Use it in place of `hudi-spark-bundle`, not 
alongside it.

Review Comment:
   Worth adding the sharper co-existence hazard here: since Comet cannot be 
relocated, a cluster- or user-provided `comet-spark-*.jar` at a different 
version gives per-class first-jar-wins resolution across two Comet versions, 
and `libcomet.so` is resolved as a classpath resource 
(`org/apache/comet/<os>/<arch>/`) independently of which classes won, ending in 
`UnsatisfiedLinkError`/`NoSuchMethodError`. This is Hudi's oldest bundle bug 
class (HUDI-1787, HUDI-1797, HUDI-2136, HUDI-7016).
   
   Please add one line: remove any Comet jar from `--jars`/`spark.jars` and the 
cluster's `jars/` directory before using this bundle.



##########
README.md:
##########
@@ -139,6 +139,24 @@ Refer to the table below for building with different Spark 
and Scala versions.
 | `-Dspark4.2`              | hudi-spark4.2-bundle_2.13                    | 
For Spark 4.2 and Scala 2.13 (Needs java 17)     |
 | `-Dspark3`                | hudi-spark3-bundle_2.12 (legacy bundle name) | 
For Spark 3.5.x and Scala 2.12                   |
 
+### Native Spark bundle
+
+`hudi-native-spark-bundle` is `hudi-spark-bundle` plus [Apache DataFusion 
Comet](https://datafusion.apache.org/comet/)
+for native vectorized execution. It is built alongside the Spark bundle for 
the Spark versions Comet
+publishes artifacts for, and produces nothing for the others.
+
+| Maven build options       | Expected native bundle jar name | Notes          
                                |
+|:--------------------------|:--------------------------------|:-----------------------------------------------|
+| `-Dspark3.4`              | hudi-native-spark3.4-bundle_2.12 | For Spark 
3.4.x and Scala 2.12                 |
+| `-Dspark3.5 -Dscala-2.12` | hudi-native-spark3.5-bundle_2.12 | For Spark 
3.5.x and Scala 2.12                 |
+| `-Dspark3.5 -Dscala-2.13` | hudi-native-spark3.5-bundle_2.13 | For Spark 
3.5.x and Scala 2.13                 |
+| `-Dspark4.0`              | hudi-native-spark4.0-bundle_2.13 | For Spark 4.0 
and Scala 2.13                   |
+| `-Dspark4.1`              | hudi-native-spark4.1-bundle_2.13 | For Spark 4.1 
and Scala 2.13                   |
+| `-Dspark3.3`, `-Dspark4.2` | none                            | Comet 
publishes no artifact for these versions |

Review Comment:
   `-Dspark3` (the legacy alias listed in the table above, and a live release 
pass in `deploy_staging_jars.sh`) maps to Spark 3.5/Scala 2.12 but does not 
activate `comet-spark3.5` -- a Maven profile cannot OR two property activators 
-- so it produces no native bundle even though Comet publishes for 3.5. A 
reader of "built alongside the Spark bundle for the Spark versions Comet 
publishes artifacts for" would expect one.
   
   ```suggestion
   | `-Dspark3.3`, `-Dspark4.2` | none                            | Comet 
publishes no artifact for these versions |
   | `-Dspark3`                | none                            | Legacy 
alias; does not activate the Comet profile for 3.5 |
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to