This is an automated email from the ASF dual-hosted git repository.
morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new 72e7af9736c [chore](paimon) Upgrade the docker Spark fixture to Paimon
1.4.2 (#69224)
72e7af9736c is described below
commit 72e7af9736c8cdf7fe564fed60aaef30175d9385
Author: Mingyu Chen (Rayner) <[email protected]>
AuthorDate: Mon Oct 19 07:54:41 2026 +0100
[chore](paimon) Upgrade the docker Spark fixture to Paimon 1.4.2 (#69224)
### What problem does this PR solve?
Issue Number: None
Related PR: #66346, #66536, #67023
Problem Summary:
**In short.** Ports the docker part of branch-4.1 #66346 and #66536 to
master. The Spark of the Iceberg docker environment, which creates the
Paimon fixtures and reads back what Doris writes to Paimon, moves from
Paimon 1.3.1 to 1.4.2, the version Doris itself has used since #67395.
The Paimon fixture script gets the change Paimon 1.4.2 needs,
`test_paimon_write_external_paths` gets back its weight-robin case, and
the file sizes in `test_paimon_partition_table.out` follow the new
fixture.
**Background.** #66346 upgraded Paimon to 1.4.2 on both sides of the
regression tests: the Doris FE/BE dependency, and the `paimon-spark` /
`paimon-s3` jars the docker Spark loads, shipped in the fixture package
`iceberg_data_spark40_paimon142.zip`. Master took the dependency part
with #67395 but kept the docker environment on
`iceberg_data_spark40.zip` and Paimon 1.3.1. #66536 followed the upgrade
on branch-4.x: Paimon 1.4.2 parses a present Variant shredding schema
property as JSON, so the fixture can no longer turn shredding off by
setting the property to an empty string.
**The problem, and what it cost.**
- The Paimon suites check Doris against fixtures and read-backs from an
older Paimon than the one Doris runs, so a difference between the two
versions does not show up in CI.
- `test_paimon_write_external_paths` dropped its weight-robin case when
it was ported (#68858). Paimon 1.3.1 does not know that strategy, which
Paimon 1.4 introduced: its `ExternalPathStrategy` accepts only `none`,
`specific-fs` and `round-robin`, and Spark fails on such a table with
`Could not parse value 'weight-robin' for key
'data-file.external-paths.strategy'`. Doris writes to weight-robin
tables are not tested.
- The jars cannot be upgraded on their own. Under Paimon 1.4.2,
`run13.sql` sets `parquet.variant.shreddingSchema` to `''` and then
inserts, and that insert fails with `MismatchedInputException: No
content to map due to end-of-input`. `variant_mixed_su` keeps only its
shredded row, and the Spark entrypoint, which runs under `set -e`, stops
there.
**How this PR fixes it.**
- `run-thirdparties-docker.sh` downloads
`iceberg_data_spark40_paimon142.zip`, the package branch-4.x uses.
Compared with `iceberg_data_spark40.zip`, it replaces
`paimon-s3-1.3.1.jar` and `paimon-spark-4.0-1.3.1.jar` with
`paimon-s3-1.4.2.jar` and `paimon-spark-4.0_2.13-1.4.2.jar`; the other
3881 entries have the same size and CRC. The Hong Kong and Beijing
buckets both serve it, with the same ETag.
- `iceberg.yaml.tpl` mounts the two 1.4.2 jars into the Spark container.
- The script extracts the package into `docker-compose/iceberg/data`
once and reuses that directory, so a local environment extracted from
the previous package would keep only the 1.3.1 jars, and Compose would
create empty directories for the 1.4.2 mount sources. `start_iceberg`
now checks every jar `iceberg.yaml` mounts from `data/input/jars` and
extracts the current package again when one is missing. CI starts from a
clean environment and is not affected.
- `run13.sql` removes the property with `UNSET TBLPROPERTIES` before
writing the unshredded file of `variant_mixed_su` (#66536), so the table
still has one shredded and one unshredded file. The other rows
branch-4.x added to `run13.sql`, a primary-key Variant table, come with
a separate change and are not part of this PR.
- `test_paimon_write_external_paths` creates the weight-robin table
again, writes six rows from Doris in separate statements, checks that
every data file is under one of the two weighted paths, and compares the
rows Doris and Spark read, as in branch-4.x (#67023).
- `test_paimon_partition_table.out` is regenerated. Paimon 1.4.2 writes
smaller Parquet files for the `run07.sql` tables, so the file size
column of `SHOW PARTITIONS` changes, for example 2216 to 2100 bytes;
partitions, row counts and file counts do not. The 19 new sizes equal
those in the branch-4.x copy of the file, which was generated with the
same package (#66346 made the same change there).
**Results.** On a local single-BE cluster, with the Iceberg docker
environment rebuilt from scratch by the script (it downloaded and
unpacked the new package):
| | Before (Paimon 1.3.1 in docker Spark) | After (Paimon 1.4.2) |
|---|---|---|
| Spark container start | Succeeds | Succeeds; every fixture script
runs, `variant_mixed_su` has both rows |
| Same start with only the jars upgraded | — | Fails at the `run13.sql`
insert after the empty shredding property |
| Weight-robin table | Spark fails: `Could not parse value
'weight-robin'` | Created and read by Spark; Doris writes six rows to
the weighted paths |
| `SHOW PARTITIONS` on the `run07.sql` tables | Sizes as in master's
`.out` | Sizes as in branch-4.x's `.out` |
Of the 94 suites under `external_table_p0/paimon`, every suite that can
run on this machine passes with the new package: the 72 that passed at
once, plus `test_paimon_write_external_paths` and
`test_paimon_partition_table` with the regenerated `.out` files, and
`paimon_time_travel`, which converts commit times with the JVM default
time zone and needs `TZ=Asia/Shanghai` locally. The others need what
this machine does not run: the Hive docker environment (HDFS or HMS, 12
suites), cloud credentials (3), or Linux `/proc` (1). Three suites
failed because the local FE/BE was not a master build. For two of them
the checks that touch the new Spark pass: `test_paimon_catalog_variant`,
including its `variant_mixed_su` blocks, without the profile check that
needs counters this BE lacks, and the version of
`test_paimon_write_variant_errors` that matches this FE, which reads
back Doris writes with Spark. The third, `test_paimon_alter_properties`,
does not use Spark.
Co-authored-by: Socrates <[email protected]>
Co-authored-by: Gabriel <[email protected]>
---
.../docker-compose/iceberg/iceberg.yaml.tpl | 4 +--
.../create_preinstalled_scripts/paimon/run13.sql | 6 ++--
docker/thirdparties/run-thirdparties-docker.sh | 23 ++++++++++---
.../paimon/test_paimon_partition_table.out | 38 +++++++++++-----------
.../write/test_paimon_write_external_paths.out | 9 +++++
.../write/test_paimon_write_external_paths.groovy | 28 ++++++++++++++--
6 files changed, 77 insertions(+), 31 deletions(-)
diff --git a/docker/thirdparties/docker-compose/iceberg/iceberg.yaml.tpl
b/docker/thirdparties/docker-compose/iceberg/iceberg.yaml.tpl
index 774c83a5db3..ea267a4edea 100644
--- a/docker/thirdparties/docker-compose/iceberg/iceberg.yaml.tpl
+++ b/docker/thirdparties/docker-compose/iceberg/iceberg.yaml.tpl
@@ -35,8 +35,8 @@ services:
- ./spark-defaults.conf:/opt/spark/conf/spark-defaults.conf
-
./data/input/jars/iceberg-aws-bundle-1.10.1.jar:/opt/spark/jars/iceberg-aws-bundle-1.10.1.jar
-
./data/input/jars/iceberg-spark-runtime-4.0_2.13-1.10.1.jar:/opt/spark/jars/iceberg-spark-runtime-4.0_2.13-1.10.1.jar
- -
./data/input/jars/paimon-s3-1.3.1.jar:/opt/spark/jars/paimon-s3-1.3.1.jar
- -
./data/input/jars/paimon-spark-4.0-1.3.1.jar:/opt/spark/jars/paimon-spark-4.0-1.3.1.jar
+ -
./data/input/jars/paimon-s3-1.4.2.jar:/opt/spark/jars/paimon-s3-1.4.2.jar
+ -
./data/input/jars/paimon-spark-4.0_2.13-1.4.2.jar:/opt/spark/jars/paimon-spark-4.0_2.13-1.4.2.jar
environment:
- AWS_ACCESS_KEY_ID=admin
- AWS_SECRET_ACCESS_KEY=password
diff --git
a/docker/thirdparties/docker-compose/iceberg/scripts/create_preinstalled_scripts/paimon/run13.sql
b/docker/thirdparties/docker-compose/iceberg/scripts/create_preinstalled_scripts/paimon/run13.sql
index 37ac16ac3d1..ec071966382 100644
---
a/docker/thirdparties/docker-compose/iceberg/scripts/create_preinstalled_scripts/paimon/run13.sql
+++
b/docker/thirdparties/docker-compose/iceberg/scripts/create_preinstalled_scripts/paimon/run13.sql
@@ -63,8 +63,10 @@ tblproperties (
insert into variant_mixed_su values
(1, date '2026-06-01',
parse_json('{"name":"alice","age":18,"layout":"shredded"}'));
-alter table variant_mixed_su set tblproperties (
- 'parquet.variant.shreddingSchema' = ''
+-- Paimon 1.4.2 parses every present shredding schema as JSON, so remove the
property
+-- before writing unshredded files.
+alter table variant_mixed_su unset tblproperties (
+ 'parquet.variant.shreddingSchema'
);
insert into variant_mixed_su values
(2, date '2026-07-01',
parse_json('{"name":"bob","age":30,"layout":"unshredded"}'));
diff --git a/docker/thirdparties/run-thirdparties-docker.sh
b/docker/thirdparties/run-thirdparties-docker.sh
index fb2d8bb4f3a..0f83913380b 100755
--- a/docker/thirdparties/run-thirdparties-docker.sh
+++ b/docker/thirdparties/run-thirdparties-docker.sh
@@ -1437,21 +1437,34 @@ start_iceberg() {
register_stack_metadata "iceberg"
"${ROOT}/docker-compose/iceberg/iceberg.yaml"
"${ROOT}/docker-compose/iceberg/iceberg.env"
compose_down_stack "${ROOT}/docker-compose/iceberg/iceberg.yaml"
"${ROOT}/docker-compose/iceberg/iceberg.env" --remove-orphans
if [[ "${STOP}" -ne 1 ]]; then
+ # data/ is extracted from the fixture archive once and then reused. A
data/ from an older archive lacks
+ # jars that iceberg.yaml now mounts, and Compose would create empty
directories in their place, so
+ # start over from the current archive.
+ if [[ -d "${ICEBERG_DIR}/data" ]]; then
+ local jar
+ for jar in $(grep -o '\./data/input/jars/[^:]*\.jar'
"${ICEBERG_DIR}/iceberg.yaml"); do
+ if [[ ! -f "${ICEBERG_DIR}/${jar#./}" ]]; then
+ echo "${ICEBERG_DIR}/${jar#./} is missing,
${ICEBERG_DIR}/data is from an older archive"
+ host_admin_cmd rm -rf "${ICEBERG_DIR:?}/data"
+ break
+ fi
+ done
+ fi
if [[ ! -d "${ICEBERG_DIR}/data" ]]; then
echo "${ICEBERG_DIR}/data does not exist"
(
cd "${ICEBERG_DIR}" || exit 1
rm -f iceberg_data*.zip
if [[ "${HOST_OS}" == "Darwin" ]]; then
- curl -fL -o iceberg_data_spark40.zip \
-
"https://${s3BucketName}.${s3Endpoint}/regression/datalake/pipeline_data/iceberg_data_spark40.zip"
+ curl -fL -o iceberg_data_spark40_paimon142.zip \
+
"https://${s3BucketName}.${s3Endpoint}/regression/datalake/pipeline_data/iceberg_data_spark40_paimon142.zip"
else
wget -P "${ROOT}/docker-compose/iceberg" \
-
"https://${s3BucketName}.${s3Endpoint}/regression/datalake/pipeline_data/iceberg_data_spark40.zip"
+
"https://${s3BucketName}.${s3Endpoint}/regression/datalake/pipeline_data/iceberg_data_spark40_paimon142.zip"
fi
- host_admin_cmd unzip iceberg_data_spark40.zip
+ host_admin_cmd unzip iceberg_data_spark40_paimon142.zip
host_admin_cmd mv iceberg_data data
- host_admin_cmd rm -rf iceberg_data_spark40.zip
+ host_admin_cmd rm -rf iceberg_data_spark40_paimon142.zip
)
else
echo "${ICEBERG_DIR}/data exist, continue !"
diff --git
a/regression-test/data/external_table_p0/paimon/test_paimon_partition_table.out
b/regression-test/data/external_table_p0/paimon/test_paimon_partition_table.out
index 3230ad01841..4da4e78a3ff 100644
---
a/regression-test/data/external_table_p0/paimon/test_paimon_partition_table.out
+++
b/regression-test/data/external_table_p0/paimon/test_paimon_partition_table.out
@@ -1,30 +1,30 @@
-- This file is automatically generated. You should know what you did if you
want to edit this
-- !show_partition_sales_by_date --
-sale_date=2024-01-15 sale_date 2 2216 1
-sale_date=2024-01-16 sale_date 2 4217 2
-sale_date=2024-01-17 sale_date 1 2118 1
+sale_date=2024-01-15 sale_date 2 2100 1
+sale_date=2024-01-16 sale_date 2 3985 2
+sale_date=2024-01-17 sale_date 1 2002 1
-- !show_partition_sales_by_region --
-region=China-Beijing region 1 2425 1
-region=Japan-Tokyo region 1 2420 1
-region=USA-California region 1 2454 1
+region=China-Beijing region 1 2295 1
+region=Japan-Tokyo region 1 2290 1
+region=USA-California region 1 2324 1
-- !show_partition_sales_by_date_region --
-sale_date=2024-01-15/region=China-Beijing sale_date,region 1
2627 1
-sale_date=2024-01-15/region=Japan-Tokyo sale_date,region 1
2614 1
-sale_date=2024-01-15/region=USA-California sale_date,region 1
2655 1
-sale_date=2024-01-16/region=China-Shanghai sale_date,region 1
2636 1
-sale_date=2024-01-16/region=Japan-Osaka sale_date,region 1
2636 1
-sale_date=2024-01-16/region=USA-New York sale_date,region 1
2643 1
+sale_date=2024-01-15/region=China-Beijing sale_date,region 1
2485 1
+sale_date=2024-01-15/region=Japan-Tokyo sale_date,region 1
2472 1
+sale_date=2024-01-15/region=USA-California sale_date,region 1
2513 1
+sale_date=2024-01-16/region=China-Shanghai sale_date,region 1
2494 1
+sale_date=2024-01-16/region=Japan-Osaka sale_date,region 1
2494 1
+sale_date=2024-01-16/region=USA-New York sale_date,region 1
2501 1
-- !show_partition_events_by_hour --
-hour_partition=2024-01-15-10 hour_partition 2 2361 1
-hour_partition=2024-01-15-11 hour_partition 2 4515 2
-hour_partition=2024-01-15-14 hour_partition 2 2371 1
+hour_partition=2024-01-15-10 hour_partition 2 2245 1
+hour_partition=2024-01-15-11 hour_partition 2 4283 2
+hour_partition=2024-01-15-14 hour_partition 2 2255 1
-- !show_partition_logs_by_date_hierarchy --
-year_val=2024/month_val=1/day_val=15 year_val,month_val,day_val 2
2841 1
-year_val=2024/month_val=1/day_val=16 year_val,month_val,day_val 2
5323 2
-year_val=2024/month_val=1/day_val=17 year_val,month_val,day_val 1
2658 1
-year_val=2024/month_val=2/day_val=1 year_val,month_val,day_val 1
2686 1
+year_val=2024/month_val=1/day_val=15 year_val,month_val,day_val 2
2701 1
+year_val=2024/month_val=1/day_val=16 year_val,month_val,day_val 2
5042 2
+year_val=2024/month_val=1/day_val=17 year_val,month_val,day_val 1
2517 1
+year_val=2024/month_val=2/day_val=1 year_val,month_val,day_val 1
2546 1
diff --git
a/regression-test/data/external_table_p0/paimon/write/test_paimon_write_external_paths.out
b/regression-test/data/external_table_p0/paimon/write/test_paimon_write_external_paths.out
index 136ed02abc0..a7208f2c815 100644
---
a/regression-test/data/external_table_p0/paimon/write/test_paimon_write_external_paths.out
+++
b/regression-test/data/external_table_p0/paimon/write/test_paimon_write_external_paths.out
@@ -32,9 +32,18 @@ p2 4 4
p3 5 4
p3 6 3
+-- !external_weight_robin --
+1 weight-1
+2 weight-2
+3 weight-3
+4 weight-4
+5 weight-5
+6 weight-6
+
-- !external_specific_fs --
1 specific-1
2 specific-2
-- !external_default_path --
1 default-path
+
diff --git
a/regression-test/suites/external_table_p0/paimon/write/test_paimon_write_external_paths.groovy
b/regression-test/suites/external_table_p0/paimon/write/test_paimon_write_external_paths.groovy
index 6077175cb29..d12b3e3a751 100644
---
a/regression-test/suites/external_table_p0/paimon/write/test_paimon_write_external_paths.groovy
+++
b/regression-test/suites/external_table_p0/paimon/write/test_paimon_write_external_paths.groovy
@@ -59,9 +59,19 @@ suite("test_paimon_write_external_paths",
"p0,external,paimon") {
'data-file.external-paths.strategy' = 'round-robin'
);
- -- The Spark fixture uses Paimon 1.3.1, which cannot create a table
with the
- -- weight-robin strategy introduced in Paimon 1.4. Re-enable that
strategy
- -- after the fixture has a compatible Spark connector.
+ DROP TABLE IF EXISTS paimon.${dbName}.t_weight_robin;
+ CREATE TABLE paimon.${dbName}.t_weight_robin (
+ id INT, payload STRING
+ ) USING paimon
+ TBLPROPERTIES (
+ 'primary-key' = 'id',
+ 'bucket' = '1',
+ 'write-only' = 'true',
+ 'target-file-size' = '1 kb',
+ 'data-file.external-paths' =
'${pathRoot}/weight-a,${pathRoot}/weight-b',
+ 'data-file.external-paths.strategy' = 'weight-robin',
+ 'data-file.external-paths.weights' = '1,1'
+ );
DROP TABLE IF EXISTS paimon.${dbName}.t_specific_fs;
CREATE TABLE paimon.${dbName}.t_specific_fs (
@@ -197,6 +207,18 @@ suite("test_paimon_write_external_paths",
"p0,external,paimon") {
assertDorisSparkRows("external_round_robin_changed", "t_round_robin",
"pt, id, length(payload)", "ORDER BY pt, id")
+ (1..6).each { id ->
+ sql """INSERT INTO t_weight_robin VALUES (${id}, 'weight-${id}')"""
+ }
+ def weightedFiles = dataFiles("t_weight_robin")
+ assertFalse(weightedFiles.isEmpty())
+ assertTrue(weightedFiles.every {
+ it.startsWith("${pathRoot}/weight-a/") ||
+ it.startsWith("${pathRoot}/weight-b/")
+ })
+ assertDorisSparkRows("external_weight_robin", "t_weight_robin",
+ "id, payload", "ORDER BY id")
+
sql """INSERT INTO t_specific_fs VALUES (1, 'specific-1')"""
sql """INSERT INTO t_specific_fs VALUES (2, 'specific-2')"""
def specificFiles = dataFiles("t_specific_fs")
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]