This is an automated email from the ASF dual-hosted git repository.

jackylee-ch pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gluten.git


The following commit(s) were added to refs/heads/main by this push:
     new 32ce0f10c4 [VL] Take Arrow out of the bundle for Spark 4.x and drop 
dead arrow-dataset (#12737)
32ce0f10c4 is described below

commit 32ce0f10c42e3cb150fce4056b35c9208530abab
Author: jackylee <[email protected]>
AuthorDate: Fri Aug 14 21:37:47 2026 +0800

    [VL] Take Arrow out of the bundle for Spark 4.x and drop dead arrow-dataset 
(#12737)
---
 backends-velox/pom.xml                             |  63 ++++++++
 .../org/apache/gluten/fs/ArrowFilesystemTest.java  | 106 --------------
 .../java/org/apache/gluten/fs/CsvWriteSupport.java |  52 -------
 .../java/org/apache/gluten/fs/TestDataset.java     | 117 ---------------
 .../org/apache/gluten/fs/TestNativeDataset.java    |  31 ----
 dev/check-arrow-c-shading.sh                       | 162 ++++++++++++++++++---
 gluten-arrow/pom.xml                               |  49 +++----
 .../memory/arrow/pool/ArrowNativeMemoryPool.java   |  75 ----------
 .../arrow/pool/ArrowReservationListener.java       |  41 ------
 package/pom.xml                                    |  27 +++-
 pom.xml                                            |  43 +++++-
 11 files changed, 284 insertions(+), 482 deletions(-)

diff --git a/backends-velox/pom.xml b/backends-velox/pom.xml
index 2e3aa223d3..8f833020bb 100644
--- a/backends-velox/pom.xml
+++ b/backends-velox/pom.xml
@@ -79,6 +79,69 @@
       <version>${project.version}</version>
       <scope>compile</scope>
     </dependency>
+    <!--
+      Re-declared here because `provided` scope is not transitive: when
+      ${arrow.deps.scope} is `provided` (Spark 4.x), gluten-arrow's Arrow
+      dependencies do not reach this module's compile classpath on their own.
+      Under `compile` (Spark 3.x) these are redundant but harmless.
+
+      The allocator implementation (${arrow-memory.artifact}) is the exception:
+      it is never compiled against, only discovered on the classpath at 
runtime,
+      so it uses ${arrow-memory.scope} (runtime on Spark 3.x, provided on 4.x)
+      rather than ${arrow.deps.scope}.
+    -->
+    <dependency>
+      <groupId>org.apache.arrow</groupId>
+      <artifactId>${arrow-memory.artifact}</artifactId>
+      <version>${arrow.version}</version>
+      <scope>${arrow-memory.scope}</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>io.netty</groupId>
+          <artifactId>netty-common</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>io.netty</groupId>
+          <artifactId>netty-buffer</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.arrow</groupId>
+      <artifactId>arrow-memory-core</artifactId>
+      <version>${arrow.version}</version>
+      <scope>${arrow.deps.scope}</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>io.netty</groupId>
+          <artifactId>netty-common</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>io.netty</groupId>
+          <artifactId>netty-buffer</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.arrow</groupId>
+      <artifactId>arrow-vector</artifactId>
+      <version>${arrow.version}</version>
+      <scope>${arrow.deps.scope}</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>io.netty</groupId>
+          <artifactId>netty-common</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>io.netty</groupId>
+          <artifactId>netty-buffer</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>commons-codec</groupId>
+          <artifactId>commons-codec</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
     <dependency>
       <groupId>com.github.ben-manes.caffeine</groupId>
       <artifactId>caffeine</artifactId>
diff --git 
a/backends-velox/src/test/java/org/apache/gluten/fs/ArrowFilesystemTest.java 
b/backends-velox/src/test/java/org/apache/gluten/fs/ArrowFilesystemTest.java
deleted file mode 100644
index 5dd29856ac..0000000000
--- a/backends-velox/src/test/java/org/apache/gluten/fs/ArrowFilesystemTest.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * 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.
- */
-package org.apache.gluten.fs;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.common.primitives.Primitives;
-import org.apache.arrow.dataset.file.FileFormat;
-import org.apache.arrow.dataset.file.FileSystemDatasetFactory;
-import org.apache.arrow.dataset.jni.NativeMemoryPool;
-import org.apache.arrow.dataset.scanner.ScanOptions;
-import org.apache.arrow.util.AutoCloseables;
-import org.apache.arrow.vector.VectorLoader;
-import org.apache.arrow.vector.VectorSchemaRoot;
-import org.apache.arrow.vector.ipc.message.ArrowRecordBatch;
-import org.apache.arrow.vector.types.pojo.Schema;
-import org.junit.Assert;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import static org.junit.Assert.assertEquals;
-
-public class ArrowFilesystemTest extends TestNativeDataset {
-
-  @ClassRule public static final TemporaryFolder TMP = new TemporaryFolder();
-
-  private void checkParquetReadResult(
-      Schema schema, String expectedJson, List<ArrowRecordBatch> actual) 
throws IOException {
-    final ObjectMapper json = new ObjectMapper();
-    final Set<?> expectedSet = json.readValue(expectedJson, Set.class);
-    final Set<List<Object>> actualSet = new HashSet<>();
-    final int fieldCount = schema.getFields().size();
-    try (VectorSchemaRoot vsr = VectorSchemaRoot.create(schema, 
rootAllocator())) {
-      VectorLoader loader = new VectorLoader(vsr);
-      for (ArrowRecordBatch batch : actual) {
-        System.out.println(batch.toString());
-        loader.load(batch);
-        int batchRowCount = vsr.getRowCount();
-        for (int i = 0; i < batchRowCount; i++) {
-          List<Object> row = new ArrayList<>();
-          for (int j = 0; j < fieldCount; j++) {
-            Object object = vsr.getVector(j).getObject(i);
-            if (Primitives.isWrapperType(object.getClass())) {
-              row.add(object);
-            } else {
-              row.add(object.toString());
-            }
-          }
-          actualSet.add(row);
-        }
-      }
-    }
-    Assert.assertEquals(
-        "Mismatched data read from Parquet, actual: " + 
json.writeValueAsString(actualSet) + ";",
-        expectedSet,
-        actualSet);
-  }
-
-  @Test
-  public void testBaseCsvRead() throws Exception {
-    CsvWriteSupport writeSupport =
-        CsvWriteSupport.writeTempFile(
-            TMP.newFolder(), "Name,Language", "Juno,Java", "Peter,Python", 
"Celin,C++");
-    String expectedJsonUnordered =
-        "[[\"Juno\", \"Java\"], [\"Peter\", \"Python\"], [\"Celin\", 
\"C++\"]]";
-    ScanOptions options = new ScanOptions(100);
-    try (FileSystemDatasetFactory factory =
-        new FileSystemDatasetFactory(
-            rootAllocator(),
-            NativeMemoryPool.getDefault(),
-            FileFormat.CSV,
-            writeSupport.getOutputURI())) {
-      List<ArrowRecordBatch> datum = collectResultFromFactory(factory, 
options);
-      Schema schema = inferResultSchemaFromFactory(factory, options);
-
-      assertScanBatchesProduced(factory, options);
-      assertEquals(1, datum.size());
-      assertEquals(2, schema.getFields().size());
-      assertEquals("Name", schema.getFields().get(0).getName());
-
-      checkParquetReadResult(schema, expectedJsonUnordered, datum);
-
-      AutoCloseables.close(datum);
-    }
-  }
-}
diff --git 
a/backends-velox/src/test/java/org/apache/gluten/fs/CsvWriteSupport.java 
b/backends-velox/src/test/java/org/apache/gluten/fs/CsvWriteSupport.java
deleted file mode 100644
index bcc1cceb9a..0000000000
--- a/backends-velox/src/test/java/org/apache/gluten/fs/CsvWriteSupport.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.
- */
-package org.apache.gluten.fs;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Random;
-
-public class CsvWriteSupport {
-  private final URI uri;
-  private final Random random = new Random();
-
-  public CsvWriteSupport(File outputFolder) throws URISyntaxException {
-    uri =
-        new URI(
-            "file",
-            outputFolder.getPath() + File.separator + "generated-" + 
random.nextLong() + ".csv",
-            null);
-  }
-
-  public static CsvWriteSupport writeTempFile(File outputFolder, String... 
values)
-      throws URISyntaxException, IOException {
-    CsvWriteSupport writer = new CsvWriteSupport(outputFolder);
-    try (FileWriter addValues = new FileWriter(new File(writer.uri), true)) {
-      for (Object value : values) {
-        addValues.write(value + "\n");
-      }
-    }
-    return writer;
-  }
-
-  public String getOutputURI() {
-    return uri.toString();
-  }
-}
diff --git a/backends-velox/src/test/java/org/apache/gluten/fs/TestDataset.java 
b/backends-velox/src/test/java/org/apache/gluten/fs/TestDataset.java
deleted file mode 100644
index f2a1095bb2..0000000000
--- a/backends-velox/src/test/java/org/apache/gluten/fs/TestDataset.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * 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.
- */
-package org.apache.gluten.fs;
-
-import org.apache.arrow.dataset.scanner.ScanOptions;
-import org.apache.arrow.dataset.scanner.Scanner;
-import org.apache.arrow.dataset.source.Dataset;
-import org.apache.arrow.dataset.source.DatasetFactory;
-import org.apache.arrow.memory.RootAllocator;
-import org.apache.arrow.util.AutoCloseables;
-import org.apache.arrow.vector.VectorSchemaRoot;
-import org.apache.arrow.vector.VectorUnloader;
-import org.apache.arrow.vector.ipc.ArrowReader;
-import org.apache.arrow.vector.ipc.message.ArrowRecordBatch;
-import org.apache.arrow.vector.types.pojo.Schema;
-import org.junit.After;
-import org.junit.Before;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Spliterator;
-import java.util.Spliterators;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import java.util.stream.StreamSupport;
-
-public abstract class TestDataset {
-  private RootAllocator allocator = null;
-
-  @Before
-  public void setUp() {
-    allocator = new RootAllocator(Long.MAX_VALUE);
-  }
-
-  @After
-  public void tearDown() {
-    allocator.close();
-  }
-
-  protected RootAllocator rootAllocator() {
-    return allocator;
-  }
-
-  protected List<ArrowRecordBatch> collectResultFromFactory(
-      DatasetFactory factory, ScanOptions options) {
-    final Dataset dataset = factory.finish();
-    final Scanner scanner = dataset.newScan(options);
-    try {
-      final List<ArrowRecordBatch> ret = collectTaskData(scanner);
-      AutoCloseables.close(scanner, dataset);
-      return ret;
-    } catch (RuntimeException e) {
-      throw e;
-    } catch (Exception e) {
-      throw new RuntimeException(e);
-    }
-  }
-
-  protected List<ArrowRecordBatch> collectTaskData(Scanner scan) {
-    try (ArrowReader reader = scan.scanBatches()) {
-      List<ArrowRecordBatch> batches = new ArrayList<>();
-      while (reader.loadNextBatch()) {
-        VectorSchemaRoot root = reader.getVectorSchemaRoot();
-        final VectorUnloader unloader = new VectorUnloader(root);
-        batches.add(unloader.getRecordBatch());
-      }
-      return batches;
-    } catch (IOException e) {
-      throw new RuntimeException(e);
-    }
-  }
-
-  protected Schema inferResultSchemaFromFactory(DatasetFactory factory, 
ScanOptions options) {
-    final Dataset dataset = factory.finish();
-    final Scanner scanner = dataset.newScan(options);
-    final Schema schema = scanner.schema();
-    try {
-      AutoCloseables.close(scanner, dataset);
-    } catch (Exception e) {
-      throw new RuntimeException(e);
-    }
-    return schema;
-  }
-
-  protected <T> Stream<T> stream(Iterable<T> iterable) {
-    return StreamSupport.stream(iterable.spliterator(), false);
-  }
-
-  protected <T> List<T> collect(Iterable<T> iterable) {
-    return stream(iterable).collect(Collectors.toList());
-  }
-
-  protected <T> Stream<T> stream(Iterator<T> iterator) {
-    return StreamSupport.stream(
-        Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), 
false);
-  }
-
-  protected <T> List<T> collect(Iterator<T> iterator) {
-    return stream(iterator).collect(Collectors.toList());
-  }
-}
diff --git 
a/backends-velox/src/test/java/org/apache/gluten/fs/TestNativeDataset.java 
b/backends-velox/src/test/java/org/apache/gluten/fs/TestNativeDataset.java
deleted file mode 100644
index b06fa3c606..0000000000
--- a/backends-velox/src/test/java/org/apache/gluten/fs/TestNativeDataset.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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.
- */
-package org.apache.gluten.fs;
-
-import org.apache.arrow.dataset.scanner.ScanOptions;
-import org.apache.arrow.dataset.scanner.Scanner;
-import org.apache.arrow.dataset.source.Dataset;
-import org.apache.arrow.dataset.source.DatasetFactory;
-import org.junit.Assert;
-
-public abstract class TestNativeDataset extends TestDataset {
-  protected void assertScanBatchesProduced(DatasetFactory factory, ScanOptions 
options) {
-    final Dataset dataset = factory.finish();
-    final Scanner scanner = dataset.newScan(options);
-    Assert.assertNotNull(scanner.scanBatches());
-  }
-}
diff --git a/dev/check-arrow-c-shading.sh b/dev/check-arrow-c-shading.sh
index 620407603e..51504867d1 100755
--- a/dev/check-arrow-c-shading.sh
+++ b/dev/check-arrow-c-shading.sh
@@ -14,34 +14,65 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-# Verify the bundled gluten-velox jar's Arrow C-Data classes have method
-# signatures referencing the *unshaded* org.apache.arrow.memory.BufferAllocator
-# and org.apache.arrow.vector.* types — not the gluten-shaded copies.
+# Verify the bundled gluten-velox jar's Arrow C-Data classes reference the
+# *unshaded* Apache Arrow API — both in their method signatures and in their
+# constant pools.
 #
 # Background: org.apache.arrow.c.* must NOT be relocated (its native JNI binds
-# to the original class names), but its public API methods accept/return
-# org.apache.arrow.memory.* and org.apache.arrow.vector.* types. Those types
-# must therefore also stay unshaded in the bundle, otherwise the bundled
-# ArrowArrayStream/ArrowSchema get re-bound to the shaded BufferAllocator at
-# compile time and any caller passing a vanilla Apache Arrow allocator hits
-# `NoSuchMethodError`. See gluten#12225.
+# to the original class names), but it reaches into three other Arrow packages:
+# org.apache.arrow.memory.*, org.apache.arrow.vector.* (public signatures) and
+# org.apache.arrow.util.* (internal calls — Preconditions, AutoCloseables,
+# Collections2). All three must stay unshaded in the bundle:
+#
+#   - a shaded *signature* type re-binds the bundled 
ArrowArrayStream/ArrowSchema
+#     so any caller passing a vanilla Apache Arrow allocator hits
+#     `NoSuchMethodError` (gluten#12225);
+#   - a shaded *constant-pool* reference is worse when Arrow is no longer
+#     bundled at all: the shaded target does not exist anywhere on the
+#     classpath and the call site throws `ClassNotFoundException`.
 #
 # Usage:
-#   dev/check-arrow-c-shading.sh <path-to-gluten-velox-bundle.jar>
+#   dev/check-arrow-c-shading.sh <path-to-gluten-velox-bundle.jar> \
+#     [shade-package-name] [arrow-deps-scope]
+#
+# The shade package name defaults to org.apache.gluten.shaded and is passed by
+# package/pom.xml as ${gluten.shade.packageName}. Keep it parameterized: if 
this
+# script hard-coded the prefix and the Maven property were ever changed, both
+# checks below would silently match nothing and the whole guard would pass
+# vacuously.
+#
+# The arrow-deps-scope is the value of the Maven property ${arrow.deps.scope}
+# and drives the bundle-content assertion:
+#   - `compile`   (Spark 3.x): gluten ships its own Arrow inside the bundle, so
+#                              arrow-memory / arrow-vector classes MUST be
+#                              present (the bundle is self-contained).
+#   - `provided`  (Spark 4.x): Arrow is expected to come from the Spark
+#                              distribution at runtime, so those packages MUST
+#                              NOT be inside the bundle (otherwise the bundle
+#                              has silently regressed to shipping its own 
copy).
+# Any other value is not asserted against.
 #
 # Exit codes:
