diff --git a/.github/workflows/README.md b/.github/workflows/README.md index 8a8791e711..3db3dab1b2 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -38,8 +38,8 @@ is a `workflow_call` reusable invoked from the umbrella. (PR+push) (PR+push) (PR+push) | | | v v v - spark_3_4 / spark_4_1 iceberg_1_8 / 1_9 - (push or PR + label) (push only) + spark_3_4 / spark_4_1 / spark_4_2 iceberg_1_8 / 1_9 + (push or PR + label) (push only) reusable workflows invoked via `uses:`: pr_build_linux.yml spark_sql_test_reusable.yml @@ -62,6 +62,7 @@ is a `workflow_call` reusable invoked from the umbrella. | `spark_4_0` | PR or push, paths matched | Spark 4.0 sources | | `spark_3_4` | push, **or** PR with `run-spark-3.4-tests` label | Spark 3.4 sources | | `spark_4_1` | push, **or** PR with `run-spark-4.1-tests` label | Spark 4.1 sources | +| `spark_4_2` | push, **or** PR with `run-spark-4.2-tests` label | Spark 4.2 sources | | `iceberg_1_10` | PR or push, paths matched | Iceberg sources | | `iceberg_1_8` | push only | Iceberg sources | | `iceberg_1_9` | push only | Iceberg sources | @@ -86,14 +87,14 @@ umbrella doesn't watch, or operate independently of the rest of CI: ## Reusable workflows (called by `ci.yml`) -| File | Called from `ci.yml` job(s) | -| --------------------------------- | -------------------------------------------------- | -| `pr_build_linux.yml` | `pr_build_linux` | -| `pr_build_macos.yml` | `pr_build_macos` | -| `pr_benchmark_check.yml` | `pr_benchmark_check` | -| `docs.yaml` | `docs` | -| `spark_sql_test_reusable.yml` | `spark_3_4`, `spark_3_5`, `spark_4_0`, `spark_4_1` | -| `iceberg_spark_test_reusable.yml` | `iceberg_1_8`, `iceberg_1_9`, `iceberg_1_10` | +| File | Called from `ci.yml` job(s) | +| --------------------------------- | --------------------------------------------------------------- | +| `pr_build_linux.yml` | `pr_build_linux` | +| `pr_build_macos.yml` | `pr_build_macos` | +| `pr_benchmark_check.yml` | `pr_benchmark_check` | +| `docs.yaml` | `docs` | +| `spark_sql_test_reusable.yml` | `spark_3_4`, `spark_3_5`, `spark_4_0`, `spark_4_1`, `spark_4_2` | +| `iceberg_spark_test_reusable.yml` | `iceberg_1_8`, `iceberg_1_9`, `iceberg_1_10` | ## Modifying path filters diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index be277efa29..6069fb2d43 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,6 +58,7 @@ jobs: github.event.label.name == 'run-spark-3.4-tests' || github.event.label.name == 'run-spark-4.0-tests' || github.event.label.name == 'run-spark-4.1-tests' || + github.event.label.name == 'run-spark-4.2-tests' || github.event.label.name == 'run-iceberg-tests' steps: - uses: actions/checkout@v7 @@ -114,6 +115,7 @@ jobs: spark_3_5: ${{ steps.compute.outputs.spark_3_5 }} spark_4_0: ${{ steps.compute.outputs.spark_4_0 }} spark_4_1: ${{ steps.compute.outputs.spark_4_1 }} + spark_4_2: ${{ steps.compute.outputs.spark_4_2 }} iceberg_1_8: ${{ steps.compute.outputs.iceberg_1_8 }} iceberg_1_9: ${{ steps.compute.outputs.iceberg_1_9 }} iceberg_1_10: ${{ steps.compute.outputs.iceberg_1_10 }} @@ -263,6 +265,23 @@ jobs: spark-full: '4.1.2' java: 17 + spark_4_2: + name: Spark SQL Tests (Spark 4.2) + needs: changes + # Main-only by default; PRs need the `run-spark-4.2-tests` label. Spark 4.2 + # support is still experimental, so keep it off the default PR path. + if: | + needs.changes.outputs.spark_4_2 == 'true' && + (github.event_name == 'push' || + github.event_name == 'workflow_dispatch' || + (github.event_name == 'pull_request' && + contains(github.event.pull_request.labels.*.name, 'run-spark-4.2-tests'))) + uses: ./.github/workflows/spark_sql_test_reusable.yml + with: + spark-short: '4.2' + spark-full: '4.2.0' + java: 17 + iceberg_1_8: name: Iceberg Spark SQL Tests (Iceberg 1.8) needs: changes diff --git a/dev/ci/compute-changes.py b/dev/ci/compute-changes.py index 47af20d450..046cedce0b 100644 --- a/dev/ci/compute-changes.py +++ b/dev/ci/compute-changes.py @@ -177,6 +177,28 @@ ".github/actions/setup-builder/**", ".github/actions/setup-spark-builder/**", ], + "spark_4_2": [ + "native/**/src/**", + "native/**/Cargo.toml", + "native/Cargo.lock", + "common/src/main/**", + "common/pom.xml", + "spark/src/main/**", + "!spark/src/main/spark-3.4/**", + "!spark/src/main/spark-3.5/**", + "!spark/src/main/spark-3.x/**", + "!spark/src/main/spark-4.0/**", + "!spark/src/main/spark-4.1/**", + "!spark/src/main/scala/org/apache/comet/GenerateDocs.scala", + "spark/pom.xml", + "dev/diffs/4.2.0.diff", + "pom.xml", + "rust-toolchain.toml", + ".github/workflows/ci.yml", + ".github/workflows/spark_sql_test_reusable.yml", + ".github/actions/setup-builder/**", + ".github/actions/setup-spark-builder/**", + ], "iceberg_1_8": [ "native/**/src/**", "native/**/Cargo.toml", diff --git a/dev/diffs/4.2.0.diff b/dev/diffs/4.2.0.diff new file mode 100644 index 0000000000..b1f51e1251 --- /dev/null +++ b/dev/diffs/4.2.0.diff @@ -0,0 +1,4230 @@ +diff --git a/core/src/test/scala/org/apache/spark/storage/FallbackStorageSuite.scala b/core/src/test/scala/org/apache/spark/storage/FallbackStorageSuite.scala +index 6df8bc85b51..dabb75e2b75 100644 +--- a/core/src/test/scala/org/apache/spark/storage/FallbackStorageSuite.scala ++++ b/core/src/test/scala/org/apache/spark/storage/FallbackStorageSuite.scala +@@ -268,6 +268,11 @@ class FallbackStorageSuite extends SparkFunSuite with LocalSparkContext { + } + + test("Upload from all decommissioned executors") { ++ // Comet replaces Spark's shuffle with its own native shuffle, which is incompatible with ++ // the fallback storage migration path used by BlockManagerDecommissioner. ++ val cometEnv = System.getenv("ENABLE_COMET") ++ assume(cometEnv == null || cometEnv == "0" || cometEnv == "false", ++ "Skipped when Comet is enabled: incompatible with Comet native shuffle storage") + sc = new SparkContext(getSparkConf(2, 2)) + withSpark(sc) { sc => + TestUtils.waitUntilExecutorsUp(sc, 2, 60000) +@@ -298,6 +303,11 @@ class FallbackStorageSuite extends SparkFunSuite with LocalSparkContext { + } + + test("Upload multi stages") { ++ // Comet replaces Spark's shuffle with its own native shuffle, which is incompatible with ++ // the fallback storage migration path used by BlockManagerDecommissioner. ++ val cometEnv = System.getenv("ENABLE_COMET") ++ assume(cometEnv == null || cometEnv == "0" || cometEnv == "false", ++ "Skipped when Comet is enabled: incompatible with Comet native shuffle storage") + sc = new SparkContext(getSparkConf()) + withSpark(sc) { sc => + TestUtils.waitUntilExecutorsUp(sc, 1, 60000) +@@ -332,6 +342,11 @@ class FallbackStorageSuite extends SparkFunSuite with LocalSparkContext { + + CompressionCodec.shortCompressionCodecNames.keys.foreach { codec => + test(s"$codec - Newly added executors should access old data from remote storage") { ++ // Comet replaces Spark's shuffle with its own native shuffle, which is incompatible with ++ // the fallback storage migration path used by BlockManagerDecommissioner. ++ val cometEnv = System.getenv("ENABLE_COMET") ++ assume(cometEnv == null || cometEnv == "0" || cometEnv == "false", ++ "Skipped when Comet is enabled: incompatible with Comet native shuffle storage") + sc = new SparkContext(getSparkConf(2, 0).set(IO_COMPRESSION_CODEC, codec)) + withSpark(sc) { sc => + TestUtils.waitUntilExecutorsUp(sc, 2, 60000) +diff --git a/pom.xml b/pom.xml +index 46558134f41..e58691eef40 100644 +--- a/pom.xml ++++ b/pom.xml +@@ -154,6 +154,8 @@ + 4.0.3 + 2.5.3 + 2.0.8 ++ 4.2 ++ 1.0.0-SNAPSHOT + + + org.apache.datasketches +diff --git a/sql/core/pom.xml b/sql/core/pom.xml +index 82810f181ac..21a83831188 100644 +--- a/sql/core/pom.xml ++++ b/sql/core/pom.xml +@@ -97,6 +97,10 @@ + org.apache.spark + spark-tags_${scala.binary.version} + ++ ++ org.apache.datafusion ++ comet-spark-spark${spark.version.short}_${scala.binary.version} ++ + +