blob: 7279a130789914aea1a4fb75d65ca03b01923d9c [file]
# 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.
# Reusable Spark SQL test workflow. Invoked once per Spark version by the
# spark_sql_test_<version>.yml caller workflows. Keep all job logic here so
# the per-version callers stay thin.
name: Spark SQL Tests (reusable)
on:
workflow_call:
inputs:
spark-short:
description: 'Spark minor version, e.g. 3.5'
required: true
type: string
spark-full:
description: 'Spark full version, e.g. 3.5.8'
required: true
type: string
java:
description: 'JDK major version, e.g. 17'
required: true
type: number
collect-fallback-logs:
description: 'Whether to collect Comet fallback reasons from spark sql unit test logs'
required: false
default: false
type: boolean
env:
RUST_VERSION: stable
RUST_BACKTRACE: 1
# Force GNU ld on Linux: recent Rust stable defaults to rust-lld on
# x86_64-unknown-linux-gnu, and rust-lld cannot resolve -ljvm against the
# Zulu JDK layout installed by setup-java. Keep bfd for all cargo invocations.
RUSTFLAGS: "-Clink-arg=-fuse-ld=bfd"
jobs:
# Build the native library AND pre-compile Spark sources + Test classes in a
# single runner, then publish two artifacts the matrix consumes:
# - native-lib-linux: libcomet.so (~50 MB)
# - jvm-compiled-spark-<full>-jdk<N>: apache-spark.tar.gz (sources +
# target/ + Zinc state, ~500 MB-1 GB)
# Combining them avoids a second runner cold-start and an extra inter-job
# artifact round-trip for the native lib, since the JVM build already
# depends on it (the Comet Maven install bundles libcomet.so into the
# Comet JAR before SBT resolves Spark's classpath).
build:
name: Build Native + JVM Test Classes
runs-on: ubuntu-24.04
container:
image: amd64/rust
steps:
- uses: actions/checkout@v7
- name: Setup Rust & Java toolchain
uses: ./.github/actions/setup-builder
with:
rust-version: ${{ env.RUST_VERSION }}
jdk-version: ${{ inputs.java }}
- name: Restore Cargo cache
uses: actions/cache/restore@v6
with:
path: |
~/.cargo/registry
~/.cargo/git
native/target
key: ${{ runner.os }}-cargo-ci-${{ hashFiles('native/**/Cargo.lock', 'native/**/Cargo.toml') }}-${{ hashFiles('native/**/*.rs') }}
restore-keys: |
${{ runner.os }}-cargo-ci-${{ hashFiles('native/**/Cargo.lock', 'native/**/Cargo.toml') }}-
- name: Build native library (CI profile)
run: |
cd native
cargo build --profile ci
env:
RUSTFLAGS: "-Ctarget-cpu=x86-64-v3 -Clink-arg=-fuse-ld=bfd"
- name: Save Cargo cache
uses: actions/cache/save@v6
if: github.ref == 'refs/heads/main'
with:
path: |
~/.cargo/registry
~/.cargo/git
native/target
key: ${{ runner.os }}-cargo-ci-${{ hashFiles('native/**/Cargo.lock', 'native/**/Cargo.toml') }}-${{ hashFiles('native/**/*.rs') }}
- name: Upload native library
uses: actions/upload-artifact@v7
with:
name: native-lib-linux
path: native/target/ci/libcomet.so
retention-days: 1
- name: Stage native library at release path
run: |
# setup-spark-builder's `mvnw install -DskipTests` (skip-native-build
# path) bundles native/target/release/libcomet.so into the Comet JAR.
# We built with --profile ci to avoid LTO, so the file lives at
# native/target/ci/. Copy it to where the Maven build expects it.
mkdir -p native/target/release
cp native/target/ci/libcomet.so native/target/release/libcomet.so
- name: Setup Spark
uses: ./.github/actions/setup-spark-builder
with:
spark-version: ${{ inputs.spark-full }}
spark-short-version: ${{ inputs.spark-short }}
skip-native-build: true
- name: Pre-compile Spark Test classes
run: |
cd apache-spark
# Mirror the workaround from `Run Spark tests` below: Comet's mvn
# install populates partial Parquet entries (main JAR + POM but no
# `*-tests.jar` classifier). Coursier then sees the POM in
# mavenLocal, declares the artifact "found locally", and refuses
# to fall back to Maven Central for the missing test classifier.
# Wiping the parquet cache forces a clean remote fetch.
rm -rf /root/.m2/repository/org/apache/parquet
# Compile Test sources for the three subprojects the matrix touches.
# SBT will transitively compile Compile/compile of their dependencies
# plus any Test/compile pulled in by `dependsOn(... % "test->test")`,
# which is enough to satisfy `sql/testOnly`, `hive/testOnly`, and
# `catalyst/test` in the downstream test jobs.
NOLINT_ON_COMPILE=true build/sbt -Dsbt.log.noformat=true -mem 3072 \
'catalyst/Test/compile' \
'sql/Test/compile' \
'hive/Test/compile'
- name: Pack apache-spark/ (sources + compiled output)
run: |
# Preserve mtimes so Zinc's incremental analysis still recognises
# the compiled output as up-to-date in the test jobs. Exclude .git
# because we don't need history downstream and it adds size.
tar -czpf apache-spark.tar.gz \
--exclude='apache-spark/.git' \
apache-spark
- name: Upload JVM compile artifact
uses: actions/upload-artifact@v7
with:
name: jvm-compiled-spark-${{ inputs.spark-full }}-jdk${{ inputs.java }}
path: apache-spark.tar.gz
retention-days: 1
spark-sql-test:
needs: build
strategy:
matrix:
module:
- {name: "catalyst", args1: "catalyst/test", args2: ""}
# sql_core-* set HEAP_SIZE / METASPACE_SIZE so SparkBuild.scala caps
- {name: "sql_core-1", args1: "", args2: "sql/testOnly * -- -l org.apache.spark.tags.ExtendedSQLTest -l org.apache.spark.tags.SlowSQLTest", heap: "3g", metaspace: "1g"}
- {name: "sql_core-2", args1: "", args2: "sql/testOnly * -- -n org.apache.spark.tags.ExtendedSQLTest", heap: "3g", metaspace: "1g"}
- {name: "sql_core-3", args1: "", args2: "sql/testOnly * -- -n org.apache.spark.tags.SlowSQLTest", heap: "3g", metaspace: "1g"}
- {name: "sql_hive-1", args1: "", args2: "hive/testOnly * -- -l org.apache.spark.tags.ExtendedHiveTest -l org.apache.spark.tags.SlowHiveTest"}
- {name: "sql_hive-2", args1: "", args2: "hive/testOnly * -- -n org.apache.spark.tags.ExtendedHiveTest"}
- {name: "sql_hive-3", args1: "", args2: "hive/testOnly * -- -n org.apache.spark.tags.SlowHiveTest"}
fail-fast: false
name: spark-sql-${{ matrix.module.name }}/spark-${{ inputs.spark-full }}-jdk${{ inputs.java }}
runs-on: ubuntu-24.04
container:
image: amd64/rust
steps:
- uses: actions/checkout@v7
- name: Setup Rust & Java toolchain
uses: ./.github/actions/setup-builder
with:
rust-version: ${{env.RUST_VERSION}}
jdk-version: ${{ inputs.java }}
- name: Download native library
uses: actions/download-artifact@v8
with:
name: native-lib-linux
path: native/target/release/
- name: Download JVM compile artifact
uses: actions/download-artifact@v8
with:
name: jvm-compiled-spark-${{ inputs.spark-full }}-jdk${{ inputs.java }}
- name: Extract apache-spark/ (sources + compiled output)
run: |
# Restore mtimes so Zinc skips compilation on the test JVM.
tar -xzpf apache-spark.tar.gz
rm -f apache-spark.tar.gz
- name: Setup Spark
uses: ./.github/actions/setup-spark-builder
with:
spark-version: ${{ inputs.spark-full }}
spark-short-version: ${{ inputs.spark-short }}
skip-native-build: true
skip-spark-clone: true
- name: Run Spark tests
run: |
cd apache-spark
rm -rf /root/.m2/repository/org/apache/parquet # somehow parquet cache requires cleanups
# set SBTOPTS
printf -- '-J-Xms1g\n-J-Xmx4g\n-J-XX:MaxMetaspaceSize=1g\n' > .sbtopts
export SERIAL_SBT_TESTS=1
# Per-row forked-test-JVM caps (read by Spark's SparkBuild.scala).
if [ -n "${{ matrix.module.heap }}" ]; then
export HEAP_SIZE="${{ matrix.module.heap }}"
fi
if [ -n "${{ matrix.module.metaspace }}" ]; then
export METASPACE_SIZE="${{ matrix.module.metaspace }}"
fi
# Cap parallel forked test JVMs at 1 so that even when
# SparkParallelTestGrouping is enabled we don't blow the
# 7 GB runner budget.
NOLINT_ON_COMPILE=true ENABLE_COMET=true ENABLE_COMET_ONHEAP=true ENABLE_COMET_LOG_FALLBACK_REASONS=${{ inputs.collect-fallback-logs }} \
build/sbt -Dsbt.log.noformat=true -mem $SBT_MEM \
'set Global / concurrentRestrictions := Seq(Tags.limit(Tags.ForkedTestGroup, 1))' \
${{ matrix.module.args1 }} "${{ matrix.module.args2 }}"
if [ "${{ inputs.collect-fallback-logs }}" = "true" ]; then
find . -type f -name "unit-tests.log" -print0 | xargs -0 grep -h "Comet cannot accelerate" | sed 's/.*Comet cannot accelerate/Comet cannot accelerate/' | sort -u > fallback.log
fi
env:
LC_ALL: "C.UTF-8"
# The build-jvm job pre-compiled Spark sources and Test classes, so
# SBT here only orchestrates `testOnly` — Zinc verifies "no changes"
# against the unpacked apache-spark/ tree and skips compilation. We
# cap SBT heap so the freed RAM goes
# to the forked test JVM and OS/container overhead, fixing the
# cgroup-OOM SIGKILLs we saw on sql_core-* under 7 GB runners.
SBT_MEM: "1024"
# G1GC + tuning for the SBT orchestrator JVM. -Xss4m replaces the
# launcher's -Xss64m default (no compile here, deep recursion not
# needed). UseStringDeduplication and MaxMetaspaceSize cap real
# and ceiling footprint. ExitOnOutOfMemoryError fails fast.
SBT_OPTS: >-
-Xss4m
-XX:+UseG1GC
-XX:+UseStringDeduplication
-XX:MaxMetaspaceSize=384m
-XX:G1HeapRegionSize=2m
-XX:InitiatingHeapOccupancyPercent=35
-XX:+ParallelRefProcEnabled
-XX:+ExitOnOutOfMemoryError
# Mirror Spark's own JDK 21 / 25 CI workaround. apache/spark's
# build_java21.yml and build_java25.yml set this same env var to
# process-isolate the V1/V2 Parquet and Orc source suites because
# they exhibit cross-suite resource interactions (file-stream and
# thread leaks) under the newer JDKs. project/SparkBuild.scala
# reads DEDICATED_JVM_SBT_TESTS and forks a separate JVM per
# listed suite. Empty value is a safe no-op.
DEDICATED_JVM_SBT_TESTS: ${{ inputs.spark-short == '4.0' && 'org.apache.spark.sql.execution.datasources.parquet.ParquetFileFormatV1Suite,org.apache.spark.sql.execution.datasources.parquet.ParquetFileFormatV2Suite,org.apache.spark.sql.execution.datasources.orc.OrcSourceV1Suite,org.apache.spark.sql.execution.datasources.orc.OrcSourceV2Suite' || '' }}
- name: Upload fallback log
if: ${{ inputs.collect-fallback-logs }}
uses: actions/upload-artifact@v7
with:
name: fallback-log-spark-sql-${{ matrix.module.name }}-spark-${{ inputs.spark-full }}-jdk${{ inputs.java }}
path: "**/fallback.log"
merge-fallback-logs:
if: ${{ inputs.collect-fallback-logs }}
name: merge-fallback-logs
needs: [spark-sql-test]
runs-on: ubuntu-24.04
steps:
- name: Download fallback log artifacts
uses: actions/download-artifact@v8
with:
path: fallback-logs/
- name: Merge fallback logs
run: |
find ./fallback-logs/ -type f -name "fallback.log" -print0 | xargs -0 cat | sort -u > all_fallback.log
- name: Upload merged fallback log
uses: actions/upload-artifact@v7
with:
name: all-fallback-log-spark-${{ inputs.spark-full }}-jdk${{ inputs.java }}
path: all_fallback.log