-#   0 — bundle is well-shaded (Arrow C-Data API uses public Apache Arrow types)
-#   1 — bundle is broken (Arrow C-Data API references gluten-shaded types)
+#   0 — bundle is well-shaded (Arrow C-Data API uses public Apache Arrow API)
+#   1 — bundle is broken (Arrow C-Data references gluten-shaded types, OR
+#       Arrow content does not match the declared arrow-deps-scope)
 #   2 — usage / setup error
 
 set -euo pipefail
 
-JAR="${1:?usage: $0 <path-to-gluten-velox-bundle.jar>}"
+JAR="${1:?usage: $0 <path-to-gluten-velox-bundle.jar> [shade-package-name] 
[arrow-deps-scope]}"
 if [[ ! -f "$JAR" ]]; then
   echo "error: jar not found: $JAR" >&2
   exit 2
 fi
 
+# Dotted form for javap signatures, slashed form for JVM internal names in
+# constant pools. `.` is escaped so the dotted form is a literal regex.
+SHADE_PACKAGE="${2:-org.apache.gluten.shaded}"
+SHADE_DOTS_RE="${SHADE_PACKAGE//./\\.}"
+SHADE_SLASHES="${SHADE_PACKAGE//.//}"
+ARROW_DEPS_SCOPE="${3:-}"
+
 if ! command -v javap >/dev/null; then
   echo "error: javap not found on PATH" >&2
   exit 2
@@ -59,14 +90,22 @@ CLASSES=(
 )
 
 failures=0
+# Track whether the bundle actually contains any org.apache.arrow.c.* class.
+# When it doesn't, this jar is not the velox bundle (e.g. the intermediate
+# jar-plugin output built without the data-lake profiles that would pull Arrow
+# into the shade artifactSet), and the bundle-content assertion below has
+# nothing to say about it. The two shading checks are already SKIP-safe in
+# that case; the content assertion has to be too.
+cdata_present=0
 for cls in "${CLASSES[@]}"; do
   if ! unzip -p "$JAR" "${cls}.class" > "$WORKDIR/$(basename "$cls").class" 
2>/dev/null; then
     echo "  SKIP $cls (not in bundle)"
     continue
   fi
+  cdata_present=1
   signatures=$(javap -p "$WORKDIR/$(basename "$cls").class" 2>/dev/null || 
true)
-  # Any method signature mentioning the gluten-shaded Arrow path is the bug.
-  bad=$(echo "$signatures" | grep -E 
"org\.apache\.gluten\.shaded\.org\.apache\.arrow\.(memory|vector)\." || true)
+  # Any method signature mentioning the shaded Arrow path is the bug.
+  bad=$(echo "$signatures" | grep -E 
"${SHADE_DOTS_RE}\.org\.apache\.arrow\.(memory|vector)\." || true)
   if [[ -n "$bad" ]]; then
     echo "  FAIL $cls — public API references gluten-shaded Arrow types:"
     echo "$bad" | sed 's/^/    /'
@@ -76,12 +115,97 @@ for cls in "${CLASSES[@]}"; do
   fi
 done
 
+# Second check: no class under org/apache/arrow/c/ may *call* a shaded Arrow
+# class. Signatures alone miss org.apache.arrow.util.Preconditions & friends,
+# which are invoked from constructors but never appear in a descriptor.
+#
+# Both org.apache.arrow.c.* and org.apache.arrow.c.jni.* are excluded from
+# relocation in package/pom.xml, so both are scanned. The jni subpackage is
+# named explicitly rather than relying on `unzip` treating `c/*` as recursive —
+# that is implementation-defined, and the existence check below would otherwise
+# see an empty top level and skip the scan entirely.
+#
+# The name pattern covers every character legal in a JVM internal name after 
the
+# package prefix: identifier chars (letters, digits, `_`, `$`), `/` for nested
+# packages, and `-` for the synthetic `package-info` / `module-info` entries.
+mkdir -p "$WORKDIR/all"
+unzip -qo "$JAR" 'org/apache/arrow/c/*' 'org/apache/arrow/c/jni/*' \
+  -d "$WORKDIR/all" 2>/dev/null || true
+if compgen -G "$WORKDIR/all/org/apache/arrow/c/**/*.class" > /dev/null ||
+   compgen -G "$WORKDIR/all/org/apache/arrow/c/*.class" > /dev/null; then
+  cdata_present=1
+  refs=$(grep -rahoE "${SHADE_SLASHES}/org/apache/arrow/[a-zA-Z0-9_$/-]+" \
+    "$WORKDIR/all/org/apache/arrow/c" 2>/dev/null | sort -u || true)
+  if [[ -n "$refs" ]]; then
+    echo "  FAIL org/apache/arrow/c/** — calls into gluten-shaded Arrow:"
+    echo "$refs" | sed 's/^/    /'
+    failures=$((failures + 1))
+  else
+    echo "  OK   org/apache/arrow/c/** constant pools"
+  fi
+fi
+
+# Third check: the bundle's Arrow content must match ${arrow.deps.scope}.
+# This is the regression guard for #12737 — if any Arrow dependency ever slips
+# from `provided`/`runtime` back to `compile` on a Spark 4.x profile, the 
memory
+# and vector packages silently re-enter the bundle, undoing the size win and
+# re-introducing the Spark-vs-gluten Arrow version conflict. Assert directly on
+# the jar contents so the mistake fails the build instead of shipping.
+#
+# Gated on arrow-c-data being present. Whether Arrow lands in the jar at all is
+# a function of the dependency closure and the shade artifactSet, not just of
+# ${arrow.deps.scope}: `mvn install -Pspark-3.5 -Pbackends-velox` (no data-lake
+# profiles) produces an intermediate jar with no Arrow whatsoever. arrow-c-data
+# is bundled on every profile precisely because Spark never ships it, so its
+# presence is the reliable marker for "this is the velox bundle". Without that
+# gate, the `compile` branch below fires on jars that were never meant to carry
+# Arrow at all.
+if [[ -n "$ARROW_DEPS_SCOPE" && "$cdata_present" -eq 0 ]]; then
+  echo "  SKIP bundle-content assertion (no org.apache.arrow.c.* in jar —"
+  echo "       not a velox bundle, so its Arrow content is not asserted)"
+elif [[ -n "$ARROW_DEPS_SCOPE" ]]; then
+  # arrow-memory-core / arrow-vector classes, excluding the always-bundled
+  # org.apache.arrow.c.* (arrow-c-data) which Spark never ships.
+  arrow_impl=$(unzip -l "$JAR" 2>/dev/null \
+    | grep -oE "org/apache/arrow/(memory|vector)/[^ ]*\.class" | sort -u || 
true)
+  impl_count=$(printf '%s' "$arrow_impl" | grep -c . || true)
+  case "$ARROW_DEPS_SCOPE" in
+    provided)
+      if [[ "$impl_count" -gt 0 ]]; then
+        echo "  FAIL bundle content — arrow.deps.scope=provided but the bundle"
+        echo "       still ships $impl_count arrow-memory/arrow-vector 
class(es):"
+        printf '%s\n' "$arrow_impl" | head -5 | sed 's/^/    /'
+        echo "    A dependency likely regressed to compile scope. Arrow must 
come"
+        echo "    from the Spark distribution at runtime on Spark 4.x."
+        failures=$((failures + 1))
+      else
+        echo "  OK   bundle carries no arrow-memory/arrow-vector 
(scope=provided)"
+      fi
+      ;;
+    compile)
+      if [[ "$impl_count" -eq 0 ]]; then
+        echo "  FAIL bundle content — arrow.deps.scope=compile but the bundle"
+        echo "       ships no arrow-memory/arrow-vector classes; the 
self-contained"
+        echo "       bundle is incomplete and will fail to allocate Arrow 
buffers."
+        failures=$((failures + 1))
+      else
+        echo "  OK   bundle carries arrow-memory/arrow-vector (scope=compile)"
+      fi
+      ;;
+    *)
+      echo "  SKIP bundle-content assertion (unrecognized 
arrow.deps.scope='$ARROW_DEPS_SCOPE')"
+      ;;
+  esac
+fi
+
 if (( failures > 0 )); then
   echo
-  echo "Bundle has $failures Arrow C-Data class(es) with shaded API types."
-  echo "See gluten#12225 for context. Update package/pom.xml's"
-  echo "<relocation org.apache.arrow> excludes to also exclude"
-  echo "org.apache.arrow.memory.** and org.apache.arrow.vector.**."
+  echo "Bundle has $failures Arrow shading/content problem(s)."
+  echo "For shading failures, see gluten#12225 and update package/pom.xml's"
+  echo "<relocation org.apache.arrow> excludes so every package reachable"
+  echo "from org.apache.arrow.c stays unshaded (memory, vector, util)."
+  echo "For content failures, see gluten#12737 and check each Arrow"
+  echo "dependency's <scope> against \${arrow.deps.scope} for this profile."
   exit 1
 fi
 
diff --git a/gluten-arrow/pom.xml b/gluten-arrow/pom.xml
index d08d997ed2..435e967685 100644
--- a/gluten-arrow/pom.xml
+++ b/gluten-arrow/pom.xml
@@ -89,13 +89,23 @@
       <groupId>org.apache.arrow</groupId>
       <artifactId>${arrow-memory.artifact}</artifactId>
       <version>${arrow.version}</version>
-      <scope>runtime</scope>
+      <scope>${arrow-memory.scope}</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>io.netty</groupId>
+          <artifactId>netty-common</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>io.netty</groupId>
+          <artifactId>netty-buffer</artifactId>
+        </exclusion>
+      </exclusions>
     </dependency>
     <dependency>
       <groupId>org.apache.arrow</groupId>
       <artifactId>arrow-memory-core</artifactId>
       <version>${arrow.version}</version>
-      <scope>compile</scope>
+      <scope>${arrow.deps.scope}</scope>
       <exclusions>
         <exclusion>
           <groupId>io.netty</groupId>
@@ -111,6 +121,7 @@
       <groupId>org.apache.arrow</groupId>
       <artifactId>arrow-vector</artifactId>
       <version>${arrow.version}</version>
+      <scope>${arrow.deps.scope}</scope>
       <exclusions>
         <exclusion>
           <groupId>io.netty</groupId>
@@ -132,37 +143,19 @@
       <version>${arrow.version}</version>
       <scope>compile</scope>
       <exclusions>
+        <!--
+          arrow-vector / arrow-memory-core are declared above with
+          ${arrow.deps.scope}; keep them out of this artifact's transitive
+          closure so they cannot re-enter at compile scope and land in the
+          shaded bundle when the scope is `provided`.
+        -->
         <exclusion>
           <groupId>org.apache.arrow</groupId>
           <artifactId>arrow-vector</artifactId>
         </exclusion>
         <exclusion>
-          <groupId>com.google.protobuf</groupId>
-          <artifactId>protobuf-java</artifactId>
-        </exclusion>
-      </exclusions>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.arrow</groupId>
-      <artifactId>arrow-dataset</artifactId>
-      <version>${arrow.version}</version>
-      <scope>compile</scope>
-      <exclusions>
-        <exclusion>
-          <groupId>io.netty</groupId>
-          <artifactId>netty-common</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>io.netty</groupId>
-          <artifactId>netty-buffer</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>com.fasterxml.jackson.core</groupId>
-          <artifactId>jackson-core</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>com.fasterxml.jackson.core</groupId>
-          <artifactId>jackson-annotations</artifactId>
+          <groupId>org.apache.arrow</groupId>
+          <artifactId>arrow-memory-core</artifactId>
         </exclusion>
         <exclusion>
           <groupId>com.google.protobuf</groupId>
diff --git 
a/gluten-arrow/src/main/java/org/apache/gluten/memory/arrow/pool/ArrowNativeMemoryPool.java
 
b/gluten-arrow/src/main/java/org/apache/gluten/memory/arrow/pool/ArrowNativeMemoryPool.java
deleted file mode 100644
index f1aa6149f9..0000000000
--- 
a/gluten-arrow/src/main/java/org/apache/gluten/memory/arrow/pool/ArrowNativeMemoryPool.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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.
- */
-package org.apache.gluten.memory.arrow.pool;
-
-import org.apache.arrow.dataset.jni.NativeMemoryPool;
-import org.apache.spark.task.TaskResource;
-import org.apache.spark.task.TaskResources;
-import org.apache.spark.util.Utils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ArrowNativeMemoryPool implements TaskResource {
-  private static final Logger LOGGER = 
LoggerFactory.getLogger(ArrowNativeMemoryPool.class);
-
-  private final NativeMemoryPool arrowPool;
-  private final ArrowReservationListener listener;
-
-  public ArrowNativeMemoryPool() {
-    listener = new ArrowReservationListener(TaskResources.getSharedUsage());
-    arrowPool = NativeMemoryPool.createListenable(listener);
-  }
-
-  public static NativeMemoryPool arrowPool(String name) {
-    if (!TaskResources.inSparkTask()) {
-      throw new IllegalStateException("This method must be called in a Spark 
task.");
-    }
-    String id = "ArrowNativeMemoryPool:" + name;
-    return TaskResources.addResourceIfNotRegistered(id, () -> 
createArrowNativeMemoryPool(name))
-        .getArrowPool();
-  }
-
-  private static ArrowNativeMemoryPool createArrowNativeMemoryPool(String 
name) {
-    return new ArrowNativeMemoryPool();
-  }
-
-  @Override
-  public void release() throws Exception {
-    if (arrowPool.getBytesAllocated() != 0) {
-      LOGGER.warn(
-          String.format(
-              "Arrow pool still reserved non-zero bytes, "
-                  + "which may cause memory leak, size: %s. ",
-              Utils.bytesToString(arrowPool.getBytesAllocated())));
-    }
-    arrowPool.close();
-  }
-
-  @Override
-  public int priority() {
-    return 10;
-  }
-
-  @Override
-  public String resourceName() {
-    return "arrow_mem";
-  }
-
-  public NativeMemoryPool getArrowPool() {
-    return arrowPool;
-  }
-}
diff --git 
a/gluten-arrow/src/main/java/org/apache/gluten/memory/arrow/pool/ArrowReservationListener.java
 
b/gluten-arrow/src/main/java/org/apache/gluten/memory/arrow/pool/ArrowReservationListener.java
deleted file mode 100644
index 2e1a254453..0000000000
--- 
a/gluten-arrow/src/main/java/org/apache/gluten/memory/arrow/pool/ArrowReservationListener.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.
- */
-package org.apache.gluten.memory.arrow.pool;
-
-import org.apache.gluten.memory.SimpleMemoryUsageRecorder;
-
-public class ArrowReservationListener implements 
org.apache.arrow.dataset.jni.ReservationListener {
-  private final SimpleMemoryUsageRecorder sharedUsage; // shared task metrics
-
-  public ArrowReservationListener(SimpleMemoryUsageRecorder recorder) {
-    this.sharedUsage = recorder;
-  }
-
-  @Override
-  public void reserve(long size) {
-    synchronized (this) {
-      sharedUsage.inc(size);
-    }
-  }
-
-  @Override
-  public void unreserve(long size) {
-    synchronized (this) {
-      sharedUsage.inc(-size);
-    }
-  }
-}
diff --git a/package/pom.xml b/package/pom.xml
index 513a3352bd..cee31a8ecf 100644
--- a/package/pom.xml
+++ b/package/pom.xml
@@ -122,22 +122,31 @@
                   <pattern>org.apache.arrow</pattern>
                   
<shadedPattern>${gluten.shade.packageName}.org.apache.arrow</shadedPattern>
                   <!--
-                    arrow's C and dataset wrappers refer to the original class
-                    path, so they must not be relocated. Their public APIs also
-                    take and return org.apache.arrow.memory.* and
-                    org.apache.arrow.vector.* types, so those packages must 
also
-                    stay unshaded — otherwise the bundled (unshaded)
-                    ArrowArrayStream/ArrowSchema get compiled against the
-                    relocated BufferAllocator/VectorSchemaRoot, producing
+                    arrow's C wrapper refers to the original class path, so it
+                    must not be relocated. Its public APIs also take and return
+                    org.apache.arrow.memory.* and org.apache.arrow.vector.*
+                    types, so those packages must also stay unshaded —
+                    otherwise the bundled (unshaded) 
ArrowArrayStream/ArrowSchema
+                    get compiled against the relocated
+                    BufferAllocator/VectorSchemaRoot, producing
                     `NoSuchMethodError` for any caller passing a vanilla
                     Apache Arrow allocator. See #12225.
+
+                    org.apache.arrow.util.** is the fourth and last package
+                    org.apache.arrow.c reaches: Preconditions.checkNotNull from
+                    the ArrowArray/ArrowSchema constructors, plus 
AutoCloseables
+                    and Collections2 from the import/export paths. It is not 
part
+                    of the public signature so it survived #12225, but the call
+                    sites live in the constant pool of the unshaded classes all
+                    the same, and there is no unshaded copy to bind to once
+                    arrow-memory-core stops being bundled.
                   -->
                   <excludes>
                     <exclude>org.apache.arrow.c.*</exclude>
                     <exclude>org.apache.arrow.c.jni.*</exclude>
                     <exclude>org.apache.arrow.memory.**</exclude>
                     <exclude>org.apache.arrow.vector.**</exclude>
-                    <exclude>org.apache.arrow.dataset.**</exclude>
+                    <exclude>org.apache.arrow.util.**</exclude>
                   </excludes>
                 </relocation>
                 <relocation>
@@ -341,6 +350,8 @@
               
<executable>${project.basedir}/../dev/check-arrow-c-shading.sh</executable>
               <arguments>
                 
<argument>${project.build.directory}/${project.build.finalName}.jar</argument>
+                <argument>${gluten.shade.packageName}</argument>
+                <argument>${arrow.deps.scope}</argument>
               </arguments>
             </configuration>
           </execution>
diff --git a/pom.xml b/pom.xml
index 6ea3e03b12..69adaaed86 100644
--- a/pom.xml
+++ b/pom.xml
@@ -82,6 +82,31 @@
     <uniffle.version>0.10.0</uniffle.version>
     <arrow.version>15.0.0</arrow.version>
     <arrow-memory.artifact>arrow-memory-unsafe</arrow-memory.artifact>
+    <!--
+      Scope of gluten's Arrow dependencies. `compile` means gluten ships its 
own
+      Arrow inside the bundle jar; `provided` means the Spark distribution on 
the
+      runtime classpath owns Arrow and gluten only compiles against it. Spark 
4.x
+      already ships an Arrow new enough for gluten, so those profiles switch to
+      `provided`.
+    -->
+    <arrow.deps.scope>compile</arrow.deps.scope>
+    <!--
+      Scope of the Arrow allocator *implementation* (${arrow-memory.artifact}).
+      Gluten never compiles against it — `CheckAllocator` discovers it by
+      scanning the classpath at runtime — so it stays out of the compile scope
+      and off downstream modules' compile classpaths. `runtime` still lands it
+      in the shaded bundle; Spark 4.x overrides this with `provided` so Spark's
+      own allocator is used instead.
+    -->
+    <arrow-memory.scope>runtime</arrow-memory.scope>
+    <!--
+      groupId used in the Arrow <exclusion>s on the Spark dependencies below.
+      Set to `org.apache.arrow` (the real groupId) the exclusions apply, so
+      gluten's own bundled Arrow wins. Profiles that use `provided` Arrow
+      override this with a groupId that matches nothing, letting Spark's Arrow
+      through instead.
+    -->
+    
<spark.arrow.exclusion.groupId>org.apache.arrow</spark.arrow.exclusion.groupId>
     <hadoop.version>2.7.4</hadoop.version>
     <antlr4.version>4.9.3</antlr4.version>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -186,7 +211,7 @@
         <scope>provided</scope>
         <exclusions>
           <exclusion>
-            <groupId>org.apache.arrow</groupId>
+            <groupId>${spark.arrow.exclusion.groupId}</groupId>
             <artifactId>arrow-vector</artifactId>
           </exclusion>
           <exclusion>
@@ -242,7 +267,7 @@
         <scope>provided</scope>
         <exclusions>
           <exclusion>
-            <groupId>org.apache.arrow</groupId>
+            <groupId>${spark.arrow.exclusion.groupId}</groupId>
             <artifactId>*</artifactId>
           </exclusion>
         </exclusions>
@@ -339,7 +364,7 @@
         <scope>test</scope>
         <exclusions>
           <exclusion>
-            <groupId>org.apache.arrow</groupId>
+            <groupId>${spark.arrow.exclusion.groupId}</groupId>
             <artifactId>*</artifactId>
           </exclusion>
         </exclusions>
@@ -352,7 +377,7 @@
         <scope>test</scope>
         <exclusions>
           <exclusion>
-            <groupId>org.apache.arrow</groupId>
+            <groupId>${spark.arrow.exclusion.groupId}</groupId>
             <artifactId>*</artifactId>
           </exclusion>
           <exclusion>
@@ -1302,6 +1327,10 @@
         <log4j.version>2.24.3</log4j.version>
         <commons-lang3.version>3.17.0</commons-lang3.version>
         <arrow.version>18.1.0</arrow.version>
+        <arrow.deps.scope>provided</arrow.deps.scope>
+        <arrow-memory.scope>provided</arrow-memory.scope>
+        <!-- Matches no groupId: let Spark's own Arrow through. -->
+        <spark.arrow.exclusion.groupId>none</spark.arrow.exclusion.groupId>
         <scala.compiler.version>4.9.2</scala.compiler.version>
       </properties>
       <dependencies>
@@ -1380,7 +1409,11 @@
         <slf4j.version>2.0.16</slf4j.version>
         <log4j.version>2.24.3</log4j.version>
         <commons-lang3.version>3.17.0</commons-lang3.version>
-        <arrow.version>18.1.0</arrow.version>
+        <arrow.version>18.3.0</arrow.version>
+        <arrow.deps.scope>provided</arrow.deps.scope>
+        <arrow-memory.scope>provided</arrow-memory.scope>
+        <!-- Matches no groupId: let Spark's own Arrow through. -->
+        <spark.arrow.exclusion.groupId>none</spark.arrow.exclusion.groupId>
         <scala.compiler.version>4.9.5</scala.compiler.version>
       </properties>
       <dependencies>


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to